SettleMint
Developer guidesAPI integration

Token holders and transfers

Query token holders, inspect balances, execute transfers, and understand the controls around standard, allowance-based, forced, and pre-approved transfer workflows.

DALP exposes holder and transfer APIs for day-two asset operations after a token is live. Use them to reconcile holder balances, execute transfers, inspect allowances, and operate governed exception workflows such as forced transfers or pre-approved transfers.

These APIs do not bypass asset controls. Transfers still execute against the asset's configured identity, compliance, freeze, role, allowance, and approval rules. Amount fields use the token's smallest units, sent as decimal strings.

Choose the transfer path

Pick the narrowest operation that matches the business instruction before you queue a mutation. That keeps the request shape, role requirement, and retry record clear.

  • Use a standard transfer to move the authenticated signer's balance to one or more recipients. Send transferType: "standard", with one to 10,000 recipient and amount items, and omit from.
  • Use transferFrom when the authenticated signer spends another holder's allowance. Send transferType: "transferFrom" with one item that includes from, recipient, and amount.
  • Use a forced transfer only for an approved exception workflow. Send one to 10,000 from, recipient, and amount items; the caller still needs the required token role and the contract-side forced-transfer controls still apply.
  • Use transfer approvals when the asset requires an explicit from-to approval before execution. Create the approval with fromWallet, toWallet, amount, and optional identity overrides, then revoke it through the revocation endpoint if it is no longer valid.

Use an Idempotency-Key header on transfer and forced-transfer mutations when your integration may retry after a timeout. Reuse the same key only for the same business instruction.

Endpoint summary

The token API exposes the main holder and transfer operations:

  • GET /api/v2/tokens/{tokenAddress}/holders lists holder balances for a token.
  • GET /api/v2/tokens/{tokenAddress}/holder-balances reads one holder balance.
  • GET /api/v2/tokens/{tokenAddress}/events lists indexed token events.
  • GET /api/v2/tokens/{tokenAddress}/historical-balances lists indexed balance checkpoints for tokens with the historical balances feature attached.
  • GET /api/v2/tokens/{tokenAddress}/permit-info reads EIP-2612 permit metadata for tokens with the permit feature attached.
  • POST /api/v2/tokens/{tokenAddress}/permits relays an EIP-2612 permit signature through the transaction queue.
  • POST /api/v2/tokens/{tokenAddress}/transfers executes standard or allowance-based transfers.
  • POST /api/v2/tokens/{tokenAddress}/burns burns tokens from one or more holder addresses.
  • POST /api/v2/tokens/{tokenAddress}/forced-transfers executes custodian forced transfers.
  • PUT /api/v2/tokens/{tokenAddress}/address-freezes sets or clears an address freeze.
  • POST /api/v2/tokens/{tokenAddress}/partial-freezes freezes part of a holder balance.
  • POST /api/v2/tokens/{tokenAddress}/partial-unfreezes releases part of a frozen holder balance.
  • POST /api/v2/tokens/{tokenAddress}/recoveries recovers tokens from a lost wallet to the caller's wallet.
  • POST /api/v2/tokens/{tokenAddress}/forced-recoveries recovers tokens from a lost wallet to a specified replacement wallet.
  • GET /api/v2/tokens/{tokenAddress}/transfer-approvals lists transfer approval records.
  • POST /api/v2/tokens/{tokenAddress}/transfer-approvals creates a pre-approved from-to transfer approval.
  • POST /api/v2/tokens/{tokenAddress}/transfer-approval-revocations revokes a transfer approval.

Older endpoints also exist for legacy integrations, including /api/token/{tokenAddress}/holders and /api/token/{tokenAddress}/holder. Use the /api/v2/tokens/... endpoints for new integrations because they use path-based token addresses and collection-style pagination.

List token holders

Use the holders endpoint to power cap-table style views, reconciliation jobs, and post-operation checks.

curl "https://your-platform.example.com/api/v2/tokens/0xTOKEN/holders?limit=50&sortBy=-lastUpdatedAt" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Holder collection items include:

  • account.id: the holder wallet address
  • value: the indexed token balance
  • frozen: the frozen amount in the holder balance
  • available: the spendable balance after frozen amounts and address-level freezes are applied
  • isFrozen: whether the holder address is frozen
  • lastUpdatedAt: the indexed balance update time

The collection supports pagination, filtering, and sorting. lastUpdatedAt is the default sort field, descending. You can filter by holder address, update time, and frozen-address state.

Read one holder balance

Use the holder-balance endpoint when you need to verify one address before or after an operation.

