NAV

Developer Portal

Welcome to the KYT Developer Portal! Here you will find resources to help you integrate with the KYT API, including quickstarts, workflows, use-cases, tutorials, and many other resources.

Quickstart: Register a transfer

Learn how to register a received transfer using the POST /v2/users/{userId}/transfers endpoint.

Before you begin

Ensure you create an API key before you continue to the steps below.

Add your headers

For the POST /v2/users/{userId}/transfers endpoint, use the Token header for your API key and a Content-type: application/json header to indicate you're sending JSON content. The following is an example:

curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/{userId}/transfers' \
  --header 'Token: {YOUR_API_KEY}' \
  --header 'Content-type: application/json' \

Create a user id

Use the path parameter userId to create a unique identifer for this user, such as user0001. Be sure not use any personally identifiable information.

Create your request body

The properties you need to send in your request body depend on the asset's tier. Transfers on mature and emerging networks require at a minimum the following properties:

In this example, you register a received transfer of the asset ETH (i.e., Ether) on the Ethereum network. The transferReference is a combination of the transaction hash (0xdd6364536f5f05cc1ea75709b676e2b1b37fad2792d3a71fb537db13100fc6b8) and receiving address, separated by a :. Since your platform received this transfer, the output address is an address you control (0x5cc17d0fa620FE99dAEAa87365C63b453BC47664) and the direction is received.

Using the information above, the following is an example of a properly formatted registration call:

curl POST 'https://api.chainalysis.com/api/kyt/v2/users/user0001/transfers' \
-H 'Token: {YOUR-API-KEY}' \
-H 'Content-Type: application/json' \
--data-raw '{
    "network": "Ethereum",
    "asset": "ETH",
    "transferReference": "0xdd6364536f5f05cc1ea75709b676e2b1b37fad2792d3a71fb537db13100fc6b8:0x5cc17d0fa620FE99dAEAa87365C63b453BC47664",
    "direction": "received"
}'

Assess your response

If properly formatted, you should received a 202 code with a response similar to the following:

{
    "updatedAt": null,
    "asset": "ETH",
    "network": "ETHEREUM",
    "transferReference": "0xdd6364536f5f05cc1ea75709b676e2b1b37fad2792d3a71fb537db13100fc6b8:0x5cc17d0fa620FE99dAEAa87365C63b453BC47664",
    "tx": null,
    "idx": null,
    "usdAmount": null,
    "assetAmount": null,
    "timestamp": null,
    "outputAddress": null,
    "externalId": "2774e6d5-aafe-3a26-ad0b-7812c295cb48"
}

Save the externalId for future use. You will need it to identify the transfer when retrieving alerts, exposure, or identifications.

Verify KYT processed your transfer

KYT indicates it has processed your transfer by returning a non-null value for updatedAt. Since it takes a number of seconds to process, updatedAt typically returns null immediately after registering the transfer. To check whether the transfer was processed, call the GET /v2/transfers/{externalId} summary endpoint with your stored externalId until updatedAt returns a timestamp. After KYT processes your transfer, the other properties (assetAmount, timestamp, tx, etc.) should also populate.

Below is an example request body from the summary endpoint for the above transfer:

{
    "updatedAt": "2022-06-30T16:43:53.172475",
    "asset": "ETH",
    "network": "ETHEREUM",
    "transferReference": "0xdd6364536f5f05cc1ea75709b676e2b1b37fad2792d3a71fb537db13100fc6b8:0x5cc17d0fa620FE99dAEAa87365C63b453BC47664",
    "tx": "dd6364536f5f05cc1ea75709b676e2b1b37fad2792d3a71fb537db13100fc6b8",
    "idx": 0,
    "usdAmount": 2744.02,
    "assetAmount": 2.6773581135091926,
    "timestamp": "2018-01-18T07:26:28.000+00:00",
    "outputAddress": "5cc17d0fa620fe99daeaa87365c63b453bc47664",
    "externalId": "2774e6d5-aafe-3a26-ad0b-7812c295cb48"
}

What's next

To learn more, check out the following resources:

Quickstart: Register a withdrawal attempt

Learn how to register a withdrawal attempt using the POST /v2/users/{userId}/withdrawal-attempts endpoint.

Before you begin

Ensure you create an API key before you continue to the steps below.

Format your headers

For the POST /v2/users/{userId}/withdrawal-attempts endpoint, use the Token header for your API key and a Content-type: application/json header to indicate you're sending JSON content. The following is an example:

curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/{userId}/withdrawal-attempts' \
  --header 'Token: {YOUR_API_KEY}' \
  --header 'Content-type: application/json' \

Create a user id

Use the path parameter userId to create a unique identifer for this user, such as user0002. Be sure not use any personally identifiable information.

Create your request body

In your request body, supply at least the following request body properties:

In this example, you register a withdrawal attempt for five ADA on the Cardano network. The attempt is made to the address 1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG. Create identification for the attempt with a unique attemptIdentifier.

Using the information above, the following is an example of a properly formatted registration request:

curl -X POST 'https://api.chainalysis.com/api/kyt/v2/users/user0002/withdrawal-attempts' \
  --header 'Token: {YOUR_API_KEY}' \
  --header 'Content-type: application/json' \
  --data '{
    "network": "Cardano",
    "asset": "ADA", 
    "address": "1EM4e8eu2S2RQrbS8C6aYnunWpkAwQ8GtG", 
    "attemptIdentifier": "attempt1", 
    "assetAmount": 5.0
}'

Assess your response

If the request was successful, you should receive a 202 code with a response similar to the following:

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

Save the externalId for future use. You will need it to identify the withdrawal attempt when retrieving alerts, exposure, or identifications. For withdrawals, updatedAt typically returns a timestamp immediately, indicating KYT successfully processed the request.

In the rare instance that updatedAt does return null, call the GET /v2/withdrawal-attempts/{externalId} summary endpoint with your extneralId until updatedAt populates.

Register for continuous monitoring

You can also register the withdrawal attempt as a sent transfer. Doing so will configure KYT to continuously monitor the transfer for updates in exposure and identifications, generating alerts according to your risk settings. To register the transfer as sent follow the steps in Quickstart: Register a transfer, but this time indicate the direction as sent in the request body.

What's next

To learn more, check out the following resources:

Workflows

The API implementation guide details three common use cases:


This diagram shows a general overview of common KYT workflows. For information on which endpoints to use, and in what order, see the procedures below.


Crediting a user’s funds

Typically, services do not have control over received transfers. This guide details how to use KYT data to take programmatic action when receiving a user deposit. Outlined below is an example describing how to use the KYT API to navigate received deposits.

When you receive a user deposit:

  1. Call the POST /v2/users/{userId}/transfers endpoint. Be sure to indicate the "direction" as "RECEIVED" in the request body. If successful, you will:
    1. Receive a 202 response.
    2. Receive an external identifier (externalId). Store this external identifier in your system for later use.
  2. Call the GET /v2/transfers/{externalId} summary endpoint using the externalId received in step 1. You will need to poll this endpoint until updatedAt is no longer null. Once populated, KYT generates alerts according to your organization’s alert rules.

    Note: How quickly the updatedAt field populates depends on how many confirmations Chainalysis requires before processing transactions for a given asset. Some require fewer confirmations or are quicker than others. Learn more about polling the summary endpoints here.

  3. Once the updatedAt field populates, determine whether the asset is part of a mature or emerging network or pre-growth network and follow the corresponding procedure below.

