Introduction
Welcome to the Crytom API (v1). You can use our API to access Crytom's comprehensive borderless crypto payment infrastructure. The API is designed for external merchants, partners, and developers integrating Crytom into their own platforms.
Our API is built on RESTful principles, returns standard JSON responses, and uses HTTP status codes to indicate success or failure.
Base URLs
All API requests must be made over HTTPS. Calls made over plain HTTP will fail.
- Live Environment:
https://www.api.crytom.com/v1 - Sandbox Environment:
https://www.sandbox-api.crytom.com/v1
# Live API Base URL
https://www.api.crytom.com/v1
# Sandbox API Base URL
https://www.sandbox-api.crytom.com/v1
Supported Assets & Networks
Crytom supports a wide range of cryptocurrencies and blockchain networks. Below is a list of the currently supported assets. Use these symbols and network names in your API requests.
| Asset Name | Currency | Network | Token Standard |
|---|---|---|---|
| Bitcoin | BTC |
Bitcoin | Native |
| Ethereum | ETH |
Ethereum | Native |
| Chainlink | LINK |
Ethereum | ERC20 |
| BNB / Binance Coin | BNB |
BNB Chain | Native (BEP20) |
| Tether (USDT) | USDT |
BSC | BEP20 |
| USD Coin (USDC) | USDC |
BNB Chain | BEP20 |
| Solana | SOL |
Solana | Native |
| Stacks | STX |
Stacks | Native |
| Tron | TRX |
Tron | Native |
| Tether (USDT) | USDT |
Tron | TRC20 |
| USD Coin (USDC) | USDC |
Tron | TRC20 |
| Polygon (MATIC) | MATIC |
Polygon | Native |
| Tether (USDT) | USDT |
Polygon | ERC20 |
| USD Coin (USDC) | USDC |
Polygon | ERC20 |
| Polkadot | DOT |
Polkadot | Native |
| Base | BASE |
Base | Native |
{
"networks": ["Bitcoin", "Ethereum", "BNB Chain", "BSC", "Solana", "Stacks", "Tron", "Polygon", "Polkadot", "Base"],
"currencies": ["BTC", "ETH", "LINK", "BNB", "USDT", "USDC", "SOL", "STX", "TRX", "MATIC", "DOT", "BASE"]
}
Authentication
Crytom authenticates your API requests using API keys. If you do not include your key when making an
API request, or use an incorrect or outdated one, Crytom returns a 401 Unauthorized
response.
Authentication is performed via the Authorization: Bearer header.
Environments
Your API keys determine your environment. There is no need for manual environment headers for v1.
- Keys starting with
sk_live_route to production funds. - Keys starting with
sk_test_route to your sandbox test environment.
curl https://www.api.crytom.com/v1/balance \
-H "Authorization: Bearer sk_live_YOUR_SECRET_KEY" \
-H "X-Crytom-Timestamp: 1718299100000" \
-H "X-Crytom-Signature: YOUR_HMAC_SIGNATURE"
const axios = require('axios');
axios.get('https://www.api.crytom.com/v1/balance', {
headers: {
'Authorization': 'Bearer sk_live_YOUR_SECRET_KEY',
'X-Crytom-Timestamp': '1718299100000',
'X-Crytom-Signature': 'YOUR_HMAC_SIGNATURE'
}
}).then(res => console.log(res.data));
<?php
$ch = curl_init('https://www.api.crytom.com/v1/balance');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer sk_live_YOUR_SECRET_KEY',
'X-Crytom-Timestamp: 1718299100000',
'X-Crytom-Signature: YOUR_HMAC_SIGNATURE'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.api.crytom.com/v1/balance"))
.header("Authorization", "Bearer sk_live_YOUR_SECRET_KEY")
.header("X-Crytom-Timestamp", "1718299100000")
.header("X-Crytom-Signature", "YOUR_HMAC_SIGNATURE")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
import requests
headers = {
'Authorization': 'Bearer sk_live_YOUR_SECRET_KEY',
'X-Crytom-Timestamp': '1718299100000',
'X-Crytom-Signature': 'YOUR_HMAC_SIGNATURE'
}
response = requests.get('https://www.api.crytom.com/v1/balance', headers=headers)
print(response.json())
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, HeaderValue::from_static("Bearer sk_live_YOUR_SECRET_KEY"));
headers.insert("X-Crytom-Timestamp", HeaderValue::from_static("1718299100000"));
headers.insert("X-Crytom-Signature", HeaderValue::from_static("YOUR_HMAC_SIGNATURE"));
let client = reqwest::Client::new();
let res = client.get("https://www.api.crytom.com/v1/balance")
.headers(headers)
.send()
.await?
.json::<serde_json::Value>()
.await?;
println!("{:#?}", res);
Ok(())
}
Security (HMAC Signing)
To prevent replay attacks and mathematically prove that requests come from you, all POST and PUT requests via the API require an HMAC SHA256 signature.
You must provide two custom headers:
X-Crytom-Timestamp: The current Unix timestamp in milliseconds. Replays older than 5 minutes will be rejected.X-Crytom-Signature: Your generated HMAC signature.
Signature Generation
The signature is a SHA256 HMAC hash of the following concatenated string:
timestamp + HTTP_METHOD + request_path + request_body
Use your Secret Key as the HMAC key.
const crypto = require('crypto');
function generateSignature(secretKey, method, path, body) {
const timestamp = Date.now().toString();
const payloadStr = timestamp + method.toUpperCase() + path + JSON.stringify(body);
const signature = crypto.createHmac('sha256', secretKey)
.update(payloadStr)
.digest('hex');
return {
'X-Crytom-Timestamp': timestamp,
'X-Crytom-Signature': signature
};
}
<?php
function generateSignature($secretKey, $method, $path, $body) {
$timestamp = (string)(time() * 1000);
$payloadStr = $timestamp . strtoupper($method) . $path . json_encode($body);
$signature = hash_hmac('sha256', $payloadStr, $secretKey);
return [
'X-Crytom-Timestamp' => $timestamp,
'X-Crytom-Signature' => $signature
];
}
?>
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public static String generateSignature(String secretKey, String method, String path, String body) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis());
String payload = timestamp + method.toUpperCase() + path + body;
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
hmac.init(secretKeySpec);
byte[] hash = hmac.doFinal(payload.getBytes());
// Convert hash to hex string
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
import hmac
import hashlib
import time
import json
def generate_signature(secret_key, method, path, body):
timestamp = str(int(time.time() * 1000))
payload = timestamp + method.upper() + path + json.dumps(body)
signature = hmac.new(
secret_key.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return {
'X-Crytom-Timestamp': timestamp,
'X-Crytom-Signature': signature
}
use hmac::{Hmac, Mac};
use sha2::Sha256;
use std::time::{SystemTime, UNIX_EPOCH};
type HmacSha256 = Hmac<Sha256>;
fn generate_signature(secret_key: &str, method: &str, path: &str, body: &str) -> (String, String) {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis()
.to_string();
let payload = format!("{}{}{}{}", timestamp, method.to_uppercase(), path, body);
let mut mac = HmacSha256::new_from_slice(secret_key.as_bytes())
.expect("HMAC can take key of any size");
mac.update(payload.as_bytes());
let result = mac.finalize();
let signature = hex::encode(result.into_bytes());
(timestamp, signature)
}
Understanding X-Crytom-Timestamp
The X-Crytom-Timestamp header is a critical security component of the Crytom V1 API. It
ensures that every request is fresh and protected against replay attacks.
1. What X-Crytom-Timestamp Is
X-Crytom-Timestamp is a required HTTP header that you, the developer, must include in
every request to the Crytom API.
- It is NOT provided by Crytom: You must generate it on your own server.
- It is a Unix time value: Specifically, it represents the number of milliseconds that have elapsed since the Unix Epoch (January 1, 1970, 00:00:00 UTC).
- Generate on-the-fly: It must be generated at the exact moment your server prepares to send the request.
2. Why It Is Required
Security is our priority. This header is used for Replay Protection. Without it, an attacker could intercept a valid signed request and send it again (replay it) to perform unauthorized actions.
By requiring a timestamp, Crytom ensures:
- Request Freshness: We reject any request older than 5 minutes.
- One-Time Use: Outdated or reused timestamps are automatically blocked by our security layer.
3. How to Generate It
You must generate the timestamp programmatically within your code.
Critical Rules:
- Milliseconds, not Seconds: Ensure your platform returns the 13-digit
millisecond value (e.g.,
1708712345678), not the 10-digit second value. - New for Every Request: Never reuse a timestamp. Every individual API call requires a fresh value.
What is Unix Time in Milliseconds?
Unix time in milliseconds is obtained by taking the current system time and converting it into the total number of milliseconds that have passed since January 1, 1970 (UTC).
Code Examples:
- Node.js:
Date.now() - PHP:
round(microtime(true) * 1000) - Python:
int(time.time() * 1000)
4. Example Value
A typical valid timestamp looks like this:
1708712345678
Usage:
- Send this exact value as the
X-Crytom-Timestampheader in your HTTP request. - Important: You must use this same exact value as part of the
payload when generating your
X-Crytom-Signature. If the values differ, the request will be rejected.
5. How Crytom Validates Your Request
When your request reaches our servers, we perform the following steps:
- Read the Header: We extract the
X-Crytom-Timestampfrom your request. - Drift Check: We compare your timestamp with the current time on the Crytom server.
- The 5-Minute Rule: If the difference between your time and our time is
greater than 5 minutes (300,000 milliseconds), the request is rejected
immediately with a
401 Unauthorizederror. - Signature Verification: If the timestamp is valid and recent, we proceed to verify the HMAC signature to ensure the request body hasn't been tampered with.
6. Common Mistakes to Avoid
Avoid these common pitfalls to ensure your integration works smoothly:
- [!] Using Seconds: Using a 10-digit timestamp (seconds) will cause the request to fail our drift check.
- [!] Reusing Timestamps: Reusing a timestamp from a previous request will result in a rejection.
- [!] Frontend Generation: Never generate the timestamp (or signature) in a browser or mobile app. This exposes your Secret Key. Always generate them on your secure backend server.
- [!] Mismatched Values: Using one timestamp for the header and a slightly different one (even by 1ms) for the signature payload will cause a signature mismatch.
7. Summary for Documentation
X-Crytom-Timestamp is a required request header generated by the client using the current Unix time in milliseconds. Crytom validates this timestamp to ensure the request is recent (within 5 minutes) and has not been replayed. Every signed request must include a fresh, unique timestamp generated programmatically on your server.
// Node.js
const timestamp = Date.now();
// PHP
$timestamp = round(microtime(true) * 1000);
// Python
import time
timestamp = int(time.time() * 1000)
IP Whitelisting & Security
To provide an extra layer of security for your automated systems, Crytom supports IP
Whitelisting for all third-party API (v1) integrations. When enabled, only
requests originating from your specified server IP addresses will be processed, even if the request
includes a valid API key and HMAC signature.
[Process] How it Works
IP Whitelisting acts as a "Gatekeeper" that verifies the source of the network traffic before any business logic is executed.
- Detection: Every time a request hits our
/v1endpoints, Crytom detects the origin IP address (supporting proxies and load balancers). - Verification: If the organization owner has enabled IP Whitelisting, the backend checks if the incoming IP exists in the allowed list.
- Action:
- If the IP is whitelisted, the request proceeds to HMAC validation.
- If the IP is not whitelisted, the request is immediately rejected with
a
403 Forbiddenerror.
[Config] Managing Whitelisted IPs
Whitelisting is managed centrally from your account settings to ensure consistency across all your API keys.
Where to manage:
- Log in to the Crytom Dashboard.
- Navigate to Settings > Developer Settings (or the Security/API section).
- Find the IP Whitelist section.
Actions:
- Toggle Whitelist: You can turn the enforcement ON or OFF. When OFF, any IP can call the API (provided they have a valid signature).
- Add IP: Enter the IPv4 address of your server (e.g.,
192.168.1.1). - Remove IP: Delete existing IPs to immediately revoke their access.
Best Practices
- Always Enable in Production: We strongly recommend enabling IP whitelists for
your "Live" environment to prevent unauthorized access if your
SECRET_KEYis ever leaked. - Minimalist Approach: Only whitelist the specific servers that need to make API calls.
- Test in Sandbox: Enable whitelisting with your development machine's IP first to ensure your integration handles the security handshake correctly.
{
"error": "Unauthorized IP",
"message": "The IP address 203.0.113.42 is not whitelisted in your account settings."
}
curl ifconfig.me
Metadata Registry
Access the platform's flat registry of supported assets and network combinations.
Returns a complete list of all Currency + Network combinations valid for derivation and payouts.
{
"status": "success",
"data": [
{ "currency": "USDT", "network": "BSC", "precision": 18 },
{ "currency": "BTC", "network": "Bitcoin", "precision": 8 }
]
}
Error Handling & Rollbacks
Crytom uses standard HTTP response codes to indicate the success or failure of an API request.
400 Bad Request: Invalid parameters or broadcast failure (includes specific rollback confirmation).401 Unauthorized: Authentication failed (invalid API key or signature).403 Forbidden: IP not whitelisted.404 Not Found: Resource does not exist.429 Too Many Requests: Rate limit exceeded.500 Internal Server Error: Server-side exception.
Auto-Rollbacks: If a blockchain broadcast fails, the system automatically rolls back any pending balance debits and includes a rollback_confirmed: true flag in the error response.
{
"error": "broadcast_failure",
"message": "Node rejected transaction. Balance rolled back.",
"rollback_confirmed": true
}
Developer Checkout API (Hosted)
The Hosted Checkout API is the simplest way to accept cryptocurrency on any website. When you call this API, Crytom handles everything: currency conversion, virtual wallet generation, real-time blockchain monitoring, and an optimized payment interface.
[Rocket] The Checkout Lifecycle
- Step 1: Your server calls
POST /v1/checkout/sessionsto create a new session. - Step 2: Crytom returns a unique
checkout_url. - Step 3: Redirect your customer to this URL.
- Step 4: Your customer pays using their preferred cryptocurrency.
- Step 5: Crytom redirects the customer back to your site and sends you a webhook.
[Shield] Authentication
Every request to the /v1 API requires a strict HMAC-SHA256 signature in the headers
based on your SECRET_KEY.
Required Headers:
Authorization: Bearer <SECRET_KEY>X-Crytom-Timestamp: <Unix Timestamp in ms>X-Crytom-Signature: <HMAC-SHA256 Result>
Signature Payload:
Timestamp + HTTP_METHOD + req.path + JSON.stringify(req.body)
// Constructing the payload for signature
const payload = timestamp + 'POST' + '/v1/checkout/sessions' + JSON.stringify(body);
Customer & Metadata Tracking
Associate your internal user IDs and custom business data with every resource. customer_id and metadata are strictly preserved across the entire lifecycle (Invoices → Payments → Conversions → Payouts) and are included in all Webhook payloads.
[Shield] Technical Implementation
- Schema Support:
customer_idandmetadataare persisted throughout the entire lifecycle. - Persistence: Data passed during session creation is automatically attached to the final Transaction record.
- Webhooks: All custom identifiers are included in outgoing webhook payloads.
[Link] Why Use This?
By passing a customer_id, you ensure that once a payment is confirmed, your dashboard (and backend via Webhooks) can immediately identify which user paid for which order without manual lookup.
{
"amount": 100.00,
"currency": "USD",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500",
"plan_type": "annual"
}
}
Create a Checkout Session
Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
amount |
Number | Yes | The amount your customer needs to pay. |
currency |
String | Yes | The fiat currency code (e.g., USD, ). |
product_name |
String | Yes | The name of the product or service. |
success_url |
String | No | Redirect URL after a successful payment. |
cancel_url |
String | No | Redirect URL if the customer cancels. |
accepted_assets |
Array | No | Currencies allowed (e.g., ["BTC", "USDT_BSC"]). |
customer_id |
String | No | Your internal user or customer identifier. |
metadata |
Object | No | Key-value pairs for custom data (e.g., order IDs). |
{
"amount": 250.50,
"currency": "USD",
"product_name": "Premium Plan - Annual",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500",
"plan_type": "annual"
},
"success_url": "https://myshop.com/payment/success",
"accepted_assets": ["BTC", "USDT_BSC"]
}
{
"status": "success",
"data": {
"id": "chk_123456",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500",
"plan_type": "annual"
},
"checkout_url": "https://crytom.com/checkout/chk_123456",
"product_name": "Premium Plan - Annual",
"amount": "250.5",
"currency": "USD",
"environment": "live"
}
}
Retrieve a Checkout Session
Retrieves the status and payment details of a specific checkout session.
{
"status": "success",
"data": {
"id": "chk_123456",
"status": "pending",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500",
"plan_type": "annual"
},
"amount": "250.5",
"currency": "USD",
"success_url": "...",
"cancel_url": "...",
"payment_details": [
{
"currency": "BTC",
"network": "Bitcoin",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"amount": "0.00412",
"status": "pending"
},
{
"currency": "USDT_BSC",
"network": "BSC",
"address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"amount": "250.5",
"status": "pending"
}
]
}
}
Verify Payment Claim
Use this when a user claims they've sent funds (e.g., clicks "I Have Paid"). This creates a Pending record for the merchant and initiates 24-hour blockchain monitoring.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
currency |
String | Yes | The symbol of the asset sent (e.g., USDT_BSC). |
[Wait] Monitoring Workflow
- Immediate Feedback: Respond with
pendingto confirm the claim is recorded. - Extended Monitoring: The system scans the blockchain for 24 hours.
- Auto-Failure: Moves to
failedif no payment is found within 24 hours.
{
"status": "success",
"data": {
"status": "pending",
"message": "Payment not detected yet. Please ensure you have sent the funds.",
"wallets": [
{ "currency": "USDT_BSC", "status": "pending", "tx_hash": null }
]
}
}
Webhooks
Crytom will post a JSON notification to your configured Webhook URL when the status of a checkout session changes.
[OK] Best Practices
- Verify Signatures: Always verify the
X-Crytom-Signatureon incoming webhooks. - Handle Idempotency: If your server goes offline, ensure your webhook handler logic can process the same event multiple times safely.
- Environment Parity: Use your
sk_test_key for local development. Transactions on testnet/sandbox never use real money.
{
"event": "checkout.session.confirmed",
"data": {
"id": "chk_123456",
"amount": "250.5",
"currency": "USD",
"status": "confirmed",
"tx_hash": "0xabc123...",
"customerId": "user_xxxx",
"metadata": {
"order_id": "123"
}
}
}
Create an Invoice
Create an invoice for a specific fiat or crypto amount. This behaves identically to creating a Payment Link from the dashboard but operates headlessly.
Body Parameters
| Parameter | Description |
|---|---|
amount Required |
The amount to charge the customer (Number). |
currency Required |
The base currency of the invoice (e.g. USD). |
customer_email |
Email of the customer paying the invoice. |
description |
A description of the product or service. |
redirect_url |
URL to redirect the user after payment completion. |
customer_id |
Your internal user ID to associate with this invoice. |
metadata |
JSON object for internal custom fields (e.g. order IDs). |
{
"amount": 100.50,
"currency": "USD",
"customer_email": "user@example.com",
"description": "Premium Subscription",
"redirect_url": "https://your-site.com/success",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500"
}
}
{
"status": "success",
"message": "Invoice created successfully",
"data": {
"id": "inv_8x99A2M",
"amount": 100.50,
"currency": "USD",
"status": "pending",
"customer_id": "user_998877",
"metadata": {
"order_id": "ORD-500"
},
"hosted_url": "https://pay.crytom.com/inv_8x99A2M",
"created_at": "2026-02-25T12:00:00Z"
}
}
Fetch an Invoice
Retrieves the details of an existing invoice by its ID.
Path Parameters
id Required |
The unique identifier of the invoice. |
customer_id and metadata in the response, allowing for seamless reconciliation.
curl https://www.api.crytom.com/v1/invoices/inv_8x99A2M \
-H "Authorization: Bearer sk_test_YOUR_KEY"
const axios = require('axios');
axios.get('https://www.api.crytom.com/v1/invoices/inv_8x99A2M', {
headers: {
'Authorization': 'Bearer sk_test_YOUR_KEY'
}
}).then(res => console.log(res.data));
<?php
$ch = curl_init('https://www.api.crytom.com/v1/invoices/inv_8x99A2M');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer sk_test_YOUR_KEY'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.api.crytom.com/v1/invoices/inv_8x99A2M"))
.header("Authorization", "Bearer sk_test_YOUR_KEY")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
import requests
url = 'https://www.api.crytom.com/v1/invoices/inv_8x99A2M'
headers = {
'Authorization': 'Bearer sk_test_YOUR_KEY'
}
response = requests.get(url, headers=headers)
print(response.json())
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, HeaderValue::from_static("Bearer sk_test_YOUR_KEY"));
let client = reqwest::Client::new();
let res = client.get("https://www.api.crytom.com/v1/invoices/inv_8x99A2M")
.headers(headers)
.send()
.await?
.json::<serde_json::Value>()
.await?;
println!("{:#?}", res);
Ok(())
}
Create a Payment
If you prefer to bypass Invoices, you can create a direct payment session for checkout. This provisions temporary deposit addresses across supported blockchains.
Body Parameters
amount Required |
Target fiat amount to receive. |
fiat_currency Required |
Desired base pricing currency (e.g. USD). |
metadata |
JSON object containing your custom internal reference IDs. |
{
"amount": 500,
"fiat_currency": "USD",
"metadata": {
"order_id": "ORD-77A01",
"customer_id": "CUS-001"
}
}
{
"status": "success",
"data": {
"payment_id": "pay_xyz789",
"status": "awaiting_payment",
"addresses": {
"USDT_TRC20": "TXYZ...",
"USDC_ERC20": "0xABC..."
},
"expires_at": "2026-02-25T13:00:00Z"
}
}
List Payments
Retrieves a paginated list of all payments and checkout sessions created by your account or via API. Includes customer_id and metadata if they were provided during session creation.
{
"status": "success",
"data": [
{
"id": "chk_123456",
"amount": "250.5",
"currency": "USD",
"status": "confirmed",
"customer_id": "user_998877",
"metadata": { "order_id": "123" },
"created_at": "2026-03-12T14:00:00Z"
}
],
"pagination": { "page": 1, "total": 120 }
}
Fetch a Payment
Retrieves the specific details of a payment by its ID.
Path Parameters
id Required |
The ID of the payment to retrieve. |
{
"status": "success",
"data": {
"id": "chk_123456",
"amount": "250.5",
"currency": "USD",
"status": "confirmed",
"customer_id": "user_998877",
"metadata": { "order_id": "123" },
"created_at": "2026-03-12T14:00:00Z"
}
}
Developer Wallet API (v1)
The Developer Wallet API allows you to provision customer-specific crypto wallets. These wallets are persistent, derived via Hierarchical Deterministic (HD) derivation, and tied to your Organization's internal ledger.
[Key] Core Principles
- Isolation: Each wallet is unique to a
customer_idandcurrencypair. No two customers share an address. - Ledger Sync: Every deposit and withdrawal updates both the specific Developer Wallet sub-account and your Organization's master internal ledger.
- Persistence: Once created, a wallet and its deposit address remain active for that customer indefinitely.
1. POST /v1/wallets (Create)
2. User sends BTC to deposit_address
3. POST /v1/wallets/:id/deposit (Record credit)
4. webhook: wallet.deposit.completed triggered
Create a Wallet
Provisions a new HD-derived wallet for a specific customer.
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
customer_id |
String | Yes | Your internal unique user ID. |
currency |
String | Yes | Asset (e.g., USDT, BTC, STX). |
network |
String | Yes | Network (e.g., BSC, Stacks). |
label |
String | No | A friendly name for the wallet. |
metadata |
Object | No | Custom JSON data. |
{
"customer_id": "user_123",
"currency": "USDT",
"network": "BSC",
"label": "John Doe Main Wallet"
}
List Wallets
Retrieves a paginated list of all developer-managed wallets.
Query Parameters
customer_id: Filter by customer.currency: Filter by asset.page/limit: Pagination.
{
"status": "success",
"data": [
{
"wallet_id": "wal_abc123",
"customer_id": "user_123",
"currency": "USDT",
"balance": "100.50",
"deposit_address": "0x..."
}
]
}
Aggregated Balances
Get the total USD value across all or a specific customer's wallets.
{
"status": "success",
"data": {
"total_balance_usd": 1500.25,
"wallet_count": 3,
"wallets": [...]
}
}
Wallet Details
{
"status": "success",
"data": {
"wallet_id": "wal_...",
"balance": "50.0",
"balance_usd": 50.0,
"deposit_address": "..."
}
}
Wallet Transactions
History of deposits and withdrawals for a specific wallet.
{
"status": "success",
"data": [
{ "type": "deposit", "amount": "10.5", "amount_usd": 10.5, "status": "completed" }
]
}
Record Deposit
Credits a wallet balance after a successful on-chain deposit is detected. This updates both the client sub-account and your organization's internal ledger.
{
"amount": "1.25",
"tx_hash": "0x..."
}
Withdrawal
Initiate an on-chain transfer from a customer's wallet to an external address. Fees are deducted from the customer's balance.
{
"amount": "0.5",
"recipient_address": "TQxyZ..."
}
Wallet Lookup
Find a specific wallet without knowing the wallet_id. Useful for checking if a customer already has a wallet provisioned for a specific chain.
Query Parameters
customer_idRequired: Your internal user ID.currencyRequired: Asset symbol.networkRequired: Network name.
{
"status": "success",
"data": {
"wallet_id": "wal_abc123",
"deposit_address": "0x...",
"balance": "10.0",
"balance_usd": 10.0
}
}
Supported Assets (Discovery)
Discovery of all valid asset/network pairs available for derivation.
{
"status": "success",
"data": [
{ "currency": "USDT", "networks": ["BSC", "Polygon", "Tron"] },
{ "currency": "BTC", "networks": ["Bitcoin"] }
]
}
Wallet Webhooks
Receive asynchronous notifications for wallet-related events. All payloads include the customer_id for easy user reconciliation.
| Event Type | Trigger |
|---|---|
wallet.deposit.completed |
Triggered when a wallet balance is successfully credited. |
wallet.withdrawal.initiated |
Triggered when a withdrawal request is accepted and broadcast. |
wallet.withdrawal.failed |
Triggered if an on-chain withdrawal fails to broadcast. |
{
"event": "wallet.deposit.completed",
"data": {
"wallet_id": "wal_abc123",
"customer_id": "user_123",
"currency": "USDT",
"network": "BSC",
"amount": "100.50",
"new_balance": "150.75",
"tx_hash": "0x..."
}
}
Create a Payout
Withdraw funds from your Crytom balance to a specific external cryptocurrency address. High-amount payouts ($5,000+) are automatically flagged as Pending Verification.
Body Parameters
amount Required |
Amount of crypto to withdraw. |
currency Required |
The asset to withdraw (e.g. USDT). |
network Required |
The blockchain network (e.g. TRC20). |
destination_address Required |
Valid wallet address on the specified network. |
{
"amount": 1500,
"currency": "USDT",
"network": "TRC20",
"destination_address": "TQxyZ48abc123..."
}
{
"status": "success",
"data": {
"payout_id": "po_6541qw",
"status": "processing",
"estimated_fee": 1.5,
"net_amount": 1498.5
}
}
Verify Payout (OTP)
Approve high-risk payouts ($5,000+). An OTP is sent to the Organization Owner's email when the payout is first created.
Body Parameters
otp_code Required |
The 6-digit code sent via email. |
{
"status": "success",
"message": "Payout verified and broadcast successfully."
}
Mass Payout
Submit a batch payout request. Perfect for payroll, vendor payments, or airdrops. You can pass up to 50 addresses in a single request.
Body Parameters
You provide an array of destinations inside the payload.
{
"batch_reference": "Payroll-Q3",
"destinations": [
{
"amount": 500,
"currency": "USDT",
"network": "TRC20",
"address": "TQxyZ1..."
},
{
"amount": 1000,
"currency": "USDC",
"network": "BEP20",
"address": "0xABC..."
}
]
}
{
"status": "success",
"data": {
"batch_id": "batch_99xY1",
"status": "processing",
"total_payouts": 2,
"total_amount": 1500
}
}
Payout Status
Status of a specific withdrawal or list all historical payouts.
{
"status": "success",
"data": {
"payout_id": "po_6541qw",
"status": "completed",
"tx_hash": "0x..."
}
}
Payout Discovery
Query dynamic minimum limits and gas fee estimates for different chains.
{
"status": "success",
"data": {
"network_fee": 1.5,
"crytom_fee": 0.5,
"total_estimated_fee": 2.0
}
}
Estimate Price
Get real-time exchange rates and estimated payout amounts for swaps.
Query Parameters
base_currencyRequiredquote_currencyRequiredamount
{
"status": "success",
"data": {
"rate": 65000.50,
"estimated_received": 32500.25
}
}
Execute Physical Swap
Execute an internal atomic swap seamlessly between your balances. Convert volatile assets into stablecoins instantly.
Body Parameters
from_currency Required |
Source balance asset (e.g. BTC). |
to_currency Required |
Target balance asset (e.g. USDT). |
amount Required |
Amount of the source currency to sell. |
{
"from_currency": "BTC",
"to_currency": "USDT",
"amount": 0.5
}
{
"status": "success",
"data": {
"conversion_id": "cv_001",
"rate_applied": 65000.50,
"received_amount": 32500.25,
"status": "completed"
}
}
Conversion History
Retrieve history and specific status of internal swaps.
{
"status": "success",
"data": [
{ "id": "cv_001", "from": "BTC", "to": "USDT", "amount": 0.5, "status": "completed" }
]
}
List Supported Routes
Retrieves all asset/chain pairs supported for Burn & Mint wrapping operations.
{
"status": "success",
"data": [
{ "asset": "BTC", "source": "Bitcoin", "destinations": ["Solana", "BNB Chain"] },
{ "asset": "SOL", "source": "Solana", "destinations": ["BNB Chain"] }
]
}
Initiate Burn & Mint
Initiate a wrapping process by locking/burning a native token to mint a wrapped version on a destination chain.
Parameters
source_asset: The asset to wrap (e.g. BTC).source_chain: Source network (e.g. Bitcoin).destination_chain: Target network (e.g. Solana).amount: Quantity to process.customer_id: (Optional) Your internal ID tracking who requested the mint.metadata: (Optional) Additional custom JSON properties to track perfectly.
Supported Asset Pairs (Burn & Mint)
- BTC (Bitcoin) ➔ Solana / BNB Chain (as wBTC)
- ETH (Ethereum / Base) ➔ Solana / BNB Chain (as wETH)
- LINK (Ethereum) ➔ Solana / BNB Chain (as wLINK)
- SOL (Solana) ➔ BNB Chain (as wSOL)
- BNB (BNB Chain) ➔ Solana (as wBNB)
{
"source_asset": "BTC",
"source_chain": "Bitcoin",
"destination_chain": "Solana",
"amount": 0.5,
"customer_id": "user_xxxx",
"metadata": {
"wallet_source": "internal_app"
}
}
Track Status
Track progress: Lock Status ➔ Validator Approval ➔ Minting Status.
{
"status": "success",
"data": {
"id": "m_123",
"status": "minted",
"tx": "0x...",
"customer_id": "user_xxxx",
"metadata": {
"wallet_source": "internal_app"
}
}
}
Node.js SDK
The official Crytom Node.js SDK simplifies the integration process by handling HMAC signature generation, timestamp management, and request routing automatically.
[Package] Installation
npm install crytom-sdk
[Key] Basic Usage
Initialize the client with your secret key. The SDK automatically detects if it's a test or live environment based on the key prefix.
[Features] SDK Resources
Access all platform features through a clean, programmatic interface:
| Resource | Description & Methods |
|---|---|
crytom.payouts |
Single & mass withdrawals. .create(), .mass(), .verify(), .estimateFee(), .minAmount()
|
crytom.prices |
Real-time rates and swaps. .estimate(), .convert(), .listConversions()
|
crytom.wallets |
Full wallet lifecycle. .lookup() (by customer_id), .supported() (asset discovery), .create(), .list()
|
const { CrytomClient } = require('crytom-sdk');
const crytom = new CrytomClient('sk_live_YOUR_SECRET_KEY');
// Example: Create a checkout session
async function createOrder() {
const session = await crytom.checkout.create({
amount: 50.00,
currency: 'USD',
product_name: 'Premium Subscription'
});
console.log(session.checkout_url);
}