Start here

KYB developer guide

Early access. Security controls are in place. Tool names, input fields, and documentation may change as we incorporate feedback.

This guide shows the shortest working path for business verification: connect an MCP client, find the correct business, verify it, and retrieve the report. Start with sandbox data. Move to live verification only after the flow works end to end.

Before you start

  • An MCP client that supports streamable HTTP.
  • A business name and country, or a known registration number.
  • Start in sandbox so you can test the full flow without billing.

The flow

  1. Connect. Add https://mcp.trulioo.com/mcp to your MCP client and complete OAuth.
  2. Find the business. Search by name, or look up the registration rules for the country.
  3. Confirm the candidate. If search returns more than one business, ask the user to choose before you verify.
  4. Verify. Call kyb_verify with the selected registration identifier.
  5. Handle the result. Follow next_action when the result is not terminal. Save the transaction ID.
  6. Retrieve the report. Call kyb_get_report after verification completes.

Tools used in this guide

Search for a businesskyb_search · Tools →
Look up registration detailskyb_registration_lookup · Tools →
Verify a businesskyb_verify · Tools →
Retrieve a completed reportkyb_get_report · Tools →
Build with Trulioo

Zero to verified

Early access. Security controls are in place. Tool names, input fields, and documentation may change as we incorporate feedback.

One MCP connection gives any agent KYC, KYB, and Know Your Agent - the signed identity an agent carries so anyone can prove who is behind it. There is no key to copy-paste - your client enrols itself over OAuth. Here is the whole path.

  1. Connect the MCP server. Point any MCP client at the hosted endpoint - it discovers the authorization server and registers itself, so there is no key to copy-paste. Client setup →
  2. Call a verification tool. Run kyc_verify or kyb_verify against synthetic test entities and branch on the typed result. Tools →
  3. Give your agent an identity. Verify the organization behind the agent, then mint a signed, scoped attestation with kya_issue_mandate. Know Your Agent →
  4. Let anyone verify it. Publish the attestation in your A2A card; any party checks it against the issuer JWKS - no key needed. Verify agents →

I want to…

Verify a personkyc_verify · Tools →
Verify a businesskyb_verify · Tools →
Screen a name on its ownaml_screen - per-account · Tools →
Capture a document or a selfiedocv_create_session - per-account · Tools →
Prove who is behind an agentKnow Your Agent →
Verify another agent's profile (DAP)kya_verify_agent · Verify agents →
Connect an MCP clientClient setup →
Authenticate with OAuthAuthentication →
Have an agent set this up for meLet your agent introduce you →
Read the docs as an agentindex.md · llms.txt

Let your agent guide your KYB setup

Paste this into your coding agent. It will check the current connection before asking you to configure anything, then guide one sandbox business verification from discovery through report retrieval.

Paste this to your agent

Help me connect Trulioo MCP and complete a KYB verification in sandbox. Read https://mcp.trulioo.com/agent-guide.md first. Check whether Trulioo is already connected, then guide me through business discovery, verification, polling, and report retrieval. Stay within the KYB tools documented in the guide.

agent-guide.md is a focused operating guide for this early access workflow. It covers connection checks, OAuth, business search, optional candidate confirmation, verification, non-terminal results, and report retrieval.

It checks before it acts. The guide first looks for an existing Trulioo connection and confirms the session mode. It starts verification only after the developer confirms the correct business.

Review the KYB workflow and response fields →

The MCP endpoint

One hosted endpoint, spoken over MCP streamable HTTP. Any MCP-compatible client or agent framework connects to the same URL - one integration for your whole fleet.

Endpoint

# Streamable HTTP MCP transport https://mcp.trulioo.com/mcp

One endpoint, two connection modes. Use the client-managed OAuth consent flow for sandbox testing. For a live integration, exchange your Trulioo client_id and client_secret for an MCP access token before connecting to the same endpoint.

Authentication

/mcp requires an access token. Start with the sandbox connection to validate your KYB workflow. When your account is approved for live use, bootstrap a live token with your Trulioo client credentials.

Sandbox connection

Claude Code, Cursor, Codex, and ChatGPT use the client-managed OAuth 2.1 + PKCE flow:

  1. Add https://mcp.trulioo.com/mcp to the client.
  2. The client discovers Trulioo authorization and opens the consent flow.
  3. Choose sandbox.
  4. The client initializes the MCP session and loads the tools available to that connection.

Let the client manage sandbox OAuth. Do not copy sandbox tokens, register a client by hand, or hardcode authorization endpoints.

Start in sandbox

