{"openapi":"3.0.3","info":{"title":"Chainy API","version":"1.0.0","description":"Chainy is an AML/KYT API for crypto compliance. Screen wallet addresses and incoming deposits, get a risk score and an allow / review / reject decision, and read your account balance — all over a simple REST API.\n\n## Authentication\nAll endpoints require your API key in the `X-API-Key` header. Create and manage keys in the Chainy dashboard (API Keys).\n\n## Sandbox\nA sandbox API key returns realistic mock responses (with `\"sandbox\": true`) and is never billed — use it to build and test your integration before going live.\n\n## Pricing\nWallet checks are billed per request from your prepaid balance (new accounts start with a few free checks). See `GET /api/external/balance`.\n\n## Idempotency\nPass an `Idempotency-Key` header on `POST /api/external/checks/create` to safely retry a request without creating or charging twice — the original result is returned for repeats.\n\n## Errors\nErrors return `{ \"status\": false, \"error\": \"<message>\" }` with an appropriate HTTP status (400 invalid input, 401 missing/invalid key, 402 insufficient balance, 404 not found, 409 idempotency conflict, 429 rate limited, 500 server error).\n"},"servers":[{"url":"https://app.chainysoft.io","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Wallet checks","description":"Screen a wallet address for AML risk."},{"name":"Deposit checks","description":"Screen an incoming on-chain deposit (transaction) for AML risk."},{"name":"Account","description":"Account balance and pricing."},{"name":"Risk model","description":"The active risk model applied to your checks."},{"name":"Utilities","description":"Supporting data endpoints."},{"name":"Webhooks","description":"Instead of polling, register a callback URL and we POST each result to you.\n\n**Registering.** Webhooks are managed from your dashboard (API Keys → Webhooks),\nnot through this API. You choose which events to receive and get a signing\nsecret, shown once.\n\n**The request we send.** `POST` to your URL with `Content-Type: application/json`\nand this body:\n\n```json\n{ \"event\": \"check.completed\", \"eventId\": \"check.completed:1234:COMPLETED\", \"data\": { } }\n```\n\n`data` is exactly the object this API would have returned for that subject — the\nsame white-labelled shape, never raw provider output.\n\nHeaders on every delivery:\n\n| Header | Meaning |\n|---|---|\n| `X-Chainy-Signature` | `t=<unix-seconds>,v1=<hex>` — see below |\n| `X-Chainy-Event-Id` | Stable id for this event. **Use it to deduplicate.** |\n| `X-Chainy-Event-Type` | `check.completed` or `deposit.decision` |\n| `X-Chainy-Delivery-Attempt` | 1 for the first try, then 2, 3, … |\n\n**Verifying the signature.** Take `t` and `v1` from `X-Chainy-Signature`, compute\n`HMAC-SHA256(secret, \"<t>.<raw request body>\")` and compare it to `v1` in constant\ntime. Sign the **raw bytes** you received — re-serialising the parsed JSON will not\nmatch. Reject a delivery whose `t` is far from your clock to blunt replays.\n\n**Delivery semantics.** At-least-once: a retry re-signs with a fresh timestamp, so\ndedupe on `X-Chainy-Event-Id`, not on the signature. Reply `2xx` to acknowledge;\nanything else is retried with exponential backoff (~4s, 8s, 16s, … capped at one\nhour) up to 8 attempts, after which the delivery is dropped. Redirects are not\nfollowed — respond directly on the registered URL.\n"}],"paths":{"/api/external/checks/create":{"post":{"tags":["Wallet checks"],"summary":"Create a wallet check","description":"Screen a wallet address. Billed one check from your balance (or a free check, if any remain).","operationId":"createCheck","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address","network"],"properties":{"address":{"type":"string","example":"0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae"},"network":{"type":"string","description":"Blockchain network.","enum":["eth","bsc","trx","sol","btc","ltc"],"example":"eth"}}}}}},"responses":{"200":{"description":"Check created (and, depending on network, scored).","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WalletCheck"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"callbacks":{"checkCompleted":{"$ref":"#/components/callbacks/CheckCompleted"}}}},"/api/external/checks/{uuid}":{"get":{"tags":["Wallet checks"],"summary":"Get a wallet check","operationId":"getCheck","parameters":[{"$ref":"#/components/parameters/Uuid"}],"responses":{"200":{"description":"The check.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WalletCheck"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/checks/list":{"get":{"tags":["Wallet checks"],"summary":"List your wallet checks","operationId":"listChecks","responses":{"200":{"description":"Your recent wallet checks.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WalletCheck"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/deposit-checks":{"post":{"tags":["Deposit checks"],"summary":"Create a deposit check","description":"Screen an incoming on-chain deposit (by transaction hash and receiving address).","operationId":"createDepositCheck","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["network","tx_hash","deposit_address"],"properties":{"network":{"type":"string","enum":["ETH","BSC","TRX","SOL"],"example":"TRX"},"tx_hash":{"type":"string","example":"0xabc123…"},"deposit_address":{"type":"string","example":"TXYZ…"},"token_id":{"type":"string","nullable":true,"description":"Token contract for token transfers; omit for native."},"amount":{"type":"string","nullable":true,"example":"1000.00"}}}}}},"responses":{"200":{"description":"Deposit check created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DepositCheck"},"already_exists":{"type":"boolean"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}},"callbacks":{"depositDecision":{"$ref":"#/components/callbacks/DepositDecision"}}},"get":{"tags":["Deposit checks"],"summary":"List your deposit checks","operationId":"listDepositChecks","responses":{"200":{"description":"Your recent deposit checks.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DepositCheck"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/deposit-checks/{uuid}":{"get":{"tags":["Deposit checks"],"summary":"Get a deposit check","operationId":"getDepositCheck","parameters":[{"$ref":"#/components/parameters/Uuid"}],"responses":{"200":{"description":"The deposit check.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DepositCheck"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/balance":{"get":{"tags":["Account"],"summary":"Get account balance","operationId":"getBalance","responses":{"200":{"description":"Balance and pricing.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Balance"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/risk-models/current":{"get":{"tags":["Risk model"],"summary":"Get the active risk model","description":"The risk model (thresholds and version) currently applied to your checks.","operationId":"getCurrentRiskModel","responses":{"200":{"description":"The active risk model.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RiskModel"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/risk-models/simulate":{"post":{"tags":["Risk model"],"summary":"Simulate scoring with the active risk model","description":"Run the active risk model against a supplied payload to preview the score and decision. Not billed and performs no on-chain lookup.","operationId":"simulateRiskModel","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["checkType"],"properties":{"checkType":{"type":"string","enum":["wallet","deposit"]},"payload":{"type":"object","description":"Inputs to score (e.g. provider risk score, risk signals, exposure).","properties":{"riskScore":{"type":"number"},"risks":{"type":"array","items":{"type":"object"}}}}}}}}},"responses":{"200":{"description":"Simulated result.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SimulationResult"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api/external/usdt-transfers":{"post":{"tags":["Utilities"],"summary":"List USDT transfers for an address","description":"Recent USDT (stablecoin) transfers for an address, with sent / received / net totals.","operationId":"getUsdtTransfers","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address","network"],"properties":{"address":{"type":"string"},"network":{"type":"string","enum":["eth","bsc","trx","sol"],"example":"trx"},"limit":{"type":"integer","default":50,"example":50}}}}}},"responses":{"200":{"description":"USDT transfers and totals.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UsdtTransfers"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"}},"parameters":{"Uuid":{"name":"uuid","in":"path","required":true,"schema":{"type":"string"},"description":"The check's unique id."},"WebhookSignature":{"name":"X-Chainy-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1769472000,v1=8f1c1c0a…","description":"`t=<unix-seconds>,v1=<hex>`. v1 is HMAC-SHA256(secret, \"<t>.<raw body>\")."},"WebhookEventId":{"name":"X-Chainy-Event-Id","in":"header","required":true,"schema":{"type":"string"},"description":"Stable per event and repeated on retries — deduplicate on this."},"WebhookEventType":{"name":"X-Chainy-Event-Type","in":"header","required":true,"schema":{"type":"string","enum":["check.completed","deposit.decision"]}},"WebhookDeliveryAttempt":{"name":"X-Chainy-Delivery-Attempt","in":"header","required":true,"schema":{"type":"integer","minimum":1},"description":"1 on the first attempt, incremented on each retry."},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Provide a unique key to make a create request safely retryable."}},"responses":{"BadRequest":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PaymentRequired":{"description":"Insufficient balance.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"A request with this Idempotency-Key is already in progress.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"callbacks":{"CheckCompleted":{"https://your-server.example.com/chainy-webhook":{"post":{"summary":"check.completed","description":"Sent once a wallet check reaches a final state. Not sent for failed or refunded checks.","operationId":"onCheckCompleted","parameters":[{"$ref":"#/components/parameters/WebhookSignature"},{"$ref":"#/components/parameters/WebhookEventId"},{"$ref":"#/components/parameters/WebhookEventType"},{"$ref":"#/components/parameters/WebhookDeliveryAttempt"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","properties":{"event":{"type":"string","enum":["check.completed"]},"data":{"$ref":"#/components/schemas/WalletCheck"}}}]}}}},"responses":{"200":{"description":"Acknowledged. Any non-2xx (or no response) is retried."}}}}},"DepositDecision":{"https://your-server.example.com/chainy-webhook":{"post":{"summary":"deposit.decision","description":"Sent when a deposit check reaches a terminal decision (ALLOW, HOLD or REJECT).","operationId":"onDepositDecision","parameters":[{"$ref":"#/components/parameters/WebhookSignature"},{"$ref":"#/components/parameters/WebhookEventId"},{"$ref":"#/components/parameters/WebhookEventType"},{"$ref":"#/components/parameters/WebhookDeliveryAttempt"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEnvelope"},{"type":"object","properties":{"event":{"type":"string","enum":["deposit.decision"]},"data":{"$ref":"#/components/schemas/DepositCheck"}}}]}}}},"responses":{"200":{"description":"Acknowledged. Any non-2xx (or no response) is retried."}}}}}},"schemas":{"WebhookEnvelope":{"type":"object","description":"Every webhook body has this shape; `data` is the subject in its usual API form.","required":["event","eventId","data"],"properties":{"event":{"type":"string","description":"Event type. Matches the X-Chainy-Event-Type header.","enum":["check.completed","deposit.decision"]},"eventId":{"type":"string","description":"Stable identifier for this event, repeated on every retry. Deduplicate on\nthis value — delivery is at-least-once.\n","example":"check.completed:1234:COMPLETED"},"data":{"type":"object","description":"The subject, in the same shape this API returns it."}}},"Envelope":{"type":"object","properties":{"status":{"type":"boolean","example":true}},"required":["status"]},"Error":{"type":"object","properties":{"status":{"type":"boolean","example":false},"error":{"type":"string","example":"address and network are required"}},"required":["status","error"]},"Decision":{"type":"string","description":"The compliance decision for the subject.","enum":["ALLOW","HOLD","REJECT","PENDING"]},"RiskLevel":{"type":"string","enum":["none","low","medium","high"]},"WalletCheck":{"type":"object","description":"A wallet screening result.","properties":{"uuid":{"type":"string"},"status":{"type":"string","description":"Processing status, e.g. NEW, COMPLETED."},"network":{"type":"string","example":"eth"},"address":{"type":"string"},"decision":{"$ref":"#/components/schemas/Decision"},"risk_level":{"$ref":"#/components/schemas/RiskLevel"},"risk_score":{"type":"number","description":"0–100 risk score.","example":0},"risks":{"type":"array","description":"Risk signals contributing to the score.","items":{"type":"object","properties":{"category":{"type":"string"},"level":{"$ref":"#/components/schemas/RiskLevel"}}}},"createdAt":{"type":"string","format":"date-time"}}},"DepositCheck":{"type":"object","description":"An incoming-deposit screening result.","properties":{"uuid":{"type":"string"},"network":{"type":"string","example":"TRX"},"tx_hash":{"type":"string"},"deposit_address":{"type":"string"},"token_id":{"type":"string","nullable":true},"kyt_status":{"type":"string","description":"Processing status, e.g. NEW, REGISTERED, COMPLETED."},"decision":{"$ref":"#/components/schemas/Decision"},"risk_score":{"type":"number","nullable":true,"example":0},"createdAt":{"type":"string","format":"date-time"}}},"Balance":{"type":"object","properties":{"balance":{"type":"number","example":25},"currency":{"type":"string","example":"USD"},"pricePerCheck":{"type":"number","example":1},"availableChecks":{"type":"integer","example":25}}},"RiskModel":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"integer"},"name":{"type":"string"},"thresholds":{"type":"object","properties":{"holdMin":{"type":"number","example":50},"rejectMin":{"type":"number","example":75}}}}},"SimulationResult":{"type":"object","description":"Result of running the active risk model against a supplied payload.","properties":{"model":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"version":{"type":"integer"}}},"riskEngine":{"type":"object","properties":{"score":{"type":"number","example":0},"decision":{"$ref":"#/components/schemas/Decision"}}}}},"UsdtTransfer":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"valueUsdt":{"type":"number"},"hash":{"type":"string"}}},"UsdtTransfers":{"type":"object","properties":{"address":{"type":"string"},"network":{"type":"string"},"contractAddress":{"type":"string","description":"USDT token contract on the network."},"transfers":{"type":"array","items":{"$ref":"#/components/schemas/UsdtTransfer"}},"stats":{"type":"object","properties":{"total":{"type":"integer"},"totalSent":{"type":"string","example":"0.00"},"totalReceived":{"type":"string","example":"0.00"},"netBalance":{"type":"string","example":"0.00"}}}}}}}}