User deposits for mature and emerging assets

With mature and emerging assets, you can retrieve the following additional information about the transfer, if available:

To retrieve additional information about the received transfer:

  1. Call the GET /v2/transfers/{externalId}/exposures endpoint to retrieve any available direct exposure information.
  2. Call the GET /v2/transfers/{externalId}/alerts endpoint to retrieve any generated alerts specific to this transfer.

Learn more about retrieving alert data for ongoing transaction monitoring here.

User deposits for pre-growth assets

For pre-growth assets, you can retrieve the following additional information about the transfer, if available:

To retrieve additional information about the received transfer:

  1. Call the GET /v2/transfers/{externalId}/alerts endpoint to retrieve any generated alerts specific to this transfer.
  2. Call the GET /v2/transfers/{externalId}/network-identifications endpoint to retrieve the counterparty name for any asset and transaction hash matches.

Learn more about retrieving alert data for ongoing transaction monitoring here.

Note: Depending on the transfer, direct exposure information may be available. You can check by calling the GET /v2/transfers/{externalId}/exposures endpoint.

Processing withdrawals

Sometimes services do not have information about the counterparty where their users attempt to make a withdrawal. This guide details how to use KYT data to take programmatic action when users attempt withdrawals. Outlined below is an example describing how to use the KYT API to navigate withdrawal attempts.

When a user attempts a withdrawal:

  1. Call the POST /v2/users/{userId}/withdrawal-attempts endpoint. If successful, you will:
    1. Receive a 202 response.
    2. Receive an external identifier (externalId). Store the external identifier in your system for later use.
  2. Call the GET /v2/withdrawal-attempts/{externalId} summary endpoint, using the externalId received in step 1. You will need to poll this endpoint until updatedAt is no longer null. Once populated, KYT generates alerts according to your organization’s alert rules.
  3. Once the updatedAt field populates, determine whether the asset is part of a mature or emerging network or pre-growth network and follow the corresponding procedure below.

Withdrawal attempts for mature and emerging assets

With mature and emerging assets, you can retrieve the following additional information, if available:

To retrieve additional information about the withdrawal attempt:

  1. Call the GET /v2/withdrawal-attempts/{externalId}/exposures endpoint to retrieve any counterparty exposure information.
  2. Call the GET /v2/withdrawal-attempts/{externalId}/alerts endpoint to retrieve any available alerts specific to this counterparty.
  3. Call the GET /v2/withdrawal-attempts/{externalId}/high-risk-addresses endpoint to check if the counterparty has any Chainalysis Address Identifications.
  4. After successfully processing a user’s withdrawal, call the POST /v2/users/{userId}/transfers endpoint and indicate the "direction" as "SENT" to register the transfer for ongoing monitoring.

Withdrawal attempts for pre-growth assets

With pre-growth assets, you can retrieve the following additional information, if available:

To retrieve additional information about the withdrawal attempt:

  1. Call the GET /v2/withdrawal-attempts/{externalId}/alerts endpoint to retrieve any alerts specific to the counterparty.
  2. Call the GET /v2/withdrawal-attempts/{externalId}/high-risk-addresses endpoint to check if the counterparty has any Chainalysis Address Identifications.
  3. Call the GET /v2/withdrawal-attempts/{externalId}/network-identifications endpoint to retrieve the counterparty name of any asset and transaction hash matches.
  4. After successfully processing a user’s withdrawal, call the POST /v2/users/{userId}/transfers endpoint and indicate the "direction" as "SENT"to register the transfer for ongoing monitoring.

Retrieving alerts for transaction monitoring

After you've decided whether to credit a user's funds or process a user's withdrawal attempt, KYT automatically monitors the transaction and generates alerts according to your Alert Rules. You can retrieve those alerts with the GET /v1/alerts endpoint.

If you call the endpoint without any query parameters, you will retrieve all of the alerts within your organization. To retrieve specific alerts, you can filter or sort with various query parameters.

Use the following query parameters to filter the alerts you wish to retrieve:

Use the sort parameter with one of the following items to sort the order in which you retrieve alerts:

After choosing the item you wish to sort by, you must add a URL encoded space character and indicate the order as either ascending (asc) or descending (desc). For example, sort=createdAt%20asc.

Retrieving high severity alerts for a specified user

You can specify a combination of these query parameters to retrieve a specific result. As an example, to retrieve only HIGH severity alerts of a specific userId generated after a particular timestamp (createdAt_gte), call GET /v1/alerts?level=HIGH&userId=user001&createdAt_gte=2020-01-06

This will return all high severity alerts for user001 after January 6th, 2020. Notice the timestamp includes only the date. You can filter even further with the inclusion of time to retrieve alerts down to the microsecond: &createdAt_gte=2020-01-06T12:42:14.124Z

If you want to sort the alerts by their creation date, add sort=createdAt%20asc as a query parameter.

Retrieving severe alerts for a specified date range

You can use both createdAt_gte andcreatedAt_lte to retrieve alerts for a determined time period. As an example, to retrieve only SEVERE alerts within your organization between the hours of 1:00AM and 2:00AM, call GET /v1/alerts?level=SEVERE&createdAt_gte=2021-05-01T00:00:00.00Z&createdAt_lte=2021-05-07T00:00:00.00Z

You can adjust these parameters to then retrieve all SEVERE alerts between the hours of 2:00AM and 3:00AM, so on and so forth. Alternatively, you can discard the time information (T00:00:00Z) from the query parameters altogether to retrieve alerts for certain days, weeks, or even months. The level of frequency you choose to call these endpoints depends on your organizational needs.

Polling the summary endpoints

Generally, KYT processes requests to register withdrawal attempts and transfers with blockchain confirmations in near real-time, thereby providing a quick risk assessment to make synchronous decisions. To verify KYT processed your request, you can call the summary endpoints (i.e., summary for withdrawal attempts or summary for transfers) and check whether updatedAt returns a non-null value. Once updatedAt returns a non-null value, you can attempt to retrieve alerts, exposure, or identifications.

Withdrawal attempts

KYT usually processes withdrawal attempts immediately and returns a non-null value for the updatedAt property in the response of the POST request. In this scenario, you do not need to call the summary endpoint for verification and can immediately check for any generated alerts, exposure, or identifications.

While KYT often processes withdrawal attempts immediately, we still recommend setting a policy for how long to wait in case of latency or updatedAt does return null for an extended amount of time.

Transfers with confirmation

Assuming you have made the initial POST request after a block has been confirmed on the network, most transfers process in less than a minute (see the table below for more information). However, we do suggest building a buffer for instances of increased latency and setting a policy for how long to wait before crediting a user's account (for received transfers).

Many services require a few confirmations before crediting a user's funds, which usually takes several minutes. It is during this time that you can begin polling the GET /transfers/{externalId} endpoint.

Transfers without confirmation

