sumsub-create-transaction

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Sumsub — Create Transaction (KYT)

Sumsub — 创建交易(KYT)

Builds a
KytTxnData
JSON payload from a compact spec, POSTs it to the Sumsub KYT endpoint, and reports the resulting
txnId
/
score
/
reviewAnswer
.
根据简洁规范构建
KytTxnData
JSON负载,将其POST到Sumsub KYT端点,并返回生成的
txnId
/
score
/
reviewAnswer

Endpoint

端点

Two variants, picked automatically by the post script:
CaseMethod + 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
. 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. No v2/v3 replacement exists.
POST脚本会自动选择以下两种变体:
场景方法 + 路径
申请人已存在
POST https://api.sumsub.com/resources/applicants/{applicantId}/kyt/txns/-/data
申请人不存在(Sumsub会通过
applicant.externalUserId
创建申请人)
POST https://api.sumsub.com/resources/applicants/-/kyt/txns/-/data?levelName=<levelName>
请求体:
KytTxnData
。返回带监控评分的已持久化
KytTxn
这两个端点均标记为已弃用,但它们仍是官方文档中标准的“提交交易”入口,目前尚无v2/v3替代方案。

Auth — App Token + secret (sandbox only)

认证 — App Token + 密钥(仅沙箱环境)

This skill talks to the public Sumsub API and signs each request per the authentication reference. The full how-it-works writeup lives in the
sumsub-api-auth
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/devSpace/appTokens (toggle the workspace to Sandbox first, then Create). 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:
.
VarExample
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
.
该Skill对接公开的Sumsub API,并按照认证参考文档对每个请求进行签名。完整的工作原理说明在
sumsub-api-auth
Skill中——如果遇到
401 Invalid signature
错误,请阅读该文档。
⚠️ 仅支持沙箱令牌。 请勿接受或使用生产环境的App Token——交易监控会作用于真实申请人数据,并可能触发真实的KYT警报。如果用户提供生产令牌,请拒绝并要求他们在https://cockpit.sumsub.com/checkus/devSpace/appTokens生成沙箱令牌对(先将工作区切换为Sandbox,再点击Create)。令牌和密钥仅会显示一次——关闭对话框前请复制两者。辅助脚本会强制验证这一点——它会拒绝不以
sbx:
开头的令牌。
变量示例
SUMSUB_APP_TOKEN
sbx:...
— 来自控制台的沙箱App Token。
SUMSUB_SECRET_KEY
创建令牌时一次性显示的配对密钥。
SUMSUB_BASE
可选,默认值为
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.
这是一个路由细节——必须对包含查询字符串的路径进行签名。POST脚本会处理这一点:它读取构建器生成的辅助路由文件,选择URI(
/resources/applicants/{id}/…
/resources/applicants/-/…?levelName=…
),对动态段进行URL编码,并对发送的相同字节进行签名。如果绕过脚本,请记住:
  • 对传输中的路径进行签名——使用编码格式,包含查询字符串。
  • 签名的请求体字节必须与发送的字节完全一致(不能重新排版空白字符)。