Sandbox uses the same endpoint and tool schemas as live access. It is unbilled and intended for testing the full integration before you work with production data. Sandbox results include a test_mode marker so your application can identify them.

Live integration with client credentials

For an approved live account, store the Trulioo client_id and client_secret in your secret manager or environment. Send them only to the token bootstrap endpoint over TLS.

Request an MCP access token

export TRULIOO_CLIENT_ID="your-client-id" export TRULIOO_CLIENT_SECRET="your-client-secret" # -u sends Authorization: Basic base64(client_id:client_secret) curl -sS -X POST https://mcp.trulioo.com/oauth/token \ -u "$TRULIOO_CLIENT_ID:$TRULIOO_CLIENT_SECRET" \ -H 'content-type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials'

Response

{ "access_token": "eyJ...", "token_type": "Bearer", "expires_in": 3600 }

The bootstrap validates the credentials with Trulioo, holds the upstream credential server-side, and returns a short-lived MCP access token. Store the returned access_token in TOKEN; the Raw JSON-RPC client setup below shows the complete initialization sequence.

export TOKEN="eyJ..."
  • Never send client_secret to /mcp, place it in a URL, or log it.
  • The bootstrap does not return a refresh token. Re-run the bootstrap when the MCP access token expires or the server returns 401.
  • 401 invalid_client means the credentials were malformed or rejected. Retry only after checking the credential configuration.
  • If Trulioo authentication is temporarily unavailable, retry the bootstrap with bounded backoff.

Usage limits

Usage limits apply and may change during early access. If a result includes retry_after_seconds, wait for that interval before retrying. Contact Trulioo before a production-scale rollout so limits can be reviewed for your use case.

Client setup

Pick your client and point it at the hosted endpoint. Use its OAuth flow for sandbox. For live use, the client must support sending the bearer token returned by the client-credentials bootstrap.

Add the endpoint

claude mcp add --transport http trulioo https://mcp.trulioo.com/mcp

That single line is the whole setup - the client registers itself over OAuth. It gives you the tools, and nothing else.

Going live does not change the MCP URL. It changes how the bearer token is obtained: use the approved account's client_id and client_secret at /oauth/token. Authentication →

KYB tools reference

Tools reference

The KYB surface is a typed sequence: discover the business, resolve ambiguity, verify it, poll when needed, and fetch the report. tools/list remains the authority for the tools available to your account.

Every capability is a typed, discoverable MCP tool - schema-enforced inputs, structured results agents branch on, and no raw passthrough - a tool that is not on your connection is not reachable by another route. A default progressive connection advertises 17 resident tools and exposes a default union of 42 tools through runtime discovery. Per-account families change the enabled set. The exact resident set is what tools/list returns for your connection, so discover it rather than hardcoding this list.

Example: call a tool over JSON-RPC

curl -sN https://mcp.trulioo.com/mcp \ -H "Authorization: Bearer $TOKEN" -H "mcp-session-id: $SID" \ -H 'MCP-Protocol-Version: 2025-06-18' \ -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"kyb_verify","arguments":{"country_code":"GB","registration_id":"08123456"}}}'
curl -sN https://mcp.trulioo.com/mcp \ -H "Authorization: Bearer $TOKEN" -H "mcp-session-id: $SID" \ -H 'MCP-Protocol-Version: 2025-06-18' \ -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"kyc_verify","arguments":{"country_code":"US","data_fields":{}}}}'

Both headers are required: $TOKEN from Authentication, and $SID from the initialize handshake - see Raw JSON-RPC under Client setup.

KYB workflow and responses

Identity & business verification

