# KYT
# KYT API Reference
All API requests must be authenticated as described in this section.
Also, pay attention to the failed requests. Error descriptions can be found here.
# Process transaction for existing applicant
POST /resources/applicants/{applicantId}/kyt/txns/-/data
If you do not have an applicant to process transaction, you can call
POST /resources/applicants/-/kyt/txns/-/data?levelName={levelName}
This method should only be used where there is no existing applicant with the same externalUserId
that you intend to pass within an applicant
object of request body.
The new applicant will be created using provided levelName
and data from the applicant
object.
Make sure to send a unique externalUserId
and a proper fullName
within an applicant
object to us to create fresh applicant and process transaction.
# REQUEST ARGUMENTS
Name | Type | Required | Description |
---|---|---|---|
applicantId | String | Yes | Id of applicant that have been already processed by SumSub KYC. In case you don't have such an applicant, provide - . |
levelName | String | No | Level name to create a new applicant. |
#{body} | Object | Yes | An object representing transaction (see example). |
# REQUEST BODY
Name | Type | Required | Description |
---|---|---|---|
txnId | String | Yes | Transaction ID. |
txnDate | Date | No | Time when the transaction was initiated (format yyyy-MM-dd HH:mm:ss+XXXX , e.g. 2022-11-24 23:37:02+0000). |
info | Object | Yes | Transaction info. |
props | Object | No | Transaction properties. Map of strings - json of custom keys and string values. |
applicant | Object | Yes | Transaction participant data with mandatory applicantId (sender or remitter depending on info.direction ). |
counterparty | Object | Yes | Transaction participant data (sender or remitter depending on info.direction ). |
type | String | No | Transaction type - takes predefined values: finance /gamblingBet /gamblingLimitChange /kyc /login /signup /passwordChange /twoFaReset (finance by default). |
sourceKey | String | No | Source Key indication to separate accesses to transactions. |
# info
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
direction | String | Yes | out (applicant sends to counterparty) or in (counterparty sends to applicant). |
amount | Double | Yes | Amount of sent funds. |
currencyCode | String | Yes | Currency code (USD, GBP, BTC, etc). |
cryptoChain | String | No | Crypto chain name. Mandatory for crypto tokens only. Specifies the network name to which the token at currencyCode belongs. Empty for native tokens (e.g. for BTC, ETH). For more information, see chain codes. |
paymentTxnId | String | No | Transaction ID from payment processor: blockchain, bank. |
paymentDetails | String | No | Comment with payment details. |
# applicant
AND counterparty
ELEMENTS ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
externalUserId | String | Yes | Transaction participant externalUserId. |
fullName | String | Yes | Participant's full name. |
type | String | Yes | Participant entity type (company or individual ). |
address | Object | No | Participant's address. Address available elements are described here. |
institutionInfo | Object | No | Transaction institution info. |
paymentMethod | Object | No | Info about payment method. |
device | Object | No | Device info. |
# institutionInfo
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
code | String | No | Transaction institution code. |
name | String | No | Transaction institution name. |
address | Object | No | Transaction institution address. Available address elements are described here. |
internalId | String | No | VASP ID for counterparty transaction. If provided, we trust the exchange and use the expected VASP for transaction approval. |
# paymentMethod
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
type | String | No | Payment method type: card /account /crypto . |
accountId | String | No | Representation of the account id: account number, IBAN/BIC or DC hash for card , crypto wallet address for crypto type, smart contract or not, etc. |
issuingCountry | String | No | Payment issuing country code in Alpha-3 format. |
3dsUsed | Boolean | No | Indication of 3d secure auth being used. |
2faUsed | Boolean | No | Indication of 2fa being used. |
# gamblingBet
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
amount | Double | Yes | Bet amount. |
currencyCode | String | Yes | Currency ISO code (USD, GBP, BTC, etc.). |
resultAmount | Double | Yes | Result amount. |
betType | String | Yes | Bet type — takes predefined value: Casino , Sport , Poker , Other . |
gameType | String | No | Game type. |
# gamblingLimitChange
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
type | String | Yes | Limit type — takes predefined value: Deposit , Loss , Wager , Session time , Self Exclusion . |
reverted | Boolean | No | Indicates that the limit has been removed. |
amount | Double | Yes | Limit amount. |
currencyCode | String | Yes | Currency ISO code (USD, GBP, BTC, etc.). |
period | String | Yes | Period type — takes predefined value: Daily , Weekly , Monthly . |
resolutionDate | Date | Yes | Indicates the limit ending date. |
sessionLimitInMins | Integer | No | Indicates the session limit period. |
# device
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
userAgent | String | No | Device user agent. |
sessionId | String | No | Transaction session identifier. |
sessionAgeMs | Long | No | Session lifetime in milliseconds. |
acceptLang | String | No | From browser, e.g. en . |
platform | String | No | Device platform, e.g. Mobile Android . |
fingerprint | String | No | Device fingerprint. |
address | Object | No | Device address. Address available elements are described here. |
coords | Object | No | Coordinates. |
ipInfo | Object | No | Data about used IP address. |
# coords
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
lat | Double | No | Position's latitude in decimal degrees. |
lon | Double | No | Position's longitude in decimal degrees. |
accuracy | Double | No | Accuracy of the latitude and longitude properties, expressed in meters. |
# ipInfo
ELEMENT ATTRIBUTES
Name | Type | Required | Description |
---|---|---|---|
lat | Double | No | Position's latitude in decimal degrees. |
lon | Double | No | Position's longitude in decimal degrees. |
ip | String | No | IP address. |
countryCode3 | String | No | Country Alpha-3 code. |
asn | Integer | No | ASN. |
asnOrg | String | No | ASN organisation. |
riskyAsn | Boolean | No | ASN is risky or not. |
# Example request
curl -X POST \
'https://api.sumsub.com/resources/applicants/631f268442d8290001e1eee9/kyt/txns/-/data' \
-H 'Content-Type: application/json' \
-d '{
"txnId": "631f268442d8290001e1eee9_newTxn",
"applicant": {
"externalUserId": "uniqueRemitterId",
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"device": {
"ipInfo": {
"ip": "87.141.63.130"
}
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
},
"paymentMethod": {
"type": "card",
"accountId": "eg_hash_of_credit_card_number",
"issuingCountry": "GBR"
}
},
"counterparty": {
"externalUserId": "uniqueBeneficiaryId",
"fullName": "John Smith",
"type": "individual",
"institutionInfo": {
"code": "CRESCHZZXXX",
"name": "Credit Swiss (Schweiz)"
}
},
"info": {
"direction": "out",
"amount": 101.42,
"currencyCode": "GBP",
"cryptoChain": "TRX",
"paymentTxnId": "84bf83c10dfddc9d1f0ea6a1a131c638488fb161e819dae25fd8128c671d2d5a",
"paymentDetails": "Birthday Present"
},
"props": {
"customProperty": "Custom value that can be used in rules"
}
}'
# RESPONSE ATTRIBUTES
Response contains the information from created transaction (all attributes) above, with data
object and additional objects that contain
current review and scoring info of transaction.
# RESPONSE ATTRIBUTES
Name | Type | Optional | Description |
---|---|---|---|
id | String | No | Transaction ID. |
applicantId | String | No | An applicant ID. |
score | Integer | Yes | Transaction review scoring. |
data | Object | No | Transaction data that was sent before. |
review | Object | No | Transaction review result. |
scoringResult | Object | Yes | Detailed info on transaction scoring. |
# review
ELEMENT ATTRIBUTES
Name | Type | Optional | Description |
---|---|---|---|
reviewStatus | String | No | Transaction status ( onHold , completed , init ). |
reviewResult | Object | Yes | Object representing transaction review result. |
reviewResult.reviewAnswer | String | Yes | GREEN (approved), RED (rejected). |
# scoringResult
ELEMENT ATTRIBUTES
Name | Type | Optional | Description |
---|---|---|---|
matchedRules | Array of Objects | Yes | List of matched rules. |
action | String | No | Result of all matched rules combined (score /onHold /reject ). |
# matchedRules
ELEMENTS ATTRIBUTES
Name | Type | Optional | Description |
---|---|---|---|
id | String | No | Rule ID. |
name | String | Yes | Rule name. |
title | String | Yes | Rule title. |
score | Integer | Yes | Amount that will be added to overall score if rule is matched. |
action | String | No | Result action of the matched rule (score /onHold /reject ). |
# Example response
{
"id": "638f1e3656df2d000138bff0",
"applicantId": "631f268442d8290001e1eee9",
"data": {
"txnId": "631f268442d8290001e1eee9_newTxn",
"applicant": {
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"device": {
"ipInfo": {
"ip": "87.141.63.130"
}
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
}
},
"counterparty": {
"fullName": "John Smith",
"type": "individual",
"institutionInfo": {
"code": "CRESCHZZXXX",
"name": "Credit Swiss (Schweiz)"
}
},
"info": {
"direction": "out",
"amount": 10100.42,
"currencyCode": "GBP",
"paymentDetails": "Birthday Present"
},
"props": {
"customProperty": "Custom value that can be used in rules"
}
},
"review": {
"reviewStatus": "onHold"
},
"scoringResult": {
"matchedRules": [
{
"id": "6391b0d1ac5401000190cf02",
"name": "PAAM2",
"title": "Large amount",
"score": 30,
"action": "onHold"
},
{
"id": "6391b0b2d8f0730001bea772",
"name": "PATX15",
"title": "Average amount for the same beneficiary for the last month is greater by 35% of average amount for last 3 months",
"score": 5,
"action": "score"
}
],
"action": "onHold"
}
}
# Getting transaction
GET /resources/kyt/txns/{id}/one
# REQUEST ARGUMENTS
Name | Type | Required | Description |
---|---|---|---|
id | String | Yes | Transaction ID. |
# RESPONSE ATTRIBUTES
Response contains the info from created transaction (all attributes) above with additional objects that contain current review and scoring info of requested transaction.
# Example response
{
"id": "638f1e3656df2d000138bff0",
"applicantId": "631f268442d8290001e1eee9",
"data": {
"txnId": "631f268442d8290001e1eee9_newTxn",
"applicant": {
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"device": {
"ipInfo": {
"ip": "87.141.63.130"
}
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
}
},
"counterparty": {
"fullName": "John Smith",
"type": "individual",
"institutionInfo": {
"code": "CRESCHZZXXX",
"name": "Credit Swiss (Schweiz)"
}
},
"info": {
"direction": "out",
"amount": 101.42,
"currencyCode": "GBP",
"paymentDetails": "Birthday Present"
},
"props": {
"customProperty": "Custom value that can be used in rules"
}
},
"review": {
"reviewStatus": "onHold"
}
}
# Bulk transaction import
This endpoint allows you to import a list of transactions to your dashboards for our service to consider them in
the next transactions processing for scoring.
It expects transactions to be passed in valid NDJSON with the Content-Type: application/x-ndjson
header being set.
There is a limit on a number of transaction in the bulk import: 10000 records.
POST /resources/kyt/misc/txns/import
# REQUEST BODY
The list of JSON strings representing a KYT transaction divided by \n
is expected.
Transaction object contains properties below:
Name | Type | Required | Description |
---|---|---|---|
applicantId | String | Yes | Id of applicant that have been already processed by SumSub KYC for binding transaction to it. |
data | Object | Yes | Object representing transaction. Properties for it are shown above. |
# Example request
curl -X POST \
'https://api.sumsub.com/resources/kyt/misc/txns/import' \
-H 'Content-Type: application/x-ndjson' \
-d $'{
"applicantId": "636cee6b17d6c7000144673b",
"data": {
"txnId": "631f268442d8290001e1eee8_newTxn",
"applicant": {
"externalUserId": "uniqueRemitterId",
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"device": {
"ipInfo": {
"ip": "87.141.63.130"
}
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
}
},
"counterparty": {
"externalUserId": "uniqueBeneficiaryId",
"fullName": "John Smith",
"type": "individual",
"institutionInfo": {
"code": "CRESCHZZXXX",
"name": "Credit Swiss (Schweiz)"
}
},
"info": {
"direction": "in",
"amount": 101.42,
"currencyCode": "GBP",
"paymentDetails": "Birthday Present"
}
}
}\n{
"applicantId": "636cee6b17d6c7000144673b",
"data": {
"txnId": "631f268442d8290001e1eee9_newTxn",
"applicant": {
"externalUserId": "uniqueRemitterId",
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
}
},
"counterparty": {
"externalUserId": "uniqueBeneficiaryId",
"fullName": "John Smith",
"type": "individual"
},
"info": {
"direction": "out",
"amount": 101.42,
"currencyCode": "GBP",
"paymentDetails": "Birthday Present"
}
}
}'
# RESPONSE ATTRIBUTES
Response contains a number of imported transactions.
# Example response
{
"createdCnt": 2
}
# Changing transaction custom properties
For the cases when some parameter is needed to be added to the transaction, we provide a possibility to do so via method below. Its scope is restricted, and not all fields can be changed.
PATCH /resources/kyt/txns/{id}/props?unsetKeys={unsetKeys}
# REQUEST ARGUMENTS
Name | Type | Required | Description |
---|---|---|---|
id | String | Yes | Transaction ID. |
unsetKeys | String | No | List of property names separated by commas that should be set to null . |
#{body} | Object | Yes | An object representing transaction props with new values. |
# Example request
curl -X POST \
'https://api.sumsub.com/resources/kyt/txns/631f268442d8290001e1eee8/props?unsetKeys=customProp1,customProp2' \
-H 'Content-Type: application/json' \
-d '{
"customProperty": "New custom value",
"newCustomProp": "Another custom prop"
}'
# Example response
{
"id": "631f268442d8290001e1eee8",
"applicantId": "631f268442d8290001e1eee9",
"data": {
"txnId": "631f268442d8290001e1eee9_newTxn",
"applicant": {
"address": {
"country": "DEU",
"street": "Chauseestr. 60",
"postCode": "101115",
"town": "Berlin"
},
"device": {
"ipInfo": {
"ip": "87.141.63.130"
}
},
"institutionInfo": {
"code": "DEUTDEDB101",
"name": "Deutsche Bank"
}
},
"counterparty": {
"fullName": "John Smith",
"type": "individual",
"institutionInfo": {
"code": "CRESCHZZXXX",
"name": "Credit Swiss (Schweiz)"
}
},
"info": {
"direction": "out",
"amount": 10100.42,
"currencyCode": "GBP",
"paymentDetails": "Birthday Present"
},
"props": {
"customProperty": "New custom value",
"newCustomProp": "Another custom prop"
}
},
"review": {
"reviewStatus": "onHold"
},
"scoringResult": {
"matchedRules": [
{
"id": "6391b0d1ac5401000190cf02",
"name": "PAAM2",
"title": "Large amount",
"score": 30,
"action": "onHold"
},
{
"id": "6391b0b2d8f0730001bea772",
"name": "PATX15",
"title": "Average amount for the same beneficiary for the last month is greater by 35% of average amount for last 3 months",
"score": 5,
"action": "score"
}
],
"action": "onHold"
}
}
# Re-scoring transaction
In case transaction data or rules were changed you can run re-scoring for a particular transaction with method below.
POST /resources/kyt/txns/{id}/-/score
# REQUEST ARGUMENTS
Name | Type | Required | Description |
---|---|---|---|
id | String | Yes | Transaction ID. |
# Example request
curl -X POST \
'https://api.sumsub.com/resources/kyt/txns/631f268442d8290001e1eee8/-/score'
Response represents a full transaction data. Same as for transaction creation.
# Approve and reject transaction
POST /resources/kyt/txns/{id}/review/status/completed
# REQUEST ARGUMENTS
Name | Type | Required | Description |
---|---|---|---|
id | String | Yes | Transaction ID. |
#{body} | Object | Yes | An object representing transaction review result. |
# Example request for approval
curl -X POST \
'https://api.sumsub.com/resources/kyt/txns/631f268442d8290001e1eee8/review/status/completed' \
-H 'Content-Type: application/json' \
-d '{
"reviewAnswer": "GREEN"
}'
# Example request for rejection
curl -X POST \
'https://api.sumsub.com/resources/kyt/txns/631f268442d8290001e1eee8/review/status/completed' \
-H 'Content-Type: application/json' \
-d '{
"reviewAnswer": "RED",
"reviewRejectType": "FINAL"
}'
Response represents a full transaction data. Same as for transaction creation.
# Webhooks
The types of webhooks we send depend on the settings of the dashboard.
On the KYT request stats change, we send different types of webhooks depending on the transaction status.
Value | Description |
---|---|
applicantKytTxnApproved | Transaction was approved. |
applicantKytTxnRejected | Transaction was rejected. |
applicantKytOnHold | Transaction status was set to onHold . |
applicantKytTxnAwaitingUser | Transaction status was set to awaitingUser . |
applicantKytTxnDataChanged | Txn data was enriched by the service. |
# Webhook payload attributes
Name | Type | Optional | Description |
---|---|---|---|
applicantId | String | No | Applicant ID. |
externalUserId | String | No | Unique user Id on your side. |
correlationId | String | No | This id uniquely identifies an event on our side. |
type | String | No | Webhook type. |
sandboxMode | Boolean | No | True if the webhook was sent from the Sandbox mode. |
reviewStatus | String | No | Current status of transaction. |
createdAtMs | Date | No | Date and time of webhook creation (format yyyy-MM-dd HH:mm:ss.fff , e.g. 2021-05-14 16:00:25.032) in UTC. |
applicantType | String | Yes | Type of the applicant e.g. company /individual . |
reviewResult | Object | Yes | Field that contains extra information on transaction verification results. |
clientId | String | No | Unique identifier of you as our client. |
kytTxnId | String | No | Unique transaction Id on our service side (.id ). |
kytDataTxnId | String | No | Unique transaction Id on your side (data.txnId ). |
# Example applicantKytTxnApproved webhook payload
{
"applicantId": "634829375766b80001a40152",
"applicantType": "individual",
"correlationId": "f24f6616020245053139a6537303a251",
"sandboxMode": false,
"externalUserId": "customExternalUserId",
"type": "applicantKytTxnApproved",
"reviewResult": {
"reviewAnswer": "GREEN"
},
"reviewStatus": "completed",
"createdAtMs": "2022-10-24 12:42:07.143",
"clientId": "coolClientId",
"kytTxnId": "64a7dc05fbf57c624afcb72d",
"kytDataTxnId": "uauu08x44xexbohyh4lkp9"
}
# Example applicantKytOnHold webhook payload
{
"applicantId": "634829375766b80001a40152",
"applicantType": "individual",
"correlationId": "98d4dac61c977c1b3f81d6ab78d29c3c",
"sandboxMode": false,
"externalUserId": "customExternalUserId",
"type": "applicantKytOnHold",
"reviewStatus": "onHold",
"createdAtMs": "2022-10-24 12:44:32.341",
"clientId": "coolClientId",
"kytTxnId": "64a7dc05fbf57c624afcb72d",
"kytDataTxnId": "j8bqz29yn491vksi9qfydw"
}
# Example applicantKytTxnRejected webhook payload
{
"applicantId": "634829375766b80001a40152",
"applicantType": "individual",
"correlationId": "0f5a7c828bab750775564534fc0470a8",
"sandboxMode": false,
"externalUserId": "customExternalUserId",
"type": "applicantKytTxnRejected",
"reviewResult": {
"reviewAnswer": "RED",
"reviewRejectType": "FINAL"
},
"reviewStatus": "completed",
"createdAtMs": "2022-10-24 12:45:04.982",
"clientId": "coolClientId",
"kytTxnId": "64a7dc05fbf57c624afcb72d",
"kytDataTxnId": "j8bqz29yn491vksi9qfydw"
}
# FAQ
# What should we do if we don't have a checked applicant to add a transaction to it?
If you'd like to create a transaction for a user that hasn't passed verification via our service yet, you can create a new applicant and add a transaction to it using single request POST /resources/applicants/-/kyt/txns/-/data?levelName={levelName}
.
More info is in documentation above.
# What happens to a transaction when it is added?
It is saved and then scored. Depending on the matched rules, the transaction may end up in the “approved”, “rejected” or “on hold” state. Also, it may affect an applicant by requesting additional verifications.
# How can I apply different rules to transactions from different sources?
Provide the sourceKey
field in the transaction data when creating it. Rules without a source key, or source keys
that include the transaction source key will be applied.
# How can I get notified about the scoring result?
You can set up webhooks the same way you do for the applicants. You can react on approved, rejected, and “on hold” transactions.
# How can I test a new rule without fear of breaking anything?
When installing a rule, it is in the Dry run mode by default, meaning that it will be applied but will not affect the final scoring. Additionally, on the Rules tab, you can test the rule by applying it to existing transactions retrospectively.
# What do I do with transactions that are put on hold?
You can explore them at My queues tab and make a final decision. Or you may decide to request an additional applicant action that you set up in advance, e.g. a liveness check, source of funds request, or a questionnaire. So when the applicant action is complete, the status of the transaction will change accordingly. Thus, you can automate risky or suspicious transactions.
# What if I want to have rules that are based on some custom data that are not in your data model?
Add custom fields into the props
map in the transaction data. We will be able to set up rules based on them.
# What can I base my rules on?
Pretty much on everything that we collected about the applicant or transaction. For example, applicant data, id docs, questionnaires, aggregations of data based on devices, geolocation, transaction amounts, and so on. If you miss anything, get in touch. In most cases, it would be an easy exercise to add it for you.
# Can I control certain transactions that match certain rules?
You can set up a custom queue based on rules and computed transaction status. Then you can review transactions that appear in such custom queues, take immediate actions, assign them to yourself or other colleagues for further investigation or confirm the resulting status (if it was approved or rejected).
# What do I need to pass to stay protected?
In general, as much information as you can map to our data structure, plus put the rest into custom properties if you think this field is important. Even if you do not have rules that work on certain fields, you may have some in the future. Then you can do a re-scoring in case you decide to add more rules.
# What kind of reporting do you have?
You can get the events that happened to a transaction, plus you can get the transactions in the CSV report or a detailed PDF report about a particular transaction. If you miss some reporting feature, contact us, and we will try to satisfy your request.
# How do I get reports on certain users or transactions of interest?
Set up a filter that matches your criteria and get a CSV export. If you miss some filters contact us, we will add them for you.