REST API reference

Base URL, authentication, and every public and API-key endpoint with example request bodies and responses.

Introduction

The Chain Monitor API lets you manage wallet monitors and receive real-time transaction notifications across Ethereum, BSC, Polygon, Avalanche, and Fantom. Create an API key in Dashboard → API and use it for server-to-server requests.

Base URL

https://api.chain-monitor.online
  • REST JSON API with predictable resource URLs
  • Ethereum, BSC, Polygon, Avalanche, Fantom
  • Real-time webhook notifications

Authentication

Authenticate with a Bearer token. Create an API key in Dashboard → API and pass it in the Authorization header.

Request Header

Authorization: Bearer api_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keep your API key secure. Do not share it publicly or commit it to version control. If compromised, rotate it in the dashboard.

Error Handling

The API uses standard HTTP status codes.

CodeDescription
200Success
201Resource created
400Bad request — invalid parameters
401Unauthorized — invalid or missing token
403Forbidden — account suspended
404Resource not found
422Validation error
429Rate limit exceeded
500Internal server error

Public (no auth)

These endpoints do not require auth. Use them to discover network UUIDs and token UUIDs before creating wallet monitors.

GET /public/networks

GET /public/networks — active networks and tokens (no auth).

Example response (JSON)

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Ethereum",
    "slug": "ethereum",
    "tokens": [
      { "id": "…", "name": "ETH", "slug": "eth", "type": "native" },
      { "id": "…", "name": "USDT", "slug": "usdt", "type": "token" }
    ]
  }
]

GET /public/pack-credits

GET /public/pack-credits — available credit packs (no auth).

Example response (JSON)

[
  {
    "id": "…",
    "popular": false,
    "count": "1000",
    "price": 9.99,
    "discount": 0,
    "status": "active",
    "createdAt": "…",
    "updatedAt": "…"
  }
]

Wallets

Wallet monitors are blockchain addresses you track. Each monitor has a network, tokens, minimum amount, and optional webhook URL.

Get networkUuid and tokenUuids from GET /public/networks (no auth). Use network.id and token.id from the response.

GET /v1/wallets

Returns all wallet monitors for your account.

Example response (JSON)

[
  {
    "id": "…",
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
    "networkUuid": "…",
    "tokenUuids": ["…"],
    "minAmount": "0",
    "webhookUrl": null,
    "status": "active",
    "notifySettings": { "telegram": false, "webhook": true, "notifyIncoming": true, "notifyOutgoing": true },
    "network": { /* … */ },
    "tokens": [ /* … */ ],
    "createdAt": "…",
    "updatedAt": "…"
  }
]
curl -X GET "https://api.chain-monitor.online/v1/wallets" \
  -H "Authorization: Bearer api_key_xxx"

POST /v1/wallets

Add a new wallet to monitor.

Request body (JSON)

{
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
  "networkUuid": "UUID_FROM_GET_PUBLIC_NETWORKS",
  "tokenUuids": ["TOKEN_UUID_FROM_NETWORK"],
  "minAmount": "100",
  "webhookUrl": "https://your-app.com/webhook",
  "notifySettings": {
    "webhook": true,
    "telegram": false,
    "notifyIncoming": true,
    "notifyOutgoing": true
  }
}

Example response (JSON)

{
  "id": "…",
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
  "status": "active",
  "tokenUuids": ["…"],
  "minAmount": "100",
  "webhookUrl": "https://your-app.com/webhook",
  "notifySettings": { "webhook": true, "telegram": false, "notifyIncoming": true, "notifyOutgoing": true },
  "network": { /* … */ },
  "tokens": [ /* … */ ],
  "createdAt": "…",
  "updatedAt": "…"
}
curl -X POST "https://api.chain-monitor.online/v1/wallets" \
  -H "Authorization: Bearer api_key_xxx" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

PATCH /v1/wallets/:id

Update monitor settings (tokens, min amount, webhook URL).

Optional fields — send only what you want to change.

{
  "tokenUuids": ["…"],
  "minAmount": "50",
  "webhookUrl": "https://example.com/hook",
  "notifySettings": { "webhook": true },
  "status": "paused"
}

DELETE /v1/wallets/:id

Remove a wallet monitor. Associated data is deleted.

curl -X DELETE "https://api.chain-monitor.online/v1/wallets/WALLET_UUID" \
  -H "Authorization: Bearer api_key_xxx"

POST /v1/wallets/:id/toggle

Enable or pause monitoring for a wallet.

Example response (JSON)

{ "status": "paused" }  // or "active"

Notifications

List and fetch notification records using your API key (same filters as the dashboard list).

  • GET /v1/notifications

    Query params: limit (1–100, default 25), offset (default 0), status, channel, networkSlug. Response: { notifications, total }.

    Example response (JSON)

    {
      "notifications": [
        {
          "id": "…",
          "userId": "…",
          "walletId": "…",
          "channel": "webhook",
          "eventType": "transaction_detected",
          "status": "sent",
          "transactionHash": "0x…",
          "networkSlug": "ethereum",
          "payload": { },
          "createdAt": "…"
        }
      ],
      "total": 42
    }
    curl -G "https://api.chain-monitor.online/v1/notifications" \
      --data-urlencode "limit=25" \
      --data-urlencode "offset=0" \
      -H "Authorization: Bearer api_key_xxx"
  • GET /v1/notifications/:id

    Get a single notification by ID.

    The legacy route GET /notifications (without v1) uses the dashboard JWT session only.

Payment pages (API key)

Automate payment pages: add a receiving address to the pool, or create a payment that reserves a free wallet for the requested network.

POST /v1/payment-pages/pool-wallets

Adds one address to the pool of a payment page you own. Use paymentPageUuid from the dashboard when you create a page.

{
  "paymentPageUuid": "PAGE_UUID_FROM_DASHBOARD",
  "wallet": "0x…",
  "networkUuid": "…"
}

Example response (JSON)

{
  "uuid": "…",
  "wallet": "0x…",
  "paymentPageUuid": "…",
  "status": "free",
  "networkUuid": "…",
  "network": { "id": "…", "name": "Ethereum", "slug": "ethereum" },
  "createdAt": "…",
  "updatedAt": "…"
}

POST /v1/payment-pages/payments

Reserves the next free wallet in the pool for the given network and records expected amount and token. Returns 400 if no free wallet is available.

{
  "paymentPageUuid": "…",
  "networkUuid": "…",
  "tokenUuid": "…",
  "amount": "100.50",
  "webHookUrl": "https://optional-callback.example/hook",
  "dataOrder": { "orderId": "shop-123" }
}

Example response (JSON)

{
  "uuid": "…",
  "webHookUrl": "https://…",
  "status": "waiting",
  "wallet": "0x…",
  "networkUuid": "…",
  "tokenUuid": "…",
  "amount": "100.50",
  "dataOrder": { "orderId": "shop-123" },
  "dataTx": null,
  "createdAt": "…",
  "updatedAt": "…"
}

Webhooks

When a transaction matches your monitor (network, token, min amount), we send a POST request to your webhook URL. The payload includes transaction data (txHash, network, direction, asset, amount, from, to, timestamp). After you create your first API key, a webhook signing secret is issued once (Dashboard → API); we send X-Webhook-Signature so you can verify the body.

HTTP request

Method POST, header Content-Type: application/json, body is a UTF-8 JSON object. Top-level fields: eventType, userId, optional correlationId, ISO8601 timestamp, and data (transaction details). Return HTTP 2xx to accept; other statuses may trigger retries.

Where the signing secret comes from

The secret is shown only once in Dashboard → API when you create your first API key. Format: whsec_ followed by hex. One secret per account—all wallet monitors use it. Rotating an API key does not show the secret again. If you lost it, contact support.

Header X-Webhook-Signature

When a secret is stored for your account, every webhook request includes this header. The value is a string of 64 hexadecimal characters (0-9, a-f): the HMAC-SHA256 digest of the raw body, encoded as hex without a prefix.

How the signature is computed (exactly)

Let rawBody be the exact byte sequence of the request body as received over the wire (before JSON.parse). Let secret be your whsec_… string interpreted as UTF-8.

  1. signature_hex = HMAC-SHA256(key = secret as UTF-8, message = rawBody)
  2. X-Webhook-Signature = signature_hex as a lowercase hex string (64 characters).

In Node.js this matches: crypto.createHmac('sha256', secret).update(rawBody).digest('hex') when rawBody is a Buffer or string of the same bytes as the HTTP body.

When the header is missing

If no signing secret has been created for the account yet, we do not send X-Webhook-Signature. After the first API key is created and the secret is stored, new deliveries include the header.

Verifying on your server

Read the raw body from the HTTP layer (Buffer / Uint8Array / string of raw bytes). Do not re-serialize a parsed JSON object—whitespace and key order must match what we sent. Compute the expected hex with the same HMAC. Compare the header to the expected value using a constant-time comparison (e.g. crypto.timingSafeEqual on two Buffers built from the hex strings).

Common mistakes

  • Using JSON.stringify(parsedObject) instead of the raw body — the digest will not match.
  • Trimming or altering the body before verification.
  • Case-sensitive hex compare without normalizing, or string compare instead of timing-safe compare.

Node.js (Express) — verify with raw body

import express from 'express';
import { createHmac, timingSafeEqual } from 'crypto';

const app = express();

app.post(
  '/webhook',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const secret = process.env.CHAIN_MONITOR_WEBHOOK_SECRET; // whsec_...
    const rawBody = req.body; // Buffer — must match bytes we sent
    const sigHeader = (req.get('x-webhook-signature') || '').trim().toLowerCase();
    const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
    const a = Buffer.from(sigHeader, 'utf8');
    const b = Buffer.from(expected, 'utf8');
    if (a.length !== b.length || !timingSafeEqual(a, b)) {
      return res.status(401).send('invalid signature');
    }
    const payload = JSON.parse(rawBody.toString('utf8'));
    // ... handle payload
    return res.status(200).send('ok');
  }
);

Example JSON body

{
  "eventType": "transaction_detected",
  "userId": "uuid",
  "correlationId": "tx-0x...-timestamp",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "txHash": "0x...",
    "network": "Ethereum",
    "blockNumber": 19485738,
    "direction": "in",
    "asset": "USDT",
    "amount": "250.00",
    "from": "0x...",
    "to": "0x...",
    "timestamp": "2024-01-15T10:30:00Z",
    "txHashLink": "https://etherscan.io/tx/0x...",
    "fromLink": "https://etherscan.io/address/0x...",
    "toLink": "https://etherscan.io/address/0x..."
  }
}

Contact

Need help? Use the contact page for integration questions and support.

Email: support@chain-monitor.online

Contact