NAV
cURL Python Node.js Java

Welcome to the KYT API

The Chainalysis KYT API (Know Your Transaction) is an automated cryptocurrency transaction monitoring and compliance solution. The KYT API provides near real-time insights into blockchain transactions and their involved counterparties.

At the core of KYT is a REST API that allows you to:

How it works

With the KYT 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 KYT-generated alerts, exposure information, or identifications to help you quickly make synchronous decisions about how to treat the transfer or withdrawal.

KYT API Overview Diagram

In addition to receiving an initial risk assessment of a deposit or withdrawal, you can also use the KYT API to continuously monitor historical transfers (previously registered transfers). KYT 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 KYT API, check out the following resources:

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 KYT API. An example of a minimal integration might be using the API to only programmatically register transfers, then using the KYT 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.

What's new

See below for KYT API releases, updates, and changes.

July 2022

We've recently released our Developer Portal! The Developer Portal can be accessed here and houses information such as:

With the addition of the Developer Portal, we've published two quickstarts (Register a transfer and Register a withdrawal attempt) and a tutorial (Retrieve alerts as Slack notifications). Watch this space as we continue to add more content!

Note that the API technical overview and reference documentation can still be found on this page. We’ve reorganized information to make the appropriate content easier to find and keep the endpoint reference cleaner.


Click here to expand or collapse previous entries


February 15, 2022

On March 10, 2022, we will be increasing our asset coverage extensively with the Emerging asset tier. To complement this change, we've added a new request body property (network) to identify the blockchain network a transfer occurs on. For all assets and networks that Chainalysis supported before February 15, 2022, you can effectively ignore the network property, and KYT is backward compatible for those assets. The network property will be required for all new assets and networks that Chainalysis begins to support going forward.

To help customers acclimate to this transition, we've published a new article, Navigating asset tiers, and updated our lists of Mature and emerging networks and Pre-growth networks. We will update the rest of our KYT API reference documentation to account for the network property as we near the March 10th release date.

To learn more about KYT's functionality for each asset tier, see our knowledge base article, Asset coverage.

Additionally, on March 10th, 2022, we will be deprecating the KYT API /assets endpoint. This endpoint will not be updated with a current asset list after March 10th, 2022 and will be fully deprecated and unavailable on June 15th, 2022.

January 28, 2022

We've added support to our GET /v1/alerts endpoint for behavioral alerts. You can now programmatically retrieve behaiovral alerts with the query parameter alertType. Additionally, we've added the following JSON response properties for behavioral alerts:

  • transferCountWindow
  • ruleAsset
  • period
  • windowSize
  • transferCount
  • alertType

To learn more about the new query parameter or response properties, check out the definitions and descriptions in the schema.

August 18, 2021

We've released a new endpoint to assign alerts. You can now make a POST request to programmatically assign alerts to users in your organization. To unassign an alert, use null in the request body.

Additionally, we've added the following response body fields to the the GET /v1/alerts endpoint:

  • assignedTo - the email address of the user assigned to the alert.
  • assignedAt - the UTC timestamp when the alert was assigned, in IS0 8601 format with timezone information.
  • assignedBy - the email address of the user who assigned the alert.

You can also sort and filter with these fields.

August 11, 2021

We've changed the requirement of certain request body fields for the POST /v2/users/{userId}/transfers endpoint. Now, transferTimestamp, assetAmount, outputAddress, inputAddress, assetPrice, and assetDenomination are optional for both CDN and fully-supported assets.

July 26, 2021

We've recently released a new endpoint that retrieves an alert's status and comment history.

We've also added two new parameters to the get alerts endpoint:

  • alertStatusCreatedAt_gte
  • alertStatusCreatedAt_lte

Use these parameters to retrieve alerts with statuses and comments that were recently updated.

You can also use the sort parameter with alertStatusCreatedAt to sort your alerts by the time their status was created.

July 9, 2021

We've updated our KYT API docs to restructure and reframe our endpoints. We believe the new structure brings more clairity to our API. It is important to note that both v1 and v2 endpoints are comptaible. We've included a new API implementation that details how you might integrate with our API. We've renamed our old integration guide to Legacy implementation.

May 27, 2021

We've recently released a new endpoint, POST: alert status and comment.

You can now make a POST request to change an alert's status and include a comment, giving you the ability to action historic alerts programmatically and ensure your case management syncs with KYT. View the endpoint here.

March 31, 2021

We've recently added Algorand as a supported asset.

For your transfers, KYT includes staking rewards where present. Algorand block explorers display staking rewards separately from the main payment transfer(s). Therefore, block explorers may introduce a discrepancy in the output index, e.g. a block explorer presents a counterparty at position 0, yet our representation shows the same counterparty at position 2. For this reason, you should include the output address, rather than output index, in transfer references for your KYT API requests.

View all the assets that Chainalysis supports here.

October 28, 2020

We’ve recently added support for another 16 ERC-20 tokens. These include DeFi tokens, one of the most exciting and talked about areas of crypto, and a tranche of stable coins. Chainalysis now supports over 100 cryptocurrency assets. See the complete list of assets that KYT suppports here.

June 8, 2020

Chainalysis has launched support for two notable cryptocurrencies: Dash and Zcash. As two of the most popular so-called “privacy coins” — cryptocurrencies with privacy enhancing features encoded into their protocols — they account for over $1.5 billion of reported daily trading volume.

Our latest blog post explains how these two privacy coins allow investigators and compliance professionals to investigate and monitor illicit activity using our products.

See all cryptocurrencies that Chainalysis supports here.

May 26, 2020

KYT has introduced a new user risk score calculation that's easier to understand, customize, and control.

  • There will be a new property in the API called riskScore, found in GET /users and GET /users/{userId}. It returns the risk score based on the new model as SEVERE, HIGH, MEDIUM, and LOW.

  • The score property in the API, based on the legacy model, will remain. SEVERE and HIGH will be returned as red, MEDIUM as amber, and LOW as green. However, we recommend using the riskScore field going forward.

  • Note that this is an additive change; no existing fields will be removed.


March 12, 2020

Chainalysis has added 43 new tokens, more than doubling the number of ERC-20 tokens we support. KYT can now help you understand what’s happening with 97% of the total value in ERC-20s and over $1 billion of ERC-20 transfers every day. See a complete list of assets that KYT suppports here.


February 11, 2020

  • XRP is now available in Chainalysis! XRP is the cryptocurrency best known as a payment protocol for remittances, payment settlement, and the exchange of assets. It is the native currency of Ripple, a company that works with financial institutions to enable fast and low cost global payments. See the Assets section for more information.


December 10, 2019

  • Ethereum Classic (ETC) is now supported in Chainalysis! Ethereum Classic is an alternate version of Ether.
  • Register ETH smart contract transfers in KYT using a new transfer reference: "transaction hash:output address".


December 5, 2019

  • You can now sort and filter alerts via the API. Sort GET /alerts by timestamp, createdAt, level, and alertAmountUsd, and filter by level. Read more about alert sorting and filtering capabilities here.


October 16, 2019

  • KYT has released support for many new ERC-20s including LINK, CRPT, MCO, CRO, GNO, HT, MLN, LEO, WETH, ZIL, TGBP, REP, HOLD, AUDX, CADX, CHFX, CNYX, EURX, GBPX, GLDX, NZDX, RUBX, SLVX, USDEX, JPYX, HUSD, PAXG, and BUSD. See a full list of all coins that KYT supports here.


September 25, 2019

  • Send data to the KYT API for hundreds of assets we don’t yet support. Implement the KYT API once and no changes are required when we support a new asset.
  • Filter the /alerts KYT API endpoint by transferReference and asset.


August 6, 2019

  • Alert information is now available via the KYT API. Users can use this API to integrate KYT Alerts into your own internal tools. See here for more information.


July 23, 2019

  • ZRX, BAT, OMG, and MKR are now supported in the API.

API overview

The KYT 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 KYT and Chainalysis environment URLs:

Create API keys

You can create API keys from the Setting option in KYT's Account menu.

To create an API key:

  1. Log into the KYT instance (either sandbox or primary) for which you want to create an API key.
  2. From the Account drop-down menu, click Developers > API Keys.
  3. Click the Generate API Key button. Your API key appears below.

You can also obtain an API key from the Settings menu in Reactor, under the API Keys tab.

Move from a test instance

We recommend using a sandbox KYT instance to test initial API integration and validation. Once you have finished testing and completed the integration, you can move to a second, "clean" KYT instance with new data and API keys. This second instance will be your primary, ongoing KYT instance.

Please contact your CSM to help you create your KYT instances and obtain their credentials.

Once you have both of your KYT instances created:

  1. Log into KYT with your sandbox credentials (obtained via email) and generate your API key for your sandbox KYT instance.
  2. Make successful requests on the sandbox KYT instance. Ensure requests are successful (register a transfer, register a withdrawal attempt, get alerts)
  3. Set up compliance workflows and verify that requests are aligned in the sandbox instance.
  4. Log into KYT with your primary credentials (obtained via email) and generate your API key for your primary KYT instance environment (URLs provided above).

Authentication

The KYT 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, retrieve the exposure details for a specific user, etc. 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 100 total items.

Note that the "data" array would typically display the data queried for these objects but has been truncated for this example.

The KYT 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.

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 KYT 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 to KYT, please ensure your timestamps adhere to the UTC time standard.

Errors

KYT 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.

KYT 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.
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 KYT 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 KYT 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

These endpoints register transfers and withdrawal attempts.

POST /v2/users/{userId}/transfers

POST /v2/users/{userId}/withdrawal-attempts

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, KYT stores it and begins processing.

For transfers that are valid and KYT can process, the transfer should process within 30 seconds.

This endpoint returns the below 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 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, e.g., BTC for Bitcoin, ETH for Ether, UNI for Uniswap etc.
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",
    "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: After your initial POST request, this value will be null until KYT processes your 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, e.g., BTC for Bitcoin, ETH for Ether, etc.
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: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
idx Integer or null The transfer’s index. Note: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
usdAmount Number or null The US Dollar amount of funds used in this transfer. Note: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
assetAmount Number or null The amount of cryptocurrency funds used in this transfer. Note: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
timestamp String or null The timestamp when the transfer occurred, in the UTC ISO 8601 format. Note: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
outputAddress String or null The destination address for funds within the transaction. Note: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
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": "Cardano",
    "asset": "ADA", 
    "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': 'Cardano',
    'asset': 'ADA',
    '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': 'Cardano',
        'asset': 'ADA',
        '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\": \"Cardano\",\n    \"asset\": \"ADA\", \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, KYT stores it and begins processing.

For a valid address, KYT will process the withdrawal attempt immediately after receiving the POST request.

This endpoint returns the below 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.

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, e.g., BTC for Bitcoin, ETH for Ether, UNI for Uniswap etc.
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": "ADA",
    "network": "CARDANO",
    "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, e.g., BTC for Bitcoin, ETH for Ether, etc.
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: After your initial POST request, this value will be null until KYT processes your transfer and you call a subsequent GET request.
updatedAt String or null The timestamp when the withdrawal attempt was last updated, in the UTC ISO 8601 format. Note: After your initial POST request, this value may be null until KYT processes your 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.

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",
    "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"
}

Tip: If the updatedAt property returns null, KYT 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.
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 KYT 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 KYT has not finished processing the transfer or the information was not sent to Chainalysis in the GET request.
assetAmount Number or null The amount of cryptocurrency funds used in this transfer. If null, either KYT has not finished processing the transfer or the information was not sent to Chainalysis in the GET request.
timestamp String or null The blockchain timestamp when the transfer occurred, in the UTC ISO 8601 format. If null, either KYT has not finished processing the transfer or the information was not sent to Chainalysis in the GET request.
outputAddress String or null The destination address for funds within the transaction. If null, either KYT has not finished processing the transfer or the information was not sent to Chainalysis 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 KYT has processed your transfer. To verify whether KYT has processed your transfer, call the Transfers summary endpoint, then check whether the updatedAt response body property contains a value. If updatedAt returns null, KYT has not yet processed the transfer.

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",
        "category": "merchant services"
    }
}

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 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.

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 returns a transfer's alerts, if available.

You will receive a successful response after KYT has processed your transfer.

