# Managed permits

Source: https://docs.settlemint.com/docs/api-reference/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](/docs/api-reference/tokens/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](/docs/api-reference/tokens/token-permits). For the feature model, see [Permit architecture](/docs/architects/components/token-features/permit).

## Prerequisites [#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 [#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.

```bash
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:

| Field      | Meaning                                                                                                                                          |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `spender`  | The address being approved to spend the holder's tokens.                                                                                         |
| `value`    | Approved amount in the token's smallest units, as a uint256 decimal string. Use the uint256 maximum for an unlimited approval, or `0` to revoke. |
| `deadline` | Signature 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:

```json
{
  "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`.

| Field           | Meaning                                                                                                           |
| --------------- | ----------------------------------------------------------------------------------------------------------------- |
| `nonce`         | EIP-2612 permit nonce assigned at signing time. Stored permits relay in nonce order.                              |
| `signatureKind` | `ecdsa` for an externally owned account holder, `bytes` for a smart-wallet holder verified on-chain via EIP-1271. |
| `status`        | Persistence status. A freshly signed permit is always `pending`.                                                  |

## Step 2: List stored permits [#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.

```bash
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:

| Field           | Meaning                                                                                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`        | `relayed` once relayed on-chain, `expired` when the deadline passed or the nonce was superseded by the owner's current on-chain nonce, otherwise `pending`. |
| `relayable`     | `true` only when the permit is `pending`, its nonce equals the owner's current on-chain nonce, and its deadline has not passed.                             |
| `relayedTxHash` | Transaction 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 [#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.

```bash
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](/docs/api-reference/tokens/token-permits) for that form.

## Endpoints [#endpoints]

| Endpoint                                                        | Use it for                                                                               |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `POST /api/v2/tokens/{tokenAddress}/features/permit/signatures` | Sign a permit over the caller's own balance and store it as pending.                     |
| `GET /api/v2/tokens/{tokenAddress}/features/permit/signatures`  | List stored permits with computed status and relayability.                               |
| `POST /api/v2/tokens/{tokenAddress}/features/permit/permits`    | Relay a stored permit by `signedPermitId`, or an externally signed permit by raw fields. |

## Troubleshooting [#troubleshooting]

| What you see                            | What to check                                                                                            |
| --------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Relay rejected: stored permit not found | Confirm the `signedPermitId` is correct and belongs to your organization. See `DALP-0662`.               |
| Relay rejected: already relayed         | A relayed permit cannot be relayed again. Sign a fresh permit. See `DALP-0663`.                          |
| Relay rejected: expired or out of order | Relay 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](/docs/api-reference/errors/platform-api-error-reference).

## Read next [#read-next]

* [Token permits](/docs/api-reference/tokens/token-permits) for relaying an externally signed permit and inspecting permit replay history.
* [permit feature API reference](/docs/api-reference/token-features/permit) for the EIP-712 domain and signing payload.
* [Permit architecture](/docs/architects/components/token-features/permit)
