> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dfns.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Sumsub

> Integrate Sumsub with DFNS to meet FATF Travel Rule requirements by exchanging encrypted originator and beneficiary data with counterparty VASPs.

DFNS helps you comply with the FATF's Travel Rule through its integration with Sumsub. Outgoing transfers carry the originator and beneficiary information in the IVMS101 format, encrypted on your side with your Sumsub integration's public key. DFNS never decrypts this data.

## How to set it up

> [!NOTE]
>
> Before you set up Sumsub, you need:
>
> * A Sumsub account with Travel Rule enabled.
> * Travel Rule enabled for your DFNS tenant. If the Sumsub card shows **This feature is not enabled on your plan**, reach out to your DFNS representative.

### Connect Sumsub

**1. Open the Sumsub integration**

In the DFNS dashboard, go to **Integrations**, find the **Sumsub** card, and click **Configure**.

**2. Activate and enter your credentials**

Toggle **Activate Sumsub Integration**, then enter your **Sumsub App Token**, **Sumsub Secret Key**, and **Sumsub Webhook Signing Secret**. DFNS stores all three encrypted at rest. All three are required: without them, Sumsub travel rule evaluations fail and the policy triggers.

**3. Register the webhook in Sumsub**

Copy the webhook URL shown in the settings panel and set it in your Sumsub dashboard. See [Sumsub webhook](#sumsub-webhook).

**4. Save**

Click **Save**. The Sumsub vendor becomes available in the Travel Rule policy rule.

### Sumsub webhook

DFNS learns the final status of a Travel Rule message (TRM) from Sumsub webhooks. The URL shown in the dashboard has this form:

```text theme={null}
https://api.dfns.io/v2/policies/webhooks/travel-rule/sumsub/{orgId}
```

`{orgId}` is your organization ID, on the API base URL of your [region](https://docs.dfns.co/api-reference/regions.md). DFNS verifies each push against the `X-Payload-Digest` header, an HMAC of the raw body keyed with your webhook signing secret. The algorithm is read from `X-Payload-Digest-Alg`: `HMAC_SHA256_HEX`, `HMAC_SHA512_HEX`, or `HMAC_SHA1_HEX`. A push without `X-Payload-Digest-Alg` is verified as `HMAC_SHA1_HEX`, which older Sumsub webhooks use. A push with an invalid signature is rejected with `401`.

### Policy

Outgoing transfers are screened for Sumsub Travel Rule compliance by a policy with the following traits:

* activity kind [`Wallets:Sign`](https://docs.dfns.co/api-reference/policies#wallets-sign-activity)
* rule kind [`TravelRuleTransactionPrescreening`](https://docs.dfns.co/api-reference/policies#travelruletransactionprescreening-policy-rule), with `vendor` set to `Sumsub` and an `autoTriggerTimeoutSeconds` value
* action kind [`Block`](https://docs.dfns.co/api-reference/policies#block-policy-action)

From the dashboard, create the policy under **Policies** > **Create Policy**, choose the **Wallet usage (transfer, transaction, signature)** activity, select the **Transfers requiring travel rule compliance** rule, and set **Vendor** to **Sumsub**.

```json theme={null}
{
  "kind": "TravelRuleTransactionPrescreening",
  "configuration": {
    "vendor": "Sumsub",
    "autoTriggerTimeoutSeconds": 300
  }
}
```

Unlike the Notabene configuration, the Sumsub configuration has no `autoClearAfterDeliveredTimeoutSeconds` setting.

The rule only applies to transfers initiated through the [Transfer Asset](https://docs.dfns.co/api-reference/wallets/transfer-asset.md) API. It is not supported for transfers initiated from the dashboard. A transfer sent without a `travelRule` payload does not trigger the rule.

> [!WARNING]
>
> The travel-rule vendor is determined by the policy rule's `configuration.vendor`, and the transfer's `travelRule` payload must be of the matching kind. A mismatch triggers the policy and applies its configured action. A given wallet must be covered by at most one travel-rule policy, of any vendor. If several travel-rule policies apply to the same transfer, DFNS treats it as a misconfiguration and blocks the transfer without contacting any vendor.

### Screening flow

When the policy evaluates a transfer, DFNS creates a TRM at Sumsub and acts on the status Sumsub returns:

| Sumsub status | Result |
| - | - |
| `ACCEPTED` | The policy clears. |
| `PENDING` | The policy waits for Sumsub to push `ACCEPTED` or `REJECTED` to the webhook. After `autoTriggerTimeoutSeconds`, the policy's action applies. |
| `REJECTED` | The policy triggers. |
| Any other | Treated as rejected: the policy triggers and DFNS cancels the TRM. |

The policy also triggers without creating a TRM when the asset is not supported, or when the transfer's source address or asset decimals are unknown. If the call to Sumsub fails, the policy triggers.

After the evaluation, DFNS keeps the TRM in sync with the transfer:

* When the transfer confirms on chain, DFNS finalizes the TRM with the transaction hash.
* When the transfer is blocked, rejected, fails, or is cancelled, DFNS cancels the TRM.

### Supported assets

The Sumsub integration supports these assets. Any other asset or token contract triggers the policy.

| Network | Assets |
| - | - |
| Algorand | ALGO, USDC |
| Arbitrum One | ETH, USDC, USDT |
| Avalanche C-Chain | AVAX, USDC, USDT |
| Base | ETH, USDC, USDT |
| Berachain | BERA |
| Bitcoin | BTC |
| BNB Smart Chain | BNB, USDC, USDT |
| Cardano | ADA |
| Celo | CELO, USDC, USDT |
| Cosmos Hub | ATOM |
| Ethereum | ETH, USDC, USDT |
| Hedera | HBAR |
| IOTA | IOTA |
| Kaspa | KAS |
| Litecoin | LTC |
| Polygon | POL, USDC, USDT |
| Polymesh | POLYX |
| Solana | SOL, USDC, USDT |
| Stellar | XLM |
| Sui | SUI |
| Tron | TRX |

## Encrypt the IVMS101 payload

The originator and beneficiary information must follow the IVMS101 (interVASP Messaging Standard 101) format, version `IVMS101.2023`, and is encrypted client-side before it is sent with the transfer.

**1. Retrieve the Sumsub public key**

Call [Get Sumsub Travel Rule public key](https://docs.dfns.co/api-reference/policies/get-sumsub-travel-rule-public-key.md). It returns the RSA public key of your organization's Sumsub integration as a JWK (RFC 7517). The call fails with `412` if Travel Rule is not enabled for your tenant or the Sumsub integration is not activated on your organization.

**2. Build the IVMS101 payload**

Fill in the originator and beneficiary information using the IVMS 101.2023 field names (for example `Originator.originatorPerson[]`, `Beneficiary.beneficiaryPerson[]`, `naturalPersonNameIdentifierType`), and set `payloadMetadata.payloadVersion` to `101.2023`. Without it, Sumsub parses the payload as IVMS 101.2020 and ignores the 2023 field names. Keep the list of IVMS101 field paths you filled in (for example `Originator.originatorPerson[].naturalPerson.name.nameIdentifier[].primaryIdentifier` and `payloadMetadata.payloadVersion`). You send this list as `filledFields`.

**3. Sign, then encrypt**

Sign the payload as a JWS, then encrypt the result as a JWE with the Sumsub public key, using `RSA-OAEP-256` for key encryption and `A256GCM` for content encryption. Use the compact serialization. The result is the `data` value.

## Travel Rule transfer payload

Once the integration is configured and a policy is in place, send [transfers](https://docs.dfns.co/api-reference/wallets/transfer-asset.md) with a `travelRule` field of kind `Sumsub`.

| Field | Type | Required | Description |
| - | - | - | - |
| `kind` | string | yes | `Sumsub`. |
| `ivms101.version` | string | yes | `IVMS101.2023`. |
| `ivms101.data` | string | yes | The IVMS101 payload, JWS-signed then JWE-encrypted with the Sumsub public key (compact serialization). |
| `ivms101.filledFields` | string\[] | yes | The IVMS101 field paths present in `data`. |
| `beneficiaryVaspId` | string | no | Sumsub id of the beneficiary VASP, for a transfer to a hosted (custodial) wallet. |
| `beneficiaryWalletType` | string | no | `unhosted`, for a transfer to a self-custody wallet. This skips VASP attribution. |

Set exactly one of `beneficiaryVaspId` or `beneficiaryWalletType`. A request with both or neither is rejected.

To find the `beneficiaryVaspId` of a destination address, call [Look up the Sumsub Travel Rule VASP of a wallet address](https://docs.dfns.co/api-reference/policies/look-up-the-sumsub-travel-rule-vasp-of-a-wallet-address.md) with the transfer's `network` and the destination `walletAddress`. When Sumsub attributes the address, the response has `found: true` and the `vaspId` to pass, along with the VASP's name and risk tags. `found: false` means Sumsub could not attribute the address, not that the wallet is unhosted. The lookup supports the networks listed above and requires wallet attribution to be enabled on your Sumsub account.

```json theme={null}
{
  "kind": "Native",
  "to": "0x1234567890abcdef1234567890abcdef12345678",
  "amount": "1000000000000000000",
  "travelRule": {
    "kind": "Sumsub",
    "ivms101": {
      "version": "IVMS101.2023",
      "data": "<JWE compact serialization>",
      "filledFields": [
        "Originator.originatorPerson[].naturalPerson.name.nameIdentifier[].primaryIdentifier",
        "payloadMetadata.payloadVersion"
      ]
    },
    "beneficiaryVaspId": "<Sumsub VASP id>"
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.