curl --request GET \
--url https://scienter.xyz/api/v1/wallet/{address}/cex \
--header 'Authorization: Bearer <token>'import requests
url = "https://scienter.xyz/api/v1/wallet/{address}/cex"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://scienter.xyz/api/v1/wallet/{address}/cex', 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://scienter.xyz/api/v1/wallet/{address}/cex",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://scienter.xyz/api/v1/wallet/{address}/cex"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://scienter.xyz/api/v1/wallet/{address}/cex")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://scienter.xyz/api/v1/wallet/{address}/cex")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"state": "ok",
"subject": "<string>",
"sources": [
{
"name": "scienter:intelligence",
"url": "<string>",
"as_of": 123
}
],
"as_of": 123,
"data": {
"address": "<string>",
"checksum": "<string>",
"direct": {
"address": "<string>",
"label": "Binance 14",
"entity": "Binance",
"role": "hot_wallet",
"confidence": "<string>",
"clusterable": true
},
"linked": [
{
"address": "<string>",
"label": "Binance 14",
"entity": "Binance",
"role": "hot_wallet",
"confidence": "<string>",
"clusterable": true
}
],
"activity": {
"checked": true,
"exchanges": [
{}
],
"inferred_deposit_addresses": [
{}
],
"truncated": true,
"reason": "<string>",
"provenance": "warehouse"
},
"table_rows": 123,
"caveat": "<string>"
},
"reason": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"reason": "no_credential",
"entitlements_durable": true
}{
"error": "<string>"
}Exchange attribution and activity
Three things, kept apart.
direct: the address itself is a labelled exchange wallet (from a committed table of block-explorer labels, each activity-checked on chain). linked: labelled addresses in the same engine cluster. activity: this address’s own deposits to labelled exchange wallets and any per-user deposit addresses inferred from its behaviour, read from real chain history.
An exchange hot or cold wallet is paid by millions of unrelated people, so clusterable is false for those rows: two wallets that both funded Binance 14 are two customers of Binance and nothing more. Only inferred per-user deposit addresses link wallets.
A miss is insufficient_evidence, not ok with an empty list: “not in the table” means “no label held”, not “not an exchange”.
curl --request GET \
--url https://scienter.xyz/api/v1/wallet/{address}/cex \
--header 'Authorization: Bearer <token>'import requests
url = "https://scienter.xyz/api/v1/wallet/{address}/cex"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://scienter.xyz/api/v1/wallet/{address}/cex', 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://scienter.xyz/api/v1/wallet/{address}/cex",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://scienter.xyz/api/v1/wallet/{address}/cex"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://scienter.xyz/api/v1/wallet/{address}/cex")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://scienter.xyz/api/v1/wallet/{address}/cex")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"state": "ok",
"subject": "<string>",
"sources": [
{
"name": "scienter:intelligence",
"url": "<string>",
"as_of": 123
}
],
"as_of": 123,
"data": {
"address": "<string>",
"checksum": "<string>",
"direct": {
"address": "<string>",
"label": "Binance 14",
"entity": "Binance",
"role": "hot_wallet",
"confidence": "<string>",
"clusterable": true
},
"linked": [
{
"address": "<string>",
"label": "Binance 14",
"entity": "Binance",
"role": "hot_wallet",
"confidence": "<string>",
"clusterable": true
}
],
"activity": {
"checked": true,
"exchanges": [
{}
],
"inferred_deposit_addresses": [
{}
],
"truncated": true,
"reason": "<string>",
"provenance": "warehouse"
},
"table_rows": 123,
"caveat": "<string>"
},
"reason": "<string>"
}{
"error": "<string>"
}{
"error": "<string>",
"reason": "no_credential",
"entitlements_durable": true
}{
"error": "<string>"
}Authorizations
An sc_ key from https://scienter.xyz/settings/api, sent as Authorization: Bearer sc_.... The same key is accepted in the x-scienter-membership header. Prefer the header over any query form: a credential in a URL reaches access logs, proxies and browser history.
Path Parameters
An EVM (0x, 40 hex) or Solana (base58) address. EVM addresses are lower-cased on the way in; base58 keeps its case.
Response
ok when a direct label, a linked label or activity rows exist; otherwise insufficient_evidence naming what was checked.
The four-state envelope. state: ok carries data as described; the three absences carry data: null and reason. See the Absent schema.