curl "https://your-platform.example.com/api/v2/tokens/0xTOKEN/holder-balances?holderAddress=0xHOLDER" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

The response contains the same holder balance fields as the holders collection, wrapped in data.holder. If the address has no positive indexed balance, the holder field can be null.

List token events

Use the token events endpoint to read indexed on-chain events for one token.

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?filter[walletAddress]=0xHOLDER" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

The response uses the canonical collection envelope:

  • data: event items
  • meta: total count and facet counts
  • links: pagination links for the current query

The default sort is -blockTimestamp, so the newest events are returned first. Supported sortable fields are blockTimestamp and blockNumber.

Supported filters are:

  • eventName
  • senderAddress
  • accountAddress
  • walletAddress, which matches senderAddress, accountAddress, or the event emitter address; supports only eq and inArray
  • transactionHash, which uses case-insensitive substring matching by default; use eq for exact matches
  • blockTimestamp date range

The token address in the path still scopes the result set. A walletAddress filter only narrows events for that token. It does not return activity from other tokens, even when the same wallet or feature contract address appears there.

Wallet address filters must use the supported operator format:

filter[walletAddress][eq]=0xHOLDER
filter[walletAddress][inArray]=0xHOLDER1,0xHOLDER2

Transaction hash shorthand uses substring matching. For an exact transaction hash match, use:

filter[transactionHash][eq]=0xTRANSACTION_HASH

Filter by event name:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?filter[eventName]=TransferCompleted" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Filter by sender address:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?filter[senderAddress]=0xSENDER" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Filter by transaction hash:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?filter[transactionHash][eq]=0xTRANSACTION_HASH" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Filter by block timestamp range:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?filter[blockTimestamp][gte]=2026-01-01T00:00:00Z&filter[blockTimestamp][lte]=2026-01-31T23:59:59Z" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Paginate through the token events collection:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/events?page[offset]=50&page[limit]=50&sort=-blockTimestamp" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

List historical balance checkpoints

Use the historical balances endpoint when you need a block-by-block balance trail for a token that has the historical balances feature attached. The endpoint returns account checkpoint rows by default. Total-supply checkpoints are available with the kind filter.

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/historical-balances?filter[account][eq]=0xHOLDER&sort=-blockNumber" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

Historical balance items include:

  • account: the holder address for account checkpoints, or the zero address for total-supply checkpoints
  • kind: account or totalSupply
  • sender: the address that triggered the checkpoint
  • oldBalance and newBalance: display balance strings
  • oldBalanceExact and newBalanceExact: exact smallest-unit values for filtering and reconciliation
  • blockNumber, blockTimestamp, txHash, and logIndex: chain position fields for ordering and replay

The endpoint uses the canonical collection envelope with data, meta, and links. The default sort is newest block first. Supported filters include account, kind, blockNumber, blockTimestamp, oldBalance, and newBalance. Use equality filters for the checkpoint discriminators: filter[account][eq]=0xHOLDER and filter[kind][eq]=totalSupply are the only operator forms for account and kind. Balance filters use exact smallest-unit values, while the response also includes display balance strings.

To include total-supply checkpoints, filter by kind:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/historical-balances?filter[kind][eq]=totalSupply" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"

If the token does not have the historical balances feature attached, the endpoint returns an empty collection envelope.

Read account activity

Use account activity endpoints when you need the event history or activity metrics for one address in the active system:

  • GET /api/v2/system/accounts/{accountAddress}/activities lists indexed events where the address is involved.
  • GET /api/v2/system/accounts/{accountAddress}/activity-metrics returns the activity time series and count for the address.

Account activity reads are visibility-scoped. The API returns activity for the caller's own wallet set, participant wallet or identity targets that the caller's role can inspect, active-system feed addresses, and configured account-abstraction infrastructure addresses that the caller's role can inspect. Requests for other arbitrary addresses return an empty collection or zero-count metrics instead of exposing unrelated activity.

Read permit metadata

Use the permit-info endpoint when an integration needs the EIP-2612 domain data and current holder nonce before collecting or relaying a permit signature. The token must be indexed in the caller's tenant scope. If the token has no attached permit feature, data is null.

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/permit-info?owner=0xHOLDER" \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx"
{
  "data": {
    "featureAddress": "0x00000000000000000000000000000000000000f3",
    "owner": "0xabcdef0000000000000000000000000000000001",
    "nonce": "12",
    "domainSeparator": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "permitTypeHash": "0x6e71edae12b1b97f4d1f60370fef10178563ef29188d1232f565f79b8f6aad8c"
  },
  "links": {
    "self": "/v2/tokens/0xTOKEN/permit-info"
  }
}