If you register a transfer before it has any confirmations, processing times may increase as KYT first needs to validate the transaction exists on a blockchain, and updatedAt will remain null for longer.

If you register a transfer well before it is confirmed (e.g., during high network congestion), KYT may take longer to process the transfer. We recommend registering the transfer in KYT either after it is confirmed on the blockchain or shortly before.

KYT processing times per network

KYT begins processing block data after a transaction achieves a predetermined number of confirmations. Often this threshold is a single confirmation, but some networks require more (e.g., EOS). Additionally, the speed at which networks acquire confirmations varies from network to network (e.g., Bitcoin’s block time is ~10 minutes while Ethereum’s block time is ~12-14 seconds).

See the table below for KYT’s confirmation threshold and approximate KYT processing time per network. Note that our team is continually working to improve the speed at which we ingest and process block data.

Network Confirmations required for KYT to ingest block data After the threshold is met, the approximate KYT processing time
Bitcoin 1 confirmation Approx. 30 seconds Caution: These times are estimates, and sometimes latency can fluctuate. After the threshold, KYT may take additional time to process depending on various factors, such as how long before confirmation you submitted a transfer. We suggest building a buffer in your internal system to account for potential irregularities.
Bitcoin Cash 1 confirmation Approx. 10 seconds
Bitcoin SV 1 confirmation Approx. 1 minute
Ethereum 1 confirmation Approx. 5 seconds
Ethereum Classic 1 confirmation Approx. 5 minutes
Litecoin 1 confirmation Approx. 10 seconds
EOS 360 confirmations Approx. 3 minutes
XRP 1 confirmation Approx. 5 seconds
Zcash 1 confirmation Approx. 5 seconds
Dogecoin 1 confirmation Approx. 5 seconds
Dash 1 confirmation Approx. 5 seconds
TRON 1 confirmation Approx. 5 seconds

Legacy implementation

Suggested implementations of the Chainalysis KYT API are detailed below, increasing in complexity and the amount of functionality you will receive. You can choose to work entirely in the KYT user interface (UI), or build a response within your own internal systems based on feedback and analysis from Chainalysis.

Building the analysis and data from the KYT API into your internal system provides robust functionality and gives you a more comprehensive picture of your risk. We suggest reviewing example compliance workflows to help assess which implementation best meets your needs.

At minimum, the two major endpoints required for integration are: /transfers/sent and /transfers/received. For basic functionality, you must execute at least those two requests.

Overview

The following graphic serves as a preview and comparison for the various KYT implementations. The implementations are described in detail in the sections below, including benefits and drawbacks as well as required endpoints for each.

Implementations overview

To help you visualize a compliance workflow using data from the KYT API, here is a basic KYT implementation.

Customer lifecycle

Prepare for launch 1

KYT UI only

This is the minimum implementation and keeps all data and functionality entirely within Chainalysis’s environment. It does not pull data into your internal systems.

You will receive the full functionality of the KYT UI, but you will not have the ability to automate actions on transfers within your internal systems based on the information from KYT.

Prepare for Launch 1

This implementation requires registering /transfers/sent and /transfers/received. /depositaddresses is optional.

POST /users/{userId}/transfers/received

POST /users/{userId}/transfers/sent

POST /users/{userId}/depositaddresses

Transactions must be associated with a User ID for user risk score calculation.

Prepare for launch 2

Internal systems only

While you can work entirely in the Chainalysis environment (see above), this implementation pulls Chainalysis’s data into your own system where you can incorporate KYT into your automated payments workflow.

Integrating Chainalysis’s data into your internal system helps you to get a more comprehensive picture of your risk activity and automate actions on transfers based on Chainalysis data. However, you will be missing out on functionality and convenience by not working within the KYT UI.

Prepare for Launch 2

This implementation requires registering /transfers/sent and /transfers/received (described above), as well as /withdrawaladdresses.

For example, if you want to stop the withdrawal of funds to a sanction or terrorist financing entity, you would use this request.

POST /users/{userId}/withdrawaladdresses

Lift off

KYT UI & Internal systems

This setup is more robust than the previous implementations, as it encompasses both the KYT UI and your internal systems. You will be able to take action on transfers within your system and also have the full functionality of the UI, helping to provide continuity in the data you review between systems.

However, it does not take advantage of all the KYT features, such as alerts.

Lift off implementation

This implementation requires registering /transfers/sent, /transfers/received, and /withdrawaladdresses (described above).

With this implementation you can:

Cruising altitude

KYT UI & Internal systems

This implementation pulls Chainalysis data into both the KYT UI and your internal systems with an additional API endpoint, /alerts.

Cruising Altitude brings the most powerful data that KYT offers - alerts - into your internal system. You can perform the actions mentioned above (setting flags, pulling the risk score into payments queues, etc) with the benefit that the data you are using is the most robust. This implementation can also help you match the alerts workflows that your compliance team is likely doing in the UI.

Cruising altitude implementation

This implementation requires registering /transfers/sent, /transfers/received, /withdrawaladdresses (described above), as well as /alerts.

GET /alerts

To the moon

KYT UI & Internal systems

This implementation pulls Chainalysis data into both the KYT UI and your internal systems. It builds on the implementations above with an additional endpoint, /users. GET /users provides you with a user risk score for each of your users.

Alerts and user risk score are two powerful analytic metrics that are provided by the KYT API for assessing your risk activity. User risk scores allow you to perform user-level automated review in your internal system on top of the transfer-level review from above.

To the Moon implementation

This implementation requires registering /transfers/sent, /transfers/received, /withdrawaladdresses, /alerts (described above), as well as /users.

GET /users

Compliance workflows

Below are example compliance workflows using KYT’s most powerful risk assessment features to help you formulate policies and procedures based on the information provided by the KYT and Reactor UIs, and the KYT API.

The workflows below focus on three KYT features that help you prioritize risk activity: alerts, user risk score, and counterparty screen:

We suggest using alerts as a notification and starting point for review and interacting with user risk profiles. The KYT Dashboard in the UI gives you a high-level overview of your risk for managerial and organizational reporting/monitoring, while alerts is where an analyst will spend most of their time.

Deposit workflow

This is a suggested workflow for funds that are received by a user at your organization. Note that in most cases, you cannot stop an incoming transfer from occurring. However, KYT helps you to detect the risk associated with the transfer and take appropriate compliance action. For example, if a user receives funds directly from a cluster categorized as child abuse material, you can decide how you want to react (e.g. freeze funds, investigate, and likely file a SAR).

Integration graphic

1. Register the transfer
When funds arrive at a user address, POST the received transfer.

2. Check alerts and/or user risk score

You can check alerts:

We suggest checking alerts first to assess risky transfer activity and then moving to review all alerts at the user level by clicking the unique URL for the user. You can also check the user’s risk score to see if the user is high risk.

You can check user risk score:

3. Take action

Take action on the received funds. For example, you can hold the transfer and submit it to be manually reviewed, immediately freeze the user’s funds, or deem the transfer non-risky.

Chainalysis continually monitors for risk on each registered transfer.

Withdrawal workflow