如果用户已在对话中提供凭据,请复用;否则在运行前询问一次。切勿返回密钥内容。

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:
    https://cockpit.sumsub.com/checkus/kyt/txns/<id>?clientId=<clientId>&xSNSEnv=sbx
    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
    xSNSEnv=sbx
    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.
  1. 映射用户意图到下方的简洁规范。绝大多数交易为
    type: finance
    (支付)——对于这类交易,用户实际需要提供金额 + 货币 + 方向 + 申请人 + 交易对手
  2. 验证
    txnId
    非空,
    applicant.externalUserId
    非空,并根据
    type
    进行验证:
    • finance
      /
      travelRule
      → 必填
      info.amount
      info.currencyCode
      info.direction
      (OpenAPI标记这三个字段为
      KytTxnInfo
      的必填项)。
    • userPlatformEvent
      → 必填
      userPlatformEvent.type
    • 枚举值(
      direction
      currencyType
      applicant.type
      nameType
      等)会提前验证,验证失败时会返回完整的允许值列表。
  3. 生成完整负载:使用
    ${CLAUDE_SKILL_DIR}/scripts/build_transaction.py
    (标准输入为简洁规范 → 标准输出为完整的
    KytTxnData
    负载)。
  4. POST请求:通过
    ${CLAUDE_SKILL_DIR}/scripts/post_transaction.sh
    发送——根据规范中是否设置
    _applicantId
    自动路由到已存在申请人或不存在申请人的URL(注意:是规范中的设置,而非负载中的设置)。
  5. 构建控制台链接:从响应体中读取
    id
    服务器分配的标识符,而非你提供的
    txnId
    )和
    clientId
    ,并格式化为:
    https://cockpit.sumsub.com/checkus/kyt/txns/<id>?clientId=<clientId>&xSNSEnv=sbx
    规范中用户提供的
    txnId
    (例如
    finance-2026-05-21-0001
    不能用于URL——Sumsub在持久化时会分配单独的标识符。
    xSNSEnv=sbx
    查询参数指向沙箱工作区——这是所有Skill通用的标准沙箱链接参数。
  6. 返回结果:返回
    txnId
    (你提供的)、服务器分配的
    id
    、申请人
    externalUserId
    、交易方向+金额+货币、交易对手(如有)、响应中的
    score
    /
    reviewAnswer
    /
    riskLabels
    (如有),以及可点击的Markdown格式控制台链接

Compact spec format (JSON or YAML on stdin)

简洁规范格式(标准输入为JSON或YAML)

yaml
undefined
yaml
undefined

Top-level

顶层字段

txnId: "finance-2026-05-21-0001" # REQUIRED, unique alphanumeric in your system txnDate: "2026-05-21 14:30:00+0000" # optional; format: yyyy-MM-dd HH:mm:ss+XXXX zoneId: "UTC+01:00" # optional, time zone string type: finance # finance | travelRule | kyc | userPlatformEvent | iGamingSession (default: finance)
txnId: "finance-2026-05-21-0001" # 必填,在你的系统中唯一的字母数字标识符 txnDate: "2026-05-21 14:30:00+0000" # 可选;格式:yyyy-MM-dd HH:mm:ss+XXXX zoneId: "UTC+01:00" # 可选,时区字符串 type: finance # finance | travelRule | kyc | userPlatformEvent | iGamingSession(默认值:finance)

Routing — pick ONE

路由选择 — 二选一

_applicantId: "67abc..." # post to existing applicant (path id, NOT a payload field)
_applicantId: "67abc..." # 提交到已存在申请人的路径(路径中的id,非负载字段)

- OR -

或 -

_levelName: "Default" # post to non-existing-applicant URL with ?levelName=... # (Sumsub creates the applicant from applicant.externalUserId)
_levelName: "Default" # 提交到不存在申请人的URL,附带?levelName=...参数 # (Sumsub会通过applicant.externalUserId创建申请人)

Finance / Travel Rule info (required for those types)

金融/旅行规则信息(对应类型必填)

amount: 1500.50 currency: USD # ISO-4217 fiat or crypto ticker (BTC, ETH, …) currencyType: fiat # fiat | crypto (default: fiat) direction: out # in | out amountInDefaultCurrency: 1500.50 # optional, converted to client default defaultCurrencyCode: USD paymentDetails: "Invoice #INV-2026-001" mcc: 5411 # optional, 4-digit Merchant Category Code
amount: 1500.50 currency: USD # ISO-4217法定货币或加密货币代码(BTC、ETH等) currencyType: fiat # fiat | crypto (默认值:fiat) direction: out # in | out amountInDefaultCurrency: 1500.50 # 可选,转换为客户默认货币的金额 defaultCurrencyCode: USD paymentDetails: "Invoice #INV-2026-001" mcc: 5411 # 可选,4位商户类别代码

Crypto-only block (used when currencyType=crypto)

仅加密货币区块(当currencyType=crypto时使用)

crypto: chain: ETH # ETH | BTC | TRX | … (mandatory for tokens; empty for native) contract: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" paymentTxnId: "0x1234abcd..." # on-chain hash fingerprint: "0x1234abcd..." # alternative blockchain identifier attemptId: "attempt-01" # optional, when retrying outputIndex: 0 # for UTXO chains
crypto: chain: ETH # ETH | BTC | TRX | …(代币必填;原生货币留空) contract: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" paymentTxnId: "0x1234abcd..." # 链上哈希 fingerprint: "0x1234abcd..." # 可选的区块链标识符 attemptId: "attempt-01" # 可选,重试时使用 outputIndex: 0 # 适用于UTXO链

Applicant (REQUIRED) — the person/entity acting on your platform

申请人(必填)—— 在你的平台上操作的个人/实体

applicant: externalUserId: "user-001" # REQUIRED — your stable user id type: individual # individual | company (default: individual) fullName: "John Smith" # required for company; recommended for non-existing-applicant flow dob: "1990-05-01" email: "john@example.com" phone: "+1234567890" placeOfBirth: "London" address: country: USA town: "New York" street: "5th Avenue" formatted: "5th Avenue, New York, USA" paymentMethod: type: bankCard # bankCard | bankAccount | crypto | cryptoWallet | # eWallet | unhostedWallet | card | other accountId: "4111********1111" # IBAN, last4-hash, wallet address, etc. issuingCountry: USA "3dsUsed": true "2faUsed": false memo: "optional memo" idDoc: number: "A12345678" country: USA idDocType: PASSPORT device: fingerprint: "abc123" userAgent: "Mozilla/5.0 ..." ipInfo: { ip: "1.2.3.4" }
applicant: externalUserId: "user-001" # 必填 — 你的稳定用户ID type: individual # individual | company(默认值:individual) fullName: "John Smith" # 公司类型必填;非申请人流程推荐填写 dob: "1990-05-01" email: "john@example.com" phone: "+1234567890" placeOfBirth: "London" address: country: USA town: "New York" street: "5th Avenue" formatted: "5th Avenue, New York, USA" paymentMethod: type: bankCard # bankCard | bankAccount | crypto | cryptoWallet | # eWallet | unhostedWallet | card | other accountId: "4111********1111" # IBAN、后四位哈希、钱包地址等 issuingCountry: USA "3dsUsed": true "2faUsed": false memo: "optional memo" idDoc: number: "A12345678" country: USA idDocType: PASSPORT device: fingerprint: "abc123" userAgent: "Mozilla/5.0 ..." ipInfo: { ip: "1.2.3.4" }

Counterparty (typical for finance + travelRule; same shape as applicant + a few extras)

交易对手(金融/旅行规则类型常见;结构与申请人类似,新增部分字段)

counterparty: externalUserId: "merchant-XYZ" type: company fullName: "Acme Inc." registrationNumber: "12345678" leiCode: "529900XXXX0000XXXX00" residenceCountry: QAT address: { country: QAT } institution: # → institutionInfo code: "ACME-CODE" name: "Acme Bank" internalId: "<VASP id from directory>" ceo: # only for company counterparties (Travel Rule) firstName: "Jane" lastName: "Roe"
counterparty: externalUserId: "merchant-XYZ" type: company fullName: "Acme Inc." registrationNumber: "12345678" leiCode: "529900XXXX0000XXXX00" residenceCountry: QAT address: { country: QAT } institution: # → institutionInfo code: "ACME-CODE" name: "Acme Bank" internalId: "<VASP id from directory>" ceo: # 仅适用于公司类型交易对手(旅行规则) firstName: "Jane" lastName: "Roe"

user-platform-event only (when type=userPlatformEvent)

仅用户平台事件(当type=userPlatformEvent时使用)

userPlatformEvent: type: login # login | failedLogin | signup | passwordReset | twoFaReset | general twoFaUsed: true passwordHash: "..."
userPlatformEvent: type: login # login | failedLogin | signup | passwordReset | twoFaReset | general twoFaUsed: true passwordHash: "..."

Optional escape hatches

可选扩展字段

sourceKey: "<segregation key>" props: # custom string-string map customField: "value" dailyOutLimit: "10000"
undefined
sourceKey: "<segregation key>" props: # 自定义字符串键值对 customField: "value" dailyOutLimit: "10000"
undefined

Enums (validated upfront)

枚举值(提前验证)

FieldAllowed 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.
字段允许值
type
(顶层)
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
故意不做枚举验证——OpenAPI列出了
KytTxnPaymentMethodType
(仅包含
smartContract
bankCard
bankAccount
),但文档和实际数据支持更多类型(
crypto
eWallet
unhostedWallet
等)。构建器会直接传递调用者提供的任何值。

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>&xSNSEnv=sbx
    . 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;
    xSNSEnv=sbx
    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).
