# Chainhook API reference Chainhook watches blockchain addresses and sends every matching transfer to your webhook endpoint. This document is the complete REST API reference. - Base URL: https://api.chainhook.io/v1 - Supported networks: ethereum, bsc, polygon, arbitrum, optimism, base, avalanche, tron, bitcoin - Webhook types: address, native, token (address = all transfers, native = native-coin transfers, token = transfers of the registered tokens on that network, such as USDT and USDC) - Directions: in, out, any (relative to the watched address) - Webhook statuses: active, paused, suspended - Delivery statuses: pending, delivered, failed ## Authentication Authenticate every request with a bearer token. Create an API key in the dashboard under API keys, then send it in the `Authorization` header: ``` Authorization: Bearer YOUR_API_KEY Accept: application/json ``` Each key expires on the date chosen when it's created, or never. A missing, invalid, or expired key returns 401. Each key has full access (`*`, which also covers permissions added later) or a chosen set of permissions. Every endpoint below names the permission it requires; a key without it gets 403. - `webhooks:read`: List and retrieve webhooks. - `webhooks:write`: Create, update, and delete webhooks. - `deliveries:read`: List and retrieve deliveries. - `deliveries:replay`: Replay deliveries. - `account:read`: Read account stats and plan usage. - `mcp:use`: Connect to the MCP server. The tools it lists still depend on the other permissions. ## Conventions - All IDs are UUIDs. All timestamps are UTC ISO 8601 (Zulu). - List endpoints are cursor-paginated. Pass `per_page` (1-100, default 25) and `cursor`. Read the next and previous cursors from `meta.next_cursor` and `meta.prev_cursor`, and the next page URL from `links.next`. - Rate limit: 120 requests per minute, keyed by account. Exceeding it returns 429 with a `Retry-After` header. - Request and response bodies are JSON. Send `Content-Type: application/json` on writes. ## Errors Errors use standard HTTP status codes and a JSON body of the shape `{ "message": "...", "errors": { "field": ["..."] } }` (the `errors` object is present on 422 validation failures). - 401 Unauthorized: the API key is missing or invalid. - 403 Forbidden: the API key doesn't have the permission the endpoint requires. - 404 Not Found: the resource does not exist or belongs to another account. - 409 Conflict: the delivery is still in progress and cannot be replayed yet. - 422 Unprocessable Content: validation failed, a webhook can't be created or resumed because your plan's active webhook limit was reached, or a webhook can't be resumed while detection is paused. - 429 Too Many Requests: the rate limit was exceeded. ## Endpoints - `GET https://api.chainhook.io/v1/webhooks` - List your webhooks. Query: search, status, network, type, direction, per_page, cursor. Requires `webhooks:read`. - `POST https://api.chainhook.io/v1/webhooks` - Create a webhook. Returns 201 with the signing secret, which is only returned once. Body: network, type, direction, address (all required); webhook_url (required, public HTTPS URL); secret (optional, 32-128 chars, generated if omitted). Requires `webhooks:write`. - `GET https://api.chainhook.io/v1/webhooks/{id}` - Retrieve a webhook. Requires `webhooks:read`. - `PATCH https://api.chainhook.io/v1/webhooks/{id}` - Update a webhook. Body: status ("active" or "paused") and/or webhook_url. Requires `webhooks:write`. - `DELETE https://api.chainhook.io/v1/webhooks/{id}` - Delete a webhook and its delivery history. Returns 204. Requires `webhooks:write`. - `POST https://api.chainhook.io/v1/webhooks/bulk-delete` - Delete up to 1,000 webhooks at once. Body: ids (array of UUIDs). Returns { "deleted": n }. Requires `webhooks:write`. - `GET https://api.chainhook.io/v1/deliveries` - List deliveries. Query: search, webhook_id, status, network, direction, type, currency, per_page, cursor. Requires `deliveries:read`. - `GET https://api.chainhook.io/v1/deliveries/{id}` - Retrieve a delivery, including its payload and your endpoint's latest response. Requires `deliveries:read`. - `POST https://api.chainhook.io/v1/deliveries/{id}/replay` - Send a delivered or failed delivery again. Returns 202, or 409 while still in progress. Replays are free. Requires `deliveries:replay`. - `GET https://api.chainhook.io/v1/stats` - Webhook and delivery counts, the delivery success rate, and your most recent deliveries. Requires `account:read`. ## Webhook deliveries When a transfer matches, we POST a JSON body to your webhook URL with the event `transfer.detected`: ```json { "id": "", "event": "transfer.detected", "created_at": "", "webhook_id": "", "data": { "network": "bsc", "direction": "in", "type": "token", "transaction_hash": "0x...", "transfer_index": 26, "block_number": 41234567, "block_hash": "0x...", "block_timestamp": null, "confirmations": 15, "from": "0x...", "to": "0x...", "currency": "USDT", "amount": "12.5", "amount_raw": "12500000000000000000", "decimals": 18, "contract_address": "0x55d398326f99059ff775485246999027b3197955" } } ``` Each request carries these headers: - `X-Webhook-Id`: the delivery ID (UUID). It is stable across retries and replays, so use it for idempotency. - `X-Webhook-Signature`: hex-encoded HMAC-SHA256 of the raw request body, signed with the webhook's signing secret. Verify the signature by computing the HMAC-SHA256 of the raw body with your signing secret and comparing it to `X-Webhook-Signature` in constant time. Identify tokens by `data.network` and `data.contract_address`, not by `data.currency`, which is not unique. ## Billing Each account is on a plan with a monthly detection allowance and an active webhook limit: - Pay as you go (`free`): $0/month. 100 trial detections for 1 month. 3 active webhooks. $0.001 per detection after the trial. - Starter (`starter`): $9/month or $90/year. 25,000 detections a month. 25 active webhooks. $0.0006 per extra detection. - Growth (`growth`): $29/month or $290/year. 100,000 detections a month. 100 active webhooks. $0.0003 per extra detection. - Scale (`scale`): $99/month or $990/year. 400,000 detections a month. 200 active webhooks. $0.0002 per extra detection. - A detection is one transfer matched by one webhook, counted once against the allowance whether or not your endpoint accepts it. Retries and replays are free. - Only active webhooks count toward the webhook limit. At the limit, creating a webhook returns 422 on `network`, and setting `status` to "active" returns 422 on `status`. If a plan change lowers the limit, active webhooks over it are suspended. - Pay as you go has no monthly fee and includes 100 trial detections for 1 month after sign-up, then each detection is paid from prepaid credit at $0.001. Paid plans keep detecting and bill extra detections at the plan's overage rate after each period. If an overage cap is set, detection pauses at the cap until the next period. - While detection is paused, active webhooks are suspended and transfers aren't detected or delivered. New webhooks are created with status "suspended" and a `suspension_reason`, such as "Trial detections used and credit balance is empty. Add credit or subscribe to a plan to resume detection.", and setting `status` to "active" returns 422 with the same message. Suspended webhooks resume automatically when detection resumes; paused webhooks stay paused. ## MCP server An MCP server is available at `https://mcp.chainhook.io/mcp` (streamable HTTP). Clients that support OAuth discover the authorization server from this URL and sign in through the browser; other clients send an API key as a bearer token. An API key needs the `mcp:use` permission to connect, and the server lists only the tools its other permissions allow; apps connected by signing in can use every tool. It exposes tools for listing, creating, updating, and deleting webhooks, listing and replaying deliveries, and reading account stats and plan usage. The `get-usage-tool` tool (requires `account:read`) returns `{ plan, plan_label, detections, included, remaining, resets_at }`: the plan, detections used this period, detections included, detections left before detection pauses (null when overage is unlimited), and when the period resets. Connect a client: - Claude Code: `claude mcp add --transport http chainhook https://mcp.chainhook.io/mcp` - Codex: `codex mcp add chainhook --url https://mcp.chainhook.io/mcp` - Gemini CLI: `gemini mcp add --scope user --transport http chainhook https://mcp.chainhook.io/mcp` - Cursor (`~/.cursor/mcp.json`): `{"mcpServers":{"chainhook":{"url":"https://mcp.chainhook.io/mcp"}}}` - VS Code (`.vscode/mcp.json`): `{"servers":{"chainhook":{"type":"http","url":"https://mcp.chainhook.io/mcp"}}}` - Claude and ChatGPT: add a custom connector with the server URL and sign in. - With an API key, send `Authorization: Bearer YOUR_API_KEY` as a header.