This is a suggested workflow for funds that are being sent by a user at your organization. Unlike deposits, you can stop a risky withdrawal from occurring if at the time of the withdrawal, the withdrawal address has been identified as risky. For example, if a user requests a withdrawal towards a sanctioned address, you can decide to block this request.

Integration graphic

1. Check Withdrawal Address

The withdrawal prescreen is used in real-time to pre-screen for counterparty risk. When a user requests a withdrawal, register the withdrawal address by making a POST request to the /withdrawaladdresses endpoint. For known counterparties, a risk rating of high risk or low risk will be provided, as well as the counterparty’s name.

Note that it is common to withdraw to a previously unknown address, so the majority of addresses you check may have an unknown rating.

2. Take action

After performing the withdrawal address counterparty screen, take action on the pending transfer. You may choose to block a transfer that is high risk, or flag it for further review.

3. Register the transfer

Always be sure to register an approved withdrawal as a sent transfer upon completion so that your team can access it in the compliance dashboard and KYT can monitor the transfer. Note that KYT updates risk for transfers on an ongoing basis, but does not update withdrawal addresses. The latter will always return the rating when the address was first screened.

As with deposits, Chainalysis monitors sent transfers for you over time.

4. Check alerts

Look at the user information page in the UI for the user's associated withdrawal addresses and alerts. Alerts that have a sent direction mean that the withdrawal was approved.

Example compliance actions

Here are some examples of compliance actions taken by our customers when following the workflows above:

“If we notice a withdrawal request towards terrorism financing, we will show the user the withdrawal request is processing and call our Financial Intelligence Unit hotline to ask if they want us to block the transaction (and likely tip off the user) or allow it to occur (for ongoing monitoring).”

“If we detect a direct deposit from a darknet market, we will silently freeze the account. Typically we will file a SAR report, offboard the user, and allow the user to withdraw their funds via a fiat conversion to their bank account.”

“If we detect a pattern of risky (in)direct darknet market transactions, we will freeze the account. Typically we will file a SAR report, offboard the user, and allow the user to withdraw their cryptocurrency.”

“Transfers to mixing services are prohibited on our platform. If we see a withdrawal request to a mixer, we flag the transfer for review and ask the user to explain the purpose of the withdrawal.”

Internal systems

Note that instead of performing these checks manually, you can automate the process by building a response within your own internal systems. See the suggested implementations above for more information. The benefits of automating compliance include:

Register Lightning Network transfers and withdrawals

You can use the KYT API to register Lightning Network (LN) transfers and withdrawal attempts. Registering LN transfers is similar to registering any other transfer, but with a few modifications to the values of a handful of request body properties.

This article describes how to register transfers using the POST /v2/users/{userId}/transfers and /v2/users/{userId}/withdrawal-attempts endpoints, but you can also use the v1 received transfers, sent transfers, and withdrawal pre-screening endpoints by applying the principles outlined in this article to the values of the v1 request body properties.

Updated request properties

Since Lightning Network transfers occur “off-chain”, Chainalysis requires you to treat certain request properties slightly differently than in typical “on-chain” transfers. The following properties are required and use slightly different values:

network and asset

Be sure to use Lightning as the value for the network property and BTC as the value for the asset property. Failing to specify Lightning may result in a failed request.

For example, the property value pair should look like the following: "network": "Lightning", "asset": "BTC".

transferReference

To uniquely identify a Lightning Network transfer, you must supply a combination of the payment hash and node key the funds are being sent to as the value for the transferReference property. Separate the payment hash and node key with a colon (payment-hash:node-key) and supply that string as the value for the property.

As an example, the property value pair should look similar to the following but supplied with your own payment hash and the recipient node key: "transferReference": "2db4d5579a0e198bd5ce8ffe83ecd0de94acde98cde94125337e2419ebb4cc50:02a0c9089ace681ef4e6ae5310b028d9c2a09187bfbc616da6251e3d08801851b8".

transferTimestamp

For Lightning Network transfers, transferTimestamp is a required property. Chainalysis uses the timestamp to (1) identify the USD value for any transferred Bitcoin and (2) generate time-based behavioral alerts.

Be sure to send your timestamp in the UTC ISO 8601 format. For example, the property value pair should look similar to the following: "transferTimestamp": "2021-11-25T11:48:21.000000".

assetAmount

assetAmount is also a required property and should be denominated in Bitcoin.

The following is an example of the property value pair: "assetAmount": ".00588".

Unrequired request properties

You aren't required to send the remaining request properties such as outputAddress, assetPrice, and assetDenomination, but you won't receive an error response if you do send them. In the scenario that you do send them, you won't receive any values that you sent in the POST request in subsequent GET requests.

Since the Lightning Network handles transfers off-chain, there is no standard wallet address to use as a value for the outputAddress property. Instead, use the Node Key as the value for this property, similarly to the transferReference property.

Putting it all together

You can register transfers or withdrawal attempts with either the v1 or v2 endpoints; both provide the same capability. See the right-most column for request examples of each endpoint.

The following is an example to register a sent LN transfer using the v2/users/{userId}/transfers endpoint:

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": "Lightning",
    "asset": "BTC",
    "transferReference": "2db4d5579a0e198bd5ce8ffe83ecd0de94acde98cde94125337e2419ebb4cc50:02a0c9089ace681ef4e6ae5310b028d9c2a09187bfbc616da6251e3d08801851b8",
    "direction": "sent",
    "transferTimestamp": "2021-11-25T11:48:21.000000",
    "assetAmount": ".00588"
}'

The following is an example to register the same transfer as above, but with the v1/users/{userId}/transfers/sent endpoint:

curl -X POST 'https://api.chainalysis.com/api/kyt/v1/users/new_user_01/transfers/sent' \
  --header 'Token: {YOUR_API_KEY}' \
  --header 'Content-type: application/json' \
--data-raw '[
    {
      "network": "Lightning",
      "asset": "BTC",
      "transferReference": "2db4d5579a0e198bd5ce8ffe83ecd0de94acde98cde94125337e2419ebb4cc50:02a0c9089ace681ef4e6ae5310b028d9c2a09187bfbc616da6251e3d08801851b8",
      "transferTimestamp": "2021-11-25T11:48:21.000000",
      "assetAmount": ".00588"
    }
]'

Withdrawal attempts and withdrawal pre-screening

You can use either the POST /v2/users/{userId}/withdrawal-attempts or POST /v1/users/{userId}/withdrawaladdresses endpoint to assess the risk of a Node Key a user is attempting to withdraw funds to.

When registering with either endpoint, be sure to use Lightning as the value for the network property, BTC as the value for the asset property, and the Node Key as the value for the address property. To learn more about using these endpoints, see Register a withdrawal attempt (v2) and Register withdrawal addresses (v1).

Navigate asset tiers

The asset's tier determines which request body properties are required. For mature and emerging assets, KYT populates transfer information with blockchain and pricing data.

For pre-growth assets, the additional information (e.g., transferTimestamp or assetAmount) is optional, but we suggest supplying it for maximal value as KYT uses it to generate alerts. In subsequent GET requests, KYT will return only the information supplied in the initial POST registration request. Once a network graduates to the emerging or mature tiers, KYT will backfill the transfer with blockchain and pricing data.

