curl --request GET \
--url https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token \
--header 'X-Api-Key: <api-key>'import requests
url = "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token"
headers = {"X-Api-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<api-key>'}};
fetch('https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token")
.header("X-Api-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"breakdown": [
{
"id": 1054,
"key": "arbitrum",
"name": "Arbitrum",
"unlockValue": "48200000"
}
],
"date": "2026-08-01T00:00:00.000Z",
"totalUnlockValue": "1250000000"
}
],
"status": {
"timestamp": 1780000000000,
"usedCredits": 1
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"status": 400
}
}{
"error": {
"code": "API_KEY_MISSING",
"message": "API key is missing",
"status": 401
}
}{
"error": {
"code": "NO_ACTIVE_SUBSCRIPTION",
"message": "No active subscription found",
"status": 403
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"status": 429
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error",
"status": 500
}
}Token Unlock Dynamics by Token
Returns market-wide token unlock dynamics as a time series (history and forecast), split by individual token.
Available from: Pro
Cost: 1 credit per request
curl --request GET \
--url https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token \
--header 'X-Api-Key: <api-key>'import requests
url = "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token"
headers = {"X-Api-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-Api-Key': '<api-key>'}};
fetch('https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Api-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token")
.header("X-Api-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cryptorank.io/v3/token-unlocks/dynamics/by-token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Api-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"breakdown": [
{
"id": 1054,
"key": "arbitrum",
"name": "Arbitrum",
"unlockValue": "48200000"
}
],
"date": "2026-08-01T00:00:00.000Z",
"totalUnlockValue": "1250000000"
}
],
"status": {
"timestamp": 1780000000000,
"usedCredits": 1
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"status": 400
}
}{
"error": {
"code": "API_KEY_MISSING",
"message": "API key is missing",
"status": 401
}
}{
"error": {
"code": "NO_ACTIVE_SUBSCRIPTION",
"message": "No active subscription found",
"status": 403
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"status": 429
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error",
"status": 500
}
}topN tokens are ranked by unlock value over the whole window, so one set of tokens carries the whole series — though a token with no unlocks in a given bucket is absent from that point. Everything outside the top-N is summed into a single Others entry, always placed last, so the breakdown always adds up to totalUnlockValue.from/to the window is skewed towards upcoming unlocks, sized to the selected interval. Both bounds snap to interval bucket starts. One response carries at most 366 daily, 520 weekly or 1000 monthly points — wider ranges have to be requested in slices.Authorizations
Query Parameters
Bucket size for aggregation: 1d — daily, 1w — weekly (ISO week, starts Monday), 1m — monthly.
1d, 1w, 1m Lower bound on the unlock date, snapped down to the start of its interval bucket. Accepts ISO 8601 string or Unix timestamp (sec/ms). Defaults to the history side of the window for the selected interval.
"2026-01-01T00:00:00.000Z"
Upper bound on the unlock date, snapped down to the start of its interval bucket, which is then included in full. May be in the future — upcoming unlocks are part of the series. Accepts ISO 8601 string or Unix timestamp (sec/ms). Defaults to the forecast side of the window for the selected interval.
"2027-01-01T00:00:00.000Z"
Fiat ISO code for monetary fields (e.g. USD, EUR, RUB, AED). See: GET /v3/fiat/list.
How many tokens to list separately. Ranked by unlock value over the whole window, so one set of tokens carries the whole series; everything outside it is summed into Others. Up to 50.