Response fields are:

  • featureAddress: the attached permit feature contract address that was read
  • owner: the queried holder address, or null when no owner query parameter was supplied
  • nonce: the current permit nonce for the queried holder, or null when no owner was supplied
  • domainSeparator: the EIP-712 domain separator reported by the permit feature
  • permitTypeHash: the EIP-712 Permit struct typehash used by the feature

When you only need domain metadata, omit owner. The endpoint then reads the domain separator without reading a holder nonce. If live permit metadata cannot be read from the attached feature, the API returns a token feature availability error instead of returning stale nonce data.

Relay a permit signature

Use the permits endpoint after a holder signs an EIP-2612 Permit message. The signature authorizes spender for value in the token's smallest units. The API caller supplies the transaction-queue sender wallet that submits the permit call to the attached permit feature.

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/permits \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "0xabcdef0000000000000000000000000000000001",
    "spender": "0xabcdef0000000000000000000000000000000002",
    "value": "1000000000000000000",
    "deadline": "1767225600",
    "v": 27,
    "r": "0x1111111111111111111111111111111111111111111111111111111111111111",
    "s": "0x2222222222222222222222222222222222222222222222222222222222222222"
  }'

Permit inputs are:

FieldDescription
ownerHolder address that signed the permit.
spenderAddress approved to spend the holder's tokens.
valueApproved token amount in the token's smallest units.
deadlineSignature deadline as a Unix timestamp in seconds.
vECDSA recovery id. The value must be 27 or 28.
rECDSA signature r value as a 32-byte hex string.
sECDSA signature s value as a 32-byte hex string.

The token must have the permit feature attached. The holder signature authorizes the allowance, so the relay caller does not need a token role such as governance, supply management, or custody. The caller still needs authenticated API access to the token in its tenant scope, a verified sender wallet, and the normal transaction-queue path for submitting the permit call. After the queue accepts the call, the response follows the same queued-operation envelope used by other token feature mutations.

Execute standard transfers

Use standard transfers when the authenticated signer is moving its own balance to one or more recipients.

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/transfers \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: transfer-northwind-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "transferType": "standard",
    "transfers": [
      {
        "recipient": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
        "amount": "1000000000000000000"
      }
    ]
  }'

Each request accepts between 1 and 10,000 transfer items. For standard transfers, do not include from addresses.

A transfer response uses the standard blockchain mutation envelope. Store the returned transaction hash or queued action status with your workflow record, then verify the final chain result through transaction tracking.

Before the API queues a standard transfer, it checks the sender's indexed available balance for the total requested amount. Available balance excludes frozen amounts and returns zero for frozen holder addresses. If the token metadata or latest holder state is not indexed yet, the pre-check can also see zero available balance. If the pre-check rejects the request, reduce the amount or wait for recent token, balance, or freeze changes to index before retrying.

Standard transfer batching

Standard transfer batches use the token's batchTransfer path when the request contains more than one transfer item. Requests with up to 10 transfer items are queued as one on-chain batch transaction. Larger requests enter the durable batch execution path, which estimates a safe chunk size, processes chunks sequentially, and records the resulting transaction hashes.

This changes the operational boundary by batch size:

Request shapeExecution behaviorOperational note
1 standard transferOne transfer transactionUse for a single sender-to-recipient move.
2 to 10 standard transfersOne batchTransfer transactionThe batch succeeds or reverts as one transaction.
11 to 10,000 standard transfersChunked durable batch executionReconcile all returned transaction hashes. If a later chunk fails, earlier chunks may already be on-chain.
Any multi-item transferFrom requestRejected before executionSubmit one transferFrom request per allowance-based transfer.

Use one Idempotency-Key per business instruction. For large standard batches, retry the same request with the same key after a timeout so the platform can reattach to the accepted queued operation instead of accepting a duplicate batch.

Execute allowance-based transfers

Use transferFrom when the operation spends from another address using an allowance.

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/transfers \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "transferType": "transferFrom",
    "transfers": [
      {
        "from": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
        "recipient": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
        "amount": "1000000000000000000"
      }
    ]
  }'

For transferFrom, every transfer item must include a from address. A transferFrom request supports one transfer item only. If you need to spend from multiple allowance sources or send to multiple recipients, send one request per transferFrom operation and reconcile each queued transaction separately. Do not build retry logic around a multi-item transferFrom request because DALP rejects or fails it before queueing the allowance-based batch.

Burn holder balances