For more information about KYT's functionality for each tier, see Asset coverage.

To register transfers on mature or emerging networks, you need to supply at minimum the following request body properties:

To register transfers from pre-growth networks, you need to supply at minimum the following request body properties:

To maximize KYT value, we recommend you also supply the following request body properties:

The network property informs KYT which blockchain network the transaction occurred on. For example, values could be Ethereum, Avalanche, Bitcoin, Lightning, etc.

The asset property informs KYT of which asset or metatoken was used in the transfer. For example, if Ether was transacted, you would supply ETH as the value. If the ERC-20 Aave was transacted, you would supply AAVE as the value.

The combination of network and asset allows KYT to distinguish between assets that operate on two or more networks, such as the stablecoin USDT. USDT exists on multiple networks, including Ethereum, Tron, Avalanche, etc. Another example is bitcoin, which exists on both the Bitcoin and Lightning networks.

To register a transfer of USDT on the Avalanche network, you would supply "Network": "Avalanche", "Asset": "USDT". However, to register a transfer of USDT on the Ethereum network, you would supply "Network": "Ethereum", "Asset": "USDT".

For lists of the networks Chainalysis currently supports, see Mature and emerging networks and Pre-growth networks.

The transferReference property enables Chainalysis to locate the transfer on a blockchain and typically comprises a transaction hash and output address.

The transaction hash is a unique identifier a blockchain generates for each transaction and is used to identify the transaction. The output address is the destination address for funds within the transaction. It is used to determine the particular transfer within a transaction (which may contain multiple transfers). For received transfers, the output address is an address you control. For sent transfers, the output address is an external address.

Because blockchains use different record-keeping models (e.g., UTXO, account-based, etc.), you must supply different values for the transferReference property depending on the blockchain. In our list of networks, we indicate the proper format for the property.

For networks using a UTXO model, you must reference a transaction hash and corresponding output address or corresponding transaction hash index:

As an example, let's say you want to register a transfer with the transaction hash 9022c2d59d1bed792b6449e956b2fe26b44b1043bbc1662d92ecd29526d7f34e and an output address of 18SuMh4AFgTSQRvwFzdYGieHtgKDveHtc, which is in the 6th place in the transaction.

To register the above transfer using an output address, the property should look like this:

To register the transfer using the output index, the property should look like this:

For networks using an account model (e.g., Ethereum and EVM-compatible), you must reference a transaction hash and corresponding output address: {transaction_hash}:{output_address}.

As an example, let's say you want to register a simple Ether transfer with the transaction hash 0xe823c9b7895f9c47985c80e4611272f8194403e885c9cc603422cd609d738098 and output address 0x3d21a92285bf17cbdde5f77531b8b58ac400288a.

To register this transfer, the property should look like this:

If registering a transfer that sent funds to a smart contract, use the smart contract's contract address as the output address. If registering a transfer that received funds from a smart contract, use the end user's destination address as the output address.

In transactions where an output address is used multiple times (e.g., some interactions with smart contracts), KYT will register the first output address where the transferred amount exceeds 0.

Some assets require a unique transferReference value that does not fit into the above schemas.

Monero

For deposits, you should format transferReference like the following:

For withdrawals, you should format transferReference like the following:

Lightning Network

For the Lightning Network, you must supply a combination of the payment hash and recipient node key. You should format transferReference like the following:

To learn more, see Registering Lightning Network transactions and withdrawals.

Solana

For Solana, the transferReference property differs depending on whether you send SOL or an SPL token. For transfers of SOL, we accept the system account address (i.e., the wallet address) as the value for the output address. For registering a transfer of SOL, you should format transferReference like the following:

Note that the system account address is the only address that SOL can be sent to.

For transfers of SPL tokens, we accept the token account address (i.e., the ATA address). See Solana's Associated Token Account Program to learn more about ATA addresses. To register a transfer of an SPL token, you should format transferReference like the following:

Just a transaction hash

Some blockchain protocols require just a transaction hash and no output address or output index. We indicate these networks in the transferReference column of the network tables.

In rare instances, two metatokens on a single network may share the same asset symbol. Since KYT uses the transferReference property to identify the transaction, nonunique asset symbols do not affect KYTs ability to monitor the transaction. In the extremely rare scenario that two metatokens shared an asset symbol and sent funds to the same outputAddress in the same transaction, KYT will register the first transaction seen. If this is the incorrect transaction, please contact Chainalysis Customer Support.

Troubleshooting

Below are a couple of common troubleshooting issues:

Retrieve alerts as Slack notifications

Example slack notification

This article guides you through a Python script that retrieves KYT alerts as Slack notifications. You can use the script as-is or customize it (e.g., to create notifications for all alerts or only alerts that meet a target criteria).

The script is especially beneficial for team members in your organization who may not be familiar with the API or have time to monitor KYT's dashboard constantly.

The Python script outlined here automates the following things:

Before you start

Before you continue this tutorial, please ensure you meet the following prerequisites:

Build the script

Import the necessary libraries

At its core, the KYT API is a client that makes HTTP requests and returns JSON. To interact with the API successfully, import the following libraries:

Import each of these libraries:

from datetime import datetime
import requests
import argparse
import json

Enable multiple users to access the script

argparse allows you to input arguments that the script can use as variables. In this case, your API key that points toward your KYT organization and authenticates your requests. If multiple team members use the script, each can input their KYT API key in the command line.

The following code creates an argument that asks for an API key upon running:

parser = argparse.ArgumentParser(description="Check for new alerts")
parser.add_argument("-k", "--key", required=True,
                    help="Chainalysis API Key",metavar="key")

args = parser.parse_args()

Retrieve alerts

This function checks for KYT alerts generated since that script was last run. It calls the GET /v1/alerts/ endpoint with the query parameter createdAt_gte to avoid creating notifications for old alerts.

As an example, GET https://api.chainalysis.com/api/kyt/v1/alerts/?createdAt_gte=2021-06-01T12:30:00 retrieves all alerts generated after 12:30PM UTC on June 1st, 2021.

The following code creates the function get_alerts, which only retrieves alerts generated since the last time the script was run.

def get_alerts()
   """Retrieve alerts from KYT that were generated after the last time the script was run."""

   base = "https://api.chainalysis.com"
   h = {
     'token': args.key,
     'Content-Type': 'application/json',
     'accept': 'application/json'
   }

url = f"{base}/api/kyt/v1/alerts/?createdAt_get={last_runtime}"

response = requests.get(url,headers=h)
return response.json()

Send Slack notifications

Once you've retrieved your newly created alerts from KYT, you can use Slack's webhook to deliver them in a notification to your Slack workspace. To learn more about creating a webhook URL for your Slack workspace, see Slack's documentation Sending messages using Incoming Webhooks. Once you have this URL, replace it in the code below as the value for url.

The following code creates the function send_slack_message, which sends you a Slack notification with the following information:

def send_slack_message():
  """Trigger a Slack notification via webhook"""

  url = "" # Insert your webhook URL here.
  h = {'Content-Type': 'application/json'}
  payload = {
    "blocks": [
      {
        "type": "header",
        "text": {
          "type": "plain_text",
          "text": "You have new alerts!"
        }
      },
      {
        "type": "section",
        fields": [
          {
            "type": "mrkdwn",
            "text": f"*Total new alerts:*\n{total_alerts}"
          },
          {
            "type": "mrkdwn",
            "text": f"*Last runtime:*\n{last_runtime[0:19]}"
          }
        ]
      },
      {
        "type": "section",
        "fields": [
          {
            "type": "mrkdwn",
            "text": f"<https://kyt.chainalysis.com/alerts?alertStatus=Unreviewed&createdAt_get={last_runtime}|*View new alerts*>"
          }
        ]
      }
    ]
  }

    response = requests.post(url,headers=h,data=json.dumps(payload))

    # print(response.text) # If your webhook is working as expected, this will return 'ok'.

You can customize the payload variable to present different information. This variable was constructed using Slack's Block Kit Builder.

The code and payload above generate a Slack notification that looks like this:

Example slack notification

Update your latest run time

After you have retrieved any new alerts, you want to ensure you don't re-retrieve old alerts. To retrieve only newly generated alerts, the code below creates the function update_last_runtime to rewrite the script and set the last_runtime variable as the current time in UTC. The get_alerts function uses the last_runtime variable when checking for alerts.

def update_last_runtime():
  """Modify script to set last_runtime variable to the current time in UTC."""

  with open(__file__, 'r') as f:
    lines = f.read().split('\n')

  # Find which line last_runtime variable resides and modify it to the current time
  variable_index = [i for i, e in enumerate(lines) if "last_runtime = " in e]
  lines[variable_index[0]] = (f'last_runtime = "{(str(datetime.utcnow())).replace("", "T")}"')

  # Update the script to include last_runtime variable as time now in UTC.
  with open(__file__, 'w') as f:
    f.write('\n'.join(lines))

Putting it together

If you combine the sections above, you can write a template script to send a notification whenever there is more than one newly generated alert:

from datetime import datetime
import requests
import argparse
import sys
import json

parser = argparse.ArgumentParser(description="Check for new alerts")
parser.add_argument(
    "-k", "--key", required=True, help="Chainalysis API Key", metavar="key"
)
args = parser.parse_args()
last_runtime = (str(datetime.utcnow())).replace(" ","T")


def get_alerts():
    """Get any alerts from KYT that were generated after the last time the script was run"""

    base = "https://api.chainalysis.com"
    h = {
        "token": args.key,
        "Content-Type": "application/json",
        "accept": "application/json",
    }
    url = f"{base}/api/kyt/v1/alerts/?createdAt_gte={last_runtime}"
    response = requests.get(url, headers=h)
    if response.status_code != 200:
        print("Failed to get alerts. Try again. Exiting...")
        sys.exit()
    return response.json()


def send_slack_message():
    """Trigger a Slack notification via webhook."""

    url = ""  # keep this secret
    h = {"Content-Type": "application/json"}
    payload = {
        "blocks": [
            {"type": "header", "text": {"type": "plain_text", "text": "You have new alerts!"}},
            {
                "type": "section",
                "fields": [
                    {"type": "mrkdwn", "text": f"*Total new alerts:*\n{total_alerts}"},
                    {
                        "type": "mrkdwn",
                        "text": f"*Last runtime:*\n{last_runtime[0:19]}",
                    },
                ],
            },
            {
                "type": "section",
                "fields": [
                    {
                        "type": "mrkdwn",
                        "text": f"<https://kyt.chainalysis.com/alerts?alertStatus=Unreviewed&createdAt_gte={last_runtime}|*View new alerts*>",
                    }
                ],
            },
        ]
    }
    response = requests.post(url, headers=h, data=json.dumps(payload))
    # print(response.text) <- if your webhook is working as expected, this will return 'ok'


def update_last_runtime():
    """Modify script to set last_runtime variable to current time in UTC"""
    with open(__file__, "r") as f:
        lines = f.read().split("\n")

    # find which line last_runtime variable resides
    variable_index = [i for i, e in enumerate(lines) if "last_runtime = " in e]
    lines[
        variable_index[0]
    ] = f'last_runtime = "{(str(datetime.utcnow())).replace(" ","T")}"'

    # update script to include last_runtime variable as time now in UTC
    with open(__file__, "w") as f:
        f.write("\n".join(lines))


if __name__ == "__main__":
    alerts = get_alerts()
    total_alerts = alerts["total"]
    if total_alerts > 0:
        send_slack_message()
    update_last_runtime())

Use the script

After completing your script, follow the steps below to use it:

  1. Generate an API key here. (If you are unable to, contact support to check your permissions.).
  2. Using the sections above, build your script (we named ours alerter.py).
  3. In your CLI, navigate to the directory where your script lives.
  4. Run the following command, being sure to replace $KEY with your KYT API key:

    python3 alerter.py -k $KEY

Congratulations! If successful, you should have received a Slack notification in your workspace detailing new alerts.

Frequency

Run the script at your desired frequency with a utility of choice. For example, cron is a job scheduler that allows you to run scripts (and other things) at fixed times, dates, or intervals. You can use cron to enable workflows that run only Monday-Friday, avoiding weekend notifications, or once a month, etc. For some examples of how to write various scheduling expressions, see crontab guru.

Customizations

There are many ways to customize the type of alerts you retrieve. Depending on your volume of alerts and compliance workflows, you may want to restrict notifications to specific categories, alert severities, or user groups. The following examples below detail some of these possibilities:

Standard

The following code sends a notification whenever there is at least one new alert:

if total_alerts > 0:
  send_slack_message()

Severity

The following code only sends notifications when a target alert severity of HIGH or SEVERE is found:

if total_alerts > 0:
  for alert in alerts:
    severity_count =
    [alert for alert in alerts if alert['level'] == 'HIGH' or 'SEVERE']
    if len(severity_count)> 0 :
      send_slack_message()

You could filter the above to target only SEVERE severities.

Category

The following code only sends notifications when the target alert category of sanctions is found:

if total_alerts > 0:
  for alert in alerts:
    category_count =
    [alert for alert in alerts if alert['category'] == 'sanctions']
    if len(category_count) > 0:
      send_slack_message()

You could filter the above to target any desired category.

User group

The following code only sends notifications for a target group of userId (e.g., listed in userid_list) that would contain your list or target user ids):

The following code only sends notifications for user IDs (userId) specified in a list (e.g., userid_list):

if total_alerts > 0:
  for alert in alerts:
    target_user_count =
    [alert for alert in alerts in alert['userId'] in userid_list]
    if len(target_user_count) > 0 :
      send_slack_message()

You could specify multiple different lists of different groups of user IDs.

Resources

Glossary

Account

An Account, sometimes known as a Balance, is the method that some cryptocurrencies and tokens use to keep track of transactions in their transaction ledger in the Blockchain. The Account transaction method keeps track of the total currency in the Account in a global state. This transaction method allows for Smart Contracts to be created that keep track of different states to perform different tasks based on the state.

Examples of Account transaction based cryptocurrencies include:

Address

An Address is a cryptographic hash of a Public and Private key pair that holds value for a given cryptocurrency or token Asset. Bitcoin and other cryptocurrencies that use UTXO based transactions use what is called an "Address". Ethereum and other currencies that use Account based transactions use what is known as an "Account".

