# Compliance Providers

Source: https://docs.settlemint.com/docs/architects/integrations/compliance-providers
Architecture reference for compliance-provider intake across identity, business, AML, and wallet-monitoring providers, covering how provider events become tenant-scoped on-chain claims and where per-transfer decisions belong instead.



This page explains how compliance providers connect external KYC, KYB, AML, and wallet-monitoring systems to DALP claim issuance, and where each integration type belongs. External provider events become tenant-scoped on-chain claims issued by a trusted issuer. Supported providers include [Sumsub](https://docs.sumsub.com/), [Elliptic](https://developers.elliptic.co/), [ComplyAdvantage](https://docs.complyadvantage.com/), [Jumio](https://docs.jumio.com/), [Middesk](https://docs.middesk.com/), [Onfido](https://documentation.onfido.com/), [Persona](https://docs.withpersona.com/), [Trulioo](https://developer.trulioo.com/), and [Veriff](https://developers.veriff.com/). Use this reference to choose the right integration path and understand the provider record model, the webhook contract, and revocation mechanics.

ClaimSource is the durable intake path for persistent identity, business, or wallet subjects. Per-transfer decisions use a separate transfer-time surface.

## Current coverage boundary [#current-coverage-boundary]

DALP compliance-provider adapters cover three categories of events that ClaimSource reduces to durable claims.

* Identity and KYB verdicts from configured KYC/KYB providers
* Monitoring alerts from applicant, entity, and wallet-monitoring providers
* Wallet-monitoring alerts from Elliptic

Travel Rule transfer gating is a separate per-transfer decision surface, not a compliance-provider adapter. DALP does not publish a default Travel Rule provider adapter. [Chainalysis KYT](https://docs.chainalysis.com/) is not a DALP compliance-provider adapter.

## Choose the right compliance path [#choose-the-right-compliance-path]

DALP separates durable claim intake from per-transfer decisions. Choose the path by the subject you need to evaluate:

| If the provider evaluates...                                                           | Use this DALP path                                  | Result                                                                                                             |
| -------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| A person, organisation, or wallet that should keep a compliance status after the event | ClaimSource through the compliance-provider webhook | DALP maps the provider subject to a DALP identity and issues or revokes an on-chain claim for the configured topic |
| A trusted issuer that should manually issue claims through DALP APIs                   | Trusted issuer claim issuance                       | DALP checks the caller's trusted-issuer topics before queueing the claim transaction                               |
| One outbound or inbound transfer                                                       | TransferGate or another per-transfer adapter        | DALP evaluates the transfer-time decision without turning it into a persistent identity claim                      |

Do not route Travel Rule or other transaction-specific decisions through ClaimSource. Use ClaimSource for events that attach to an identity, business, or wallet subject and map to a standard claim topic.

## Provider intake model [#provider-intake-model]

Compliance integrations split by what the provider produces and how long the subject lives:

| Surface | Provider shape              | DALP behaviour                                                                                                                                                                                                              |
| ------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A       | Identity verdicts           | Sumsub, Jumio, Middesk, Onfido, Persona, Trulioo, and Veriff terminal verdicts issue or remove on-chain claims for one or more topics the provider is trusted for                                                           |
| B       | Monitoring alerts           | Sumsub AML watchlist events, Sumsub applicant-on-hold events, ComplyAdvantage entity monitoring, and Elliptic wallet alerts normalise to a 0 to 100 severity score and revoke claims above a configured per-topic threshold |
| C       | Per-transaction Travel Rule | Outside the current Console compliance-provider flow                                                                                                                                                                        |

ClaimSource covers identity or wallet subjects that persist beyond one transaction. Sumsub applicant-review events produce identity verdicts. Sumsub AML watchlist events, Sumsub applicant-on-hold events, and ComplyAdvantage monitored-search events produce monitoring alerts. Elliptic produces wallet-monitoring alerts. TransferGate handles Travel Rule and similar per-transaction decisions. In those cases, the subject is one transfer rather than a durable identity or wallet.

### Supported provider topics [#supported-provider-topics]

Each provider kind can only attest the topic names DALP publishes for that adapter. Multi-topic providers let you reuse the same provider identity for each supported topic. Single-topic providers require a separate provider lifecycle when your tenant needs a different topic.

| Provider kind   | Supported topic names                  |
| --------------- | -------------------------------------- |
| Sumsub          | `knowYourCustomer`                     |
| Sumsub AML      | `antiMoneyLaundering`                  |
| Sumsub KYT      | `knowYourTransaction`                  |
| ComplyAdvantage | `antiMoneyLaundering`                  |
| Elliptic        | `antiMoneyLaundering`                  |
| Jumio           | `knowYourCustomer`                     |
| Middesk         | `knowYourBusiness`                     |
| Onfido          | `knowYourCustomer`, `knowYourBusiness` |
| Persona         | `knowYourCustomer`, `knowYourBusiness` |
| Trulioo         | `knowYourCustomer`                     |
| Veriff          | `knowYourCustomer`                     |

## Provider record model [#provider-record-model]

Each compliance provider in DALP is a parent record with one or more attached claim topics. One provider identity can attest every topic the platform trusts it for. Two records hold the policy you configure:

`compliance_providers` holds the provider record: credentials, signing secret(s), the autonomous EOA, the on-chain claim-issuer identity address, and the webhook URL token. Exactly one provider record exists per (provider × tenant). `compliance_provider_topics` holds the per-topic policy: topic name, on-chain topic id, status (`active` / `revoked`), revocation severity threshold, and notification channels. Multiple topic rows attach to the same provider.

Subject mappings (Sumsub applicants, Elliptic wallets) re-key at the provider level, not at the topic level, so a single mapping covers every topic the provider is trusted for.

### Provider identity and key list [#provider-identity-and-key-list]

A provider's on-chain trust path uses the same participant, OnchainID, and key list primitives as the organisation deployment. Provisioning creates a `claim_issuer` participant for the provider (via `createClaimIssuerParticipant`). The participant id is deterministic so retries are idempotent. The configured custody adapter then provisions a tenant-scoped, custodied EOA dedicated to this participant; the EOA signs every claim the provider emits without another DALP approval step.

The Identity Factory deploys a fresh OnchainID identity contract for the participant. The provider's identity is separate from the tenant organization identity and from any subject identity. The platform then adds the autonomous EOA to that identity as a `MANAGEMENT_KEY` (purpose 1). ERC-734's `keyHasPurpose` checks against `MANAGEMENT_KEY` as a superset: one key entry satisfies the addClaim authorisation check (`ACTION_KEY` semantics), the claim signature verification check (`CLAIM_SIGNER_KEY` semantics), and the addKey rotation check (`MANAGEMENT_KEY` semantics) simultaneously. This mirrors the organisation deployment pattern and avoids maintaining three separate purpose entries. The same generic primitives drive both organisation and provider deployments:

```text
provisionParticipantEoa(walletName)            ← generic primitive
  ↳ provisionOrganisationEoa(orgId)            ← thin wrapper for organisation deployment
  ↳ provisionClaimIssuerEoa(participantId)     ← thin wrapper for provider provisioning

createParticipantRow(kind, id, …)              ← generic query
  ↳ createOrganisationParticipant(orgId, …)    ← thin wrapper
  ↳ createClaimIssuerParticipant(providerId, …) ← thin wrapper
```

### Multi-topic trusted-issuer registration [#multi-topic-trusted-issuer-registration]

The trusted issuers registry contract registers an issuer identity with an array of claim topics:

```solidity
function addTrustedIssuer(IClaimIssuer issuer, uint256[] topics);
function updateIssuerClaimTopics(IClaimIssuer issuer, uint256[] topics);
function removeTrustedIssuer(IClaimIssuer issuer);
```

Provider provisioning calls `addTrustedIssuer(providerIdentity, [firstTopicId])`. Subsequent topic mutations call `updateIssuerClaimTopics(providerIdentity, [...])` to extend or shrink the topic array. Whole-provider revocation calls `removeTrustedIssuer(providerIdentity)` and soft-deletes the provider row.

Per-topic granularity in DALP maps to per-element changes in the on-chain topic array. The provider's claim-issuer identity stays on-chain for the lifetime of the provider record. The contract is not destroyed on revocation, so historical claims previously issued by the provider continue to verify against the same issuer address.

Subject mapping happens at intake time:

* Sumsub, Jumio, Onfido, Persona, Trulioo, and Veriff applicant intake, plus Middesk business intake, map the provider subject to a DALP identity address.
* ComplyAdvantage search intake maps a monitored person or company search to its DALP identity.
* Elliptic wallet intake maps the monitored wallet to its DALP identity.

## Inbound contract [#inbound-contract]

Each provider exposes one webhook URL for the tenant to paste into the provider dashboard. All topics attached to the provider share that URL. Inbound webhooks must arrive on that URL with the provider authentication material set. DALP verifies the request against the secret or allowlist configured during onboarding.

Signature handling varies by provider.

| Provider        | Webhook authentication                     | Header or network source                                                                                           |
| --------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| Sumsub          | HMAC over raw body                         | `x-payload-digest`, `x-payload-digest-alg`                                                                         |
| Sumsub AML      | HMAC over raw body                         | `x-payload-digest`, `x-payload-digest-alg`                                                                         |
| Sumsub KYT      | HMAC over raw body                         | `x-payload-digest`, `x-payload-digest-alg`                                                                         |
| ComplyAdvantage | HMAC-SHA256 digest                         | `x-complyadvantage-signature`                                                                                      |
| Elliptic        | HMAC-SHA256 digest                         | `x-elliptic-signature`                                                                                             |
| Jumio           | Basic Auth + IP allowlist                  | `Authorization: Basic …` and callback source IP                                                                    |
| Middesk         | HMAC-SHA256 over raw body                  | `X-Middesk-Signature-256`                                                                                          |
| Onfido          | HMAC-SHA256 over raw body                  | `X-SHA2-Signature`                                                                                                 |
| Persona         | HMAC-SHA256 over `${timestamp}.${rawBody}` | `Persona-Signature` timestamp and hexadecimal signature values (space-separated sets accepted during key rotation) |
| Trulioo         | HMAC-SHA256 over raw body                  | `x-trulioo-signature`                                                                                              |
| Veriff          | HMAC-SHA256 over raw body                  | `X-HMAC-SIGNATURE`                                                                                                 |

Sumsub's dashboard webhook manager documents the HMAC digest headers and the raw-payload comparison requirement in its [Webhook manager guide](https://docs.sumsub.com/docs/webhook-manager). For Elliptic, alert webhooks and signature validation are in [Rescreening and Alerting](https://developers.elliptic.co/docs/rescreening-and-alerting).

For a brand-new provider event, DALP enforces a replay window of at most 5 minutes between the body's signed timestamp and arrival. DALP applies idempotency on the provider's event identifier and rejects out-of-order events relative to the latest applied state for that subject and topic.

If a matching event is already stored and still pending, DALP can dispatch it again under the same idempotency record so a crashed first delivery can resume. Events targeting a missing or revoked topic are rejected with `rejected_topic_mismatch` before they reach the claim-authoring path.

When you rotate a webhook signing secret in the Console, the new secret takes effect immediately. The old secret stays valid for a configurable grace period, with a default of 15 minutes and a maximum of 24 hours. During that period the platform accepts a signature from either secret, so events the provider already enqueued under the old secret are not lost. After the period expires, the old secret stops working.

When a provider drives gas-sponsored claim issuance, the platform applies a rolling ceiling on sponsored claims per issuer. This limit protects gas sponsorship from a runaway or compromised provider feed. The ceiling and the rolling interval are tunable per organization. An organization without its own setting uses the platform defaults. You can set organization-specific values to match the sponsorship policy. If an organization's ceiling override is malformed, the platform fails closed by treating the limit as zero, so a bad setting blocks sponsored issuance until the operator corrects it rather than leaving the limit undefined.

While the issuer stays under the active ceiling, issuance proceeds normally. Once it crosses the ceiling inside the rolling interval, the platform refuses further sponsored claims for that issuer with the audited outcome `rejected_over_cap` instead of submitting a transaction that would consume sponsored gas. The interval clears as earlier issuances age out. A related precondition produces `rejected_unsponsorable` when the platform cannot sponsor the issuer at all, for example when no issuer wallet resolves or the resolved wallet lacks authority to author the claim. Both outcomes appear as operations-visible refusals on the event rather than silent drops, stuck pending events, or retries. The provider integration sees a clear signal in either case.

## Outbound contract [#outbound-contract]

Each provider receives one paste-back URL of the form:

```text
/webhooks/compliance/<provider>/:providerId/:urlToken
```

The provider identifier scopes the URL to one tenant provider record; every topic attached to the provider routes onto the same URL. The URL token is a non-guessable UUID generated when you create the provider. HMAC is the primary authentication mechanism; the token limits accidental cross-provider delivery and adds a defence-in-depth layer against URL leaks.

The platform retains raw provider payloads for audit so a regulator can reconstruct the full chain of custody from raw event to on-chain claim. The platform extracts decision-driving fields (verdict state, severity, subject reference, claim topic, applied timestamp, outcome) alongside the raw payload at intake time so audit queries do not need to re-parse historical data.

## Issuer-of-record: the identity, not the EOA [#issuer-of-record-the-identity-not-the-eoa]

The on-chain attestor of every compliance-issued claim is the provider's claim-issuer identity contract address. The attestor is not the EOA, not DALP itself, and not the tenant compliance officer. The EOA is the sender of the on-chain transaction and the cryptographic signer of the claim payload, but the claim's `issuer` field is set to the identity contract address.

This issuer-of-record rule propagates to downstream consumers of `claims.issuer`: the indexer, the trusted-claim primitive, the per-tenant `IDALPTrustedIssuersRegistry` lookup, and the ERC-3643 compliance evaluation path. The trusted issuers registry checks `isTrustedIssuer(identity)` and `hasClaimTopic(identity, topicId)` on every claim. You do not need to trust the EOA directly.

A regulator audit can identify which provider asserted a given claim, retrieve the original signed webhook payload, and verify the full trusted-issuer registration history from on-chain add, update, and remove events.

## Provisioning sequence [#provisioning-sequence]

The provider provisioning workflow performs five on-chain operations in sequence. A durable workflow journal lets you resume from the last unfinished step when any operation fails:

<Mermaid
  chart="sequenceDiagram
    participant A1 as Tenant operator
    participant W as Provider provisioning workflow
    participant DB
    participant Signer as Signing provider
    participant IF as Identity Factory
    participant ID as Provider Identity<br/>(OnchainID)
    participant TIR as Trusted Issuers Registry

    A1->>W: createProvider(creds, signingSecret, firstTopic)
    W->>DB: validateCredentials (live call to provider)
    W->>DB: createClaimIssuerParticipant(deterministic id)
    W->>Signer: provisionParticipantEoa(&#x22;claim-issuer-eoa-${participantId}&#x22;)
    Signer-->>W: { wallet, walletId } [WALLET_ALREADY_EXISTS recovers]
    W->>IF: deployIdentity(participantOwner)
    IF-->>W: identityAddress [factory deterministic / pre-check]
    W->>ID: addClaimIssuerKey(eoa, MANAGEMENT_KEY) [keyHasPurpose preflight short-circuits]
    W->>TIR: addTrustedIssuer(identity, [firstTopic.topicId])
    W->>DB: writeProvider + writeProviderTopic(firstTopic, status=active)
    W-->>A1: provider active; webhook URL surfaced"
/>

Three idempotency guards cover retries cleanly: signer `WALLET_ALREADY_EXISTS`, identity factory pre-check, and ERC-734 `keyHasPurpose` short-circuit. The durable journal handles failures at any step. The Console shows a five-phase provisioning pulse that mirrors these steps in real time.

## Webhook intake and claim authoring [#webhook-intake-and-claim-authoring]

Inbound provider events flow through a claim-authoring worker keyed on `(providerId, subjectKey)`. The worker serialises events per subject and checks the active topic policy before authoring a claim. The sequence below shows each step:

<Mermaid
  chart="sequenceDiagram
    participant Provider as Compliance provider<br/>(Sumsub/Elliptic)
    participant H as Webhook handler
    participant VO as Claim-authoring worker<br/>(providerId, subjectKey)
    participant Q as Transaction queue
    participant Subject as Subject identity<br/>(OnchainID)
    participant TIR as Trusted Issuers Registry

    Provider->>H: POST /api/webhooks/compliance/<provider>/<providerId>/<token>
    H->>H: verify HMAC + normalize event
    H->>VO: dispatch (provider-keyed)
    VO->>VO: lookup compliance_provider_topics (providerId, topicName)
    Note over VO: reject rejected_topic_mismatch<br/>if topic absent or status≠active
    VO->>Q: addClaim(subject, topic, data, sig), sender = EOA, issuer = identity
    Q->>Subject: addClaim(...)
    Note over Subject: issuer field on claim = provider identity address
    Subject->>TIR: isTrustedIssuer + hasClaimTopic check during compliance evaluation"
/>

The claim-authoring worker is keyed on `(providerId, subjectKey)`, so concurrent events for different subjects on the same provider proceed in parallel while events for the same subject serialise. Topic-policy lookup happens inside that worker, so a topic revoked between event arrival and dispatch is caught before the on-chain transaction.

## Topic mutations and revocation [#topic-mutations-and-revocation]

Topic mutations operate against the existing provider's claim-issuer identity. None of them touch the EOA, the identity contract, or the webhook URL.

To add a topic, the platform calls `updateIssuerClaimTopics(identity, [...existing, newTopic])` and inserts a new `compliance_provider_topics` row with `status=active`. Use the Console Add Topic dialog on the provider detail page to drive this.

To revoke a topic, the platform calls `updateIssuerClaimTopics(identity, [...existing without topic])` and soft-deletes the topic row (`status=revoked`). The provider stays active for any remaining topics. The platform rejects an attempt to revoke the last active topic; if you need to remove all topics, use whole-provider revoke instead. That operation calls `removeTrustedIssuer(identity)`, soft-deletes the provider row, cascades soft-delete to every topic, and preserves subject mappings so you retain a full audit trail.

In every case the claim-issuer identity contract stays on-chain, so historical claims previously issued by the provider continue to verify against the same `claims.issuer` address. The provider simply loses TIR membership for the revoked topic(s).

## Two-primitive split [#two-primitive-split]

ClaimSource and TransferGate stay separate because their subjects and timing differ.

ClaimSource subjects are persistent identities or wallets. The platform takes input through event-driven webhooks and produces standard on-chain claim issuance and revocation.

TransferGate subjects are a single outbound or inbound transfer. The platform requests the decision at transfer-initiation time, not in response to a background event. The result is a transfer-time gate, not a persistent claim.

Keeping the two shapes separate prevents per-transaction decisions from mixing into the event-driven ClaimSource model. ClaimSource is the public intake path for persistent identity and wallet subjects.

DALP compliance-provider integrations support these event families through ClaimSource:

* Sumsub: identity verdicts
* Sumsub AML: watchlist monitoring alerts for existing applicants
* Sumsub: applicant-on-hold monitoring alerts
* Sumsub KYT: transaction monitoring
* ComplyAdvantage: entity monitoring alerts
* Elliptic: wallet monitoring
* Jumio: identity verdicts
* Middesk: KYB verdicts, attested to `knowYourBusiness`
* Onfido Workflow Studio and classic API: identity verdicts, attested to `knowYourCustomer`
* Persona: inquiry verdicts, attested to `knowYourCustomer`
* Trulioo DataVerify: identity and business verdicts, attested to `knowYourCustomer`
* Veriff: hosted identity-verification verdicts, attested to `knowYourCustomer`

Travel Rule transfer gating is a separate per-transfer surface, not a compliance-provider adapter. If your deployment needs Travel Rule gating, integrate a per-transfer adapter rather than routing that decision through ClaimSource. DALP does not publish a default Travel Rule provider adapter. [Chainalysis KYT](https://docs.chainalysis.com/) is not a DALP compliance-provider adapter.

## See also [#see-also]

* [Compliance provider onboarding](/docs/developers/compliance/onboarding-a-provider)
* [Rotate provider claim signer key](/docs/operators/runbooks/rotate-provider-claim-signer-key)
* [Custody providers](/docs/architects/integrations/custody-providers)
* [Supported networks](/docs/architects/integrations/supported-networks)