成功时返回以下所有内容:
  • txnId
    (你提供的)
    id
    (服务器分配的,用于控制台链接)。
  • 申请人
    externalUserId
  • direction amount currency
    、交易对手(如有)。
  • 响应中的
    score
    /
    reviewAnswer
    /
    riskLabels
    (如有返回)。
  • 控制台链接
    https://cockpit.sumsub.com/checkus/kyt/txns/<id>?clientId=<clientId>&xSNSEnv=sbx
    。以可点击的Markdown链接形式呈现。
    <id>
    服务器分配的标识符(而非你发送的
    txnId
    );它和
    clientId
    都在POST响应体中;
    xSNSEnv=sbx
    指向沙箱工作区。
失败时返回:HTTP状态码 + Sumsub的
description
/
errorName
。最常见的4xx情况:
  • 409 Entity already exists
    txnId
    冲突(使用新ID或批量导入方法进行更新)。
  • 400
    — 必填字段缺失(典型情况:
    info.amount
    info.currencyCode
    info.direction
    applicant.externalUserId
    )。
  • 400
    levelName
    不存在(使用非申请人流程时)。

Worked examples

示例

  • examples/fiat-out.json
    — outbound EUR card payment to a foreign counterparty (the docs' canonical example).
  • examples/crypto-in.json
    — inbound ETH deposit with
    cryptoParams.cryptoChain=ETH
    , contract address, on-chain
    paymentTxnId
    .
  • examples/travel-rule.json
    type: travelRule
    outbound crypto with
    institution.internalId
    (VASP id) on the counterparty.
  • examples/login-event.json
    type: userPlatformEvent
    for a successful login with 2FA.
  • examples/new-applicant.json
    — non-existing-applicant flow:
    _levelName
    is set so the POST goes to
    /-/kyt/txns/-/data
    with
    ?levelName=...
    .
  • examples/fiat-out.json
    — 向境外交易对手支付欧元的出境卡支付(文档中的标准示例)。
  • examples/crypto-in.json
    — 入境ETH存款,包含
    cryptoParams.cryptoChain=ETH
    、合约地址、链上
    paymentTxnId
  • examples/travel-rule.json
    type: travelRule
    的出境加密货币交易,交易对手包含
    institution.internalId
    (VASP ID)。
  • examples/login-event.json
    type: userPlatformEvent
    的成功登录事件,使用了2FA。
  • examples/new-applicant.json
    — 非申请人流程:设置
    _levelName
    ,POST请求会发送到
    /-/kyt/txns/-/data
    并附带
    ?levelName=...
    参数。

See also

参考链接