sumsub-create-transaction
Submit a transaction to Sumsub Transaction Monitoring (KYT) via the ApplicantResource API. TRIGGER when the user asks to "submit / create / send / record a transaction", "test a KYT rule with a transaction", post a fiat or crypto payment for monitoring, attach Travel Rule data to a transfer, log a u
By sumsub · 841 installs
npx skills add sumsub/agent-skills --skill sumsub-create-transaction
Source repository · Upstream listing
Sumsub — Create Transaction (KYT)
Builds a KytTxnData JSON payload from a compact spec, POSTs it to the Sumsub KYT endpoint, and reports the resulting txnId / score / reviewAnswer .
Endpoint
Two variants, picked automatically by the post script:
Case Method + Path
Applicant exists POST https://api.sumsub.com/resources/applicants/{applicantId}/kyt/txns/ /data
Applicant does not exist (Sumsub creates one from applicant.externalUserId ) POST https://api.sumsub.com/resources/applicants/ /kyt/txns/ /data?levelName=<levelName
Body: [ KytTxnData ](references/transaction schema.md). Returns the persisted KytTxn with monitoring scores attached.
Both endpoints are marked deprecated, but they remain the canonical "submit transaction" entry points in the [official docs](https://docs.sumsub.com/reference/submit transaction for existing applicant.md). No v2/v3 replacement exists.
Auth — App Token + secret (sandbox only)
This skill talks to the public Sumsub API and signs each request per
[the authentication reference](https://docs.sumsub.com/reference/authentication).
The full how it works writeup lives in the [ sumsub api auth ](../sumsub api auth/SKILL.md)
skill — read it if you hit 401 Invalid signature .
⚠️ Sandbox tokens only. Do not accept or use a production App Token
here — transaction monitoring acts on real applicant data and can fire
real KYT alerts. If the user offers a prod token, refuse and ask them to
generate a sandbox pair at <https://cockpit.sumsub.com/checkus/home?sbx=true
( Connect Sumsub to your AI agent Build & configure
Generate token ). Token + secret are shown once — copy both before
closing the dialog. The helper
script enforces this — it rejects tokens that don't start with sbx: .
Var Example
SUMSUB APP TOKEN sbx:... — sandbox App Token from the dashboard.
SUMSUB SECRET KEY The paired secret shown once at token creation.
SUMSUB BASE Optional. Defaults to https://api.sumsub.com .
Signing the resolved path
This is the one routing wrinkle — the path with query string must be
signed. The post script handles it: it reads the sidecar route file the
builder emits, picks the URI ( /resources/applicants/{id}/… or
/resources/applicants/ /…?levelName=… ), URL encodes the dynamic segments,
and signs the same bytes it sends. If you bypass the script, remember:
Sign the path you put on the wire — encoded form, query string included.
Body bytes signed must equal the bytes sent (no whitespace re flow).
If the user has already supplied credentials in conversation, reuse them;
otherwise ask once before running. Never echo the secret back.
Procedure
1. Map the user's intent to the compact spec below. The vast majority of transactions are type: finance (a payment) — for those, the user is really telling you amount + currency + direction + applicant + counterparty .
2. Validate : txnId non empty, applicant.externalUserId non empty, and per type :
finance / travelRule → info.amount , info.currencyCode , info.direction required (the OpenAPI marks all three required on KytTxnInfo ).
userPlatformEvent → userPlatformEvent.type required.
Enums ( direction , currencyType , applicant.type , nameType , etc.) checked upfront with full allowed values list on failure.
3. Generate the full payload with ${CLAUDE SKILL DIR}/scripts/build transaction.py (compact spec on stdin → full KytTxnData payload on stdout).
4. POST via ${CLAUDE SKILL DIR}/scripts/post transaction.sh — auto routes to existing applicant vs non existing applicant URL based on whether applicantId was set in the spec (NOT in the payload — see below).
5. Build the dashboard link. Read id (the server assigned identifier , not the txnId you supplied) and clientId from the response body and format:
The user supplied txnId in the spec (e.g. finance 2026 05 21 0001 ) is not what goes in the URL — Sumsub assigns a separate identifier on persistence. The sbx=true query param targets the Sandbox workspace — it is the canonical sandbox link param shared across all skills.
6. Report : txnId (yours), the server id , applicant externalUserId , direction + amount + currency, counterparty (if any), the response's score / reviewAnswer / riskLabels if present, and the dashboard link as a clickable markdown link .
Compact spec format (JSON or YAML on stdin)
Enums (validated upfront)
Field Allowed values
type (top level) finance , travelRule , kyc , auditTrailEvent , userPlatformEvent , scheduledEvent , iGamingSession
direction in , out
currencyType crypto , fiat
applicant.type / counterparty.type individual , company
applicant.nameType aliasName , birthName , maidenName , legalName , shortName , tradingName , other
userPlatformEvent.type login , failedLogin , signup , passwordReset , twoFaReset , general
paymentMethod.type is intentionally not enum checked — the OpenAPI lists KytTxnPaymentMethodType (only smartContract , bankCard , bankAccount ) but the docs and live data accept many more ( crypto , eWallet , unhostedWallet , etc.). The builder forwards whatever the caller supplies.
Outputs
On success, report all of:
txnId (yours) and id (server assigned, used in the dashboard link).
Applicant externalUserId .
direction amount currency , counterparty (if any).
The response's score / reviewAnswer / riskLabels if returned.
Dashboard link : https://cockpit.sumsub.com/checkus/kyt/txns/<id ?clientId=<clientId &sbx=true . Render as a clickable markdown link. <id is the server assigned identifier (not the txnId you sent); both it and clientId are in the POST response body; sbx=true targets the Sandbox workspace.
On failure: HTTP status + Sumsub's description / errorName . Most likely 4xx cases:
409 Entity already exists — txnId collision (use a fresh id or the bulk import method to update).
400 — required field missing (typical: info.amount , info.currencyCode , info.direction , or applicant.externalUserId ).
400 — levelName unknown (when using non existing applicant flow).
Worked examples
[ examples/fiat out.json ](examples/fiat out.json) — outbound EUR card payment to a foreign counterparty (the docs' canonical example).
[ examples/crypto in.json ](examples/crypto in.json) — inbound ETH deposit with cryptoParams.cryptoChain=ETH , contract address, on chain paymentTxnId .
[ examples/travel rule.json ](examples/travel rule.json) — type: travelRule outbound crypto with institution.internalId (VASP id) on the counterparty.
[ examples/login event.json ](examples/login event.json) — type: userPlatformEvent for a successful login with 2FA.
[ examples/new applicant.json ](examples/new applicant.json) — non existing applicant flow: levelName is set so the POST goes to / /kyt/txns/ /data with ?levelName=... .
See also
[references/transaction schema.md](references/transaction schema.md) — full KytTxnData schema, all sub objects, all enums, the existing vs new applicant routing, scoring response fields, common gotchas.
[Sumsub docs — Submit transaction](https://docs.sumsub.com/reference/submit transaction for existing applicant.md)
[Sumsub docs — Submit transaction for non existing applicant](https://docs.sumsub.com/reference/submit transaction for non existing applicant.md)
[Sumsub docs — Submit transactions and review results](https://docs.sumsub.com/docs/submit transactions and review results.md)