Language:

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
Base URLs
# 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
Asset Constants
{
  "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 Request
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"
Node.js (Axios)
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 (cURL)
<?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;
?>
Java (HttpClient)
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());
Python (Requests)
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())
Rust (Reqwest)
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.

Node.js HMAC
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 HMAC
<?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
    ];
}
?>
Java HMAC
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();
}
Python HMAC
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
    }
Rust HMAC
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-Timestamp header 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:

  1. Read the Header: We extract the X-Crytom-Timestamp from your request.
  2. Drift Check: We compare your timestamp with the current time on the Crytom server.
  3. 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 Unauthorized error.
  4. 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.
Generation Snippets
// 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.

  1. Detection: Every time a request hits our /v1 endpoints, Crytom detects the origin IP address (supporting proxies and load balancers).
  2. Verification: If the organization owner has enabled IP Whitelisting, the backend checks if the incoming IP exists in the allowed list.
  3. 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 Forbidden error.

[Config] Managing Whitelisted IPs

Whitelisting is managed centrally from your account settings to ensure consistency across all your API keys.

Where to manage:

  1. Log in to the Crytom Dashboard.
  2. Navigate to Settings > Developer Settings (or the Security/API section).
  3. 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

  1. Always Enable in Production: We strongly recommend enabling IP whitelists for your "Live" environment to prevent unauthorized access if your SECRET_KEY is ever leaked.
  2. Minimalist Approach: Only whitelist the specific servers that need to make API calls.
  3. Test in Sandbox: Enable whitelisting with your development machine's IP first to ensure your integration handles the security handshake correctly.
Security Rejection Response
{
  "error": "Unauthorized IP",
  "message": "The IP address 203.0.113.42 is not whitelisted in your account settings."
}
Finding your Public IP
curl ifconfig.me

Metadata Registry

Access the platform's flat registry of supported assets and network combinations.

GET /v1/currencies
GET /v1/currencies/pairs

Returns a complete list of all Currency + Network combinations valid for derivation and payouts.

