> For the complete documentation index, see [llms.txt](https://developers.coincircuit.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.coincircuit.io/webhooks/readme.md).

# Webhooks

Receive real-time event notifications for invoices, payments, transactions, payouts, and refunds.

Receive real-time event notifications when invoice, payment, transaction, payout, and refund states change.

Use webhooks to keep your system in sync without polling.

### Webhook references

Choose a page for the event family you need:

<table data-view="cards"><thead><tr><th>Reference</th><th>Description</th><th data-card-target data-type="content-ref">Page</th></tr></thead><tbody><tr><td>Payments</td><td>Payment session lifecycle events.</td><td><a href="/webhooks/readme/payments.md">Payments</a></td></tr><tr><td>Invoices</td><td>Invoice creation, payment, updates, and expiry.</td><td><a href="/webhooks/readme/invoices.md">Invoices</a></td></tr><tr><td>Transactions</td><td>On-chain transaction detection and confirmation.</td><td><a href="/webhooks/readme/transactions.md">Transactions</a></td></tr><tr><td>Payouts</td><td>Outgoing payout events.</td><td><a href="/webhooks/readme/payouts.md">Payouts</a></td></tr><tr><td>Refunds</td><td>Refund creation, completion, and failure.</td><td><a href="/webhooks/readme/refunds.md">Refunds</a></td></tr></tbody></table>

### Before you go live

* Verify the webhook signature on every request.
* Return a `2xx` response as soon as you accept the event.
* Use `X-CoinCircuit-Delivery-Id` to handle retries safely.

{% hint style="info" %}
Process webhook deliveries asynchronously when possible.

Store the delivery ID and ignore duplicates.
{% endhint %}

### Event flow

Most payment flows follow this order:

1. `transaction.received`
2. `transaction.confirmed`
3. One of the payment events
4. Any follow-up invoice, payout, or refund events

Use transaction events for blockchain state.

Use payment and invoice events for business state.

### Delivery format

All webhook deliveries are sent as `POST` requests to your webhook endpoint.

#### Standard headers

| Header                      | Description                                 |
| --------------------------- | ------------------------------------------- |
| `X-CoinCircuit-Event`       | Event name for the current delivery.        |
| `X-CoinCircuit-Delivery-Id` | Unique ID for this delivery attempt.        |
| `X-CoinCircuit-Signature`   | HMAC-SHA256 signature for the request body. |
| `X-CoinCircuit-Timestamp`   | Unix timestamp used during signing.         |

#### Retry behavior

If your endpoint does not return a `2xx` response, delivery is retried with backoff.

Build handlers to be idempotent.

Use the delivery ID to detect duplicates safely.

### Verify signatures

Verify signatures against the raw request body.

Reject invalid requests before you process the payload.

{% tabs %}
{% tab title="Verify signature" %}

```javascript
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret, timestamp) {
  try {
    const signedPayload = timestamp ? `${timestamp}.${payload}` : payload;
    const expectedSignature = crypto
      .createHmac('sha256', secret)
      .update(signedPayload, 'utf8')
      .digest('hex');

    return crypto.timingSafeEqual(
      Buffer.from(signature, 'hex'),
      Buffer.from(expectedSignature, 'hex')
    );
  } catch (_) {
    return false;
  }
}
```

{% endtab %}

{% tab title="Use in an endpoint" %}

```javascript
const payload = rawBody;
const signature = req.headers['x-coincircuit-signature'];
const timestamp = req.headers['x-coincircuit-timestamp'];
const secret = 'whsec_...';

if (!verifyWebhookSignature(payload, signature, secret, timestamp)) {
  return res.status(401).json({ error: 'Invalid signature' });
}

return res.status(200).json({ received: true });
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Use the raw request body for signature verification.

Do not reformat the JSON before calculating the HMAC.
{% endhint %}

### Shared payload shape

Every delivery includes:

* `event` — the event name
* `data` — the event payload

The object inside `data` changes by event family:

* invoice events use `data.invoice`
* payment events use `data.session`
* transaction events use `data.transaction` and `data.session`
* payout events use `data.payout`
* refund events use `data.refund`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers.coincircuit.io/webhooks/readme.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