Use burns when an authorized operator needs to remove tokens from one or more holder addresses. The token must support burning, and the signer must have the required token role.

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/burns \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "addresses": ["0x8ba1f109551bD432803012645Ac136ddd64DBA72"],
    "amounts": ["1000000000000000000"]
  }'

addresses and amounts must have the same number of items. A burn request can include up to 100 holder addresses. Amounts use the token's raw base units. When the request contains more than one holder address, DALP queues one batchBurn transaction for the matching address and amount arrays.

Before the API queues a burn, it checks each holder's indexed available balance against the requested amount for that holder. Available balance excludes frozen amounts and returns zero for frozen holder addresses. If token metadata or holder state is not indexed yet, the pre-check can see zero available balance. If a pre-check fails, adjust the burn amount or retry after the indexer reflects the latest token, balance, and freeze state.

Execute forced transfers

Forced transfers are governed exception operations. Use them only when the institution has the proper operating basis and the signer has the required asset role.

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/forced-transfers \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: forced-transfer-case-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "transfers": [
      {
        "from": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
        "recipient": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
        "amount": "1000000000000000000"
      }
    ]
  }'

Forced transfers require matching from, recipient, and amount values for each transfer item. A single request can include up to 10,000 transfer items. Store the business reason, approval evidence, and resulting transaction hash outside the API call as part of your exception workflow.

Freeze holder addresses and balances

Use freeze operations when a custodian needs to stop or limit transfers for a specific holder address. The token must support custodian operations, and the signer must have the custodian role on that token. Address freezes set or clear the holder-level freeze flag. Partial freezes lock a positive amount of one holder's balance, and partial unfreezes release a positive amount that was previously frozen.

Set an address freeze:

curl -X PUT https://your-platform.example.com/api/v2/tokens/0xTOKEN/address-freezes \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: freeze-address-case-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
    "freeze": true
  }'

Clear an address freeze by sending the same holder address with freeze set to false:

curl -X PUT https://your-platform.example.com/api/v2/tokens/0xTOKEN/address-freezes \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: clear-address-freeze-case-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
    "freeze": false
  }'

The CLI dalp tokens freeze-address command sets the address freeze flag. Use the API example above to clear the holder-level flag; partial unfreezes remain a separate operation for releasing a frozen balance amount.

Freeze part of a holder balance:

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/partial-freezes \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: partial-freeze-case-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
    "amount": "1000000000000000000"
  }'

When the indexer already has a token-holder balance row, the partial-freeze API checks the holder's indexed available balance before queueing the transaction. Available balance excludes amounts that are already frozen. If that pre-check rejects the request, reduce the amount or wait for the indexer to reflect a recent transfer before retrying. If the holder row is not indexed yet, the API can still queue the transaction and the on-chain freeze call enforces the balance constraint.

Release part of a frozen balance:

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/partial-unfreezes \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: partial-unfreeze-case-2026-01-15-001" \
  -H "Content-Type: application/json" \
  -d '{
    "userAddress": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
    "amount": "1000000000000000000"
  }'

Freeze and unfreeze operations require the custodian role on a token that supports custodian operations. Use a stable Idempotency-Key for each freeze, clear-freeze, partial-freeze, or partial-unfreeze instruction that your integration may retry. Reuse the same key only when the method, path, and request body are the same. Use the holder and event endpoints before and after the mutation when your operating process requires evidence of the affected address, amount, and resulting transaction.

Freeze operations are single-holder operations. To freeze several holder addresses, send one address-freeze request per holder and reconcile each queued transaction. The freeze is enforced after the transaction confirms on-chain and the token or holder state is read back. Until then, treat the operation as queued or pending in your operating workflow.

If a batch transfer must stop because one transfer item is on compliance hold, do not include that item in a standard transfer batch. Use the TransferApproval workflow when the asset requires pre-approval, or freeze the affected holder address or balance before submitting transfers that must not move. Keep the hold reason, approval evidence, and release decision outside the API call in your compliance record.

Recover tokens from a lost wallet

Use recovery operations when a holder has lost access to a wallet and the institution's recovery process has approved a replacement path.

Recover tokens from a lost wallet to the caller's wallet:

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/recoveries \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "lostWallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
  }'

Force recover tokens from a lost wallet to a specified replacement wallet:

curl -X POST https://your-platform.example.com/api/v2/tokens/0xTOKEN/forced-recoveries \
  -H "X-Api-Key: sm_dalp_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "lostWallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
    "newWallet": "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
  }'

Standard recovery requires the emergency role. Forced recovery requires the custodian role because it specifies both the lost wallet and the replacement wallet. Store the recovery approval, identity evidence, and transaction outcome in your operating record.