Response Example
{
  "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 Response Example
{
  "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

  1. Step 1: Your server calls POST /v1/checkout/sessions to create a new session.
  2. Step 2: Crytom returns a unique checkout_url.
  3. Step 3: Redirect your customer to this URL.
  4. Step 4: Your customer pays using their preferred cryptocurrency.
  5. 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)
Signature Payload Construction
// 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_id and metadata are 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.

Example Tracked Payload
{
  "amount": 100.00,
  "currency": "USD",
  "customer_id": "user_998877",
  "metadata": {
    "order_id": "ORD-500",
    "plan_type": "annual"
  }
}

Create a Checkout Session

POST /v1/checkout/sessions

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).
Example Request
{
  "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"]
}
Example Response
{
  "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

GET /v1/checkout/sessions/:id

Retrieves the status and payment details of a specific checkout session.

Example Response
{
  "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

POST /v1/checkout/sessions/:id/verify

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 pending to confirm the claim is recorded.
  • Extended Monitoring: The system scans the blockchain for 24 hours.
  • Auto-Failure: Moves to failed if no payment is found within 24 hours.
Example Response
{
  "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

  1. Verify Signatures: Always verify the X-Crytom-Signature on incoming webhooks.
  2. Handle Idempotency: If your server goes offline, ensure your webhook handler logic can process the same event multiple times safely.
  3. Environment Parity: Use your sk_test_ key for local development. Transactions on testnet/sandbox never use real money.
Webhook Payload Example
{
  "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.

POST /v1/invoices

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).
Request Payload
{
  "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"
  }
}
Response
{
  "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.

GET /v1/invoices/:id

Path Parameters

id Required The unique identifier of the invoice.

Note: Retrieving an invoice returns your passed customer_id and metadata in the response, allowing for seamless reconciliation.
cURL Request
curl https://www.api.crytom.com/v1/invoices/inv_8x99A2M \
  -H "Authorization: Bearer sk_test_YOUR_KEY"
Node.js (Axios)
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 (cURL)
<?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;
?>
Java (HttpClient)
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());
Python (Requests)
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())
Rust (Reqwest)
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.

POST /v1/payments

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.
Request Payload
{
  "amount": 500,
  "fiat_currency": "USD",
  "metadata": {
    "order_id": "ORD-77A01",
    "customer_id": "CUS-001"
  }
}
Response
{
  "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.

GET /v1/payments
Response
{
  "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.

GET /v1/payments/:id

Path Parameters

id Required The ID of the payment to retrieve.
Response
{
  "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_id and currency pair. 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.
Wallet Event Workflow
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

POST /v1/wallets

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.
Request Example
{
  "customer_id": "user_123",
  "currency": "USDT",
  "network": "BSC",
  "label": "John Doe Main Wallet"
}

List Wallets

GET /v1/wallets

Retrieves a paginated list of all developer-managed wallets.

Query Parameters

  • customer_id: Filter by customer.
  • currency: Filter by asset.
  • page / limit: Pagination.
Response Example
{
  "status": "success",
  "data": [
    {
      "wallet_id": "wal_abc123",
      "customer_id": "user_123",
      "currency": "USDT",
      "balance": "100.50",
      "deposit_address": "0x..."
    }
  ]
}

Aggregated Balances

GET /v1/wallets/balance/aggregated

Get the total USD value across all or a specific customer's wallets.

Response Example
{
  "status": "success",
  "data": {
    "total_balance_usd": 1500.25,
    "wallet_count": 3,
    "wallets": [...]
  }
}

Wallet Details

GET /v1/wallets/:id
Response
{
  "status": "success",
  "data": {
    "wallet_id": "wal_...",
    "balance": "50.0",
    "balance_usd": 50.0,
    "deposit_address": "..."
  }
}

Wallet Transactions

GET /v1/wallets/:id/transactions

History of deposits and withdrawals for a specific wallet.

Response
{
  "status": "success",
  "data": [
    { "type": "deposit", "amount": "10.5", "amount_usd": 10.5, "status": "completed" }
  ]
}

Record Deposit

POST /v1/wallets/:id/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.

Request Payload
{
  "amount": "1.25",
  "tx_hash": "0x..."
}

Withdrawal

POST /v1/wallets/:id/withdraw

Initiate an on-chain transfer from a customer's wallet to an external address. Fees are deducted from the customer's balance.

Request Payload
{
  "amount": "0.5",
  "recipient_address": "TQxyZ..."
}

Wallet Lookup

GET /v1/wallets/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_id Required: Your internal user ID.
  • currency Required: Asset symbol.
  • network Required: Network name.
Response
{
  "status": "success",
  "data": {
    "wallet_id": "wal_abc123",
    "deposit_address": "0x...",
    "balance": "10.0",
    "balance_usd": 10.0
  }
}

Supported Assets (Discovery)

GET /v1/wallets/supported

Discovery of all valid asset/network pairs available for derivation.

Response
{
  "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.
Deposit Webhook Payload
{
  "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.

POST /v1/payouts

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.
Request Payload
{
  "amount": 1500,
  "currency": "USDT",
  "network": "TRC20",
  "destination_address": "TQxyZ48abc123..."
}
Response
{
  "status": "success",
  "data": {
    "payout_id": "po_6541qw",
    "status": "processing",
    "estimated_fee": 1.5,
    "net_amount": 1498.5
  }
}

Verify Payout (OTP)

POST /v1/payouts/:id/verify

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.
Response
{
  "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.

POST /v1/payouts/mass

Body Parameters

You provide an array of destinations inside the payload.

Request Payload
{
  "batch_reference": "Payroll-Q3",
  "destinations": [
    {
      "amount": 500,
      "currency": "USDT",
      "network": "TRC20",
      "address": "TQxyZ1..."
    },
    {
      "amount": 1000,
      "currency": "USDC",
      "network": "BEP20",
      "address": "0xABC..."
    }
  ]
}
Response
{
  "status": "success",
  "data": {
    "batch_id": "batch_99xY1",
    "status": "processing",
    "total_payouts": 2,
    "total_amount": 1500
  }
}

Payout Status

GET /v1/payouts
GET /v1/payouts/:id

Status of a specific withdrawal or list all historical payouts.

Response
{
  "status": "success",
  "data": {
    "payout_id": "po_6541qw",
    "status": "completed",
    "tx_hash": "0x..."
  }
}

Payout Discovery

GET /v1/withdrawals/min-amount
GET /v1/withdrawals/fee-estimate

Query dynamic minimum limits and gas fee estimates for different chains.

Fee Estimate Response
{
  "status": "success",
  "data": {
    "network_fee": 1.5,
    "crytom_fee": 0.5,
    "total_estimated_fee": 2.0
  }
}

Estimate Price

GET /v1/prices/estimate

Get real-time exchange rates and estimated payout amounts for swaps.

Query Parameters

  • base_currency Required
  • quote_currency Required
  • amount
Response
{
  "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.

POST /v1/conversions

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.
Request Payload
{
  "from_currency": "BTC",
  "to_currency": "USDT",
  "amount": 0.5
}
Response
{
  "status": "success",
  "data": {
    "conversion_id": "cv_001",
    "rate_applied": 65000.50,
    "received_amount": 32500.25,
    "status": "completed"
  }
}

Conversion History

GET /v1/conversions
GET /v1/conversions/:id

Retrieve history and specific status of internal swaps.

Response
{
  "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.

GET /v1/smart-contract/routes
Response
{
  "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.

POST /v1/smart-contract/mint

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)
Request
{
  "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.

GET /v1/smart-contract/status/:id
Response
{
  "status": "success",
  "data": {
    "id": "m_123",
    "status": "minted",
    "tx": "0x...",
    "customer_id": "user_xxxx",
    "metadata": {
      "wallet_source": "internal_app"
    }
  }
}

Node.js SDK

Current Version: 1.1.0

The official Crytom Node.js SDK simplifies the integration process by handling HMAC signature generation, timestamp management, and request routing automatically.

Critical Update: Version 1.1.0 fixes HMAC signature generation for GET requests with query parameters. If you are using version 1.0.0, please upgrade immediately to avoid authentication errors.

[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()
SDK Initialization
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);
}