Output Address

Output addresses are the destination addresses of where cryptocurrency is sent. A correct output address depends on whether the transfer is RECEIVED or SENT.

For RECEIVED transfers, the output address is internal to your service (the address where your service received funds).

For SENT transfers, the output address is external to your service (the address where your service sent funds).

Deposit Address

Deposit addresses are addresses that you manage on behalf of your users, where they can deposit value to your service. A deposit address is always associated with exactly one user, and should never be reused for another user, but a user can have multiple deposit addresses. Deposit addresses can be registered even before they have received value.

Withdrawal Address

Withdrawal addresses are foreign Bitcoin addresses outside your service, to which the user intends to send value. Multiple users might send value to the same withdrawal addresses.

Withdrawal addresses should be registered as early as possible for best results, for instance right when the address is pasted into a withdrawal form. When registering a withdrawal address a real-time rating of the address as a recipient of value is returned. This allows you to take action on suspicious behavior immediately.

Asset

An Asset in KYT is the cryptocurrency or token being tracked (Bitcoin, Tether, etc). For a list of currently supported networks and assets, see Supported networks and assets.

Cluster

A cluster is a collection of cryptocurrency addresses that Chainalysis has identified to be controlled by one entity.

Interval notation

The use of parentheses and brackets to indicate whether endpoints are inclusive. Parentheses indicate the endpoints are not inclusive, brackets indicate the endpoints are inclusive, and a mixed set indicates one of the endpoints is inclusive. For example:

To learn even more, see Wikipedia.

KYT

KYT is the abbreviation for Know Your Transaction.

Transfer

A Transfer is the part of a transaction that transfers value from one address to another address. For some asset types like Ethereum each transaction is one transfer, but for asset types like Bitcoin a transaction can contain multiple transfers.

Received Transfer

Received transfers are the value transfers that your service receives on behalf of a user into their deposit address. Received transfers are registered and processed according to the same rules as sent transfers.

Sent Transfer

Sent transfers are the value that your service sends on behalf of a user when the user makes a withdrawal from your service. Regardless of asset type, the transfer will be part of a transaction. A transfer can be registered as soon as its transaction has been created, and even before it has been broadcast to a blockchain. Once a transfer has been registered, KYT will track it.

For some asset types, the transfer will have to “settle” before it is processed by KYT; in Bitcoin we will wait until the transaction is 5 blocks deep to make sure the risk score reflects stable data. Registered transfers that remain unsettled for too long will automatically discard the registered transfer after a timeout of several days.

User IDs

All user activity is recorded in the KYT API under a user ID. The API allows you to use any unique user ID within the following constraints:

UTXO

UTXO is the abbreviation for Unspent Transaction Output. UTXO is the method that some cryptocurrencies use to keep track of transactions in their transaction ledger in the Blockchain. UTXO is the amount of unspent cryptocurrency that can be spent in new transactions.

Examples of UXTO transaction based cryptocurrencies include:

Supported networks and assets

The following are network lists for each asset tier. For an overview of KYT’s functionality for each tier, see Asset coverage.

Mature and emerging networks

The following is a list of mature and emerging networks. We provide the Network's name, the native asset symbol, resources for metatoken symbols, and the transferReference property. Note that networks and any asset symbols are case insensitive.

Network Native Asset Symbol Supported tokens transferReference format
Algorand ALGO Metatokens on the Algorand network are supported as pre-growth assets: https://algoexplorer.io/assets {transaction_hash}:{output_address}
Arbitrum All tokens: arbiscan.io/tokens {transaction_hash}:{output_address}
Avalanche AVAX All tokens: avascan.info/marketcap {transaction_hash}:{output_address}
Binance_Smart_Chain BNB All tokens: bscscan.com/tokens {transaction_hash}:{output_address}
Bitcoin BTC {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}
Bitcoin_Cash BCH {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}
Bitcoin_Satoshi_Vision BSV {transaction_hash}:{output_address}
Celo CELO All tokens: explorer.celo.org/tokens {transaction_hash}:{output_address}
Cronos CRO All tokens: cronoscan.com/tokens {transaction_hash}:{output_address}
Dash DASH {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}
Dogecoin DOGE {transaction_hash}:{output_address}
EOS

Note: EOS had a hard fork on 2022-09-21. Transactions that occurred before this date (e.g., ≤ 2022-09-20) are supported in the mature tier, while transactions that occur after this date are supported in the pre-growth tier. For information on functionality provided at each tier, see Asset coverage.
EOS {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}
Ethereum ETH All tokens: https://etherscan.io/tokens {transaction_hash}:{output_address}
Ethereum_Classic ETC {transaction_hash}:{output_address}
Fantom FTM All tokens: ftmscan.com/tokens {transaction_hash}:{output_address}
Lightning {payment_hash}:{recipient_node_key}
Litecoin LTC {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}
Omni OMNI USDT {transaction_hash}
Optimism All tokens: optimistic.etherscan.io/tokens {transaction_hash}:{output_address}
Palm PALM All non-NFT tokens: explorer.palm.io/tokens {transaction_hash}:{output_address}
Polygon MATIC All tokens: polygonscan.com/tokens {transaction_hash}:{output_address}
Solana SOL ASH, CUBE, ELON, FIDA, GMT, NDRG, ORCA, OXY, PAI, RAY, RBN, SAFU, SBR, SRM, USDC, USDT, WSOL, ZBC For transfers of SOL: {transaction_hash}:{system_account_address}

For transfers of SPL tokens: {transaction_hash}:{token_account_address}
Tron TRX All TRC-20 tokens: tronscan.org/#/tokens/list {transaction_hash}:{output_address}
XRP XRP {transaction_hash}:{output_address}
Zcash ZEC {transaction_hash}:{output_address}
OR
{transaction_hash}:{output_index}

For metatoken symbols (ERC-20s, TRC-20s, etc.), we suggest the resources in the table above, as well as the following external lists:

Pre-growth networks

The following is a list of pre-growth networks. We provide the network's name and the transferReference format. If a network is listed here, we also support that network's metatokens. If a network isn't listed here that you would like Chainalysis to support, please contact your CSM.

Note that networks and any asset symbols are case insensitive.

Network transferReference format
ABBC {transaction_hash}:{output_address}
Aeternity {transaction_hash}:{output_address}
Algorand

Note: Algorand's native asset, ALGO, is supported as a mature asset. Metatokens on the Algorand network are supported as pre-growth assets.