StepToolUse it whenResponse and next step
1 kyb_search You have a business name but not a confirmed registration identifier. Returns: search_summary with candidate_count, has_results, and top_matches. Confirm a candidate before verification; do not use the top-level RecordStatus to decide whether matches were found.
As needed kyb_registration_lookup You need the registration types or jurisdiction details accepted for a country. Returns: supported registration-number types or jurisdictions of incorporation. Use them to format the search or verification input.
As needed kyb_disambiguate_candidate Search returns multiple businesses and the user must choose the correct one. Returns: resolved, candidate_index, and the selected candidate. Clients without interactive selection receive numbered options. Continue only after confirmation.
2 kyb_verify You have confirmed the business and are ready to start verification. Returns: transaction_id, record_id, status, is_terminal, and next_action. Branch on status; follow next_action when the result is not terminal.
While running kyb_get_partial_result The verification is still running and you need the latest available state. Returns: the latest available verification fields plus is_terminal and next_action. Continue polling only while the result is not terminal.
3 kyb_get_report The verification is complete and you need the final report. Returns: a structured report, or a PDF descriptor with record_id, report_available, content_type, and resource_uri. Store the report reference with the transaction.
Reference transaction_lookup You need to retrieve a previous verification from its transaction identifier. Returns: the matching record and identity context for a TransactionID or TransactionRecordID. Use the resolved record for status or report retrieval.
ToolDoes
kyc_verifyVerify a person across 195+ countries; returns match / review / nomatch + next-action hints.
kyc_get_status / kyc_get_recordPoll an async verification, then fetch the completed record.
kyb_verifyVerify a business, with UBO discovery and due-diligence sequencing.
kyb_search / kyb_get_reportFind a business, then retrieve its full report.
kyb_registration_lookupRegistration numbers + jurisdictions of incorporation (routes by the args you pass).
kyb_disambiguate_candidateWhen a search returns several businesses, have the user pick which one before verifying (interactive on clients that support it, else numbered options to confirm inline).
kyb_get_partial_resultFetch partial results for a long-running KYB job.
transaction_lookupLook up a past KYC/KYB verification by the transactionId you already hold - resolves a TransactionID or TransactionRecordID to the record + identity.

Per-account families

Off unless your account is entitled to them, each enabled on its own. They are real and supported; they are simply absent from tools/list until your deployment has them. Ask Trulioo for the families you need rather than coding around them, and read the result from tools/list - getting one family does not get you the rest.

ToolDoes
aml_screenStandalone sanctions and PEP screening for a name you are not verifying.
docv_create_sessionStart a document + liveness capture session. Returns a session_url the person opens; images and biometric data never cross the MCP stream.
docv_get_resultRead the outcome of a capture session. Returns a Task to a tasks-capable client; otherwise poll.
docv_cancel_sessionCancel a capture session the person abandoned.
docv_create_mobile_handoffHand a desktop session off to the person's phone for the camera step.
age_checkAge assurance from a known date of birth. Its sibling age_estimate_biometric is declared but returns NotImplemented until biometric estimation ships - do not build against it.
monitoring_enrollPut a verified subject under ongoing monitoring.
monitoring_get_alertRead an alert monitoring raised.
monitoring_refreshRe-run the checks behind an enrollment now.
monitoring_cancelEnd an enrollment.
monitoring_get_enrollmentRead an enrollment's current state.

tools/list and config_discover_account are the authority on what your connection has. Do not hardcode the list above, and do not synthesize a tool name that is not on it - there is no raw passthrough, so a tool that is absent is not reachable by another route.

Know Your Agent

