# token.transfer.final

Source: https://docs.settlemint.com/docs/api-reference/events/token-transfer-final
Reference for the DALP token.transfer.final webhook event that reports an indexed token transfer, final unless a chain reorg retracts it.



`token.transfer.final` tells a webhook consumer that DALP indexed a token transfer. The event is emitted at index time, so the source block can still sit inside the configured reorg window. The transfer is final unless a chain reorg invalidates the source log; in that case DALP emits a `token.transfer.retracted` event that supersedes this one.

Use this event to update downstream ledgers, reconciliation queues, and notification systems, and make those writes reversible: a consumer must handle `token.transfer.retracted` by reversing whatever this event caused, or must itself wait for the reorg depth before acting.

The event is part of the token transfer lifecycle. Pending observations can arrive before block inclusion; final events confirm the indexed on-chain log, subject to retraction. Consumers should treat the event payload as the stable transfer record and use the delivery envelope for idempotent processing.

## Delivery contract [#delivery-contract]

| Field                   | Value                                             |
| ----------------------- | ------------------------------------------------- |
| Event type              | `token.transfer.final`                            |
| Version                 | `1`                                               |
| Lifecycle state         | `final`                                           |
| Counter-signed receipts | Recommended for endpoints that consume this event |
| SDK type                | `Webhook.TokenTransferFinalV1`                    |

This row gives advice only. DALP waits for a counter-signed receipt only if the webhook endpoint's `counterSignedReceipts` value is `true` when DALP queues the delivery. When the value is `false`, a normal 2xx response completes the delivery.

Related references:

* `idxr_token`: the indexed token that emitted the transfer.

## When to consume this event [#when-to-consume-this-event]

Consume `token.transfer.final` when your integration needs an indexed transfer outcome rather than an early observation. Typical consumers include accounting exports, settlement reconciliation, investor notifications, and compliance monitoring systems.

The event fires at index time, inside the configured reorg window. A chain reorg can still invalidate the source log, and DALP then emits `token.transfer.retracted` superseding this event. Keep every downstream write this event triggers reversible, and reverse it when the retraction arrives, or delay acting until your own finality condition is met.

Do not use this event as a replacement for webhook verification. Verify the signature, timestamp, and event identifier before you process the payload.

Store `evt_id`, `request.idempotency_key` when present, and the transfer identifiers. These values keep a retry or replay from creating a duplicate downstream action.

See [webhook idempotency and on-chain outcome](/docs/events/idempotency-and-on-chain-outcome) for retry, replay, and lifecycle handling across pending, final, retracted, and recalled events.

## Payload fields [#payload-fields]

| Field             | Type             | Meaning                                                                                                        |
| ----------------- | ---------------- | -------------------------------------------------------------------------------------------------------------- |
| `tokenAddress`    | EVM address      | Token contract that emitted the transfer.                                                                      |
| `chainId`         | Integer          | EVM chain identifier for the indexed transfer.                                                                 |
| `from`            | EVM address      | Sender address recorded on the transfer log.                                                                   |
| `to`              | EVM address      | Recipient address recorded on the transfer log.                                                                |
| `amount`          | String           | Raw token amount from the transfer event. Interpret decimals from the token metadata used by your integration. |
| `transactionHash` | 32-byte EVM hash | Transaction that contained the transfer log.                                                                   |
| `blockNumber`     | Integer          | Block that contained the finalized transfer log.                                                               |
| `logIndex`        | Integer          | Log index of the transfer within the transaction receipt.                                                      |

## Payload schema [#payload-schema]

```json
{
  "type": "object",
  "properties": {
    "tokenAddress": {
      "type": "string",
      "pattern": "^0x[a-fA-F0-9]{40}$"
    },
    "chainId": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "from": {
      "type": "string",
      "pattern": "^0x[a-fA-F0-9]{40}$"
    },
    "to": {
      "type": "string",
      "pattern": "^0x[a-fA-F0-9]{40}$"
    },
    "amount": {
      "type": "string"
    },
    "transactionHash": {
      "type": "string",
      "pattern": "^0x[a-fA-F0-9]{64}$"
    },
    "blockNumber": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "logIndex": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "tokenAddress",
    "chainId",
    "from",
    "to",
    "amount",
    "transactionHash",
    "blockNumber",
    "logIndex"
  ],
  "additionalProperties": false
}
```

## TypeScript SDK example [#typescript-sdk-example]

```typescript fixture=webhook-consumer
import { verifyWebhook, type Webhook } from "@settlemint/dalp-sdk";

const result = verifyWebhook({
  rawBody,
  headers,
  secret: process.env.DALP_WEBHOOK_SECRET!,
});

if (!result.ok) {
  throw new Error(`Webhook verification failed: ${result.code}`);
}

if (result.event.type === "token.transfer.final") {
  const event: Webhook.Event<"token.transfer.final"> = result.event;
  const { transactionHash, logIndex, amount } = event.payload;

  await recordFinalTransfer({
    eventId: event.evt_id,
    idempotencyKey: event.request?.idempotency_key,
    transactionHash,
    logIndex,
    amount,
  });
}
```

## curl example [#curl-example]

```bash
curl -X POST https://consumer.example.com/dalp/webhooks \
  -H "content-type: application/json" \
  -H "webhook-id: evt_docs_token_transfer_final_001" \
  -H "webhook-timestamp: 1778112000" \
  -H "webhook-signature: v1,docs-example-signature" \
  --data '{"evt_id":"evt_docs_token_transfer_final_001","type":"token.transfer.final","version":1,"lifecycle_state":"final","request":{"idempotency_key":"idem_01JZP7R5W8M9N0P1Q2R3S4T5"},"related":{"idxr_token":"idxr_token_example"},"payload":{"tokenAddress":"0x5555555555555555555555555555555555555555","chainId":537001,"from":"0x6666666666666666666666666666666666666666","to":"0x7777777777777777777777777777777777777777","amount":"250000000000000000000","transactionHash":"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","blockNumber":18445240,"logIndex":7}}'
```

## Version history [#version-history]

* Version `1`: Initial registry entry for `token.transfer.final`.

## Deprecation [#deprecation]

This event type is not deprecated.

## Manifest [#manifest]

The machine-readable AsyncAPI entry is published in the [DALP events manifest](/.well-known/dalp-events.json).