{transaction_hash}:{output_address}
Aptos {transaction_hash}:{output_address}
Ardor {transaction_hash}:{output_address}
Ark {transaction_hash}:{output_address}
Arweave {transaction_hash}:{output_address}
Astar {transaction_hash}:{output_address}
Beam {transaction_hash}:{output_address}
Bitcoin_Diamond {transaction_hash}:{output_address}
Bitcoin_Gold {transaction_hash}:{output_address}
Bitshares {transaction_hash}:{output_address}
Binance_Chain {transaction_hash}:{output_address}
Blackcoin {transaction_hash}:{output_address}
Bytom {transaction_hash}:{output_address}
Cardano {transaction_hash}:{output_address}
Casper {transaction_hash}:{output_address}
Chia {transaction_hash}:{output_address}
Concordium {transaction_hash}:{output_address}
Consensus {transaction_hash}:{output_address}
Constellation {transaction_hash}:{output_address}
Coreum {transaction_hash}:{output_address}
Cortex {transaction_hash}:{output_address}
Cosmos {transaction_hash}
Counterparty {transaction_hash}:{output_address}
Decred {transaction_hash}:{output_address}
DeFiChain {transaction_hash}:{output_address}
Deso {transaction_hash}:{output_address}
Diamond {transaction_hash}:{output_address}
Diem {transaction_hash}:{output_address}
Digibyte {transaction_hash}:{output_address}
DigitalNote {transaction_hash}:{output_address}
Dreamcoin {transaction_hash}:{output_address}
Ecash {transaction_hash}:{output_address}
Edgeware {transaction_hash}:{output_address}
Einsteinium {transaction_hash}:{output_address}
Electra_Protocol {transaction_hash}:{output_address}
Elrond {transaction_hash}:{output_address}
Enumium {transaction_hash}:{output_address}
EOS

Note: EOS had a hard fork on 2022-09-21. Transactions that occurred before this date (e.g., ≤ 2022-09-20) are supported in the mature tier, while transactions that occur after this date are supported in the pre-growth tier. For information on functionality provided at each tier, see Asset coverage.

{transaction_hash}:{output_address}
Ergo {transaction_hash}:{output_address}
Ethereum_PoW {transaction_hash}:{output_address}
EUNO {transaction_hash}:{output_address}
ExclusiveCoin {transaction_hash}:{output_address}
Expanse {transaction_hash}:{output_address}
Factom {transaction_hash}:{output_address}
Feathercoin {transaction_hash}:{output_address}
Filecoin {transaction_hash}:{output_address}
Firo {transaction_hash}:{output_address}
Flare {transaction_hash}:{output_address}
Flo {transaction_hash}:{output_address}
Flow {transaction_hash}:{output_address}
Folmcoin {transaction_hash}:{output_address}
Force {transaction_hash}:{output_address}
Gochain {transaction_hash}:{output_address}
Gulden {transaction_hash}:{output_address}
Gxchain {transaction_hash}:{output_address}
Harmony {transaction_hash}:{output_address}
Haven {transaction_hash}:{output_address}
Hdac {transaction_hash}:{output_address}
HECO {transaction_hash}:{output_address}
Hedera {transaction_hash}:{output_address}
Helium {transaction_hash}:{output_address}
Hive {transaction_hash}:{output_address}
Horizen {transaction_hash}:{output_address}
HPB {transaction_hash}:{output_address}
Icon {transaction_hash}:{output_address}
Iconic {transaction_hash}:{output_address}
ImmutableX {transaction_hash}:{output_address}
Internet_Computer {transaction_hash}:{output_address}
Iost {transaction_hash}:{output_address}
Iota {transaction_hash}:{output_address}
Kadena {transaction_hash}:{output_address}
Kava {transaction_hash}:{output_address}
Klaytn {transaction_hash}:{output_address}
Komodo {transaction_hash}:{output_address}
Kusama {transaction_hash}:{output_address}
Link {transaction_hash}:{output_address}
Liquid {transaction_hash}:{output_address}
Lisk {transaction_hash}:{output_address}
Loopring {transaction_hash}:{output_address}
LTO_Network {transaction_hash}:{output_address}
Metadium {transaction_hash}:{output_address}
Milk {transaction_hash}:{output_address}
Mina {transaction_hash}:{output_address}
MobileCoin {transaction_hash}:{output_address}
Monacoin {transaction_hash}:{output_address}
Monero Deposits: {transaction_hash}:{output_index}:{receiving_address}:{payment_id}
Withdrawals: {transaction_hash}:{output_index}:{withdrawal_address}:{payment_id}
Moonbeam {transaction_hash}:{output_address}
Myriadcoin {transaction_hash}:{output_address}
Navcoin {transaction_hash}:{output_address}
Ndau {transaction_hash}:{output_address}
Near {transaction_hash}:{output_address}
Neblio {transaction_hash}:{output_address}
Nebulas {transaction_hash}:{output_address}
Nem {transaction_hash}:{output_address}
Neo {transaction_hash}:{output_address}
Nervos {transaction_hash}:{output_address}
Nexus {transaction_hash}:{output_address}
Oasis {transaction_hash}:{output_address}
Okexchain {transaction_hash}:{output_address}
Ontology {transaction_hash}:{output_address}
Palette {transaction_hash}:{output_address}
Payprotocol {transaction_hash}:{output_address}
Peercoin {transaction_hash}:{output_address}
Persistence {transaction_hash}:{output_address}
Pinkcoin {transaction_hash}:{output_address}
Pivx {transaction_hash}:{output_address}
Pocket_Network {transaction_hash}:{output_address}
Polkadot {transaction_hash}:{output_address}
Proton {transaction_hash}:{output_address}
Provenance {transaction_hash}:{output_address}
QRL {transaction_hash}:{output_address}
Qtum {transaction_hash}:{output_address}
Radix {transaction_hash}:{output_address}
Ravencoin {transaction_hash}:{output_address}
Reddcoin {transaction_hash}:{output_address}
Ronin {transaction_hash}:{output_address}
Salus {transaction_hash}:{output_address}
Secret {transaction_hash}:{output_address}
Sia {transaction_hash}:{output_address}
Signum {transaction_hash}:{output_address}
Simple_Ledger_Protocol {transaction_hash}:{output_address}
smartBCH {transaction_hash}:{output_address}
Social_Send {transaction_hash}:{output_address}
Sologenic {transaction_hash}:{output_address}
Stacks {transaction_hash}:{output_address}
Starknet {transaction_hash}:{output_address}
Stellar {transaction_hash}
Stratis {transaction_hash}:{output_address}
Supercoin {transaction_hash}:{output_address}
Symbol {transaction_hash}:{output_address}
Syscoin {transaction_hash}:{output_address}
Tachyon {transaction_hash}:{output_address}
Terra {transaction_hash}:{output_address}
Terra2 {transaction_hash}:{output_address}
Tezos {transaction_hash}:{output_address}
Theta {transaction_hash}:{output_address}
Thorchain {transaction_hash}:{output_address}
TNC {transaction_hash}:{output_address}
TON {transaction_hash}:{output_address}
Ubiq {transaction_hash}:{output_address}
V_Systems {transaction_hash}:{output_address}
VeChain {transaction_hash}:{output_address}
Verge {transaction_hash}:{output_address}
Vertcoin {transaction_hash}:{output_address}
Voucher_Coin {transaction_hash}:{output_address}
Wanchain {transaction_hash}:{output_address}
Waves {transaction_hash}
Wax {transaction_hash}:{output_address}
Waykichain {transaction_hash}:{output_address}
Woo_Network {transaction_hash}:{output_address}
XinFin {transaction_hash}:{output_address}
Zilliqa {transaction_hash}:{output_address}

For asset and metatoken symbols, we suggest the following resources: