Introduction
The Transaction Monitoring is an automated cryptocurrency transaction monitoring and compliance solution. The API provides near real-time insights into blockchain transactions and their involved counterparties.
At the core of Transaction Monitoring is a REST API that allows you to:
- Programmatically register deposits and withdrawals.
- Retrieve and action alerts for risky deposits and withdrawals.
- Continuously monitor historical transactions for updated risk assessments.
- Conduct case management.
- Create comprehensive, user-level risk profiles.
- Retrieve additional information the UI does not provide alone.
How it works
With the Transaction Monitoring API, you can build a solution to programmatically register your user's deposits and withdrawals and check them for risky associations. For a given transfer/withdrawal attempt, you can retrieve alerts, exposure information, or identifications to help you quickly make synchronous decisions about how to treat the transfer or withdrawal.
In addition to receiving an initial risk assessment of a deposit or withdrawal, you can also use the Transaction Monitoring API to continuously monitor historical transfers (previously registered transfers). The API will generate alerts when an address that previously sent or received cryptocurrency via your platform has either new exposure or a new identification (if the subsequent transfers meet your alert thresholds). To learn more about exposure and identifications, see Exposure and Clustering and identification.
Where to start
To get started using the Transaction Monitoring API, check out the following resources:
- Register a transfer with cURL.
- Register a withdrawal attempt with cURL.
- Workflows
- Other tutorials and resources in the Developer Portal.
For an overview or API reference, see the API overview and API reference sections below.
Development effort
Depending on your desired level of integration, it can take anywhere from one or two days to a couple of weeks to completely integrate with the API. An example of a minimal integration might be using the API to only programmatically register transfers, then using the UI to manually action any alerts.
On the other hand, a more advanced integration might include using the API for real-time transaction monitoring, programmatic registration of withdrawal attempts, or programmatic actioning of alerts.
Ultimately, your level of integration depends on your resources and pace. Your Customer Success Manager is your central point of contact for any onboarding requests. If you need technical installation guidance, they can connect you to our Technical Solutions team to help answer any integration questions you may have.
Status page
We manage a status page to monitor any ongoing incidents. You can subscribe to updates by either phone, email, or Slack. If you have any questions, please contact our Customer Support team.
API overview
The API is a REST API that uses uniform endpoint resources and standard HTTP response codes, and is secured using HTTPS with TLS (v1.2). Continue to the sections below to learn more about its build characteristics.
Environments
Below are the various Transaction Monitoring and Chainalysis environment URLs:
- Base URL: https://api.chainalysis.com/api/kyt
- Transaction Monitoring UI: https://kyt.chainalysis.com
- Chainalysis Graphs: https://reactor.chainalysis.com
Create API keys
You can create API keys from the Tools menu in the Transaction Monitoring UI. Hover your pointer over Developer and select API keys.
To create an API key:
- Log into the Transaction Monitoring environment (either sandbox or primary) for which you want to create an API key.
- From the Tools drop-down menu, click Developer > API keys.
- Click the Generate API Key button. Your API key appears below.
You can also obtain an API key from the Settings menu in Reactor.
Move from a test instance
We recommend using a sandbox instance to test initial API integration and validation. Once you have finished testing and completed the integration, you can move to a second, "clean" instance with new data and API keys. This second instance will be your primary, ongoing instance.
Please contact your CSM to help you create your Transaction Monitoring instances and obtain their credentials.
Once you have both of your Transaction Monitoring instances created:
- Login with your sandbox credentials (obtained via email) and generate your API key for your sandbox instance.
- Make successful requests on the sandbox instance. Ensure requests are successful (register a transfer, register a withdrawal attempt, get alerts)
- Set up compliance workflows and verify that requests are aligned in the sandbox instance.
- Login with your primary credentials (obtained via email) and generate your API key for your primary instance environment (URLs provided above).
Authentication
The API uses a unique API token to authorize calls. To learn how to create an API key, see Create API keys.
You pass this unique token in the token header: Token: {YOUR_API_KEY}.
Example authentication header:
curl -X GET "https://api.chainalysis.com/api/kyt/{ENDPOINT}" \
--header "Token: {YOUR_API_KEY}" \
--header "Accept: application/json"
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/{ENDPOINT}', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/{ENDPOINT}', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/{ENDPOINT}");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Note: Make sure to replace
{YOUR_API_KEY}
with your API key.
If your authentication fails, you will receive a JSON response with an error message and an HTTP status of 400 or 403.
Base URL
The base URL of the API is: api.chainalysis.com/api/kyt
.
Request and response format
All data is sent and received in JSON format, with the exception of the API key (token), which is sent as a header. For all other requests, you should use the Content-type: application/json
or Accept: application/json
in the request headers. Blank fields are included as null
instead of being omitted.
You can also sort and filter many endpoints to help facilitate specific workflows. For instance, you can retrieve only the alerts created between certain date ranges or retrieve the exposure details for a specific user. The endpoint schemas detail which endpoints utilize the sort
parameters and other filterable query parameters. To learn more about alert workflows, see Retrieving alerts for transaction monitoring.
Pagination
In the following example, the query parameters of
"limit": 25
and"offset": 3
would display items 3-28 in the result set of 100total
items.Note that the
"data"
array would typically display the data queried for these objects but has been truncated for this example.
The Transaction Monitoring API supports pagination for endpoints that return long lists of objects. Pagination allows you to retrieve a limited set (or subset) of results and to offset those results. Responses are displayed using total
, limit
, and offset
. To see a different page, append the parameters limit
and/or offset
to the GET
request.
{
"total": 100,
"limit": 25,
"offset": 3,
"data": [
...
]
}
Optional pagination parameters
Parameter | Type | Description |
---|---|---|
limit |
Integer | A limit on the number of objects returned. |
offset |
Integer | The position of the first object returned in the response. The default is 0, which starts the page at the first result. |
total
represents the total number of objects that answer the query, including the ones that are not displayed.data
is an array of the data you requested.
If there is no data to be returned, the data array will be empty.
Data types
Timestamp
2017-09-23T21:44:51.01Z
2017-09-23T21:44:51.01+00.00
Unless specified otherwise, the API returns all timestamps in the ISO 8601 format and adheres to the UTC time standard. Sometimes UTC is indicated by +00.00
, Z
, or in cases where no timezone information is provided, the timestamp is still UTC. Please ensure your system can parse the ISO 8601 format. Most modern languages and libraries will handle ISO 8601 timestamps without issue.
Whenever submitting data, please ensure your timestamps adhere to the UTC time standard.
Rate limits
The Transaction Monitoring API uses rate limiters to help manage the flow of requests to the API, increasing its stability. If you send too many requests in quick succession, you will see error responses with status code 429
.
The rate limiter restricts the number of API requests as follows:
- General rate limit: Restricts more than 4,000 requests in any 60-second period.
- Specific rate limit: Restricts more than 350 requests to the
POST /v1/users/{userId}/withdrawaladdresses
endpoint in any 10-second period .
You can request a limit increase by contacting Customer Support. Approval is at our discretion, and additional details about your use case may be required. If you’re requesting a large increase, contact us at least 6 weeks in advance.
Errors
The Transaction Monitoring API uses standard HTTP response codes to indicate the success or failure of an API request.
Response codes in the 2xx
range indicate success. Response codes in the 4xx
range indicate an error due to the information provided, such as a missing or incorrectly formatted parameter or request body property. Response codes in the 5xx
range indicate an internal server error within Chainalysis.
Transaction Monitoring API codes and meaning
Code | Meaning | Description |
---|---|---|
200 |
Successful request | The request was successful. |
400 |
Bad request | The request was unacceptable. This may refer to a missing or improperly formatted parameter or request body property, non-valid JSON, or the use of testnet blockchain data. |
403 |
Forbidden | Your API key is invalid. This may be because your API Key is expired or not sent correctly as the value of the Token HTTP header. |
404 |
Not found | This may be because you either requested a nonexistent endpoint or referenced a user that does not exist. |
406 |
Not acceptable | You requested a response format that the API cannot produce. We currently only support JSON output. |
409 |
Conflict | The request has a conflict. This may indicate a conflict of association with another user, such as overlapping addresses. |
429 |
Too many requests | Too many requests hit the API too quickly. See Rate limits for more information. |
500 |
Internal server error | (Rare.) This indicates an error with Chainalysis's server. For transfer registration requests, we suggest trying the request again to ensure the API ingests the transfer. |
503 |
Service unavailable error | (Rare.) Chainalysis's server may be unavailable or not ready to handle the request. For transfer registration requests, we suggest trying the request again to ensure the API ingests the transfer. |
504 |
Request timeout | (Rare.) This indicates that our API gateway did not get a response from our application servers within the expected time. |
Error response schema
The following is an example JSON response body from a
400
error:
{
"status": 400,
"message": "The BTC transfer reference a2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v is not syntactically valid"
}
Property | Type | Description |
---|---|---|
status |
Integer | The error code reported. |
message |
String | A human-readable string that provides further detail about the error. |
V2 endpoints
Registration
The following endpoints register transfers and withdrawal attempts:
POST /v2/users/{userId}/transfers
POST /v2/users/{userId}/withdrawal-attempts
Each request requires a userId
to associate the transfer or withdrawal attempt with a specific user in your Transaction Monitoring instance. If the provided userId
does not already exist in your instance, the API will automatically create a new user using the userId
you provided.
Register a transfer
ENDPOINT
POST /v2/users/{userId}/transfers
The following is an example request to create a user and register a transfer of a mature or emerging asset:
curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/new_user_01/transfers' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Content-type: application/json' \
--data '{
"network": "Bitcoin",
"asset": "BTC",
"transferReference": "2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v",
"direction": "received"
}'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
}
transfer_data = {
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v',
'direction': 'received',
}
response = requests.post('https://api.chainalysis.com/api/kyt/v2/users/new_user_01/transfers', headers=headers, json=transfer_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/users/new_user_01/transfers', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Content-type': 'application/json'
},
body: JSON.stringify({
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v',
'direction': 'received'
})
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/users/new_user_01/transfers");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Content-type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("{\n \"network\": \"Bitcoin\",\n \"asset\": \"BTC\",\n \"transferReference\": \"2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v\",\n \"direction\": \"received\"\n}");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
The following is an example request to create a user and register a transfer of a pre-growth asset:
curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/new_user_02/transfers' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Content-type: application/json' \
--data '{
"network": "Chia",
"asset": "XCH",
"transferReference":"0x3419e2be63a8404826a49ab250b007f27447333019079d083c2b322c4cbe3cd4:xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna",
"direction":"sent",
"transferTimestamp": "2022-03-10T20:37:32+00:00",
"assetAmount": 1.75,
"outputAddress": "xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna",
"inputAddresses": ["xch1vjgqx900fwejxgn8667h6pykn544fkxwwqtszv0dmd7ngar52eyq8gr9zd"],
"assetPrice": 69.09,
"assetDenomination": "USD"
}'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
}
transfer_data = {
'network': 'Chia',
'asset': 'XCH',
'transferReference': '0x3419e2be63a8404826a49ab250b007f27447333019079d083c2b322c4cbe3cd4:xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna',
'direction': 'sent',
'transferTimestamp': '2022-03-10T20:37:32+00:00',
'assetAmount': '1.75',
'outputAddress': 'xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna',
'inputAddresses': [
'xch1vjgqx900fwejxgn8667h6pykn544fkxwwqtszv0dmd7ngar52eyq8gr9zd',
],
'assetPrice': '69.09',
'assetDenomination': 'USD',
}
response = requests.post('https://api.chainalysis.com/api/kyt/v2/users/new_user_02/transfers', headers=headers, json=transfer_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/users/new_user_02/transfers', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Content-type': 'application/json'
},
body: JSON.stringify({
'network': 'Chia',
'asset': 'XCH',
'transferReference': '0x3419e2be63a8404826a49ab250b007f27447333019079d083c2b322c4cbe3cd4:xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna',
'direction': 'sent',
'transferTimestamp': '2022-03-10T20:37:32+00:00',
'assetAmount': '1.75',
'outputAddress': 'xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna',
'inputAddresses': [
'xch1vjgqx900fwejxgn8667h6pykn544fkxwwqtszv0dmd7ngar52eyq8gr9zd'
],
'assetPrice': '69.09',
'assetDenomination': 'USD'
})
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/users/new_user_02/transfers");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Content-type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("{\n \"network\": \"Chia\",\n \"asset\": \"XCH\",\n \"transferReference\":\"0x3419e2be63a8404826a49ab250b007f27447333019079d083c2b322c4cbe3cd4:xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna\",\n \"direction\":\"sent\",\n \"transferTimestamp\": \"2022-03-10T20:37:32+00:00\",\n \"assetAmount\": \"1.75\",\n \"outputAddress\": \"xch19ukfhgdjx9w5zw5jkhcrf7sr9qkvhgtk0lv6u7c5m9ptj60dt4tscqkmna\",\n \"inputAddresses\": [\"xch1vjgqx900fwejxgn8667h6pykn544fkxwwqtszv0dmd7ngar52eyq8gr9zd\"],\n \"assetPrice\": \"69.09\",\n \"assetDenomination\": \"USD\"\n}");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint registers a transfer. Once you make a request for a transfer, Transaction Monitoring stores it and begins processing.
For valid transfers that can be processed, the transfer should process within 30 seconds.
This endpoint returns the below response:
202
: Indicates Transaction Monitoring has accepted your transfer and will process your request.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string that identifies the user associated with this transfer. To register a transfer for an existing user, use their existing userId . To register a transfer for a new user, enter a new userId . |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
network |
String | Yes | The network this transfer occurred on. See our supported networks list for the appropriate values. |
asset |
String | Yes | The cryptocurrency or token used in this transfer. The value must be the asset's symbol, for example, BTC for Bitcoin, ETH for Ether, or UNI for Uniswap. |
assetId |
String | No | A unique identifier that represents a specific asset or token on a blockchain. For EVM blockchains, this is the smart contract address. For non-EVM blockchains like Solana, this identifier corresponds to the asset's unique address or ID as defined by the blockchain protocol. Currently, this property is only supported for networks with Dynamic Token Support. For more information, see the Asset IDs. |
transferReference |
String | Yes | A combination of the transaction hash and output address or index of the transaction, separated with a colon. For example, {transaction_hash}:{output_address} or {transaction_hash}:{output_index} . Learn more about the transferReference property here. |
direction |
String | Yes | This value defines whether the transfer is sent or received . This value is case insensitive. |
transferTimestamp |
String | No | The timestamp when the transfer occurred, in the UTC ISO 8601 format. The timestamp should correspond to the timestamp of the block that included the transaction. |
assetAmount |
Number | No | The amount of cryptocurrency funds used in this transfer. |
outputAddress |
String | No | The destination address for funds within the transaction. |
inputAddresses |
Array | No | A list of input addresses of the transfer. Chainalysis uses this property to match network identifications. Note: This property is available only when registering transactions of pre-growth assets. |
assetPrice |
Number | No | The USD price of the asset at the time of the transfer. |
assetDenomination |
String | No | The denomination of the assetPrice property. Available only as USD . |
Response schema
The following is an example JSON response body from the Bitcoin request above:
{
"updatedAt": null,
"asset": "BTC",
"assetId": null,
"network": "BITCOIN",
"transferReference": "2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v",
"tx": null,
"idx": null,
"usdAmount": null,
"assetAmount": null,
"timestamp": null,
"outputAddress": null,
"externalId": "fc8e053e-8833-344d-b025-40559eafd16f"
}
A successful request will return the following JSON response and properties:
Property | Type | Description |
---|---|---|
updatedAt |
String or null |
The timestamp when the transfer was last updated, in the UTC ISO 8601 format. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. Poll the summary endpoint until updatedAt returns a value. |
asset |
String | An echo back of the cryptocurrency asset you defined in the request body. This is the asset's symbol, for example, BTC for Bitcoin or ETH for Ether. |
assetId |
String or null |
An echo back of the assetId you defined in the request body. If null , assetId was not provided or the blockchain does not support the assetId at this time. See Asset IDs for more information. |
network |
String | An echo back of the blockchain network you defined in the request body. |
transferReference |
String | An echo back of the transfer reference you defined in the request body. |
tx |
String or null |
The transaction hash of the transfer. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
idx |
Integer or null |
The transfer’s index. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
usdAmount |
Number or null |
The US Dollar amount of funds used in this transfer. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
assetAmount |
Number or null |
The amount of cryptocurrency funds used in this transfer. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
timestamp |
String or null |
The timestamp when the transfer occurred, in the UTC ISO 8601 format. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
outputAddress |
String or null |
The destination address for funds within the transaction. If not provided in the POST request, the API infers this from the transferReference . Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the transfer. |
externalId |
String | A Chainalysis-generated identifier of this transfer. |
Register a withdrawal attempt
ENDPOINT
POST /v2/users/{userId}/withdrawal-attempts
The following is an example request to register a withdrawal attempt:
curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/user0003/withdrawal-attempts' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Content-type: application/json' \
--data '{
"network": "Bitcoin",
"asset": "BTC",
"address": "1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG",
"attemptIdentifier": "attempt1",
"assetAmount": 5.0,
"assetPrice": 1000.0,
"assetDenomination": "USD",
"attemptTimestamp": "2020-12-09T17:25:40.008307"
}'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
}
withdrawal_attempt_data = {
'network': 'Bitcoin',
'asset': 'BTC',
'address': '1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG',
'attemptIdentifier': 'attempt1',
'assetAmount': 5,
'assetPrice': 1000,
'assetDenomination': 'USD',
'attemptTimestamp': '2020-12-09T17:25:40.008307',
}
response = requests.post('https://api.chainalysis.com/api/kyt/v2/users/user0003/withdrawal-attempts', headers=headers, json=withdrawal_attempt_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/users/user0003/withdrawal-attempts', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Content-type': 'application/json'
},
body: JSON.stringify({
'network': 'Bitcoin',
'asset': 'BTC',
'address': '1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG',
'attemptIdentifier': 'attempt1',
'assetAmount': 5,
'assetPrice': 1000,
'assetDenomination': 'USD',
'attemptTimestamp': '2020-12-09T17:25:40.008307'
})
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/users/user0003/withdrawal-attempts");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Content-type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("{\n \"network\": \"Bitcoin\",\n \"asset\": \"BTC\", \n \"address\": \"1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG\", \n \"attemptIdentifier\": \"attempt1\", \n \"assetAmount\": 5.0, \n \"assetPrice\": 1000.0, \n \"assetDenomination\": \"USD\", \n \"attemptTimestamp\": \"2020-12-09T17:25:40.008307\"\n}");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint registers a withdrawal attempt. Once you make a request for a withdrawal attempt, Transaction Monitoring stores it and begins processing.
This endpoint returns the below response:
202
: Indicates Transaction Monitoring has accepted your withdrawal attempt and will process your request.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string that identifies the user associated with this withdrawal attempt. To register a withdrawal attempt for an existing user, use their existing userId . To register a withdrawal attempt for a new user, enter a new userId . |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
formatType |
String | No | Specifies the format for address and transaction hashes in the JSON response. Options are to_display and normalized . If not specified, the default is normalized for mature networks and to_display for emerging networks. This parameter is not supported for pre-growth networks and will result in a 4xx error if used. To learn more, see Address and hash formats. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
network |
String | Yes | The blockchain network this withdrawal attempt occurred on. See our supported networks list for the appropriate values. |
asset |
String | Yes | The cryptocurrency or token used in this withdrawal attempt. The value must be the asset's symbol, for example, BTC for Bitcoin, ETH for Ether, or UNI for Uniswap. |
assetId |
String | No | A unique identifier that represents a specific asset or token on a blockchain. For EVM blockchains, this is the smart contract address. For non-EVM blockchains like Solana, this identifier corresponds to the asset's unique address or ID as defined by the blockchain protocol. Currently, this property is only supported for networks with Dynamic Token Support. For more information, see the Asset IDs. |
address |
String | Yes | The cryptocurrency address of the wallet to which the withdrawal attempt is being made. |
attemptIdentifier |
String | Yes | A unique string that identifies this withdrawal attempt. Keys can be any valid string but must be unique for every distinct withdrawal attempt. |
assetAmount |
Number | Yes | The amount of cryptocurrency funds used in this withdrawal attempt. |
assetPrice |
Number | No | The USD price of the asset at the time of the withdrawal attempt. Note: If you supply an assetPrice you must also supply the assetDenomination . |
assetDenomination |
String | No | The denomination of the assetPrice property. Available only as USD . Note: If you supply the assetDenomination you must also supply an assetPrice . |
attemptTimestamp |
String | Yes | The timestamp when the withdrawal attempt occurred, in the UTC ISO 8601 format. |
Response schema
The following is an example JSON response body from the above request:
{
"asset": "BTC",
"assetId": null,
"network": "BITCOIN",
"address": "1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG",
"attemptIdentifier": "attempt1",
"assetAmount": 5.0,
"usdAmount": null,
"updatedAt": "2022-04-27T20:21:43.803+00:00",
"externalId": "e27adb25-7344-3ae3-9c80-6b4879a85826"
}
A successful request will return the following JSON response and properties:
Property | Type | Description |
---|---|---|
asset |
String | An echo back of the asset you defined in the request body. This is the asset's symbol, for example, BTC for Bitcoin or ETH for Ether. |
assetId |
String or null |
An echo back of the assetId you defined in the request body. If null , assetId was not provided or the blockchain does not support the assetId at this time. See Asset IDs for more information. |
network |
String | An echo back of the blockchain network you defined in the request body. |
address |
String | An echo back of the address you defined in the request body. |
attemptIdentifier |
String | An echo back of the identifier you created in the request body. |
assetAmount |
Number | An echo back of the asset amount defined in the request body. |
usdAmount |
Number or null |
The US Dollar amount of funds used in this transfer. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the withdrawal attempt. |
updatedAt |
String or null |
The timestamp when the withdrawal attempt was last updated, in the UTC ISO 8601 format. Note: this value remains null following the initial POST request until Transaction Monitoring finishes processing the withdrawal attempt. If null , poll the summary endpoint until updatedAt returns a value. |
externalId |
String | A Chainalysis-generated identifier of the withdrawal attempt. |
Transfers
These endpoints return a transfer's summary, direct exposure, alerts, and any available network identifications.
GET /v2/transfers/{externalId}
GET /v2/transfers/{externalId}/exposures
GET /v2/transfers/{externalId}/alerts
GET /v2/transfers/{externalId}/network-identifications
Get a summary
ENDPOINT
GET /v2/transfers/{externalId}
The following is an example request to retrieve a summary for a registered transfer:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns the summary of the transfer you registered in your POST /transfers
request.
Note: You must register your transfer using the Transfer Registration endpoint before you implement the below.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this transfer. This is returned in the response body of the POST /transfers request. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
formatType |
String | No | Specifies the format for address and transaction hashes in the JSON response. Options are to_display and normalized . If not specified, the default is normalized for mature networks and to_display for emerging networks. This parameter is not supported for pre-growth networks and will result in a 4xx error if used. To learn more, see Address and hash formats. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"updatedAt": "2022-03-16T16:17:19.613215",
"asset": "BTC",
"assetId": null,
"network": "BITCOIN",
"transferReference": "9f318afbad2a183f97750bc51a75b582ad8f9e9cbfb50401148857ca27cde10c:17A16QmavnUfCW11DAApiJxp7ARnxN5pGX",
"tx": "9f318afbad2a183f97750bc51a75b582ad8f9e9cbfb50401148857ca27cde10c",
"idx": 2,
"usdAmount": 722091.75,
"assetAmount": 11.35113454,
"timestamp": "2021-11-16T18:33:33.000+00:00",
"outputAddress": "17A16QmavnUfCW11DAApiJxp7ARnxN5pGX",
"externalId": "393905a7-bb96-394b-9e20-3645298c1079"
}
If the updatedAt
property returns null
, Transaction Monitoring has not finished processing the transfer and other properties will also return null
. We suggest you poll this GET
request until the property populates.
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
updatedAt |
String or null |
The timestamp of when the transfer was last updated, in the UTC ISO 8601 format. If null , the transfer has not yet processed, or couldn’t process as it has not appeared in the blockchain. |
asset |
String or null |
The asset used in the transfer. |
assetId |
String or null |
The asset ID for the asset used in the transfer. If null , assetId was not provided or the blockchain does not support the assetId at this time. |
network |
String or null |
The blockchain network the transfer occurred on. |
transferReference |
String or null |
The transferReference you defined in the POST call's request body. |
tx |
String or null |
The transaction hash of the transfer. |
idx |
Integer or null |
The transfer's index. If null , either Transaction Monitoring has not finished processing the transfer or the transaction does not contain indexed transfers. |
usdAmount |
Number or null |
The US Dollar amount of funds used in this transfer. If null , either Transaction Monitoring has not finished processing the transfer or the information was not sent in the GET request. |
assetAmount |
Number or null |
The amount of cryptocurrency funds used in this transfer. If null , either Transaction Monitoring has not finished processing the transfer or the information was not sent in the GET request. |
timestamp |
String or null |
The blockchain timestamp when the transfer occurred, in the UTC ISO 8601 format. If null , either Transaction Monitoring has not finished processing the transfer or the information was not sent in the GET request. |
outputAddress |
String or null |
The destination address for funds within the transaction. If null , either Transaction Monitoring API has not finished processing the transfer or the information was not sent in the GET request. |
externalId |
String | The Chainalysis-generated identifier of this transfer. This is returned in the response body of the POST /transfers request. |
Get direct exposure
ENDPOINT
GET /v2/transfers/{externalId}/exposures
The following is an example request to retrieve direct exposure from a registered
BTC
transfer:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/transfers/ae5e6b88-ad59-3688-ac2d-2b5a251e799e/exposures' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/transfers/ae5e6b88-ad59-3688-ac2d-2b5a251e799e/exposures', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/transfers/ae5e6b88-ad59-3688-ac2d-2b5a251e799e/exposures', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/transfers/ae5e6b88-ad59-3688-ac2d-2b5a251e799e/exposures");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns any available direct exposure information for a registered transfer. This endpoint only returns direct exposure for transfers of mature and emerging assets. If the transfer was of a pre-growth asset, the endpoint returns null
values.
You should call this endpoint after Transaction Monitoring has processed your transfer. To verify whether your transfer has processed, call the Transfers summary endpoint, then check whether the updatedAt
response body property contains a value. If updatedAt
returns null
, your transfer has not yet processed.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this transfer. This is returned in the response body of the POST /transfers request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"direct": {
"name": "BitPay.com",
"categoryId": 17
}
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
direct |
Object or null |
Contains information of a given cluster's direct exposure. If null , the entity has neither a name and category or Chainalysis has identified neither the name and category. |
direct.name |
String | The name of a given cluster's counterparty as identified by Chainalysis. If null , the entity has no name or Chainalysis has not identified the entity. |
direct.category |
String | This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The category of a given cluster's counterparty as identified by Chainalysis. If null , the entity has no category or Chainalysis has not identified the entity's category. |
direct.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Get alerts
ENDPOINT
GET /v2/transfers/{externalId}/alerts
The following is an example request to retrieve alert information of a registered transfer:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079/alerts' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079/alerts', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079/alerts', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/transfers/393905a7-bb96-394b-9e20-3645298c1079/alerts");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint retrieves transfer alerts generated for a specified transfer, identified by its externalId
. This endpoint does not retrieve behavioral alerts.
You will receive a successful response after Transaction Monitoring has processed your transfer. To verify your transfer has been processed, call the /v2/transfers/{externalId}
endpoint and check if the updatedAt
property in the response body is populated. If the JSON response array is empty, Transaction Monitoring has not generated any alerts for the associated transfer.
Note: Transfer alerts are generated based on your organization's alert rules. Learn more about defining these rules here.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this transfer. This is returned in the response body of the POST /transfers request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"alerts": [
{
"alertLevel": "Severe",
"service": "OFAC SDN Blender.io 2022-05-06",
"externalId": "906ff226-8b64-11eb-8e52-7b35a3dc1742",
"alertAmount": 8868.24,
"exposureType": "DIRECT",
"categoryId": 3
}
]
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
alerts |
Array | Contains alert information for a given transfer. If no alerts have been generated, the array will be empty. |
alerts.alertLevel |
String | Defines the alert's risk as SEVERE , HIGH , MEDIUM , or LOW . |
alerts.category |
String or null |
This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The entity category the alert rule is tracking. Will be null if the rule is tracking "any category". |
alerts.service |
String or null |
The name of the service as defined by Chainalysis. If null returns, Chainalysis has not yet identified the service's name. |
alerts.externalId |
String | A unique identify of the alert. |
alerts.alertAmount |
Number | The USD amount that caused the alert to trigger. |
alerts.exposureType |
String | Defines the exposure direction as DIRECT or INDIRECT . |
alerts.categoryId |
Integer or null |
A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. Note: will be null if the alert rule is tracking "any category". |
Get network identifications
ENDPOINT
GET /v2/transfers/{externalId}/network-identifications
The following is an example request to retrieve the count of network identifications from a registered transfer:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/transfers/94d72448-6963-3536-9996-1637f6756f0b/network-identifications' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/transfers/94d72448-6963-3536-9996-1637f6756f0b/network-identifications', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/transfers/94d72448-6963-3536-9996-1637f6756f0b/network-identifications', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/transfers/94d72448-6963-3536-9996-1637f6756f0b/network-identifications");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns any available network identifications for a registered transfer of a pre-growth asset. If the transfer was of a mature or emerging asset, the endpoint will return a 400
error.
You should call this endpoint after the Transaction Monitoring API has processed your transfer. To verify whether your transfer has processed, call the Transfers summary endpoint, then check whether the updatedAt
response body property contains a value. If updatedAt
returns null
, your transfer has not yet processed.
Learn more about Network Identifications here.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this transfer. This is returned in the response body of the POST /transfers request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"count": 1,
"networkIdentificationOrgs": [
{
"name": "XYZ Cryptocurrency Exchange"
}
]
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
count |
Number | The number of other organizations in the Chainalysis's data network that registered the transfer in the opposing direction. For example, if you registered the transfer in the SENT direction, you will receive the count of registered transfers in the RECEIVED direction. |
networkIdentificationOrg |
Array | Contains the names of the organizations that registered the transfer in Chainalysis's data network. If there are no network identifications, the array will be empty. |
networkIdentificationOrg.name |
String | The name of the organization that registered the transfer in Chainalysis's data network. |
Withdrawal attempts
These endpoints return a withdrawal attempt's summary, direct exposure, alerts, and any available network identifications.
GET /v2/withdrawal-attempts/{externalId}
GET /v2/withdrawal-attempts/{externalId}/exposures
GET /v2/withdrawal-attempts/{externalId}/alerts
GET /v2/withdrawal-attempts/{externalId}/high-risk-addresses
GET /v2/withdrawal-attempts/{externalId}/network-identifications
Get a summary
ENDPOINT
GET /v2/withdrawal-attempts/{externalId}
The following is an example request to retrieve a summary for a withdrawal attempt:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns the summary of the withdrawal attempt you registered in your POST /withdrawal-attempts
request.
Note: You must register your withdrawal attempt using the Withdrawal Attempt Registration endpoint before you implement the below.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST /withdrawal-attempts request. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
formatType |
String | No | Specifies the format for address and transaction hashes in the JSON response. Options are to_display and normalized . If not specified, the default is normalized for mature networks and to_display for emerging networks. This parameter is not supported for pre-growth networks and will result in a 4xx error if used. To learn more, see Address and hash formats. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"asset": "BTC",
"assetId": null,
"network": "BITCOIN",
"address": "1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG",
"attemptIdentifier": "attempt11",
"assetAmount": 5.0,
"usdAmount": 5000.00,
"updatedAt": "2021-03-23T15:21:10.835+00:00",
"externalId": "e27adb25-7344-3ae3-9c80-6b4879a85826"
}
If the updatedAt
property returns null
, Transaction Monitoring has not finished processing the withdrawal attempt and other properties will also return null
. We suggest you poll this GET
request until the property populates.
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
asset |
String or null |
The asset used in the withdrawal attempt. |
assetId |
String or null |
The asset ID for the asset used in the transfer. If null , assetId was not provided or the blockchain does not support the assetId at this time. |
network |
String or null |
The blockchain network the withdrawal attempt occurred on. |
address |
String or null |
The address where the withdrawal attempt is being made. |
attemptIdentifier |
String or null |
An echo back of the attemptIdentifier you created in the POST request. |
assetAmount |
Number or null |
The amount of cryptocurrency funds used in this withdrawal attempt. |
usdAmount |
Number or null |
The amount of US Dollars used in this withdrawal attempt. |
updatedAt |
String or null |
The timestamp of when the withdrawal attempt was last processed, in the UTC ISO 8601 format. If null , the withdrawal attempt has not yet processed. |
externalId |
String | A Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST request. |
Get direct exposure
ENDPOINT
GET /v2/withdrawal-attempts/{externalId}/exposures
The following is an example request to retrieve direct exposure information from a registered
BTC
withdrawal attempt:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826/exposures' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826/exposures', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826/exposures', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/e27adb25-7344-3ae3-9c80-6b4879a85826/exposures");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns any available direct exposure information for a withdrawal attempt. This endpoint only returns direct exposure for withdrawal attempts of mature assets and all Ethereum ERC-20s. If the withdrawal attempt was of a pre-growth asset, the endpoint returns null
values.
You should call this endpoint after Transaction Monitoring has processed your withdrawal attempt. To verify whether withdrawal attempt has processed, call the Withdrawal attempts summary endpoint, then check whether the updatedAt
response body property contains a value. If updatedAt
returns null
, your withdrawal attempt has not yet processed.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST /withdrawal-attempts request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body for a withdrawal attempt to the Litcoin address
37DKAHsmY4KsH2ZcXy1jx9vyzWqTDYiwN2
:
{
"direct": {
"name": "Benumb Shop",
"categoryId": 28
}
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
direct |
Object | Contains information of a given cluster's direct exposure. |
direct.name |
String or null |
The name of a given cluster's counterparty as identified by Chainalysis. If null , the entity has no name or Chainalysis has not identified the entity. |
direct.category |
String or null |
This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The category of a given cluster's counterparty as identified by Chainalysis. If null , the entity has no category or Chainalysis has not identified the entity's category. |
direct.categoryId |
Integer or null |
A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. If null , the entity has no category or Chainalysis has not identified the entity's category. |
Get alerts
ENDPOINT
GET /v2/withdrawal-attempts/{externalId}/alerts
The following is an example request to retrieve alert information from a registered withdrawal attempt:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/alerts' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/alerts', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/alerts', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/alerts");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns a withdrawal attempt's alerts, if available.
You will receive a successful response after the API has processed your withdrawal attempt. If the JSON response array is empty, Transaction Monitoring has not generated any alerts for the associated withdrawal-attempt.
To ensure a successful response, call the Withdrawal Attempt Summary endpoint to view if the updatedAt
property in your response body is populated before examining your withdrawal attempt's alerts.
Note: Alerts for withdrawal attempts generate according to your organization's alert rules. Learn more about how to define these rules here.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST /withdrawal-attempts request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"alerts": [
{
"alertLevel": "SEVERE",
"service": "TERRORIST FINANCING: Jaysh Al-Ummah 1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG",
"externalId": "154d68e6-e409-11eb-a1b0-0ba6b7510249",
"alertAmount": 5000.00,
"exposureType": "DIRECT",
"categoryId": 23
}
]
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
alerts |
Array | Contains alert information for a given withdrawal attempt. |
alerts.alertLevel |
String | Defines the alert's risk as SEVERE , HIGH , MEDIUM , or LOW . |
alerts.alertAmount |
Number | The USD amount that caused the alert to trigger. |
alerts.category |
String or null |
This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The entity category the alert rule is tracking. Will be null if the rule is tracking "any category". |
alerts.exposureType |
String | Defines the exposure direction as DIRECT . Currently, we don't provide indirect exposure for withdrawal attempt alerts. |
alerts.externalId |
String | A unique identifier of the alert. |
alerts.service |
String or null |
The name of the service as defined by Chainalysis. If null returns, Chainalysis has not yet identified the service's name. |
alerts.categoryId |
Integer or null |
A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Get address identifications
ENDPOINT
GET /v2/withdrawal-attempts/{externalId}/high-risk-addresses
The following is an example request to retrieve custom address information from a registered withdrawal attempt:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/high-risk-addresses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/high-risk-addresses', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/high-risk-addresses', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/eb67cbdc-8bea-11eb-83d5-378cec3052c2/high-risk-addresses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns address identification for the withdrawal attempt, either a user’s upload of custom addresses or Chainalysis identified addresses.
You will receive a successful response after Transaction Monitoring has processed your withdrawal attempt.
To ensure a successful response, call the Withdrawal Attempt Summary endpoint to view if the updatedAt
property in your response body is populated before examining your withdrawal attempt's high risk address information.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST /withdrawal-attempts request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body for a withdrawal attempt with a Chainalysis Address Identification:
{
"chainalysisIdentifications": [
{
"addressName": "SANCTIONS: OFAC SDN: Xiaobing Yan",
"description": "This specific address 12QtD5BFwRsdNsAZY76UVE1xyCGNTojH9h within the cluster has been identified as belonging to an individual on OFAC's SDN list. YAN, Xiaobing (Chinese Traditional: 顏曉兵; Chinese Simplified: 颜晓兵) (a.k.a. \"YAN, Steven\"; a.k.a. \"ZHOU, William\"), Wuhan, Hubei, China (Chinese Simplified: 武汉市, 湖北省, China; Chinese Traditional: 武漢市, 湖北省, China); DOB 25 Mar 1977; POB Wuhan City, Hubei, China; citizen China; Gender Male; Chinese Commercial Code 7346 2556 0365; Citizen's Card Number 421002197703250019 (China) (individual) [SDNTK].",
"categoryId": 3
}
],
"customAddresses": []
}
The following is an example JSON response body for a withdrawal attempt with custom address information:
{
"chainalysisIdentifications": [],
"customAddresses": [
{
"addressName": "Play Royal",
"description": "This address belongs to playroyal.com, a gambling site",
"categoryId": 999
}
]
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
chainalysisIdentifications |
Array | A Chainalysis Address Identification, representing an address-level identification that is part of a larger cluster. The array will be empty if there are no Chainalysis Address Identifications. |
chainalysisIdentifications.addressName |
String | The name designated to the Chainalysis Address Identification. |
chainalysisIdentifications.categoryName |
String | This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The category of the Chainalysis Address Identification. |
chainalysisIdentifications.description |
String | The OSINT description of the Chainalysis Address Identification. |
chainalysisIdentifications.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
customAddresses |
Array | Contains custom address information that matches the addresses in the withdrawal attempt. The array will be empty if there are no Custom Addresses. |
customAddresses.addressName |
String | The name of the address the custom address was registered under. |
customAddresses.description |
String | The description of the custom address. |
customAddresses.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Get network identifications
ENDPOINT
GET /v2/withdrawal-attempts/{externalId}/network-identifications
The following is an example request to retrieve the count of network identifications from a registered withdrawal attempt:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/159cc56a-ae87-3aab-a2fc-2d4f9f42885f/network-identifications' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/159cc56a-ae87-3aab-a2fc-2d4f9f42885f/network-identifications', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/159cc56a-ae87-3aab-a2fc-2d4f9f42885f/network-identifications', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/withdrawal-attempts/159cc56a-ae87-3aab-a2fc-2d4f9f42885f/network-identifications");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint returns any available network identifications for a registered withdrawal attempt of a pre-growth asset. If the withdrawal attempt was of a mature or emerging asset, the endpoint will return a 400 error.
You should call this endpoint after Transaction Monitoring has processed your withdrawal attempt. To verify whether your withdrawal attempt has processed, call the Withdrawal attempts summary endpoint, then check whether the updatedAt
response body property contains a value. If updatedAt
returns null
, your withdrawal attempt has not yet been processed.
Learn more about Network Identifications here.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
externalId |
String | Yes | The Chainalysis-generated identifier of this withdrawal attempt. This is returned in the response body of the POST /withdrawal-attempts request. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"count": 1,
"networkIdentificationOrgs": [
{
"name": "XYZ Cryptocurrency Exchange"
}
]
}
A successful request will return the following JSON response and properties for a given externalId
:
Property | Type | Description |
---|---|---|
count |
Integer | The number of other organizations in Chainalysis's data network that registered the withdrawal attempt. |
networkIdentificationOrgs |
Array | Contains the names of the organizations that registered the withdrawal attempt in Chainalysis's data network. |
networkIdentificationOrgs.name |
String | The name of the organization that registered the withdrawal attempt in Chainalysis's data network. |
Categories
Retrieve categories
ENDPOINT
GET /v2/categories
The following is an example request to retrieve entity categories:
curl -X GET 'https://api.chainalysis.com/api/kyt/v2/categories' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v2/categories', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v2/categories', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v2/categories");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint retrieves a list of all available entity categories and the corresponding category IDs.
We recommend that you call this endpoint periodically to ensure that you have the most recent categories Chainalysis is using, keeping your integration up-to-date.
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"categories": [
{
"categoryId": 2,
"categoryName": "darknet market"
},
{
"categoryId": 3,
"categoryName": "sanctioned entity"
},
{...}
]
}
Property | Type | Description |
---|---|---|
categories |
Array | An array containing category information. |
categoryId |
Integer | The unique identifier associated with each entity category. |
categoryName |
String | The name of the entity category. It represents the category's human-readable label. |
Administration
The following endpoint helps manage internal users:
GET /admin/organization/users
Retrieve internal users
ENDPOINT
GET /admin/organization/users
The following is an example request to retrieve a list of all internal users:
curl -X GET 'https://api.chainalysis.com/admin/organization/users' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/admin/organization/users', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/admin/organization/users', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/admin/organization/users");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint retrieves a list of internal users, including their name, email address, permissions, and other account information.
You need the ORGADMIN
permission to use this endpoint.
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
[
{
"fullName": "Satoshi Nakamoto",
"email": "satoshi@example-email-domain.com",
"permissions": [
"ORGADMIN",
"KYT_UPLOAD_TRANSFER",
"RISK_API"
],
"lastActivity": "2024-04-30T11:26:26.847Z",
"license": "Default license",
"locked": true,
"expired": true
}
],
[
{
"fullName": "John Doe",
"email": "john.doe@example-email-domain.com",
"permissions": [
"KYT_UPLOAD_TRANSFER"
],
"lastActivity": "2024-04-30T11:26:26.847Z",
"license": "Default license",
"locked": false,
"expired": false
}
],
[
{
...
}
]
Property | Type | Description |
---|---|---|
fullName |
String | The full name of the user. |
email |
String | The email address of the user. |
permissions |
Array | A list of permission types associated with the user. |
lastActivity |
String | The timestamp of the user's last activity, formatted in ISO 8601. |
license |
String | The license type associated with the user. |
locked |
Boolean | Indicates whether the user's account is locked. |
expired |
Boolean | Indicates whether the user's account has expired. |
V1 endpoints
Received transfers
These endpoints register and retrieve received transfers that occurred on mature or emerging networks.
POST /v1/users/{userId}/transfers/received
GET /v1/users/{userId}/transfers/received
With them, you can perform the following actions:
- Register incoming transfers (deposits) to a user at your organization.
- Screen deposits for illicit (high risk) counterparties, and allow for programmatic alerts and action.
- Retrieve all received transfers used to calculate an individual users risk score.
If you'd like to register transfers that occurred on pre-growth networks, please use the POST /v2/users/{userId}/transfers
endpoint.
Register a received transfer
ENDPOINT
POST /v1/users/{userId}/transfers/received
The following is an example request to register a received transfer of a mature or emerging asset:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/005/transfers/received' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '[
{
"network": "Bitcoin",
"asset": "BTC",
"transferReference": "43ed2f877b437153c78f8a2fd09b9852c65d53734590388e2698824e812a464f:12aEpHFWiogdNV1Bp6EizQwwXuV91LAn87"
}
]'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
received_transfer_data = [
{
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '43ed2f877b437153c78f8a2fd09b9852c65d53734590388e2698824e812a464f:12aEpHFWiogdNV1Bp6EizQwwXuV91LAn87',
},
]
response = requests.post('https://api.chainalysis.com/api/kyt/v1/users/005/transfers/received', headers=headers, json=received_transfer_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/005/transfers/received', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '43ed2f877b437153c78f8a2fd09b9852c65d53734590388e2698824e812a464f:12aEpHFWiogdNV1Bp6EizQwwXuV91LAn87'
}
])
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/005/transfers/received");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("[\n {\n \t\"network\": \"Bitcoin\",\n \"asset\": \"BTC\",\n \t\"transferReference\": \"43ed2f877b437153c78f8a2fd09b9852c65d53734590388e2698824e812a464f:12aEpHFWiogdNV1Bp6EizQwwXuV91LAn87\"\n }\n]");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string that identifies the user associated with this transfer. To register a transfer for an existing user, use their existing userId . To register a transfer for a new user, enter a new userId . |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
bulkImport |
Boolean | No | Determines whether to register transfers in bulk. You can submit either true or false . If set to true , no real-time response is returned and the request executes faster. We suggest using this parameter if you do not require the real-time response. There is a limit of 100 transfers when bulkImport is false or unspecified and 1000 transfers when bulkImport is true. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
network |
String | Yes | The blockchain network this transfer occurred on. See our mature and emerging networks for the appropriate values. |
asset |
String | Yes | The cryptocurrency or token used in this transfer. The value must be the asset's symbol, for example, BTC for Bitcoin, ETH for Ether, or UNI for Uniswap. |
transferReference |
String | Yes | A combination of the transaction hash and output address or index of the transaction, separated with a colon. For example, {transaction_hash}:{output_address} or {transaction_hash}:{output_index} . Learn more about the transferReference property here. |
transferTimestamp |
String | No | The blockchain timestamp when the transfer occurred, in the UTC and ISO 8601 format. |
assetAmount |
Number | No | The amount of cryptocurrency funds used in this transfer. |
Response schema
The following is an example JSON response body from the above mature request:
[
{
"transferReference": "2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v",
"asset": "BTC",
"cluster": {
"name": "Coinbase.com",
"categoryId": 21
},
"rating": "lowRisk"
}
]
A successful request will return a 200 code, indicating Transaction Monitoring successfully registered and will process your transfer.
If the asset used in the transfer is from a mature network, the response will display a populated array of the below properties. If the asset used in the transfer is from an emerging, the response will display an empty array. To get more information about transfers on emerging networks, call the GET /v1/users/{userId}/transfers/received
endpoint.
Property | Type | Description |
---|---|---|
transferReference |
String | An echo back of the transfer reference you defined in the request body. |
asset |
String | An echo back of the asset type you defined in the request body. This is the asset's symbol, for example, BTC for Bitcoin or ETH for Ether. |
cluster |
Object or null |
The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. This value will be null if the cluster has not yet been identified. |
cluster.name |
String | The name of a named Cluster. |
cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category the named Cluster belongs to (such as exchange ). |
cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
rating |
String | The risk rating of the transfer, either highRisk , lowRisk , or unknown . The rating corresponds to the entity's category. Learn more about entity categories here and highRisk categories here . unknown means Chainalysis has not yet identified the entity or the entity is Unnamed. |
Get a received transfer
ENDPOINT
GET /v1/users/{userId}/transfers/received
The following is an example request to retrieve all received transfers for user
BTC_01
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/received' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/received', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/received', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/received");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint retrieves all registered received transfers for a given userId
. Note that the response also returns received transfers registered with the POST /v2/users/{userId}/transfers
endpoint.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string of the user associated with this transfer. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
limit |
Integer | No | A limit on the number of objects returned. |
offset |
Integer | No | The position of the first object returned in the response. The default is 0, which starts the page at the first result. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"limit": 100,
"offset": 0,
"total": 1,
"data": [
{
"asset": "BTC",
"transferReference": "2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v",
"amount": "4",
"amountUSD": "561.64",
"timestamp": "2021-07-07T18:29:14Z",
"rating": "lowRisk",
"cluster": {
"name": "Coinbase.com",
"categoryId": 21
}
}
]
}
A successful request will return the following JSON response and properties for a given userId
.
Property | Type | Description |
---|---|---|
limit |
Integer | An echo back of the limit query parameter. |
offset |
Integer | An echo back of the offset query parameter. |
total |
Integer | The total number of transfer objects returned. |
data |
Array | An array containing transfer data. |
data.asset |
String | The asset that was transferred. |
data.transferReference |
String | The transferReference you defined in the POST call's request body. |
data.amount |
Number | The amount of cryptocurrency funds used in this transfer. |
data.amountUSD |
Number | The US Dollar amount of funds used in this transfer. |
data.timestamp |
String | The blockchain timestamp when the transfer occurred, in the UTC and ISO 8601 format. |
data.rating |
String | The risk rating of the transfer, either highRisk , lowRisk , or unknown . The rating corresponds to the entity's category. Learn more about entity categories here and highRisk categories here . unknown means Chainalysis has not yet identified the entity or the entity is Unnamed. |
data.cluster |
Object or null |
The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. This value will be null if the cluster has not yet been identified. |
data.cluster.name |
String | The name of a named Cluster. |
data.cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category the named Cluster belongs to, for example, an exchange. |
data.cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Sent transfers
These endpoints register and retrieve sent transfers that occurred on mature or emerging networks.
POST /v1/users/{userId}/transfers/sent
GET /v1/users/{userId}/transfers/sent
With them, you can:
- Register outgoing transfers (withdrawals) from users at your organization
- Call directly after the WithdrawalAddress endpoint for transfers executed after pre-screening
- Retrieve all sent transfers used in the calculation for a users risk score
If you'd like to register transfers that occurred on pre-growth networks, please use the POST /v2/users/{userId}/transfers
endpoint.
Register a sent transfer
ENDPOINT
POST /v1/users/{userId}/transfers/sent
The following is an example request to register a sent transfer of a mature or emerging asset:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/006/transfers/sent' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '[
{
"network": "Bitcoin",
"asset": "BTC",
"transferReference": "7c2238d4de91472061d66f918bda68541f33bd84ce994bcf191cd1315fa41118:16HgQB937BRDk3PyS9nSUuHE2P6CbjNuAe"
}
]'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
sent_transfer_data = [
{
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '7c2238d4de91472061d66f918bda68541f33bd84ce994bcf191cd1315fa41118:16HgQB937BRDk3PyS9nSUuHE2P6CbjNuAe',
},
]
response = requests.post('https://api.chainalysis.com/api/kyt/v1/users/006/transfers/sent', headers=headers, json=sent_transfer_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/006/transfers/sent', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
'network': 'Bitcoin',
'asset': 'BTC',
'transferReference': '7c2238d4de91472061d66f918bda68541f33bd84ce994bcf191cd1315fa41118:16HgQB937BRDk3PyS9nSUuHE2P6CbjNuAe'
}
])
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/006/transfers/sent");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("[\n {\n \t\"network\": \"Bitcoin\",\n \"asset\": \"BTC\",\n \t\"transferReference\": \"7c2238d4de91472061d66f918bda68541f33bd84ce994bcf191cd1315fa41118:16HgQB937BRDk3PyS9nSUuHE2P6CbjNuAe\"\n }\n]");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string that identifies the user associated with this transfer. To register a transfer for an existing user, use their existing userId . To register a transfer for a new user, enter a new userId . |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
network |
String | Yes | The blockchain network this transfer occurred on. See our mature and emerging networks for the appropriate values. |
asset |
String | Yes | The cryptocurrency or token used in this transfer. The value must be the asset's symbol, for example, BTC for Bitcoin, ETH for Ether, or UNI for Uniswap. |
transferReference |
String | Yes | A combination of the transaction hash and output address or index of the transaction, separated with a colon. For example, {transaction_hash}:{output_address} or {transaction_hash}:{output_index} . Learn more about the transferReference property here. |
transferTimestamp |
String | No | The blockchain timestamp when the transfer occurred, in the UTC ISO 8601 format. |
assetAmount |
Number | No | The amount of cryptocurrency funds used in this transfer. |
Response schema
The response will be an empty zero byte response, indicated by a response header Content-Length: 0
.
Get a sent transfer
ENDPOINT
GET /v1/users/{userId}/transfers/sent
The following is an example request for retrieving all sent transfers for user
BTC_01
.
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/sent' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/sent', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/sent', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/BTC_01/transfers/sent");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint retrieves all registered sent transfers for a given userId
. Note that the response also returns sent transfers registered with the POST /v2/users/{userId}/transfers
endpoint.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string of the user associated with this transfer. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
limit |
Integer | No | A limit on the number of objects returned. If unspecified, the default is 100. |
offset |
Integer | No | The position of the first object returned in the response. The default is 0, which starts the page at the first result. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"limit": 100,
"offset": 0,
"total": 1,
"data": [
{
"asset": "ETH",
"transferReference": "0x41af697d34230e084ff5fb74fab30fc878a14567ac8f97573ba98c401adc4d97:0x30FF461f7f077E6E18CE0670D352c0c54CA3D102",
"amount": 6.31049917,
"amountUSD": 1195.71,
"timestamp": "2019-09-16T09:36:09Z",
"cluster": {
"name": "Kraken.com",
"categoryId": 21
}
}
]
}
A successful request will return the following properties in JSON format for a given userId
.
Property | Type | Description |
---|---|---|
limit |
Integer | An echo back of the limit query parameter. |
offset |
Integer | An echo back of the offset query parameter. |
total |
Integer | The total number of transfer objects returned. |
data |
Array | An array containing transfer data. |
data.asset |
String | The asset that was transferred. |
data.transferReference |
String | The <transaction_hash:output_address OR index> combination associated with the transaction. |
data.amount |
Number | The amount of cryptocurrency funds used in this transfer. |
data.amountUSD |
Number | The US Dollar amount of funds used in this transfer. |
data.timestamp |
String | The timestamp when the transfer occurred, in the UTC and ISO 8601 format. |
data.cluster |
Object or null |
The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. This value will be null if the cluster has not yet been identified. |
data.cluster.name |
String | The name of a named Cluster. |
data.cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category the named Cluster belongs to (such as exchange ). |
data.cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Withdrawal pre-screening
These endpoints allow you to register, retrieve, or delete a withdrawal address.
POST /v1/users/{userId}/withdrawaladdresses
GET /v1/users/{userId}/withdrawaladdresses
DELETE /v1/users/{userId}/withdrawaladdresses/{asset}/{address}
With them, you can:
- Pre-screen in real-time for counterparty risk within your withdrawal workflow.
- Receive a risk rating for known counterparties.
- Determine to either proceed with a transfers/sent API call to register the transaction for a given users profile.
Note that Transaction Monitoring updates risk for transfers on a continuous basis, but does not update withdrawal addresses on a continuous basis. The /withdrawaladdresses
endpoints return the cluster information that was available when the API was called. For continuous monitoring, you should register any withdrawals as a sent transfer.
If you'd like to pre-screen withdrawals that occurred on pre-growth networks, please use the POST /v2/users/{userId}/withdrawal-attempts
endpoint.
Register withdrawal addresses
ENDPOINT
POST /v1/users/{userId}/withdrawaladdresses
This endpoint registers a withdrawal addresses and returns a risk rating for a given User ID. You can register multiple addresses at once.
The following is an example request to register two Ethereum addresses for user
0001
:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '[
{
"network": "Ethereum",
"asset": "ETH",
"address": "0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963"
},
{
"network": "Ethereum",
"asset": "ETH",
"address": "0xf977814e90da44bfa03b6295a0616a897441acec"
}
]'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
register_withdrawal_data = [
{
'network': 'Ethereum',
'asset': 'ETH',
'address': '0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963',
},
{
'network': 'Ethereum',
'asset': 'ETH',
'address': '0xf977814e90da44bfa03b6295a0616a897441acec',
},
]
response = requests.post('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses', headers=headers, json=register_withdrawal_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
'network': 'Ethereum',
'asset': 'ETH',
'address': '0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963'
},
{
'network': 'Ethereum',
'asset': 'ETH',
'address': '0xf977814e90da44bfa03b6295a0616a897441acec'
}
])
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("[\n {\n \"network\": \"Ethereum\",\n \"asset\": \"ETH\",\n \"address\": \"0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963\"\n },\n {\n \"network\": \"Ethereum\",\n \"asset\": \"ETH\",\n \"address\": \"0xf977814e90da44bfa03b6295a0616a897441acec\"\n },\n {\n \"network\": \"Ethereum\",\n \"asset\": \"ETH\",\n \"address\": \"0x742d35cc6634c0532925a3b844bc454e4438f44e\"\n }\n]");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | A unique string that identifies the user associated with this withdrawal attempt. To register a withdrawal attempt for an existing user, use their existing userId . To register a withdrawal attempt for a new user, enter a new userId . |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
bulkImport |
Boolean | No | A parameter that, when set to True , allows you to register up to 1000 addresses in bulk. When bulkImport is not specified or set to False , the default limit of 100 addresses applies. Please note that when using bulkImport , no response will be returned. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
network |
String | Yes | The blockchain network this withdrawal occurred on. See our mature and emerging networks for the appropriate values. |
asset |
String | Yes | The asset to screen. The value must be the asset's symbol, for example, BTC for bitcoin, ETH for Ether, or UNI for Uniswap. |
address |
String | Yes | The asset's address used to determine counterparty risk. |
Response schema
The following is an example JSON response body from the above request:
[
{
"asset": "ETH",
"address": "0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963",
"cluster": {
"name": "PolyNetwork Hack 2021-08-10",
"categoryId": 6
},
"rating": "lowRisk",
"customAddress": null,
"chainalysisIdentification": {
"addressName": "STOLEN FUNDS: PolyNetwork Hack 2021-08-10",
"description": "",
"categoryId": 6
}
},
{
"asset": "ETH",
"address": "0xf977814e90da44bfa03b6295a0616a897441acec",
"cluster": {
"name": "Binance.com",
"categoryId": 21
},
"rating": "lowRisk",
"customAddress": null,
"chainalysisIdentification": null
}
]
The following is an example JSON response body for a Chainalysis Address Identification on a mature network:
[
{
"network": "Litecoin",
"asset": "LTC",
"address": "LaizKtS5DUhPuP1nTQcc83MS7HwK6vk85z",
"cluster": {
"name": "Gatecoin.com",
"categoryId": 21
},
"rating": "highRisk",
"customAddress": null,
"chainalysisIdentification": {
"addressName": "SANCTIONS: OFAC SDN Guanghua Zheng 2020-07-17 LaizKtS5DUhPuP1nTQcc83MS7HwK6vk85z",
"description": "This specific address LaizKtS5DUhPuP1nTQcc83MS7HwK6vk85z within the cluster has been identified as belonging to an individual on OFAC's SDN list. \n\nZHENG, Guanghua (Chinese Traditional: 鄭广華; Chinese Simplified: 郑广华); DOB 04 Nov 1955; POB Shanghai, China; nationality China; citizen China; Email Address zhenguanghua1955@outlook.com; alt. Email Address zhenguanghua1955@gmail.com; Gender Male; Passport E51809923 (China) issued 25 May 2015 expires 24 May 2025; Identification Number 310108195511041616 (China); Chinese Commercial Code 6774 1639 5478 (individual) [SDNTK].\n\nhttps://home.treasury.gov/news/press-releases/sm1063",
"categoryId": 3
}
}
]
A successful request will return the following JSON response for known recipients.
Property | Type | Description |
---|---|---|
network |
String | The blockchain network this withdrawal occurred on. |
asset |
String | The asset associated with the withdrawal address. The value is the asset or token's symbol, for example, BTC , ETH , or UNI . |
address |
String | The asset's withdrawal address. |
cluster |
Object or null |
The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. This value will be null if the cluster has not yet been identified. |
cluster.name |
String | The name of the named cluster. |
cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category of the named cluster. |
cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
rating |
String | The risk rating of the known recipient address, either highRisk , lowRisk , or unknown . The rating corresponds to the entity's category. Learn more about entity categories here and highRisk categories here. unknown means Chainalysis has not yet identified the entity or the entity is Unnamed. |
customAddress |
Object or null |
An address you've uploaded through the Transaction Monitoring UI that allows you to receive alerts on activity. This value will be null if not applicable. |
customAddress.addressName |
String | The name you've given to the Custom Address in the CSV file. |
customAddress.description |
String | The description you've provided for the Custom Address in the CSV file. |
customAddress.categoryName |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category name you provided for the Custom Address in the CSV file. |
customAddress.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
chainalysisIdentification |
Object or null |
A Chainalysis Address Identification, representing an address-level identification that is part of a larger cluster. This value will be null if not applicable. |
chainalysisIdentification.addressName |
String | The name designated to the Chainalysis Address Identification. |
chainalysisIdentification.description |
String | The OSINT from the Chainalysis Address Identification. |
chainalysisIdentification.categoryName |
String | This property was deprecated on October 22, 2024. To learn more about this change, see our February 2024 update. The category of the Chainalysis Address Identification. |
chainalysisIdentification.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
Note that the responses are not mutually exclusive. For example, you can have a known or unknown recipient and a Custom Address and/or a Chainalysis Address Identification.
Retrieve withdrawal addresses
ENPOINT
GET /v1/users/{userId}/withdrawaladdresses
This endpoint retrieves all withdrawal addresses and risk ratings for a single User ID.
The following is an example request to list all withdrawal addresses for user
0001
:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The userId to retrieve withdrawal addresses for. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
limit |
Integer | No | A limit on the number of objects returned. |
offset |
Integer | No | The position of the first object returned in the response. The default is 0, which starts the page at the first result. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body for the above request:
{
"total": 100,
"limit": 3,
"offset": 0,
"data": [
{
"network": "Bitcoin",
"asset": "BTC",
"address": "1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk",
"cluster": {
"name": "Huobi",
"categoryId": 21
},
"customAddress": null,
"chainalysisIdentification": null,
"rating": "lowRisk",
},
{
"network": "Ethereum",
"asset": "USDC",
"address": "0x7de5aba7de728950c92c57d08e20d4077161f12f",
"cluster": null,
"rating": "unknown",
"customAddress": null,
"chainalysisIdentification": null
},
{
"network": "Verge",
"asset": "XVG",
"address": "DEa5gMxbiDb96WfTN25nwzjzfjYHzHMsWi",
"cluster": null,
"rating": "highRisk",
"customAddress": {
"addressName": "Scam Address & User",
"description": "This address belongs scamming user John Doe",
"categoryId": 18
},
"chainalysisIdentification": null
}
]
}
A successful request will return the following JSON response for a known recipient.
Property | Type | Description |
---|---|---|
limit |
Integer | The limit of the data set. |
offset |
Integer | The offset of the data set. |
total |
Integer | The total number of results in the data set. |
data |
Array | An array containing address information. |
data.network |
String | The blockchain network the withdrawal occurred on. |
data.asset |
String | The asset associated with the withdrawal address. |
data.address |
String | The asset's withdrawal address. |
data.cluster |
Object or null |
The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. This value will be null if the cluster has not yet been identified. |
data.cluster.name |
String | The name of the named cluster. |
data.cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category of the named cluster (such as exchange ). |
data.cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
data.customAddress |
Object or null |
An address you've uploaded through the Transaction Monitoring UI that allows you to receive alerts on activity. This value will be null if not applicable. |
data.customAddress.addressName |
String | The name you've given to the Custom Address in the CSV file. |
data.customAddress.description |
String | The description you've provided for the Custom Address in the CSV file. |
data.customAddress.categoryName |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category name you provided for the Custom Address in the CSV file. |
data.customAddress.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
data.chainalysisIdentification |
Object or null |
A Chainalysis Address Identification, representing an address-level identification that is part of a larger cluster. This value will be null if not applicable. |
data.chainalysisIdentification.addressName |
String | The name designated to the Chainalysis Address Identification. |
data.chainalysisIdentification.description |
String | The OSINT from the Chainalysis Address Identification. |
data.chainalysisIdentification.categoryName |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category of the Chainalysis Address Identification. |
data.chainalysisIdentification.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
data.rating |
String | The risk rating of the known recipient address. |
Delete withdrawal addresses
ENPOINT
DELETE /v1/users/{userId}/withdrawaladdresses/{asset}/{address}
This endpoint deletes a specific withdrawal address for a given user.
The following is an example request to delete a Bitcoin withdrawal address of
1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk
for user0001
:
curl -X DELETE 'https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.delete('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk', {
method: 'DELETE',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/0001/withdrawaladdresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("DELETE");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The userId to retrieve withdrawal addresses for. |
asset |
String | Yes | The asset name associated with the withdrawal address . The value must be the asset or token's symbol, for example, BTC for Bitcoin, ETH for Ether, UNI for Uniswap. |
address |
String | Yes | The asset's withdrawal address associated with the userId requested. |
Response schema
The above request returns an empty JSON response body.
The call has an empty Response Body. ie. a zero byte response, indicated by a response header Content-Length: 0
.
Deposit addresses
These endpoints allow you to register, retrieve, and delete deposit addresses for a given userId
on your platform.
POST /v1/users/{userId}/depositaddresses
GET /v1/users/{userId}/depositaddresses
DELETE /v1/users/{userId}/depositaddresses/{asset}/{address}
After you register a deposit address, other users will receive a lowRisk
rating whenever they screen that address with the POST /v1/users/{userId}/withdrawaladdresses
endpoint. This doesn't apply to the POST /v2/users/{userId}/withdrawal-attempts
endpoint since it assesses risk by generating alerts instead of providing ratings.
Note: The deposit address endpoints aren't required for integration or continuous monitoring. To register transfers for continuous monitoring, you should use the registration endpoints. In the future, the Transaction Monitoring API will automatically detect and register received transfers (but not sent transfers) of mature assets to deposit addresses. You can implement deposit addresses now for use with this upcoming capability.
Register deposit addresses
ENDPOINT
POST /v1/users/{userId}/depositaddresses
The following is an example request to register a Bitcoin deposit address of
1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk
for userBTC_01
:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '[{"asset": "BTC", "address": "1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk"}]'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
register_deposit_data = [
{
'asset': 'BTC',
'address': '1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk',
},
]
response = requests.post('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses', headers=headers, json=register_deposit_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
'asset': 'BTC',
'address': '1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk'
}
])
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("[{\"asset\": \"BTC\", \"address\": \"1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk\"}]");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The userId to associate with the deposit address. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
asset |
String | Yes | The asset to associate with the deposit address. |
address |
String | Yes | The deposit address to be associated with the userId and asset . |
Response body
The above request returns an empty JSON response.
The response will be empty (a zero byte response) indicated by a response header Content-Length: 0
.
Retrieve deposit addresses
ENDPOINT
GET /v1/users/{userId}/depositaddresses
Retrieves all deposit addresses for a single User ID.
The following is an example request to list all deposit addresses for user
BTC_01
:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The userId from which you wish to retrieve the deposit addresses. |
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
limit |
Integer | No | A limit on the number of objects returned. |
offset |
Integer | No | The position of the first object returned in the response. The default is 0, which starts the page at the first result. |
Request body
This call has no accompanying request body.
Response body
The following is an example JSON response body from the above request:
{
"total": 1000,
"limit": 0,
"offset": 0,
"data": [
{
"asset": "BTC",
"address": "1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk"
},
{...}
]
}
A successful request will return the following JSON response and properties for a given userId
.
Property | Type | Description |
---|---|---|
total |
Integer | The total number of results in the data set. |
limit |
Integer | The limit of the data set. |
offset |
Integer | The offset of the data set. |
data |
Array | An array that contains the deposit address information |
data.asset |
String | The asset associated with the deposit address for the user. |
data.address |
String | The deposit address associated with the user. |
Delete deposit addresses
ENDPOINT
DELETE /v1/users/{userId}/depositaddresses/{asset}/{address}
The following is an example request to delete an associated Bitcoin deposit address of
1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk
for userBTC_01
:
curl -X DELETE 'https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.delete('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk', {
method: 'DELETE',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/BTC_01/depositaddresses/BTC/1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("DELETE");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
This endpoint deletes the associated deposit address for a single User ID.
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The userId associated with the deposit address. |
asset |
String | Yes | The asset associated with the deposit address. |
address |
String | Yes | The deposit address to be deleted. |
Request body
This call has no accompanying request body.
Response body
The above request returns an empty JSON response body.
The response will be empty, ie. a zero byte response, indicated by a response header Content-Length: 0
.
Alerts
These endpoints allow you to retrieve alerts, assign an alert, update an alert status or comment, and retrieve an alert's history.
GET /v1/alerts/
POST /v1/alerts/{alertIdentifier}/assignment
POST /v1/alerts/{alertIdentifier}/statuses
GET /v1/alerts/{alertIdentifier}/activity
Alerts are generated for risky transfers on your platform. A single transfer can trigger multiple alerts. Alert levels include Severe, High, Medium, and Low, and are based on factors such as category, service/entity, direct versus indirect exposure, direction, and amount.
Get all alerts
This endpoint retrieves information on all alerts that have been raised within your organization. By default, only transfer alerts will be returned. To return behavioral alerts or withdrawal attempts, use the alertType
query parameter.
ENDPOINT
GET /v1/alerts/
The following is an example request to retrieve all the alerts in your system:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/alerts/' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/alerts/', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
The following is an example request to retrieve all Bitcoin alerts with a high alert level:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/alerts/?asset=BTC&level=HIGH' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
params = {
'asset': 'BTC',
'level': 'HIGH',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/alerts/', params=params, headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/?asset=BTC&level=HIGH', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/?asset=BTC&level=HIGH");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
The following is an example request to retrieve all Bitcoin alerts with a severe alert level for a particular user:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/alerts/?level=SEVERE&userId=User017&asset=BTC' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
params = {
'level': 'SEVERE',
'userId': 'User017',
'asset': 'BTC',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/alerts/', params=params, headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/?level=SEVERE&userId=User017&asset=BTC', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/?level=SEVERE&userId=User017&asset=BTC");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
asset |
String | No | Returns all alerts for a specific asset. |
createdAt_gte |
String | No | Returns all alerts created greater than or equal to a specific date and time. Must be in the UTC ISO 8601 format. |
createdAt_lte |
String | No | Returns all alerts created less than or equal to a specific date and time. Must be in the UTC ISO 8601 format. |
alertStatusCreatedAt_gte |
String | No | Returns all alert statuses and comments greater than or equal to a specific date and time. Must be in the UTC ISO 8601 format. |
alertStatusCreatedAt_lte |
String | No | Returns all alert statuses and comments less than or equal to a specific date and time. Must be in the UTC ISO 8601 format. |
level |
String | No | Filters alerts by alert level as SEVERE , HIGH , MEDIUM , and LOW (values must be in caps). |
transferReference |
String | No | Returns all alerts associated with a specific transfer reference. See Transfer Reference Formats sorted by timestamp , createdAt , level , and alertAmountUsd . For example, createdAt sorts alerts by the date the alert was created. See below for more information about the sort parameter. |
userId |
String | No | Returns all alerts for a specific user. |
limit |
Integer | No | Places a limit on the number of returned alert objects. |
offset |
Integer | No | Indicates the position of the first alert object returned in the response. The default is 0, which starts the page at the first result. |
sort |
String | No | Used to sort the order which alerts are returned in the response. You can sort by timestamp , level , alertAmountUsd , alertStatusCreatedAt , assignedTo , assignedBy , and assignedAt . Your parameter must include a direction specifier of either desc or asc preceded by a URL-encoded space character. For example: sort=timestamp%20desc . |
alertType |
String | No | Filters the the type of alerts returned as TRANSFER ,BEHAVIORAL , or WITHDRAWAL . |
Using the createdAt_gte
and createdAt_lte
parameters
You can use createdAt_gte
and createdAt_lte
to specify a date range. You can also keep track of your newest alerts by querying for all alerts after a given time (createdAt_gte
), store the time you made the query, then query it again later for all alerts since the initial query.
Using the alertStatuscreatedAt_gte
and alertStatuscreatedAt_lte
parameters
You can use these parameters to specify a date range for the alert status and periodically retrieve alerts with recent status changes or comments. You can keep track of alerts with recent status and comment updates by storing the timestamp of when you made the query, then using it in subsequent queries.
Using the sort
parameter
The sort
parameter determines the order that the alerts are returned. You can sort by timestamp
, createdAt
, level
, alertAmountUsd
, alertStatusCreatedAt
, and the assignedTo
, assignedBy
, and assignedAt
parameters. For example, to return all alerts sorted by amount from highest to lowest value (descending), use: ?sort=alertAmountUsd%20desc
.
Get all alerts from a single transfer
To return all alerts on a single transfer, it is recommended to use the userId
, asset
, and transferReference
parameters all at once. In rare circumstances, the same transferReference
can exist for multiple assets or multiple users.
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body of a transfer alert:
{
"total": 1000,
"limit": 0,
"offset": 0,
"data": [
{
"alertAmountUsd": 132.50,
"transactionHash": "b765440e872ab6e2521694d10465415bda4adf8ed7fc2fdafb6d39bd17c5fddf",
"exposureType": "DIRECT",
"alertStatus": "Flagged",
"transferReportedAt": "2017-01-05T14:23:00.397Z",
"alertIdentifier": "a6a5d0f8-9753-11e9-a517-ebce3e967522",
"transferReference": "b765440e872ab6e2521694d10465415bda4adf8ed7fc2fdafb6d39bd17c5fddf:1",
"alertStatusCreatedBy": null,
"valid": true,
"transferCountWindow": null,
"ruleAsset": null,
"direction": "SENT",
"timestamp": "2011-06-18T08:22:21Z",
"period": null,
"windowSize": null,
"transferredValuePercentage": 100.0,
"level": "HIGH",
"service": "Silk Road Marketplace",
"alertStatusCreatedAt": "2020-01-14T13:57:58.713226Z",
"userId": "mtgox_ghosts",
"transferCount": null,
"createdAt": "2019-06-17T17:39:41.550575Z",
"alertType": "TRANSFER",
"transferOutputAddress": "1DP38CC2kf6ewUDaaVd9nBfuAD8SP15g2T",
"validity": "VALID",
"transactionIndex": 1,
"asset": "BTC",
"rule": ">$100 sent directly to darknet market",
"minThreshold": 100,
"maxThreshold": null,
"categoryId": 2,
"customGroupExternalId": null
},
{...}
]
}
The following is an example JSON response body of a behavioral alert:
"total": 1000,
"limit": 0,
"offset": 0,
"data": [
{
"alertAmountUsd": 82271.52,
"transactionHash": null,
"exposureType": "DIRECT",
"alertStatus": "Unreviewed",
"transferReportedAt": null,
"alertIdentifier": "12b76b58-4706-11ec-ab82-133bbbe0a113",
"transferReference": null,
"alertStatusCreatedBy": null,
"valid": true,
"transferCountWindow": "[10,)",
"ruleAsset": "AAVE",
"direction": "RECEIVED",
"timestamp": null,
"period": "[\"2021-02-04 00:00:00+00\",\"2021-02-05 00:00:00+00\")",
"windowSize": "1 day",
"transferredValuePercentage": null,
"level": "SEVERE",
"service": null,
"alertStatusCreatedAt": "2021-11-16T17:53:15.096Z",
"userId": "Example User 1",
"transferCount": 11,
"createdAt": "2021-11-16T17:53:15.096Z",
"alertType": "BEHAVIORAL",
"transferOutputAddress": null,
"validity": "VALID",
"transactionIndex": null,
"asset": null,
"rule": "$0-$50000 received",
"minThreshold": 0,
"maxThreshold": 50000,
"categoryId": null,
"customGroupExternalId": null
},
{...}
]
}
The response is sorted by alertStatusCreatedAt
by default. Note that when an alert is created, the alertStatus
is set to Unreviewed
and the alertStatusCreatedAt
is set to the time the alert was created.
A successful request will return the following JSON response and properties for all alerts:
Property | Type | Description |
---|---|---|
total |
Integer | The total number of alert objects returned. |
limit |
Integer | An echo back of the limit query parameter. |
offset |
Integer | An echo back of the offset query parameter. |
data |
Array | An array containing alert data. |
data.alertAmountUsd |
Number | The amount of the transfer that triggered the alert in USD. |
data.transactionHash |
String or null |
The transaction hash of the transfer that triggered the alert. Will be null for behavioral alerts. |
data.exposureType |
String | The type of exposure of the transfer that triggered the alert as DIRECT or INDIRECT . |
data.alertStatus |
String | The status of the alert as Unreviewed , In Review , Flagged , No Review , or Dismissed . |
data.transferReportedAt |
String null |
The timestamp when the transfer was registered, in the UTC ISO 8601 format. Will be null for behavioral alerts. |
data.alertIdentifier |
String | The alert ID. |
data.transferReference |
String or null |
The transaction hash and index or output address of the transfer that triggered the alert. Will be null for behavioral alerts. |
data.alertStatusCreatedBy |
String or null |
The username of the person in your organization that changed the alert status. This will be null if the alert's status has not yet been updated. |
data.valid |
Boolean | Indicates whether the alert is valid. |
data.transferCountWindow |
String or null |
The range that the transfer count must fall between for the system to generate the behavioral alert. The leftmost integer represents the lower bound, and the rightmost integer represents the upper bound. The value uses interval notation to indicate whether the endpoints are inclusive. To learn more, see the interval notation definition. Will be null for transfer alerts. |
data.ruleAsset |
String or null |
The asset that the behavioral alert rule is tracking. Will be null if the behavioral alert rule is tracking behavior of any asset or for transfer alerts. |
data.direction |
String | The direction of the transfer that triggered the alert as SENT or RECEIVED . |
data.timestamp |
String or null |
The time when the transfer on the blockchain that caused the alert, in the UTC ISO 8601 format. Will be null for behavioral alerts. |
data.period |
String or null |
The time window monitored to generate the behavioral alert. The leftmost timestamp represents the start time, and the rightmost timestamp represents the end time. The timestamps are in the UTC ISO 8601 format. The value uses interval notation to indicate whether the endpoints are inclusive. To learn more, see the interval notation definition. Will be null for transfer alerts. |
data.windowSize |
String or null |
The length of the behavioral alert window, either 1 day , 1 week , or 1 month . Will be null for transfer alerts. |
data.transferredValuePercentage |
Number or null |
The measure of the alerted amount as a percentage of the total transfer amount (the alerted amount divided by the total amount of the transfer in USD). Will be null for behavioral alerts. |
data.level |
String | The level of the alert as SEVERE , HIGH , MEDIUM , or LOW . |
data.service |
String or null |
The name of the counterparty in the transfer that triggered the alert. Note that the service will be null for indirect exposure alerts, as you can have multiple indirect counterparties contributing to one alert. |
data.alertStatusCreatedAt |
String | The timestamp when the alert status was last changed, in the UTC ISO 8601 format. |
data.userId |
String | The User ID of the user. |
data.transferCount |
Integer or null |
The number of transfers that occurred during the period . Will be null for transfer alerts. |
data.createdAt |
String | The timestamp when the alert was created, in the UTC ISO 8601 format. |
data.alertType |
String | The type of alert, either TRANSFER or BEHAVIORAL . |
data.transferOutputAddress |
String or null |
The destination address for funds within the transaction. Will be null for behavioral alerts. |
data.validity |
String | The status of the alert as either VALID , INVALID , or REVALID . |
data.category |
String or null |
This property was deprecated on October 24, 2024. To learn more about this change, see our February 2024 update. The entity category the alert rule is tracking. Will be null if the rule is behavioral and tracking for any category. |
data.categoryId |
Integer or null |
A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. Will be null if alertType is BEHAVIORAL and your rule is tracking for any transfer activity (that is, not specific to any one entity category). |
data.transactionIndex |
Integer or null |
The 0-indexed number of the transfer in the transaction that caused the alert. Will be null for behavioral alerts. |
data.asset |
String or null |
The asset used in the transfer. Will be null for behavioral alerts. |
data.rule |
String | An explanation of why the transfer or behavior caused an alert. |
data.minThreshold |
Integer | The minimum amount in USD of the alert rule. |
data.maxThreshold |
Integer or null |
The maximum amount in USD of the alert rule. This value will be null if a maxThreshold is not set for the rule. |
data.customGroupExternalId |
String or null |
The custom group UUID if the alert was generated for a custom group. If this property is null , the alert was generated from a category. |
Assign an alert
This endpoint assigns an alert to a member of your organization.
ENDPOINT
POST /v1/alerts/{alertIdentifier}/assignment
The following is an example request to assign someone to an alert:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/alerts/{alertIdentifier}/assignment' \
--header 'Token: <API_KEY' \
--header 'Content-Type: application/json' \
--data '{"alertAssignee":"user.email@example.com"}'
import requests
headers = {
'Token': '<API_KEY',
}
assign_alert_data = {
'alertAssignee': 'user.email@example.com',
}
response = requests.post('https://api.chainalysis.com/api/kyt/v1/alerts/{alertIdentifier}/assignment', headers=headers, json=assign_alert_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/{alertIdentifier}/assignment', {
method: 'POST',
headers: {
'Token': '<API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
'alertAssignee': 'user.email@example.com'
})
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/{alertIdentifier}/assignment");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "<API_KEY");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("{\"alertAssignee\":\"user.email@example.com\"}");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
alertIdentifier |
String | Yes | A unique identifier that references the alert. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
alertAssignee |
String | Yes | The email address of the user you wish to assign the alert to. Note: to unassign an alert, return this value with null . |
Response schema
The following is an example JSON response body from the above request:
{
"alertIdentifier": "bdc1f806-f5ad-11eb-8540-2b716172c24d",
"assignedBy": "admin.email@example.com",
"assignedTo": "user.email@example.com",
"alertAssignedAt": "2021-08-11T21:21:59.806Z"
}
A successful request will return the following JSON response and properties for the given alert:
Property | Type | Description |
---|---|---|
alertIdentifier |
String | A unique identifier that references the alert. |
assignedBy |
String | The email address of the user who assigned the alert. |
assignedTo |
String | The email address of the user assigned to the alert. |
alertAssignedAt |
String | The timestamp when the alert was assigned, in the UTC IS0 8601 format. |
Post alert statuses and comments
This endpoint sends and changes an alert status and comment you provide for a given alert.
ENDPOINT
POST /v1/alerts/{alertIdentifier}/statuses
The following is an example request to send an alert status and comment in the system:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/alerts/1a895b44-2a78-11eb-978c-5bb1dd49843e/statuses' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"status":"No Review",
"comment":"Test comment"
}'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
alert_data = {
'status': 'No Review',
'comment': 'Test comment',
}
response = requests.post('https://api.chainalysis.com/api/kyt/v1/alerts/1a895b44-2a78-11eb-978c-5bb1dd49843e/statuses', headers=headers, json=alert_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/1a895b44-2a78-11eb-978c-5bb1dd49843e/statuses', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
'status': 'No Review',
'comment': 'Test comment'
})
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/1a895b44-2a78-11eb-978c-5bb1dd49843e/statuses");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
httpConn.setRequestProperty("Content-Type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("{\n \"status\":\"No Review\",\n \"comment\":\"Test comment\"\n}");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
alertIdentifier |
String | Yes | A unique identifier that references the alert. |
Request body schema
Property | Type | Required | Description |
---|---|---|---|
status |
String | Yes | Define the alert status, whether Unreviewed , In Review , Flagged , No Review , or Dismissed . |
comment |
String | No | Include the comment you want to specify for the given alert. |
Response schema
The following is an example JSON response body from the above request:
{
"alertIdentifier": "1a895b44-2a78-11eb-978c-5bb1dd49843e",
"alertStatus": "No Review",
"alertComment": "Test comment",
"alertStatusCreatedBy": "user@example.com",
"alertStatusCreatedAt": "2021-05-24T19:36:08.593571Z"
}
A successful request will return the following JSON response and properties for the given alert:
Property | Type | Description |
---|---|---|
alertIdentifier |
String | A unique identifier that references the alert. |
alertStatus |
String | The alert status you submitted in your request body whether Unreviewed , In Review , Flagged , No Review , or Dismissed . |
alertComment |
String or null |
The comment you submitted in your request body. This value will be null if no comment was left. |
alertStatusCreatedBy |
String | The email address of the Transaction Monitoring account that changed the alert status and/or added a comment. |
alertStatusCreatedAt |
String | The timestamp when the the alert status was created, in the UTC ISO 8601 format. |
Get alert statuses and comments
This endpoint retrieves an alert's comment and status history.
ENDPOINT
GET /v1/alerts/{alertIdentifier}/activity
The following is an example request to retrieve an alert's comment and status history:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/alerts/17124a04-cadf-11eb-9921-0bdd1e279318/activity' \
--header 'Token: {YOUR_API_KEY}'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/alerts/17124a04-cadf-11eb-9921-0bdd1e279318/activity', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/alerts/17124a04-cadf-11eb-9921-0bdd1e279318/activity', {
headers: {
'Token': '{YOUR_API_KEY}'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/alerts/17124a04-cadf-11eb-9921-0bdd1e279318/activity");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
alertIdentifier |
String | Yes | A unique identifier that references the alert. |
Request body schema
This call has no accompanying request body.
Response schema
The following is an example JSON response body from the above request:
{
"alertIdentifier": "17124a04-cadf-11eb-9921-0bdd1e279318",
"statusItems": [
{
"alertStatusIdentifier": "17124a04-cadf-11eb-9921-0bdd1e279318-10857095",
"status": "Unreviewed",
"updatedBy": "user1@yourCrytpoService.com",
"comment": ">$500 received indirectly from scam. Should review ASAP.",
"updated": "2021-07-01T06:42:23.881301Z"
},
{
"alertStatusIdentifier": "17124a04-cadf-11eb-9921-0bdd1e279318-11554113",
"status": "Flagged",
"updatedBy": "user2@yourCrytpoService.com",
"comment": "This is a definitely a scam.",
"updated": "2021-07-21T21:57:33.343724Z"
}
]
}
A successful request will return the following JSON response and properties for the given alert:
Property | Type | Description |
---|---|---|
alertIdentifier |
String | A unique identifier that references the alert. |
statusItems |
Array | An array that contains the alert status items. If the array is empty, the alert status has never been been updated or the alert has not yet been commented upon. |
statusItems.alertStatusIdentifier |
String | A unique identifier that references the alert status. |
statusItems.status |
String | The alert's status at the time of update, either Unreviewed , In Review , Flagged , No Review , or Dismissed . |
statusItems.updatedBy |
String | The email address of the account that updated the alert's status and/or comment. |
statusItems.comment |
String | The alert's comment at the time of update. |
statusItems.updated |
String | The timestamp when the alert's status and/or comment was updated, in the UTC ISO 8601 format. |
Users
These endpoints allow you to retrieve either all your users or a single user, as well as rename a user.
GET /v1/users/
GET /v1/users/{userId}
POST /v1/users/rename
Users are aggregations of transfers, tagged by User ID. Users in Transaction Monitoring should map 1:1 to users on your platform. Analyzing risk at a user level allows you to compare all the historical transfers made by a user to their current transfer.
The Users endpoint generates risk score reports for all users submitted to Transaction Monitoring. The endpoint supports both a summary format of all users and detailed reporting on specific users when passed a corresponding user ID. You are also able to rename User IDs via the API.
In determining User IDs, it is important to keep the following information in mind:
- You should use the same User ID across all supported asset types. This allows the system to assess the user risk based on his or her combined activity.
- We encourage you to use an ID which relates to your internal system, as it helps your compliance team quickly find and monitor the users.
- Important: the User ID should not contain personally identifiable information.
Get all users
ENDPOINT
GET /v1/users/
This endpoint retrieves and lists all User IDs in your Transaction Monitoring instance.
The following is an example request to list all User IDs:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Query parameters
Parameter | Type | Required | Description |
---|---|---|---|
limit |
Integer | No | Places a limit on the number of returned user objects. |
offset |
Integer | No | The position of the first user object returned in the response. The default is 0, which starts the page at the first result. |
Response schema
The following is an example JSON response body from the above request:
{
"limit": 100,
"offset": 0,
"total": 127,
"data": [
{
"userId": "new_user_01",
"score": "green",
"lastActivity": "2021-01-06T13:49:34.013Z",
"scoreUpdatedDate": "2021-07-29T21:20:18.008030Z",
"riskScore": "LOW"
},
{...}
]
}
The response body will be a brief summary of the list of User IDs in your Transaction Monitoring instance.
score
is based on the legacy user risk model, while riskScore
reflects the current model that was implemented in late May 2020. We recommend using the riskScore
property going forward. Find more information about the user risk model here (login required).
A successful request will return the following JSON
response and properties for all users.
Property | Type | Description |
---|---|---|
total |
Integer | The total number of user objects returned. |
limit |
Integer | An echo back of the limit query parameter. |
offset |
Integer | An echo back of the offset query parameter. |
data |
Array | An array containing user data. |
data.userId |
String | The User ID of the user. |
data.score |
String or null |
The score of the User ID as green , amber , or red . Based on the legacy user risk model. |
data.lastActivity |
String or null |
The timestamp of the User ID's last tracked activity, in the UTC ISO 8601 format. |
data.scoreUpdatedDate |
String or null |
The timestamp when the score was last calculated, in the UTC ISO 8601 format. This field will update whenever activity occurs that could affect the user risk score, including: a new transfer is registered, a new alert is generated, or an alert status is changed. |
data.riskScore |
String or null |
The overall score of the User ID as LOW , MEDIUM , HIGH , or SEVERE . Based on the new user risk model. We recommend using this property going forward. |
Note: If a user is created in your instance but has no associated transfers or activity, score
, lastActivity
, scoreUpdatedDate
, and riskScore
will return with null
values.
Get a single user by {userId}
ENDPOINT
GET /v1/users/{userId}
This endpoint retrieves detailed information on a single user in your Transaction Monitoring instance.
The following is an example request to list a single User ID,
BTC_01
:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/users/new_user_01' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/users/new_user_01', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/new_user_01', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/new_user_01");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
Path parameters
Parameter | Type | Required | Description |
---|---|---|---|
userId |
String | Yes | The unique identifier of the user. |
Response schema
The following is an example JSON response body from the above request:
{
"userId": "new_user_01",
"score": "green",
"lastActivity": "2021-01-06T13:49:34.013Z",
"scoreUpdatedDate": "2021-07-29T21:20:18.008030Z",
"riskScore": "LOW",
"creationDate": "2017-09-23T11:44:51.00Z",
"exposureDetails": [
{
"cluster": {
"name": "Coinbase.com",
"categoryId": 21
},
"sentIndirectExposure": 25,
"sentDirectExposure": 0,
"receivedIndirectExposure": 25,
"receivedDirectExposure": 0
}
]
}
A successful request will return the following JSON
response and properties for all users.
Property | Type | Description |
---|---|---|
userId |
String | The User ID of the user. |
score |
String or null |
The score of the User ID as green , amber , or red . Based on the legacy user risk model. |
lastActivity |
String or null |
The timestamp of the user's last tracked activity, in the UTC ISO 8601 format. |
scoreUpdatedDate |
String or null |
The timestamp when the score was last calculated, in the UTC ISO 8601 format. This field will update whenever activity occurs that could affect the user risk score, including: a new transfer is registered, a new alert is generated, or an alert status is changed. |
riskScore |
String or null |
The overall score of the User ID as LOW , MEDIUM , HIGH , or SEVERE . Based on the new user risk model. We recommend using this property going forward. |
creationDate |
String or null |
The timestamp when the user was created in your instance, in the UTC ISO 8601 format. |
exposureDetails |
Array | An array of details about the user's exposure to risk. |
exposureDetails.cluster |
Object | The identification of a group of addresses estimated by Chainalysis to be controlled by a single entity. |
exposureDetails.cluster.name |
String | The name of the named cluster. |
exposureDetails.cluster.category |
String | This property was deprecated on October 29, 2024. To learn more about this change, see our February 2024 update. The category the named cluster belongs to. |
exposureDetails.cluster.categoryId |
Integer | A unique identifier for entity categories. For a mapping of categoryId to entity categories, see Category IDs. |
exposureDetails.sentIndirectExposure |
Number | Total Sent Indirect Exposure for the user in USD. |
exposureDetails.sentDirectExposure |
Number | Total Sent Direct Exposure for the user in USD. |
exposureDetails.receivedIndirectExposure |
Number | Total Received Indirect Exposure for the user in USD. |
exposureDetails.receivedDirectExposure |
Number | Total Received Direct Exposure for the user in USD. |
Note: If a user is created but has no associated transfers or activity, score
, lastActivity
, scoreUpdatedDate
, and riskScore
will return with null
values and the exposureDetails
array will be empty.
score
is based on the legacy user risk model, while riskScore
reflects the current model that was implemented in late May 2020. We recommend using the riskScore
property going forward. Find more information about the user risk model here (login required).
Rename users
ENDPOINT
POST /v1/users/rename
This endpoint renames a userId
in your Transaction Monitoring instance. The request supports up to 1000 renames at a time.
The following is an example request to rename a User ID from
test_1
touser_1
andtest_2
touser_2
:
curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/rename' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
--header 'Content-Type: application/json' \
--data '[
{
"from": "test_1",
"to": "user_1"
},
{
"from": "test_2",
"to": "user_2"
}
]'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
user_data = [
{
'from': 'test_1',
'to': 'user_1'
},
{
'from': 'test_2',
'to': 'user_2'
},
]
response = requests.post('https://api.chainalysis.com/api/kyt/v1/users/rename', headers=headers, json=user_data)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/users/rename', {
method: 'POST',
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
},
body: JSON.stringify([
{
"from": "test_1",
"to": "user_1"
},
{
"from": "test_2",
"to": "user_2"
}
])
});
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/users/rename");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Content-type", "application/json");
httpConn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
writer.write("[\n {\n \"from\": \"test_1\",\n \"to\": \"user_1\"\n },\n {\n \"from\": \"test_2\",\n \"to\": \"user_2\"\n }\n]");
writer.flush();
writer.close();
httpConn.getOutputStream().close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
The above request returns an empty
JSON
response.
Request body schema
Property | Type | Description |
---|---|---|
from |
String | The userId that you wish to rename. |
to |
String | The new userId that you wish to use. This must be a new userId and not currently existing one. Using an existing userId will return a 4xx error. |
Response schema
The endpoint returns an empty JSON response.
Deprecated endpoints
The following section contains historical information for deprecated endpoints.
Get assets
The following is an example request for listing all assets:
curl -X GET 'https://api.chainalysis.com/api/kyt/v1/assets' \
--header 'Token: {YOUR_API_KEY}' \
--header 'Accept: application/json'
import requests
headers = {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json',
}
response = requests.get('https://api.chainalysis.com/api/kyt/v1/assets', headers=headers)
import fetch from 'node-fetch';
fetch('https://api.chainalysis.com/api/kyt/v1/assets', {
headers: {
'Token': '{YOUR_API_KEY}',
'Accept': 'application/json'
}
});
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
class Main {
public static void main(String[] args) throws IOException {
URL url = new URL("https://api.chainalysis.com/api/kyt/v1/assets");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Token", "{YOUR_API_KEY}");
httpConn.setRequestProperty("Accept", "application/json");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
System.out.println(response);
}
}
The above request returns JSON structured as below. Note that the "data" array would typically display the data for all assets but has been truncated for this example.
[
{
"symbol": "AUDX",
"name": "Etoro AUD"
},
{
"symbol": "BCH",
"name": "Bitcoin Cash"
},
{
"symbol": "BNB",
"name": "Binance Coin"
},
{
"symbol": "BTC",
"name": "Bitcoin"
},
{...}
]
GET https://api.chainalysis.com/api/kyt/v1/assets
Returns a list of cryptocurrencies supported in the API and their corresponding symbol.