ToolDoes
kya_admission_challengeMint a short-lived, single-use enterprise admission challenge for one privileged target tool. The returned token is bound to the authenticated tenant, session, target tool, and policy version.
kya_possession_challengeMint the single-use nonce a keyed card's possession proof must carry. Call this first - kya_issue_mandate rejects a proof without a fresh nonce. On a software key this proof is also what earns AAL2; tier alone does not.
kya_issue_mandateOne call: verify the organization → register the agent → sign a scoped attestation → anchor it. Returns the attestation JWS + the A2A extension block.
kya_verify_agentVerify another agent's card; optionally check a requested_action against its signed scope (the scoped handshake).
kya_lookupPublic lookup of an agent's standing by DAP handle or fingerprint. depth selects the tier: lookup (free, is it verified and who is it) or verify (paid, adds advisory signals).
kya_card_fingerprintCompute a card's fingerprint before you register it - answers “will this build keep my passport?”. Costs nothing and spends no issuance - pure arithmetic over the card you supply - but it needs your account key like the rest of the keyed surface: it is a build-time developer utility, not a relying-party read. It names which fields are identity-bearing (name, the first interface URL, code_digest, and the agent_key thumbprint - so rotating your key re-mints too) and which are free to change. Returns no trust verdict.
kya_verify_web_bot_authVerify a Web Bot Auth (RFC 9421) signed HTTP request and resolve it to the agent behind it. Note a bare, replayable signature is AAL1 even at tier 2.
kya_verify_protocolVerify a rail-specific envelope (UCP / AP2 / ACP / x402). A2A cards use kya_verify_agent.
kya_supersede_agentRotate an agent's key or reissue its profile, superseding the prior credential so verifiers follow the replacement.
kya_retire_agentRevoke standing for a retired or compromised agent. A verifier resolving its lookup sees the credential is no longer good.
kya_verify_mandateVerify a mandate credential a counterparty presented to you - signature, issuer, validity window, and with freshness: central_fresh its revocation status. Reach for this rather than kya_get_mandate whenever somebody hands you a credential: reading a mandate by an id lifted out of an unverified document trusts the document to describe itself. Pass amount to also learn whether the sum you are about to authorize sits inside the ceiling the credential declares - advisory only, and it never changes valid. An amount_advisory.within of null means unanswerable, never a pass.
kya_get_mandateRead a mandate you issued: status, validity window, and the signed scope - allowed actions, merchants, and the spend cap. A max_amount of null means uncapped, never a cap of zero.
kya_record_spendRecord a settled spend against a mandate, which is what makes a day/total ceiling answerable at all. Your settlement_id is the de-duplication key: replaying it with the same amount returns recorded: false and counts once, while the same id with a different amount is refused 409 rather than silently overwritten. Recording is not enforcement - it moves no money and blocks nothing.
kya_mandate_spendRead a mandate's spend ledger: the running totals per currency, the declared ceiling, and the headroom left. A remaining of null is not zero - it means there is no headroom to speak of, either uncapped or a per-transaction cap, which limits each purchase rather than depleting.
kya_revoke_mandateRevoke one mandate, with a reason recorded for the audit trail. The capability rails fail closed on the next verify; the A2A discovery tier is OfflineOk by design, so it lags until the credential expires.
kya_revocationsList the mandates already revoked, with the status-list index each one occupies - the bulk read behind a verifier's own cache.
kya_transparency_sthFetch the signed tree head: tree size, root hash, and the issuer's signature over both. The anchor every inclusion proof hangs from. Public - no account needed.
kya_inclusion_proofProve a leaf sits under a signed root (RFC 6962). Public - no account needed. Verify the returned audit path with verify_inclusion_hashed, not verify_inclusion: the served leaf_hash is already hashed, and hashing it twice reports a sound log as broken.
kya_status_listFetch the signed status list as its compact JWS (application/statuslist+jwt) - the revocation bitstring a verifier checks offline. Public. Re-signed per request with a fresh validFrom, so do not cache or diff it by byte hash.
kya_railsWhat each rail demands before you build for it: expected_typ, tier, freshness, binding, signing alg, schema URL, and the issuer JWKS to resolve keys from. Public.
kya_assess_readinessMeasure the public agent-facing documents a host publishes and return evidence-backed reason codes and residuals. It reports no score or grade and requires account credentials.
kya_assess_artifactSubmit one immutable software release or exact Git commit for a tenant-scoped multi-collector assessment. The selected collector portfolio is frozen with the subject and policy. The operation reports lifecycle and coverage intent, not a vendor score, grade, rank, or allow decision.
kya_assessment_statusRead one assessment's lifecycle and frozen collector coverage. Partial, failed, canceled, expired, and unavailable never mean clean. Admitted evidence and KYA signals are exposed only when the assessment contract supports them.
kya_verify_clientVerify a Client ID Metadata Document before admitting an OAuth client: fetch the https URL that is its client_id under MCP 2026-07-28, validate it against draft-ietf-oauth-client-id-metadata-document-00, and get back the document's origin, its redirect_uris, whether it publishes a key (jwks_uri + private_key_jwt) or is a public client, and any KYA operator claim it carries. Runs the same SSRF-hardened fetch the authorization server runs, so the verdict predicts admission. Two tier fields, deliberately: record_trust_tier is a statement about the URL, request_trust_tier_ceiling is the most a request carrying that client_id could reach - binding the first to a request is the mistake this shape exists to prevent. The carried attestation is never verified here (attestation_verified is always false); the issuer is the source of truth, so follow up with kya_lookup on the fingerprint.
kya_register_artifactRegister a complete software artifact package as an immutable release candidate. The server verifies publisher binding and computes package and distribution digests without publishing it.
kya_publish_artifactPublish a registered software-artifact release candidate using an audited, optimistic-concurrency transition.
kya_revoke_artifactPermanently revoke a compromised software-artifact release. This audited transition is destructive and irreversible.

Discovery, meta & workflow prompts

ToolDoes
trulioo_tool_schemaRead a tool's full input schema and complete authored guidance (up to 8 at a time). The tool list carries a one-line description to keep a client's cold start small; this is where the operational detail lives - required fields per country, which flag actually starts an ownership walk, which result fields are advisory rather than evidence.
trulioo_find_tools / trulioo_invoke_toolProgressive discovery, advertised only when TRULIOO_TOOL_DISCOVERY=progressive. The server then lists a 15-tool resident core (~2.2k tokens instead of ~6.4k) and keeps the rest reachable: trulioo_find_tools searches the manifest by keyword or family, trulioo_invoke_tool calls a tool that is not listed. Dispatch passes the same profile, family, rate-limit, circuit-breaker and KYA gates as a direct call, cannot widen a profile or re-enable a disabled family, and refuses destructive verbs - those stay advertised so your client always sees their approval hints.

