Verification & compliance

A Principal is the accountable identity behind every agent. Verification is how the platform — and the obligated entity behind it — can prove a transaction traces back to a real, vetted subject. This page covers the two verification modes, the attestation record, and the one rule that governs everything: verification gates transacting, not registering.

Why verification exists

Autonomous agents move money. Behind every agent there must be a real, accountable subject — a person or a merchant — who has been through customer due diligence (CDD). That subject is the Principal (prn_), and verification is the step that establishes who it is and that someone is on the hook for it.

The platform never lets a prn_ reach an active mandate without a verification decision behind it. The decision answers two compliance questions at once:

That second question is the one most platforms get wrong. Mandate Labs makes it explicit through the verification mode, set per Program or per Principal. The mode decides both who runs the diligence and who is liable for it.

One identity, many agents

Verification attaches to the Principal, not the agent. You verify a prn_ once; every agt_ it owns inherits that verified standing. You never re-verify per agent.

The two modes

Every Principal is verified one of two ways. The mode is declared in the verification.mode field on POST /principals and recorded on the Principal.

client_attested verified now

The Client is the obligated entity and attests, on the record, that it performed CDD on the end-user in its own program. Mandate Labs does not re-run KYC — it stores the Client's attestation as liability-bearing evidence and verifies the Principal immediately.

The call returns 201 and the Principal lands at VERIFIED in a single round trip. A VerificationAttestation row is written recording who attested, what was attested, the full statement, and an optional pointer to the Client's own KYC case.

Use this when you (the Client) are already a regulated or obligated entity running your own onboarding. The attestation block is required — omitting it returns attestation_required (422).

platform_provider pending KYC

Mandate Labs runs KYC/KYB via an integrated verification provider (MetaMap today; Sumsub/Persona on the roadmap). The end-user completes a hosted verification flow, and Mandate Labs bears the diligence responsibility.

The call returns 202 with a verification_session you hand to the user, and the Principal starts at PENDING. It moves PENDINGIN_REVIEWVERIFIED or REJECTED as the provider responds. You learn the outcome by polling the Principal or by subscribing to the verification webhook.

Use this when you are not the obligated entity and want Mandate Labs to own the KYC relationship. No attestation block is sent.

Dimensionclient_attestedplatform_provider
Who runs CDDThe Client, in its own programMandate Labs, via a provider
Who bears liabilityThe Client (obligated entity)Mandate Labs
HTTP response201 Created202 Accepted
Initial statusVERIFIEDPENDING
Evidence storedVerificationAttestation rowProvider session + result
attestation blockRequiredOmitted
How you learn the resultImmediate (in the response)Poll Principal or webhook

The attestation object

For client_attested mode, the attestation block is the compliance artifact. It is persisted as a VerificationAttestation — the liability-bearing record of the Client's CDD claim, retained per the Data Retention Schedule. It captures four fields:

FieldTypeRequiredWhat it records
attested_bystringYesWho at the Client made the attestation — typically a compliance contact (e.g. an email).
scopestringYesWhat was attested — the level/type of CDD performed (e.g. "Tier-2 CDD").
statementstringYesThe full attestation text — the Client's explicit claim that it verified this subject.
evidence_refstringNoA reference to the Client's own KYC case/record, so the underlying evidence can be located on audit.

The stored row additionally binds the attestation to the subject (principal_id), optionally to the program_id it was made under, and stamps an attested_at timestamp at the moment of registration. This is what lets a regulator, an issuer, or an internal auditor trace any agent transaction back to a named human or named approver who vouched for the underlying subject.

The attestation is a legal record

Submitting a client_attested Principal is an assertion that real CDD was performed. The statement, the attester, and the evidence reference are retained as evidence. Do not attest to diligence you did not perform.

KYC vs KYB

The verification.type field declares whether the subject is a person or a business. It is set independently of the mode and is recorded as the Principal's verification type.

TypeSubjectprincipal_kindMeaning
KYCA natural personpersonalKnow Your Customer — identity verification of an individual.
KYBA merchant / businessmerchantKnow Your Business — verification of a legal entity and its beneficial owners.

The two fields pair naturally: a personal Principal is verified KYC; a merchant Principal is verified KYB. The platform derives the verification type from the principal kind when registering, so a merchant attestation is recorded as a KYB attestation and an individual as KYC.

Verification gates transacting, not registering

This is the load-bearing rule of the whole model. An agent can be registered before its Principal is VERIFIED, but it cannot hold an active mandate or authorize a transaction until the Principal is VERIFIED.

The separation is deliberate. It lets you build out an integration — create the Principal, register one or more agents, wire up your systems — in parallel with verification finishing, without ever letting an unverified subject move money. Registration is structural; transacting is gated.

Register prn_ Register agt_ VERIFICATION GATE Grant mandate Authorize
Everything left of the gate works while verification is in flight. The gate opens — active mandate, then authorize — only once the Principal reaches VERIFIED.

Concretely:

Only VERIFIED unlocks authority