Transfer approval workflows

For assets that use the TransferApproval compliance module, an approval authority can pre-approve transfers from one identity to another for a specific approved amount. The token's configured approval mode determines how that approved amount can be consumed.

Use these operations when your transfer process requires explicit maker-checker style approval before a holder initiates the transfer:

  1. Configure the token's TransferApproval module with the correct parameter schema for the installed module. Use either exemption/one-time-use settings or approval-mode settings; do not mix them.
  2. Create the transfer approval for the source identity, recipient identity, and approved amount.
  3. Let the holder initiate a transfer that fits the configured approval mode.
  4. List transfer approvals to inspect pending, consumed, or revoked approvals.
  5. Revoke stale approvals that should no longer execute. Any configured approval authority can revoke a pending approval.

Approval and revocation requests use the same request-body shape:

  • fromWallet: wallet address of the source holder whose identity is approved to send.
  • toWallet: wallet address of the recipient holder whose identity is approved to receive.
  • amount: approved token amount in base units, sent as a decimal string greater than zero.
  • fromIdentityAddress and toIdentityAddress: optional identity contract address overrides. Provide both together or omit both. Use them when your workflow already stores the identity addresses from the approvals list and you want DALP to use those identities directly instead of resolving the wallets through the identity registry.

Approval modes apply when the installed TransferApproval module uses approval-mode settings. They determine how the approved amount can be consumed:

  • 0: exact amount: one transfer must match the approved value exactly. After that transfer succeeds, the approval is used and cannot be reused.
  • 1: up to once: one transfer can use any amount up to the approved value. Transferring less than the approved value still uses the approval.
  • 2: up to total: multiple transfers can spend against the approval until the approved total is exhausted. Further transfers require a new approval or a higher approved amount.

Expiry still applies in every mode. Approval expiry is configured in seconds, from 1 to 31,536,000 seconds. If the approval expires before it is consumed, create a new approval instead of retrying the stale one.

To update an approval, treat the change as a revoke-and-recreate operation:

  1. List the approval and confirm it is still pending.
  2. Revoke the stale approval using the same token, source identity, recipient identity, and amount. The API accepts wallet addresses, or identity address overrides when the identities are already known from the approvals list.
  3. Create a new approval with the corrected amount or operating evidence.
  4. Re-read the approvals list and store the new approval status in your workflow record.

The approval mode is fixed after the module is configured. To change from exact amount to an up-to mode, or between up-to modes, deploy a new TransferApproval module with the desired mode.

Controls and failure handling

For standard transfers, transferFrom, and burns, DALP checks indexed available balances before it submits the on-chain transaction. Available balance excludes frozen amounts. If the requested amount is higher than the available balance, the API returns an error before the transaction is queued.

The same pre-queue check normalizes the token and holder addresses. Send valid Ethereum addresses in 0x format for the token, source holder, and burn holder fields; malformed addresses fail before DALP submits the operation.

DALP also rejects transfer or burn requests while the token is paused for that operation. Fix the address, holder balance, frozen amount, or paused token state before retrying.

Transfer and burn mutations may fail when DALP or the underlying contracts reject the operation. Common categories include:

  • missing or insufficient role permissions
  • paused token state
  • frozen sender, recipient, or balance state
  • failed identity or compliance checks
  • missing allowance for transferFrom
  • stale, revoked, or missing transfer approval
  • insufficient available balance after frozen amounts are excluded

When a transfer or burn fails for insufficient available balance, re-read the holder balance and token events before retrying. The indexed balance may still be catching up after a recent operation, or another operation may have spent or frozen part of the balance since your last read.

When a transfer mutation returns a blockchain transaction hash, use the transaction-tracking guide to verify confirmation and recover from timeout cases. See Transaction tracking.

Operational guidance

For regulated operations, treat holder and transfer APIs as part of the evidence chain:

  1. Read holder state before the operation when the workflow requires a balance check.
  2. Execute the transfer using the narrowest operation that fits the case: standard, allowance-based, forced, or pre-approved.
  3. Capture the transaction hash or action status.
  4. Read holder state again after confirmation.
  5. Attach approvals, exception reasons, or reconciliation notes to your operating record outside DALP when required by policy.

This separates execution from governance evidence while keeping the on-chain operation enforceable by the asset's configured controls.

  • Use Transaction tracking to follow queued transfers after DALP returns a transaction hash or action status.
  • Use Token lifecycle to create and operate the token before you run holder and transfer operations.
  • Use Compliance modules to understand the identity and compliance controls that transfers must satisfy.

On this page