API reference
Use the Chainhook API to create and manage webhooks, look up the deliveries we send to your endpoints, and read usage for your account.
The API follows REST conventions: URLs are organized around resources, requests and responses are JSON, errors use standard HTTP status codes, and every request is authenticated with an API key. Anything you can do with webhooks and deliveries in the dashboard, you can also do here.
AI agents can use the same operations through the MCP server, and this reference is also available as plain text at llms-full.txt.
Base URL
https://api.chainhook.io/v1Authentication
Send an API key as a bearer token in the Authorization header of every request. Requests without a valid key fail with 401.
Create an account, then add a key on the API keys page of your dashboard. A key is shown only once, when you create it, so store it somewhere safe.
When you create a key, give it full access or only the permissions it needs. Each endpoint lists the permission it requires, and a key without it gets 403. Full access also covers permissions added later.
Each key expires on the date you choose, or never if you pick no expiration. Keep them on your servers, out of client-side code and source control, and revoke any key you think has leaked.
Permissions
webhooks:readscope- List and retrieve webhooks.
webhooks:writescope- Create, update, and delete webhooks.
deliveries:readscope- List and retrieve deliveries.
deliveries:replayscope- Replay deliveries.
account:readscope- Read account stats and plan usage.
mcp:usescope- Connect to the MCP server. The tools it lists still depend on the other permissions.
Authenticated request
curl https://api.chainhook.io/v1/webhooks \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
Errors
Chainhook uses conventional HTTP status codes. Codes in the 2xx range mean the request worked. Codes in the 4xx range mean something in the request needs fixing, and the body's message says what. Validation failures also include an errors object keyed by field.
Status codes
202Accepted- The request was accepted for processing, such as a replay.
204No Content- The request succeeded and returns no body, such as a delete.
401Unauthorized- The API key is missing or invalid.
403Forbidden- The API key doesn't have the permission this endpoint needs.
404Not Found- The resource doesn't exist or belongs to another account.
409Conflict- The delivery is still in progress and can't be replayed yet.
422Unprocessable Content- The request failed validation; see the errors object. Also returned when creating or resuming a webhook would go over your plan's active webhook limit, or when you resume a webhook while detection is paused.
429Too Many Requests- You exceeded the rate limit. Wait a moment and try again.
Error responses
// 422 Unprocessable Content { "message": "The type field is required.", "errors": { "type": ["The type field is required."] } } // 422 — creating a webhook at your plan's active webhook limit { "message": "Your Free plan allows 3 active webhooks. Pause a webhook or upgrade your plan.", "errors": { "network": ["..."] } } // 422 — resuming a webhook after the free allowance is used { "message": "Free allowance used. Subscribe to a plan to resume detection.", "errors": { "status": ["..."] } } // 401 Unauthorized { "message": "Unauthenticated." } // 403 Forbidden { "message": "This API key is missing the webhooks:write permission." } // 404 Not Found { "message": "The requested resource was not found." }
Pagination
List endpoints return results newest first, one page at a time. Set the page size with per_page and move between pages with cursor, using the values in meta.next_cursor and meta.prev_cursor. A null cursor means there's no page in that direction.
Query parameters
per_pagenumber- Items per page, from 1 to 100. Defaults to 25.
cursorstring- The cursor for the next or previous page, from meta.next_cursor or meta.prev_cursor.
Paginated response
{
"data": [
{ "id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72", "network": "bsc", "status": "active", ... }
],
"links": { "first": null, "last": null, "prev": null, "next": "https://api.chainhook.io/v1/webhooks?cursor=eyJpZCI6Li4ufQ" },
"meta": { "path": "https://api.chainhook.io/v1/webhooks", "per_page": 25, "next_cursor": "eyJpZCI6Li4ufQ", "prev_cursor": null }
}Rate limits
Each account can make up to 120 requests per minute, shared across its API keys. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers so you can pace your requests.
Requests over the limit fail with 429. Wait the number of seconds in the Retry-After header before you try again.
Rate-limited response
HTTP/1.1 429 Too Many Requests Content-Type: application/json Retry-After: 37 X-RateLimit-Limit: 120 X-RateLimit-Remaining: 0 { "message": "Too many requests. Wait a moment and try again." }
Networks
Use one of these values as network when you create a webhook. Native coin transfers are detected where a coin is listed, and token transfers for the tokens listed. A transfer is delivered once its block has the number of confirmations shown.
| Network | Value | Native coin | Tokens | Confirmations |
|---|---|---|---|---|
ethereum | ETH | USDT, USDC, BUSD, DAI, WETH, WBTC, LINK, UNI, SHIB, PEPE | 12 | |
bsc | Not detected | USDT, USDC, BUSD, DAI, WBNB, Cake, ETH, BTCB | 15 | |
polygon | Not detected | USDT, USDC, DAI, WETH, WPOL, WBTC | 64 | |
arbitrum | Not detected | USDT, USDC, DAI, WETH, ARB, WBTC | 20 | |
optimism | Not detected | USDT, USDC, DAI, WETH, OP, WBTC | 20 | |
base | Not detected | USDC, DAI, WETH, cbBTC | 20 | |
avalanche | Not detected | USDT, USDC, DAI.e, WAVAX, WETH.e, WBTC.e | 20 | |
tron | Not detected | USDT, USDC, WTRX, JST | 19 | |
bitcoin | BTC | Not detected | 6 |
Receiving webhooks
When a confirmed transfer matches one of your webhooks, Chainhook sends a POST request to its webhook URL. The body is JSON and has the same shape on every network.
Headers
X-Webhook-Idstring- The delivery ID (UUID). It stays the same on retries and replays, so use it to skip deliveries you have already processed.
X-Webhook-Signaturestring- Hex-encoded HMAC-SHA256 of the raw request body, signed with the webhook's signing secret.
Content-Typestring- Always application/json.
User-Agentstring- Always chainhook/1.x.
Body
idstring- The delivery ID (UUID), identical to X-Webhook-Id. It stays the same on retries and replays.
eventstring- The event type. Currently always "transfer.detected".
created_atstring- When the transfer was detected (UTC, ISO 8601).
webhook_idstring- The ID of the webhook that matched the transfer.
data.networkstring- The network, e.g. "bsc".
data.directionstring- "in" or "out", relative to the watched address.
data.typestring- "native" for the network's native coin, "token" for token transfers.
data.transaction_hashstring- The transaction hash.
data.transfer_indexnumber- Distinguishes transfers within one transaction: the log index for tokens, or the output index for Bitcoin (negative for spends).
data.block_numbernumber- The block height.
data.block_hashstring- The block hash. Compare it with the chain to detect reorganizations.
data.block_timestampstring | null- The block time (UTC, ISO 8601), or null when the network doesn't report it. Null is common for token transfers.
data.confirmationsnumber- Confirmations at the time of detection.
data.fromstring | null- The sender address. Null for Bitcoin receipts, which have no sender.
data.tostring | null- The recipient address. Null for Bitcoin spends, which have no recipient.
data.currencystring- The asset symbol, e.g. "USDT" or "BNB". Symbols aren't unique, so identify a token by data.network and data.contract_address.
data.amountstring- The amount as a decimal string, scaled by data.decimals.
data.amount_rawstring- The raw on-chain integer amount, in the smallest unit (e.g. wei).
data.decimalsnumber- The number of decimals of the coin or token.
data.contract_addressstring | null- The token contract address. Null for native coins.
Example request
POST /webhooks/chainhook HTTP/1.1 Host: api.example.com Content-Type: application/json User-Agent: chainhook/1.x X-Webhook-Id: 01a0fbfd-4fe4-7a3c-8f21-6b9d0e4c7a15 X-Webhook-Signature: 7a12d02673420517279805cf8188a1a62c6f69706161ba5cf0a8ec91ea66b8e3 { "id": "01a0fbfd-4fe4-7a3c-8f21-6b9d0e4c7a15", "event": "transfer.detected", "created_at": "2026-10-02T09:41:17Z", "webhook_id": "01a0fbf2-fadc-7c3e-9b1a-4d6f2e8a5c71", "data": { "network": "bsc", "direction": "in", "type": "token", "transaction_hash": "0x7c1e9f4a2b6d8035e4f1a9c27d3b5e8061f4a2c9d7b3e5f8a1c4d6e9b2f7a3c5", "transfer_index": 214, "block_number": 71206438, "block_hash": "0x3a8f2c6e1d9b4f7a0c5e8d2b6f1a9c4e7d0b3f6a2c8e5d1b9f4a7c0e3d6b8f2a", "block_timestamp": "2026-10-02T09:41:05Z", "confirmations": 16, "from": "0xe3b1c5a9f27d4e8b06c1a3f5d9e2b7c4a8f6d0e1", "to": "0x9d2a7e41c8b05f3e6a1d4c7b28e0f95a3b6c1d47", "currency": "USDT", "amount": "1250.75", "amount_raw": "1250750000000000000000", "decimals": 18, "contract_address": "0x55d398326f99059ff775485246999027b3197955" } }
Verify signatures
Every request carries an X-Webhook-Signature header: the hex-encoded HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret. Check it before you act on a request.
- Read the raw body exactly as it arrived. Parsing and re-encoding the JSON changes the bytes and breaks the signature.
- Compute the HMAC-SHA256 of that body with your signing secret, and hex-encode it.
- Compare the result with the header using a constant-time comparison. If they don't match, respond with
401and stop.
The signing secret is returned only when you create the webhook, so store it with your other credentials.
import crypto from 'node:crypto'; import express from 'express'; const app = express(); app.post( '/webhooks/chainhook', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.get('X-Webhook-Signature') ?? ''; const expected = crypto .createHmac('sha256', process.env.CHAINHOOK_SIGNING_SECRET) .update(req.body) .digest('hex'); const valid = signature.length === expected.length && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); if (!valid) { return res.sendStatus(401); } const event = JSON.parse(req.body); // Skip event.id if you've already processed it. res.sendStatus(200); }, );
Retries and replays
Respond with any 2xx status within 10 seconds to acknowledge a delivery. Any other status, a timeout, or a connection error counts as a failed attempt. Failed attempts are retried automatically, up to 3 attempts in total, waiting 1 minute, then 5 minutes between attempts.
Redirects aren't followed, so a 3xx response counts as a failure. Requests to private or reserved IP addresses are blocked and aren't retried.
When every attempt fails, the delivery is marked failed. You can send it again from the Deliveries page of your dashboard or with the replay endpoint. Replays are free.
Deliveries are sent at least once, so the same event can reach you more than once. The X-Webhook-Id header and the body's id stay the same across retries and replays: record the IDs you've handled and skip repeats. If your handler does slow work, queue it and respond right away.
Webhooks
A webhook watches one address on one network and sends matching transfers to your webhook URL. Use type and direction to choose which transfers match.
Attributes
idstring- Unique identifier for the webhook (UUID).
networkstring- The network being watched, e.g. "bsc".
typestring- "address", "native", or "token".
directionstring- "in", "out", or "any".
addressstring- The watched address.
webhook_urlstring- The URL that receives deliveries.
statusstring- "active", "paused", or "suspended". Webhooks are suspended while detection is paused, and resume on their own when it resumes.
suspension_reasonstring | null- Why the webhook is suspended, e.g. "Free allowance used. Subscribe to a plan to resume detection." Null when it isn't suspended.
secretstring- The signing secret. Only included in the response that creates the webhook.
created_atstring- When the webhook was created (UTC, ISO 8601).
updated_atstring- When the webhook last changed (UTC, ISO 8601).
The webhook object
{
"data": {
"id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"network": "bsc",
"type": "token",
"direction": "in",
"address": "0xaaaa000000000000000000000000000000000001",
"webhook_url": "https://api.example.com/webhooks",
"status": "active",
"suspension_reason": null,
"created_at": "2026-06-14T12:00:00Z",
"updated_at": "2026-06-14T12:00:00Z"
}
}List webhooks
GET/v1/webhooks
List your webhooks.
Requires the webhooks:read permission.
Query parameters
searchstring- Only return webhooks whose ID, address, webhook URL, network, transfer type, direction, or status starts with this term.
statusstring- "active", "paused", or "suspended".
networkstring- A network, e.g. "ethereum" or "bsc".
typestring- "address", "native", or "token".
directionstring- "in", "out", or "any".
Request
curl "https://api.chainhook.io/v1/webhooks?per_page=25" \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": [
{ "id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72", "network": "bsc", "status": "active", ... }
],
"links": { "first": null, "last": null, "prev": null, "next": "https://api.chainhook.io/v1/webhooks?cursor=eyJpZCI6Li4ufQ" },
"meta": { "path": "https://api.chainhook.io/v1/webhooks", "per_page": 25, "next_cursor": "eyJpZCI6Li4ufQ", "prev_cursor": null }
}Create a webhook
POST/v1/webhooks
Create a webhook. Returns 201 Created. The response includes the signing secret, which isn't returned again. While detection is paused, the webhook is created with the status "suspended".
Requires the webhooks:write permission.
Request body
networkstringRequired- An enabled network, e.g. "ethereum", "bsc", or "bitcoin".
typestringRequired- "address" (all transfers), "native" (native coin transfers), or "token" (token transfers). Supported coins and tokens vary by network.
directionstringRequired- "in" (incoming), "out" (outgoing), or "any" (both).
addressstringRequired- The address to watch. Up to 128 characters.
webhook_urlstringRequired- The public HTTPS URL that receives deliveries. Up to 2,048 characters.
secretstring- Signing secret, 32–128 characters. Generated for you if omitted, and returned only in the create response.
Request
curl -X POST https://api.chainhook.io/v1/webhooks \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{ "network": "bsc", "type": "token", "direction": "in", "address": "0xAaaa000000000000000000000000000000000001", "webhook_url": "https://api.example.com/webhooks" }'
Response
{
"data": {
"id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"network": "bsc",
"type": "token",
"direction": "in",
"address": "0xaaaa000000000000000000000000000000000001",
"webhook_url": "https://api.example.com/webhooks",
"status": "active",
"suspension_reason": null,
"created_at": "2026-06-14T12:00:00Z",
"secret": "N6x0cS2rUe4b8Wm1tQy9Zp3Lk5Hd7Fg0",
"updated_at": "2026-06-14T12:00:00Z"
}
}Get a webhook
GET/v1/webhooks/{webhook}
Retrieve a webhook.
Requires the webhooks:read permission.
Path parameters
webhookstringRequired- The ID of the webhook.
Request
curl https://api.chainhook.io/v1/webhooks/WEBHOOK_ID \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"network": "bsc",
"type": "token",
"direction": "in",
"address": "0xaaaa000000000000000000000000000000000001",
"webhook_url": "https://api.example.com/webhooks",
"status": "active",
"suspension_reason": null,
"created_at": "2026-06-14T12:00:00Z",
"updated_at": "2026-06-14T12:00:00Z"
}
}Update a webhook
PATCH/v1/webhooks/{webhook}
Pause or resume a webhook, or change its webhook URL.
Requires the webhooks:write permission.
Path parameters
webhookstringRequired- The ID of the webhook.
Request body
statusstring- "active" to resume the webhook, or "paused" to pause it. Resuming returns 422 at your plan's active webhook limit, or while detection is paused.
webhook_urlstring- A new public HTTPS URL.
Request
curl -X PATCH https://api.chainhook.io/v1/webhooks/WEBHOOK_ID \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": "paused" }'
Response
{
"data": {
"id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"network": "bsc",
"type": "token",
"direction": "in",
"address": "0xaaaa000000000000000000000000000000000001",
"webhook_url": "https://api.example.com/webhooks",
"status": "active",
"suspension_reason": null,
"created_at": "2026-06-14T12:00:00Z",
"updated_at": "2026-06-14T12:00:00Z"
}
}Delete a webhook
DELETE/v1/webhooks/{webhook}
Delete a webhook and its delivery history. Returns 204 No Content.
Requires the webhooks:write permission.
Path parameters
webhookstringRequired- The ID of the webhook.
Request
curl -X DELETE https://api.chainhook.io/v1/webhooks/WEBHOOK_ID \ -H "Authorization: Bearer YOUR_API_KEY"
Response
HTTP/1.1 204 No Content
Delete webhooks in bulk
POST/v1/webhooks/bulk-delete
Delete up to 1,000 webhooks at once. Returns the number of webhooks deleted.
Requires the webhooks:write permission.
Request body
idsstring[]Required- The IDs of the webhooks to delete.
Request
curl -X POST https://api.chainhook.io/v1/webhooks/bulk-delete \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ids": ["WEBHOOK_ID_1", "WEBHOOK_ID_2"] }'
Response
{ "deleted": 2 }Deliveries
A delivery is one detected transfer sent to one webhook URL. It keeps the payload, the number of attempts, and your endpoint's latest response, so you can see what happened and replay it.
Attributes
idstring- Unique identifier for the delivery (UUID). Sent to your endpoint as X-Webhook-Id.
webhook_idstring- The webhook that matched the transfer.
tx_hashstring- The transaction hash.
transfer_indexnumber- The position of the transfer within its transaction.
statusstring- "pending", "delivered", or "failed".
attemptsnumber- How many times the delivery has been sent.
response_codenumber | null- The HTTP status of your endpoint's latest response, or null if there isn't one yet.
response_bodystring | null- The body of your endpoint's latest response, or null.
delivered_atstring | null- When your endpoint accepted the delivery (UTC, ISO 8601), or null.
payloadobject- The event body sent to your endpoint.
created_atstring- When the transfer was detected (UTC, ISO 8601).
updated_atstring- When the delivery last changed (UTC, ISO 8601).
The delivery object
{
"data": {
"id": "019ebf94-1111-7000-aaaa-222233334444",
"webhook_id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"tx_hash": "0xabc...",
"transfer_index": 26,
"status": "delivered",
"attempts": 1,
"response_code": 200,
"response_body": "ok",
"delivered_at": "2026-06-14T12:00:05Z",
"payload": { "id": "019ebf94-1111-7000-aaaa-222233334444", "event": "transfer.detected", "data": { ... } },
"created_at": "2026-06-14T12:00:00Z",
"updated_at": "2026-06-14T12:00:05Z"
}
}List deliveries
GET/v1/deliveries
List deliveries.
Requires the deliveries:read permission.
Query parameters
searchstring- A status, network, direction, transfer type, currency, or HTTP status code, or the first 6 or more characters of a delivery ID, transaction hash, address, or webhook ID.
webhook_idstring- Only return deliveries for this webhook ID.
statusstring- "pending", "delivered", or "failed".
networkstring- A network, e.g. "ethereum" or "bsc".
directionstring- "in" or "out".
typestring- "native" or "token".
currencystring- A currency symbol, e.g. "USDT".
Request
curl "https://api.chainhook.io/v1/deliveries?status=failed" \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": [
{ "id": "019ebf94-1111-7000-aaaa-222233334444", "status": "failed", "attempts": 3, ... }
],
"links": { "first": null, "last": null, "prev": null, "next": null },
"meta": { "path": "https://api.chainhook.io/v1/deliveries", "per_page": 25, "next_cursor": null, "prev_cursor": null }
}Get a delivery
GET/v1/deliveries/{delivery}
Retrieve a delivery, including its payload and your endpoint's latest response.
Requires the deliveries:read permission.
Path parameters
deliverystringRequired- The ID of the delivery.
Request
curl https://api.chainhook.io/v1/deliveries/DELIVERY_ID \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"data": {
"id": "019ebf94-1111-7000-aaaa-222233334444",
"webhook_id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"tx_hash": "0xabc...",
"transfer_index": 26,
"status": "delivered",
"attempts": 1,
"response_code": 200,
"response_body": "ok",
"delivered_at": "2026-06-14T12:00:05Z",
"payload": { "id": "019ebf94-1111-7000-aaaa-222233334444", "event": "transfer.detected", "data": { ... } },
"created_at": "2026-06-14T12:00:00Z",
"updated_at": "2026-06-14T12:00:05Z"
}
}Replay a delivery
POST/v1/deliveries/{delivery}/replay
Send a delivered or failed delivery again. Returns 202 Accepted, or 409 Conflict while the delivery is still in progress. Replays are free.
Requires the deliveries:replay permission.
Path parameters
deliverystringRequired- The ID of the delivery.
Request
curl -X POST https://api.chainhook.io/v1/deliveries/DELIVERY_ID/replay \ -H "Authorization: Bearer YOUR_API_KEY"
Response
HTTP/1.1 202 Accepted
Get account stats
GET/v1/stats
Webhook and delivery counts, the delivery success rate, and your most recent deliveries.
Requires the account:read permission.
Request
curl https://api.chainhook.io/v1/stats \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"webhooks": { "total": 5, "active": 3, "paused": 1, "suspended": 1 },
"deliveries": { "total": 5, "pending": 1, "delivered": 3, "failed": 1 },
"success_rate": 75,
"recent_deliveries": [
{
"id": "019ebf94-1111-7000-aaaa-222233334444",
"webhook_id": "019ebf93-9c6a-7164-ba16-444f2e3aeb72",
"tx_hash": "0xabc...",
"status": "delivered",
"response_code": 200,
"created_at": "2026-06-14T12:00:00Z"
}
]
}Billing
Each account is on a plan with a monthly allowance of detections and a limit on active webhooks (see pricing). Each transfer that matches a webhook is one detection, counted once against your allowance when it's detected, even if your endpoint fails. Retries and replays are free.
Only active webhooks count toward your webhook limit; paused and suspended webhooks don't. At the limit, creating a webhook or setting a webhook's status to "active" fails with 422. If your plan changes to one with a lower limit, active webhooks over the new limit 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 past the allowance and bill extra detections at the plan's overage rate after the period ends. If you set a monthly overage cap, detection pauses at the cap until the next period.
While detection is paused, your active webhooks are suspended and new transfers aren't detected. Detections recorded before the pause are still delivered. New webhooks are created with the status "suspended" and a suspension_reason, and setting a webhook's status to "active" fails with 422. Suspended webhooks resume automatically when detection resumes; paused webhooks stay paused.
AI agents can read the current plan and usage with get-usage-tool on the MCP server.
Plans
free$0/month- 100 trial detections for 1 month. 3 active webhooks. $0.001 per detection after the trial.
starter$9/month or $90/year- 25,000 detections a month. 25 active webhooks. $0.0006 per extra detection.
growth$29/month or $290/year- 100,000 detections a month. 100 active webhooks. $0.0003 per extra detection.
scale$99/month or $990/year- 400,000 detections a month. 200 active webhooks. $0.0002 per extra detection.
get-usage-tool result
{
"plan": "free",
"plan_label": "Pay as you go",
"detections": 64,
"included": 100,
"remaining": 36,
"resets_at": "2026-11-01T00:00:00Z"
}MCP server
The MCP server lets AI agents and other tools that speak the Model Context Protocol manage your webhooks and deliveries. It runs at https://mcp.chainhook.io/mcp over streamable HTTP.
Clients that support OAuth only need that URL. The first time you connect, they open a browser window where you sign in to Chainhook and allow access. Other clients can send an API key in the Authorization header instead.
An API key needs the mcp:use permission to connect, and the server lists only the tools its other permissions allow. Apps you connect by signing in can use every tool.
Every tool acts only on your account. Connected apps are listed on the API keys page of your dashboard, where you can revoke their access.
Tools and required permissions
list-webhooks-toolwebhooks:read- List your webhooks, with the same filters and cursor pagination as the REST API.
get-webhook-toolwebhooks:read- Retrieve a webhook by ID.
create-webhook-toolwebhooks:write- Create a webhook. The signing secret is returned only in this result.
update-webhook-toolwebhooks:write- Pause or resume a webhook, or change its webhook URL.
delete-webhook-toolwebhooks:write- Delete a webhook and its delivery history.
bulk-delete-webhooks-toolwebhooks:write- Delete up to 1,000 webhooks at once.
list-deliveries-tooldeliveries:read- List deliveries, with the same filters and cursor pagination as the REST API.
get-delivery-tooldeliveries:read- Retrieve a delivery, including its payload.
replay-delivery-tooldeliveries:replay- Send a delivered or failed delivery again.
get-stats-toolaccount:read- Webhook and delivery counts, the success rate, and recent deliveries.
get-usage-toolaccount:read- Your plan and usage this period: plan, plan_label, detections used, detections included, detections remaining before detection pauses (null when overage is unlimited), and resets_at.
- Run the command. Add
--scope userto use it in every project. - In Claude Code, run
/mcp, choose chainhook, and sign in.
Terminal
claude mcp add --transport http chainhook https://mcp.chainhook.io/mcp