config_discover_account, config_describe_context, and config_list_test_entities tell an agent what its account can do and which safe test subjects it can use before it starts a KYB flow. trulioo_health and webhook_journal cover liveness and async callbacks. The kyb_due_diligence_workflow prompt sequences search, disambiguation, verification, and screening; prompts/list is the authority on the set your connection offers. trulioo_capabilities and trulioo_getting_started let an agent self-orient.

config_discover_account, config_describe_context, and config_list_test_entities tell an agent what its account can do and which safe test subjects it can use before it asks a user for anything. trulioo_health and webhook_journal cover liveness and async callbacks. Guided workflow prompts (kyc_onboarding_workflow, kyb_due_diligence_workflow) sequence the multi-step flows; prompts/list is the authority on the set your connection offers. trulioo_capabilities and trulioo_getting_started let an agent self-orient. There is no raw passthrough: every upstream call goes through a typed tool, so a tool that is not on your connection is not reachable by another route.

Protocol capabilities (negotiated per connection)

The revision is negotiated at initialize: the floor is 2025-06-18 and the newest draft the server supports is 2026-07-28. Features land only for a client that asked for the revision carrying them - everything else degrades to the floor behavior, so read the negotiated value back from trulioo_capabilities rather than assuming one. Two optional extensions a capable client can opt into:

Handle the result

ResultWhat your code should do
is_terminal:falseDo not treat the verification as complete. Follow next_action and poll within a bounded retry budget.
status: matchContinue the approved business onboarding flow and store the transaction ID.
status: reviewPause automation and route the result to a human reviewer.
status: nomatchStop the onboarding path and present the returned next action.
  • Tasks (io.modelcontextprotocol/tasks) - kyb_verify returns a task handle you poll with tasks/get when your client declares the capability; otherwise it returns the same next_action long-poll. Task state is per-instance today, so a not-found tasks/get means fall back to the poll.
  • Tasks (io.modelcontextprotocol/tasks) - the long-running tools (kyc_verify, kyb_verify) return a task handle you poll with tasks/get when your client declares the capability; otherwise they return the same next_action long-poll. Task state is per-instance today, so a not-found tasks/get means fall back to the poll.
  • MCP Apps / SEP-1865 (io.modelcontextprotocol/ui) - render_app_verdict returns a host-rendered ui:// verdict card (sandboxed iframe, text/html;profile=mcp-app) with a text fallback for non-Apps clients. Enabled per account (TRULIOO_ENABLE_MCP_APPS).

Result contracts

Tools return structured results an agent can branch on directly - not prose to parse.

kyb_verify (terminal shape)

