SettleMint
Tokens

Managed permits

Sign an EIP-2612 permit with a holder's managed key, store it as a pending signed permit, list stored permits, and relay one later as the token custodian.

Managed permits let the platform sign an EIP-2612 approval with a holder's managed key, store it, and relay it on-chain later as the token custodian. Use this flow when the holder's key is managed by DALP and you want to prepare an approval now and submit it on-chain when it is needed.

This is a different flow from relaying an externally signed permit. If a holder signs the EIP-2612 message in their own wallet, relay it directly with Token permits. Use managed permits when DALP holds the signing key and the platform signs on the holder's behalf.

The flow has three steps:

  1. Sign and store a permit over the holder's own balance. No transaction is sent yet.
  2. List stored permits to see which one can be relayed next.
  3. Relay a stored permit on-chain as the token custodian.

For permit metadata and the EIP-712 domain, see Token permits. For the feature model, see Permit architecture.

Prerequisites

  • The token has the permit feature attached. It attaches without operator input on almost every template.
  • The signing step runs against the caller's own managed token-holding wallet. The permit owner is always the authenticated caller's wallet; it is never read from the request body, so a caller cannot sign over another holder's balance.
  • The relay step requires the token's custodian role. The custodian's sender wallet pays for the relay transaction.
  • User-session calls that sign or relay need a configured wallet-verification method, such as PIN code, secret code, or one-time password, and must include the matching walletVerification payload. API-key sessions skip wallet verification.

Step 1: Sign and store a permit

Sign an EIP-2612 permit over the caller's own balance and store it as a pending signed permit. This call signs the permit with the holder's managed key and saves it; it does not send a transaction.

curl -X POST "$DAPI_URL/api/v2/tokens/0xTOKEN/features/permit/signatures" \
  --header "X-Api-Key: $DALP_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "spender": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
    "value": "1000000000000000000",
    "deadline": "1767225600"
  }'

The body carries only the approval terms:

FieldMeaning
spenderThe address being approved to spend the holder's tokens.
valueApproved amount in the token's smallest units, as a uint256 decimal string. Use the uint256 maximum for an unlimited approval, or 0 to revoke.
deadlineSignature deadline as a Unix timestamp in seconds.

There is no owner field. The permit owner is resolved server-side from the authenticated caller's wallet.

The response returns the stored permit:

{
  "data": {
    "id": "018f9b2a-7c3e-7a10-9c1b-2f5e8d4a6b71",
    "tokenAddress": "0xTOKEN",
    "owner": "0x1111111111111111111111111111111111111111",
    "spender": "0x71c7656ec7ab88b098defb751b7401b5f6d8976f",
    "value": "1000000000000000000",
    "deadline": "1767225600",
    "nonce": "0",
    "signatureKind": "ecdsa",
    "status": "pending",
    "createdAt": "2026-06-12T08:00:00.000Z"
  },
  "links": {
    "self": "/v2/tokens/0xTOKEN/features/permit/signatures/018f9b2a-7c3e-7a10-9c1b-2f5e8d4a6b71"
  }
}

Keep the id. You pass it to the relay step. A freshly signed permit always starts as pending.

FieldMeaning
nonceEIP-2612 permit nonce assigned at signing time. Stored permits relay in nonce order.
signatureKindecdsa for an externally owned account holder, bytes for a smart-wallet holder verified on-chain via EIP-1271.
statusPersistence status. A freshly signed permit is always pending.

Step 2: List stored permits

List the token's stored permits to see which one can be relayed next. The list is scoped to your organization.

curl --globoff -X GET "$DAPI_URL/api/v2/tokens/0xTOKEN/features/permit/signatures?filter[status]=pending" \
  --header "X-Api-Key: $DALP_API_TOKEN"

Each row reports a computed display status and whether it can be relayed right now:

FieldMeaning
statusrelayed once relayed on-chain, expired when the deadline passed or the nonce was superseded by the owner's current on-chain nonce, otherwise pending.
relayabletrue only when the permit is pending, its nonce equals the owner's current on-chain nonce, and its deadline has not passed.
relayedTxHashTransaction hash of the relay, or null while the permit is unrelayed.

The list sorts by nonce ascending by default, which is relay order: the smallest unrelayed nonce relays first. Filter to one holder with ?filter[owner]=0xHOLDER, or to a status with ?filter[status]=pending. Relay the row whose relayable is true.

Step 3: Relay a stored permit

Relay a stored permit on-chain by passing its id as signedPermitId. This step requires the token's custodian role and submits the approval on the holder's behalf.

curl -X POST "$DAPI_URL/api/v2/tokens/0xTOKEN/features/permit/permits" \
  --header "X-Api-Key: $DALP_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "signedPermitId": "018f9b2a-7c3e-7a10-9c1b-2f5e8d4a6b71"
  }'

DALP loads the stored signature, checks that the permit is still relayable against the holder's live on-chain nonce, and submits it through the transaction queue. The relay returns either a synchronous completion or a queued (202) response, depending on the request mode and how the queue resolves.

When the relay settles on-chain, the stored permit's status becomes relayed and relayedTxHash is populated. The relay response itself returns the token state and transaction metadata, not the stored permit row, so read the final permit status from the list endpoint rather than the relay response. Poll the returned status URL to confirm the relay transaction reached its terminal state, then re-read the permit through GET /api/v2/tokens/{tokenAddress}/features/permit/signatures to see its relayed status and relayedTxHash.

A permit only sets an allowance. Any later transfer still runs through the token's normal compliance and transfer checks.

The same endpoint also relays an externally signed permit when you send the raw signature fields instead of signedPermitId. See Token permits for that form.

Endpoints

EndpointUse it for
POST /api/v2/tokens/{tokenAddress}/features/permit/signaturesSign a permit over the caller's own balance and store it as pending.
GET /api/v2/tokens/{tokenAddress}/features/permit/signaturesList stored permits with computed status and relayability.
POST /api/v2/tokens/{tokenAddress}/features/permit/permitsRelay a stored permit by signedPermitId, or an externally signed permit by raw fields.

Troubleshooting

What you seeWhat to check
Relay rejected: stored permit not foundConfirm the signedPermitId is correct and belongs to your organization. See DALP-0662.
Relay rejected: already relayedA relayed permit cannot be relayed again. Sign a fresh permit. See DALP-0663.
Relay rejected: expired or out of orderRelay pending permits in nonce order, and sign a new permit if the deadline has passed. See DALP-0664.

For the full error list, see the Platform API error reference.

On this page