To ensure a successful response, call the Transfer Summary endpoint to view if the updatedAt property in your response body is populated before examining your transfer's alerts.

Note: Alerts for transfers generate according to your organization's alert rules. Learn more about how to define these rules in the KYT UI 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": "HIGH",
            "category": "custom address",
            "service": "Play Royal",
            "externalId": "906ff226-8b64-11eb-8e52-7b35a3dc1742",
            "alertAmount": 5000.00,
            "exposureType": "DIRECT"
        }
    ]
}

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 The entity category of the service as identified by Chainalysis. If null returns, Chainalysis has not yet identified the counterparty's entity 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.

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 KYT has processed your transfer. To verify whether KYT has processed your transfer, call the Transfers summary endpoint, then check whether the updatedAt response body property contains a value. If updatedAt returns null, KYT has not yet processed the transfer.

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.

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",
    "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"
}

Tip: If the updatedAt property returns null, KYT 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.
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 echoback 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 and emerging assets. If the withdrawal attempt was of a pre-growth asset, the endpoint returns null values.

You should call this endpoint after KYT has processed your withdrawal attempt. To verify whether KYT has processed your withdrawal attempt, call the Withdrawal attempts summary endpoint, then check whether the updatedAt response body property contains a value. If updatedAt returns null, KYT has not yet processed the withdrawal attempt.

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",
        "category": "fraud shop"
    }
}

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 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.

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 KYT 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 alerts.

Note: Alerts for withdrawal attempts generate according to your organization's alert rules. Learn more about how to define these rules in the KYT UI 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": [
        {
            "alertAmount": 5000.0,
            "alertLevel": "HIGH",
            "category": "custom address",
            "exposureType": "DIRECT",
            "externalId": "eb67cbdc-8bea-11eb-83d5-378cec3052c2",
            "service": "Play Royal"
        }
    ]
}

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.alertAmount Number The USD amount that caused the alert to trigger.
alerts.alertLevel String Defines the alert's risk as SEVERE, HIGH, MEDIUM, or LOW.
alerts.category String or null The entity category of the service as identified by Chainalysis. If null returns, Chainalysis has not yet identified the counterparty's entity category.
alerts.exposureType String Defines the exposure direction as DIRECT or INDIRECT.
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.

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 KYT 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",
            "categoryName": "sanctions",
            "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]."
        }
    ],
    "customAddresses": []
}

The following is an example JSON response body for a withdrawal attempt with custom address information:

{
    "chainalysisIdentifications": [],
    "customAddresses": [
        {
            "addressName": "Play Royal",
            "categoryName": "gambling",
            "description": "This address belongs to playroyal.com"
        }
    ]
}

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 The category of the Chainalysis Address Identification.
chainalysisIdentifications.description String The OSINT description of the Chainalysis Address Identification.
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.categoryName String The category of the custom address as identified by Chainalysis.
customAddresses.description String The description of the custom address.

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 KYT has processed your withdrawal attempt. To verify whether KYT has processed your withdrawal attempt, call the Withdrawal attempts summary endpoint, then check whether the updatedAt response body property contains a value. If updatedAt returns null, KYT has not yet processed the withdrawal attempt.

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.

V1 endpoints

Received transfers

These endpoints either register or retrieve received transfers.

POST /v1/users/{userId}/transfers/received

GET /v1/users/{userId}/transfers/received

With them, you can perform the following actions:

For a list of networks that KYT currently supports, see Supported networks and assets.

Register a received transfer

ENDPOINT

POST /v1/users/{userId}/transfers/received

The following is an example request to register a received Bitcoin transfer for user 005 using an output address in the transferReference.

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);
    }
}

The following is an example request to register a received Bitcoin transfer for user 005 using an output index in the transferReference.

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:1"
    }
]'
import requests

headers = {
    'Token': '{YOUR_API_KEY}',
    'Accept': 'application/json',
}

received_transfer_data = [
    {
        'network': 'Bitcoin',
        'asset': 'BTC',
        'transferReference': '43ed2f877b437153c78f8a2fd09b9852c65d53734590388e2698824e812a464f:1',
    },
]

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:1'
        }
    ])
});
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:1\"\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 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, e.g., BTC for Bitcoin, ETH for Ether, UNI for Uniswap etc.
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. Note: Available only for pre-growth assets.
assetAmount Number No The amount of cryptocurrency funds used in this transfer. Note: Available only for pre-growth assets.