{ "transaction_id": "txn_...", "status": "match", // match | review | nomatch "is_terminal": true, // false = poll or fetch partial result "next_action": { "type": "none" } }

kyc_verify (shape)

{ "transaction_id": "txn_...", "record_id": "rec_...", "status": "match", // match | review | nomatch "is_terminal": true, // false = poll kyc_get_status "next_action": { "type": "none" } }
  • Errors are results, not exceptions. A failed upstream comes back as a typed result the agent can reason about, not a thrown error that ends the run.
  • Circuit breaker per upstream. Each verification surface has its own breaker, so one degraded provider does not take down the others.
  • Async is explicit. is_terminal:false tells the agent to poll rather than assume completion. A long-running operation returns a continuation to poll; exhausting an approved poll budget requires review rather than an unbounded loop.
Know Your Agent

Give an agent an identity

Any agent can claim any name. Know Your Agent proves the real organization behind an agent and issues a signed, scoped, revocable credential - the Digital Agent Profile (DAP) - that anyone can verify. It rides in the agent's A2A card, so trust travels with the agent.

  1. Verify the organization. KYC/KYB + sanctions on the accountable owner behind the agent.
  2. Register the agent. The agent presents its own Ed25519 key; that key is the identity anchor. A build fingerprint binds the credential to this exact agent.
  3. Sign a scoped mandate. kya_issue_mandate mints a short-lived, least-privilege attestation for named scopes (e.g. purchase), signed by identity.trulioo.com.
  4. Publish it. The attestation attaches to your A2A card under capabilities.extensions[] (uri https://identity.trulioo.com/a2a/kya/v1) and is anchored in a tamper-evident log.

The KYA extension on an A2A agent card

{ "capabilities": { "extensions": [{ "uri": "https://identity.trulioo.com/a2a/kya/v1", "params": { "attestation": "<compact JWS, alg=EdDSA>", "display": { "verified": true, "verified_as_of": "<ISO 8601>", "allowed_scopes": ["purchase"], "issuer": "https://identity.trulioo.com", "fingerprint": "<sha256 of the agent key + card>" } } }] } }

Scopes are signed, but enforced by the relying party. Trulioo signs and audits the allowed scopes; the party accepting the agent is what actually enforces them. The attestation is a verifiable claim of trust, not an authorization grant on its own.

How anyone verifies it →  ·  Do it in the portal →

Why agent trust has layers

"Verified" is not one thing. A DAP asserts a stack of independent facts, and a relying party checks the layers its risk calls for. Knowing the layers tells you exactly what a profile does - and does not - prove.

  1. Identity anchor. The agent holds its own key. Everything else binds to that key, so the profile is about this agent, not a name it typed.
  2. Integrity & provenance. A build fingerprint binds the credential to the exact code. Change the code and the fingerprint changes - forcing re-attestation.
  3. Authenticity of use. A possession proof shows the party presenting the card actually controls the anchor key - not a copied card.
  4. Origin & accountability. KYC/KYB ties the agent to a real, sanctions-screened organization, and every issuance is anchored in a tamper-evident log.

This matters to your company directly: it is what lets you (or your customers) accept an agent's action with a known, accountable party behind it - and decline or step up when a layer is missing. The full trust model →

Verify an agent (DAP)

Verification is the critical path: a system deciding whether to trust an inbound agent confirms its Digital Agent Profile and attestation before acting. Verify through MCP; the issuer also publishes the two keyless, public primitives so any party can check a profile with no account.

Try it live

Drive the mint-then-verify lifecycle end to end. This simulation runs entirely in your browser - no network calls. Mint on the left; verify the same agent on the right.

1 - Issue a credential

Verify org → register agent → sign mandate → anchor in the log.

  1. The lifecycle trace streams here - one signed step at a time.

2 - Verify an agent

Against the issuer, not the card. The agent from step 1 lands here.

🔒 Run step 1 first - the agent you mint arrives here to verify.

In an agent (recommended)

Call kya_verify_agent with the agent's card - it validates the signature, fingerprint, expiry and sanctions, and returns the Verified-by-Trulioo record. Add a requested_action to check it against the signed scope in the same step. This is the integration path; the KYA verification logic lives behind MCP, not a public write API.

Verify over MCP

curl -sN https://mcp.trulioo.com/mcp \ -H "Authorization: Bearer $TOKEN" -H "mcp-session-id: $SID" \ -H 'MCP-Protocol-Version: 2025-06-18' \ -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"kya_verify_agent","arguments":{"agent_card":{ }}}}'

$TOKEN comes from Authentication and $SID from the initialize handshake. If you only need to check a profile and not run a verification, the public keyless lookup below needs neither.

Public, keyless lookup (for any verifier)

The issuer publishes two public primitives at https://identity.trulioo.com so a relying party that isn't running an MCP client can still confirm a profile without an account:

  • GET /kya/attestation/{dap} - look up an agent's current standing by its Digital Agent Profile (the "anyone can check" path).
  • GET /.well-known/jwks.json - the issuer's signing keys (rotation-aware) to verify an attestation JWS yourself.
# look up standing by Digital Agent Profile curl -s https://identity.trulioo.com/kya/attestation/<dap> # or fetch the issuer keys and verify the JWS yourself curl -s https://identity.trulioo.com/.well-known/jwks.json

What a verifier checks: the JWS signature against the pinned issuer key by kid (the algorithm is pinned from the resolved key, never read from the token header - blocks alg:none and alg-confusion); the fingerprint against the agent's own key + card; the exp (short-lived, re-attested on change); verified; assurance.trust_tier against your own minimum; and the signed allowed_scopes. Scopes are signed and auditable but enforced by you, the relying party.

There is no signed sanctions boolean. Signing a standing sanctions_clear would assert a check that may not have run, on a payment-adjacent credential. Screening is an optional provenanced claim carried only when it actually ran, and a hit or review suspends the credential's standing through its status_reference. Check standing, not a boolean.

The DAP wire schema (ats-v2)

A Digital Agent Profile is a conformant SD-JWT-VC (typ: dc+sd-jwt) carrying a vct of https://identity.trulioo.com/vct/agent-profile.1. A passport core is inline - a KYB-verified operator and a composite assurance grade - while the identity, mandate, status and behavior objects are referenced and dereferenced independently. This is the exact record the KYA card flips to; the full JSON Schema is ats-v2-dap.schema.json (governed by ADR-P-022).

DAP 2.0 presentation (public-discovery profile)

{ "typ": "dc+sd-jwt", "vct": "https://identity.trulioo.com/vct/agent-profile.1", "iss": "https://identity.trulioo.com", "sub": "agt_01j9z4k7c8m2q5v3x6n8p0w2a4", "dap": "dap_01j9z4k7c8m2q5v3x6n8p0w2a4", // public Digital Agent Profile handle (what you look up) "agent_id": "agt_01j9z4k7c8m2q5v3x6n8p0w2a4", // internal durable resolver key "build_id": "bld_01j9z4k7c8m2q5v3x6n8p0w2a4", // a code change bumps build_id alone, never agent_id "operator": { // inline; not holder-omittable at tier >= 2 "name": "Acme Payments Ltd", "kyb": "verified", "registration_id": "GB-08123456" // selectively disclosable }, "assurance": { "ial": "2", "aal": "2", "fal": "2", "trust_tier": "2" }, "cnf": { "jkt": "kFx7Q2b...9dE" }, // RFC 7800 holder key (possession-bound) "capabilities": ["read", "checkout", "refund"], "status": "status-list#4021", // Bitstring Status List (referenced) "endorsements": ["A2A", "MCP", "UCP", "AP2"] // rails that honor this profile }

Disclosure integrity. assurance (incl. trust_tier) is always inline; operator (at tier ≥ 2) and screening.result (when present) are not holder-omittable - a holder cannot strip a signed sanctions hit or claim tier ≥ 2 while hiding the operator. Only operator.registration_id, screening.watchlists, and (pairwise profile only) agent_id/build_id are selectively disclosable.

Two profiles. Public discovery reveals agent_id/build_id inline (shown above). Pairwise withholds them via SD-JWT selective disclosure and substitutes a per-relying-party sub alias, so a profile isn't linkable across verifiers. The variant is chosen by the agent's exposure mode - never a caller flag - so an agent can't be tricked into over-disclosing.

How the DAP projects onto each rail

One DAP, issued once, is projected into each protocol's native shape - KYA proves who is accountable; the rail carries and authenticates the transaction. The mapping below is what actually travels on each rail and which DAP claim the verifier reads.

RailWhere the DAP travelsWhat the verifier reads
Google A2A
Live
Inline in the Agent Card under capabilities.extensions[], uri identity.trulioo.com/a2a/kya/v1, as a compact JWS in params.attestation. The attestation JWS against the issuer JWKS, then operator + assurance.trust_tier from the verified DAP.
Google AP2
Live
The DAP is the credential - a conformant SD-JWT-VC AP2 already speaks (typ: dc+sd-jwt), presented as the mandate. iss = identity.trulioo.com, the cnf holder-key proof, and the inline operator/assurance core.
Google + Shopify UCP
Live
Referenced from the merchant profile the business publishes with its signing keys. operator.kyb = verified and assurance.trust_tier - is this a real, screened business?
OpenAI + Stripe ACP
Live
Checked out-of-band before the delegated Stripe token is honored, via kya_verify_agent(card). The signed capabilities scope (e.g. checkout) and operator - is this agent allowed to make this purchase?
Visa TAP
Preview
TAP signs the request (RFC 9421, Ed25519) with the agent key; the DAP is resolved from that key. The cnf.jkt thumbprint maps the signing key to a DAP, then operator - the accountable org behind the key.
Mastercard Agent Pay
Preview
The Agentic Token binds to the DAP's durable agent_id + verified operator. agent_id and operator - the tokenized card is bound to a real, verified organization.
Cloudflare Web Bot Auth
Live
Signed edge requests (RFC 9421) carry Signature-Agent; the DAP sits beneath the signing key. cnf key match + operator/assurance - replaces a spoofable User-Agent with a verified org.
Coinbase x402
Live
The wallet signs the on-chain payment; the DAP rides the bridged A2A card alongside it. The DAP attestation - the wallet moves value, the DAP proves the accountable org behind the agent.
Skyfire
Live
Skyfire's identity token references the DAP as its regulated assurance source. assurance.trust_tier (e.g. trulioo:tier-2) - the KYC/KYB depth the token anchors to.

Across every rail the DAP's role is the same - prove the accountable organization and its signed scope; the rail enforces and settles. No proprietary token, no lock-in: it's a conformant SD-JWT-VC anyone can verify against the issuer JWKS.

Drop-in "Verified" badge

Prefer not to build the UI? Embed the same <trulioo-verified> element Trulioo runs on its own surfaces. It runs the live attestation lookup itself, stays hidden until the agent verifies, and opens the full Digital Agent Profile on click - Organization, Issuer, DAP, verified-as-of, sanctions, attestations, scopes, and a link into the transparency log. One framework-agnostic custom element; no build step. It's live in the hero of the sibling Know Your Agent page.

← live badge (resolves the Trulioo demo agent's real profile)

Embed it

<script type="module" src="https://mcp.trulioo.com/web-components/primitives/trulioo-verified.js"></script> <!-- endpoint returns the live attestation JSON; label shows "Verified" text --> <trulioo-verified endpoint="https://mcp.trulioo.com/demo-api?identity=1&mode=identity" label></trulioo-verified>

Orchestration patterns

The tools are typed and composable, so an agent chains them mid-task and branches on each result. The examples below show how to combine the raw tools.

Pattern 1 - Verify a person before a high-risk action

The agent checks identity mid-conversation and branches on the typed status. Ships as /trulioo-mcp:kyc-onboarding.

# agent calls the tool, then branches on the result kyc_verify({ country: "US", fields: {...} }) → status == "match" // proceed - open the accountstatus == "review" // hand off / step upstatus == "nomatch" // decline, explain next_action # async? is_terminal:false -> poll kyc_get_status

KYB due diligence - discover, verify, screen

Pattern 2 - Onboard a business, then screen it

Find the business, confirm the correct candidate, verify it, and branch on the typed result.

kyb_search("Acme Ltd", "GB") → registration_id kyb_disambiguate_candidate({ candidates }) → confirmed registration_id kyb_verify({ registration_id }) → status == "match" // continue onboardingstatus == "review" // route to a human reviewerstatus == "nomatch" // stop and follow next_action

Pattern 3 - Give the agent its own identity (KYA)

Once the org behind the agent is verified, mint the agent's DAP so every downstream call is attributable.

kya_issue_mandate({ scopes: ["purchase"] }) → attestation JWS + the A2A extension block # now any counterparty verifies it, keyless: kya_verify_agent({ agent_card }) → operator verified - tier 2

Keep the business identity continuous. Carry the selected registration identifier from search into verification, store the returned transaction ID, and use that transaction as the anchor for report retrieval.

Enterprise agent teams. A fleet shares one MCP connection and one identity layer - every agent inherits the same verification tools, and each carries its own DAP, so downstream systems know which agent (and which accountable org) took an action. One integration, governed centrally.

Full tool reference →  ·  Result contracts →

Security & honest limits

  • Schema-enforced inputs. Every tool validates its arguments (additionalProperties: false), so malformed or injected calls are rejected before reaching an upstream.
  • Prompt-injection resistance. Tools act only on their typed arguments; free-text in a document or field is data, never an instruction to the server.
  • Algorithm pinning. Attestation verification pins the algorithm from the resolved key (EdDSA / ES256 only) - alg:none and alg-confusion attacks are rejected.
  • Honest limits. A DAP proves identity, integrity, scope and accountability - it does not authorize a payment or guarantee behavior. Scope enforcement is the relying party's; certified biometric liveness has a defined boundary. We surface dependencies we do not own.
  • Governed surface. The verification agents and skills behind these tools are eval-gated and release-controlled - the same discipline you would apply to a compliance-critical dependency.

FAQ

Should I search before calling kyb_verify?

Search when you do not already have an authoritative registration identifier. If search returns multiple candidates, confirm the correct business with kyb_disambiguate_candidate before verification.

What should I do when search returns several businesses?

Do not guess. Use kyb_disambiguate_candidate and ask the user to confirm the correct business before you call kyb_verify.

How do I continue after KYB completes?

Use the transaction ID to retrieve and store the completed report.

Does an agent need its own key for KYA?

Yes. The agent's own key is the identity anchor; the profile binds to it. Trulioo does not mint the agent's key for it.

Does the attestation authorize a payment?

No. It is a signed, verifiable claim of identity and scope. Whether to accept an action is the relying party's decision; scope is enforced there.

How does someone verify an agent without a key?

The issuer publishes its signing keys at /.well-known/jwks.json; verification is a public signature check against those keys.