The platform treats VERIFIED as the single gate that permits agent authority. No other status — not PENDING, not IN_REVIEW, not MANUAL_REVIEW — allows a mandate to go active.

Verification status values

The Principal's verification_status follows a defined lifecycle: UNVERIFIED → PENDING → VERIFIED | REJECTED | EXPIRED, with provider or compliance escalations routing through review states.

StatusMeaningCan transact?
UNVERIFIEDNo verification submitted yet.No
PENDINGDocs submitted; awaiting the provider's response (platform_provider).No
IN_REVIEWThe provider flagged the case for manual review.No
VERIFIEDPassed KYC/KYB — agents may hold active mandates and authorize.Yes
REJECTEDFailed verification — the subject must resubmit.No
EXPIREDA prior verification lapsed — the subject must re-verify.No
MANUAL_REVIEWEscalated to the Mandate Labs compliance team.No

A successful verification also assigns a risk tier (LOW, MEDIUM, HIGH, or PROHIBITED) that travels with the Principal and feeds downstream risk decisions.

Worked examples

Both flows are a single POST /principals authenticated with your Client API key (X-API-Key). The mode determines the response.

Mode A — client_attested (201, immediate)

The Client onboards a merchant it has already KYB'd, attaching the attestation that records its diligence. The Principal is VERIFIED in the response.

curl -X POST https://api.mandatelabs.ai/api/v1/principals \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -H "Idempotency-Key: prn-acme-001" \
  -d '{
    "principal_kind": "merchant",
    "program_ids": ["prg_…"],
    "client_customer_ref": "acme-001",
    "profile": {
      "display_name": "Acme Corp",
      "email": "[email protected]",
      "country": "US"
    },
    "verification": {
      "type": "KYB",
      "mode": "client_attested",
      "attestation": {
        "attested_by": "[email protected]",
        "scope": "Tier-2 CDD",
        "statement": "Acme performed full Tier-2 customer due diligence on this merchant, including beneficial-ownership and sanctions screening.",
        "evidence_ref": "kyc-case-123"
      }
    }
  }'
{
  "id": "prn_1718900000000_a1b2c3d4",
  "client_id": "cli_…",
  "principal_kind": "merchant",
  "client_customer_ref": "acme-001",
  "verification_status": "VERIFIED",
  "verification_mode": "client_attested",
  "risk_tier": "LOW",
  "programs": ["prg_…"],
  "agents": [],
  "verification_session": null,
  "created_at": "2026-06-27T12:00:00Z"
}

Status 201, verification_status: "VERIFIED", and verification_session: null — the agent you add next can be granted an active mandate right away.

Mode B — platform_provider (202, pending)

The Client onboards an individual and asks Mandate Labs to run KYC. No attestation is sent; the response carries a verification_session to hand to the user.

curl -X POST https://api.mandatelabs.ai/api/v1/principals \
  -H "X-API-Key: mdt_live_…" -H "Content-Type: application/json" \
  -H "Idempotency-Key: prn-jdoe-001" \
  -d '{
    "principal_kind": "personal",
    "program_ids": ["prg_…"],
    "client_customer_ref": "jdoe-001",
    "profile": {
      "display_name": "Jane Doe",
      "email": "[email protected]",
      "country": "US"
    },
    "verification": {
      "type": "KYC",
      "mode": "platform_provider"
    }
  }'
{
  "id": "prn_1718900111000_e5f6a7b8",
  "client_id": "cli_…",
  "principal_kind": "personal",
  "client_customer_ref": "jdoe-001",
  "verification_status": "PENDING",
  "verification_mode": "platform_provider",
  "risk_tier": null,
  "programs": ["prg_…"],
  "agents": [],
  "verification_session": {
    "provider": "pending",
    "session_id": "vs_9f8e7d6c5b4a3210",
    "hosted_url": "https://verify.mandatelabs.ai/s/vs_9f8e7d6c5b4a3210",
    "expires_at": "2026-06-28T12:00:00Z"
  },
  "created_at": "2026-06-27T12:00:00Z"
}

Status 202, verification_status: "PENDING". Direct the user to verification_session.hosted_url; when they finish, the status advances to VERIFIED (or REJECTED). Poll GET /principals/{prn} or subscribe to the verification webhook to learn the outcome rather than blocking on the response.

Sandbox auto-verifies

In the sandbox, verification is auto-completed so you can drive the full chain without a real provider round trip — the playground's Mandate Labs Client attests on your behalf. The two-mode distinction above is the production behavior.

Compliance note: passporting your own CDD

client_attested is the mechanism by which a Client that is itself an obligated entity — a regulated fintech, an issuer, a licensed program — passports its existing CDD into Mandate Labs without duplicating verification. You already screen your customers under your own program; client-attested lets that screening stand, while the VerificationAttestation preserves the audit trail proving you did.

The liability split is the point. Under client_attested the Client remains the obligated entity and bears KYC liability; the attestation is the evidence of that responsibility. Under platform_provider, Mandate Labs runs the diligence and carries it. Choose the mode that matches who is actually accountable for the end-user — and never attest to diligence you have not performed.

Next steps