Response schema

The following is an example JSON response body from the above requests:

[
  {
    "transferReference": "2d9bfc3a47c2c9cfd0170198782979ed327442e5ed1c8a752bced24d490347d4:1H7aVb2RZiBmdbnzazQgVj2hWR3eEZPg6v",
    "asset": "BTC",
    "cluster": {
      "name": "Coinbase.com",
      "category": "exchange"
    },
    "rating": "lowRisk"
  }
]

A successful request will return a 200 response, indicating KYT 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 or pre-growth network, the response will display an empty array. To get more information about these transfers, 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, e.g., BTC for Bitcoin, ETH for Ether, etc.
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 The category the named Cluster belongs to, ie. Exchange.
rating String The risk rating of the transfer, either highRisk, lowRisk, or unknown. The rating corresponds to the entity's category. Learn more about entities 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",
                "category": "exchange"
            }
        }
    ]
}

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 associated with the Transaction associated with the user.
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 entities 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 The category the named Cluster belongs to, e.g., an exchange.

Sent transfers

These endpoints either register or retrieve sent transfers.

POST /v1/users/{userId}/transfers/sent

GET /v1/users/{userId}/transfers/sent

With them, you can:

For a list of networks that KYT currently supports, see Supported networks and assets.

Register a sent transfer

ENDPOINT

POST /v1/users/{userId}/transfers/sent

The following is an example request to register a sent Bitcoin transfer for the user 006 using an output address in the transferReference.

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);
    }
}

The following is an example request to register a sent Bitcoin transfer for the user 006 using an output index in the transferReference.

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:0"
    }
]'
import requests

headers = {
    'Token': '{YOUR_API_KEY}',
    'Accept': 'application/json',
}

sent_transfer_data = [
    {
        'network': 'Bitcoin',
        'asset': 'BTC',
        'transferReference': '7c2238d4de91472061d66f918bda68541f33bd84ce994bcf191cd1315fa41118:0',
    },
]

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:0'
        }
    ])
});
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:0\"\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 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, e.g., BTC for Bitcoin, ETH for Ether, UNI for Uniswap etc.
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. Note: Available only for pre-growth assets.
assetAmount Number No The amount of cryptocurrency funds used in this transfer. Note: Available only for pre-growth assets.

Response schema

The above requests return an empty JSON response.

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",
                "category": "exchange"
            }
        }
    ]
}

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 associated with the Transaction associated with the user.
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 The category the named Cluster belongs to, ie. Exchange.

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:

Note that KYT 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.

For a list of networks that KYT supports, see Supported networks and assets.

Register withdrawal addresses

ENDPOINT

POST /v1/users/{userId}/withdrawaladdresses

This endpoint registers a withdrawal addresses and returns a risk rating for a single User ID.

The following is an example request to register a Bitcoin withdrawal address of 1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk 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": "Bitcoin",
        "asset": "BTC",
        "address": "1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk"
    }
]'
import requests

headers = {
    'Token': '{YOUR_API_KEY}',
    'Accept': 'application/json',
}

register_withdrawal_data = [
    {
        'network': 'Bitcoin',
        'asset': 'BTC',
        'address': '1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk',
    },
]

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': 'Bitcoin',
            '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/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\": \"Bitcoin\",\n        \"asset\": \"BTC\",\n        \"address\": \"1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk\"\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 Determines whether to register withdrawal addresses 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 items when bulkImport is false or not specified and 1000 items when bulkImport is true.

If using bulkImport, it should be passed in as a parameter in the URL, not sent in the request body:

https://api.chainalysis.com/api/kyt/v1/users/BTC_01/withdrawaladdresses?bulkImport=true

Request body schema

Property Type Required Description
network String Yes The blockchain network this withdrawal occurred on. See our supported networks list for the appropriate values.
asset String Yes The asset to screen. The value must be the asset's symbol, i.e., BTC for bitcoin, ETH for Ether, 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:

[
    {
        "network": "Bitcoin",
        "asset": "BTC",
        "address": "1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk",
        "cluster": {
            "name": "Huobi.com",
            "category": "exchange"
        },
        "rating": "lowRisk",
        "customAddress": null,
        "chainalysisIdentification": null
    }
]

The following is an example JSON response body for an unknown recipient on an emerging network:

[
    {
        "network": "Ethereum",
        "asset": "USDC",
        "address": "0x7de5aba7de728950c92c57d08e20d4077161f12f",
        "cluster": null,
        "rating": "unknown",
        "customAddress": null,
        "chainalysisIdentification": null
    }
]

The following is an example JSON response body for a Custom Address on a pre-growth network:

[
    {
        "network": "Verge",
        "asset": "XVG",
        "address": "DEa5gMxbiDb96WfTN25nwzjzfjYHzHMsWi",
        "cluster": null,
        "rating": "highRisk",
        "customAddress": {
           "addressName": "Scam Address & User",
           "description": "This address belongs scamming user John Doe",
           "categoryName": "scam"
        },
        "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",
            "category": "exchange"
        },
        "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",
            "categoryName": "sanctions"
        }
    }
]

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, e.g. BTC, ETH, UNI, etc.
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 The category of the named cluster.
rating String The risk rating of the known recipient address.
customAddress Object or null An address you've uploaded through the KYT 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 The category name you provided for the Custom Address in the CSV file.
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 The category of the Chainalysis Address Identification.

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",
        "category": "Exchange"
      },
      "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",
           "categoryName": "scam"
        },
        "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 The category of the named cluster, i.e., Exchange.
data.customAddress Object or null An address you've uploaded through the KYT 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 The category name you provided for the Custom Address in the CSV file.
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 The category of the Chainalysis Address Identification.
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 user 0001:

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, e.g., 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, or delete a cryptocurrency address for a given user that receives funds into your organization.

POST /v1/users/{userId}/depositaddresses

GET /v1/users/{userId}/depositaddresses

DELETE /v1/users/{userId}/depositaddresses/{asset}/{address}

These endpoints are not currently required for integration. For ongoing monitoring, you should register transfers with the transfers/sent and transfers/received endpoints.

Note: In the future, KYT will be able to detect deposits (but not withdrawals) based on the deposit address. While this endpoint is not currently required for monitoring or integration, you can implement it now for use with this upcoming functionality.

To view the list of assets that KYT supports, see Supported networks and assets.

Register deposit addresses

ENDPOINT

POST /v1/users/{userId}/depositaddresses

The following is an example request to register a Bitcoin deposit address of 1MCPcGbnrv4Uv9HcrjoQwzJaEFGrwzE6Pk for user BTC_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, i.e. 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 user BTC_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 in KYT are raised 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 trasfer 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 KYT 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",
      "category": "darknet market",
      "transactionIndex": 1,
      "asset": "BTC",
      "rule": ">$100 sent directly to darknet market",
      "minThreshold": 100,
      "maxThreshold": 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",
        "category": null,
        "transactionIndex": null,
        "asset": null,
        "rule": "$0-$50000 received",
        "minThreshold": 0,
        "maxThreshold": 50000
    },
    {...}
  ]
}

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 KYT, 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 KYT 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 KYT 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 The entity category the alert rule is tracking. Will be null if the rule is behavioral and tracking for any 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.

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 KYT 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 KYT 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 KYT 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 KYT 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 Chainalysis KYT. 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:

Get all users

ENDPOINT

GET /v1/users/

This endpoint retrieves and lists all User IDs in your KYT system.

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 the Chainalysis KYT system.

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 KYT 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 the Chainalysis KYT system.

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 KYT 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",
        "category": "exchange"
      },
      "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 the KYT system, 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 The category the named cluster belongs to.
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.receivedIndirectExposure Number Total Sent Indirect Exposure for the user in USD.

Note: If a user is created in KYT 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 the KYT system. The request supports up to 1000 renames at a time.

The following is an example request to rename a User ID from test_1 to user_1 and test_2 to user_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 exist in the KYT system. Using an existing userId will return a 400 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 KYT API and the corresponding symbol.