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

# Process Webhooks

Receive signed AntiVamp events — verify the HMAC signature against the raw body before parsing, reject replays, and process idempotently.

> **Verify the signature against the raw body — before you parse anything.**

Webhooks keep your UI and backend in sync with the network: reservations, launches, and protection lifecycle changes are delivered as **signed events**. Every consumer must verify the HMAC signature before trusting a payload.

## Register an endpoint

`POST /v1/webhooks` with a Bearer key returns the endpoint plus a **signing secret shown once**. Store it server-side.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.antivamp.io/api/v1/webhooks \
  -H "Authorization: Bearer $ANTIVAMP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://yourlaunchpad.io/webhooks/antivamp", "events": ["token.bonded"] }'
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "id": "wh_…",
  "url": "https://yourlaunchpad.io/webhooks/antivamp",
  "signingSecret": "whsec_…"
}
```

{% endtab %}
{% endtabs %}

Omit `events` to receive all event types. **HTTPS is required.** Webhook URLs must resolve to public addresses — private, loopback, link-local, and cloud-metadata IPs are rejected at registration and again at delivery (DNS rebinding defense). Localhost endpoints are only accepted when you run the API locally (`next-dev`); they are rejected on `sandbox-api.antivamp.io` and `api.antivamp.io` (a localhost URL on those hosts would target AntiVamp’s server, not yours). Use a public HTTPS tunnel (e.g. ngrok) for local receiver testing against the hosted APIs.

## The envelope

```json
{ "id": "<deliveryId>", "type": "token.bonded", "createdAt": "…Z", "data": { … } }
```

## The signature

The header carries a timestamp and an HMAC-SHA256 signature:

```
X-AntiVamp-Signature: t=<unix>,v1=<hmac-sha256 hex over "<t>.<rawBody>">
```

That is `v1 = HMAC_SHA256(secret, "<t>.<rawBody>")`. Verify against the **raw** request body — never a re-serialized copy.

## Consumer requirements

A correct consumer **must**, in order:

1. Read the **raw** request body (do not let a framework parse it first).
2. **Verify the signature before parsing** the JSON.
3. Check the timestamp is within your tolerance (≤5 minutes) to reject stale deliveries.
4. **Reject replayed event IDs** — track processed `id` values and ignore duplicates.
5. **Process idempotently** so a legitimate retry has no side effects.
6. Return a **2xx promptly**; queue slow work instead of blocking the response.

```ts
import { AntiVampClient } from "@antivamp_io/sdk";
import express from "express";

const antivamp = new AntiVampClient({ apiKey: process.env.ANTIVAMP_API_KEY });

app.post("/webhooks/antivamp", express.raw({ type: "*/*" }), (req, res) => {
  const raw = req.body.toString("utf8");
  const sig = req.header("X-AntiVamp-Signature") ?? "";

  // 1–2: verify against the RAW body before parsing.
  if (!antivamp.verifyWebhook(process.env.WH_SECRET, raw, sig)) {
    return res.sendStatus(400);
  }

  const event = JSON.parse(raw);

  // 4: reject replays by delivery id.
  if (alreadyProcessed(event.id)) return res.sendStatus(200);

  // 6: acknowledge fast, queue the slow work.
  enqueue(event);
  markProcessed(event.id);
  return res.sendStatus(200);
});
```

{% hint style="danger" %}
🚨 **Never parse the body before verifying the signature.** Re-serializing or trusting an unverified payload defeats the HMAC entirely. Reject anything that fails verification with a `400`.
{% endhint %}

## Delivery, retries & replay

Deliveries are recorded with status and attempt count on a durable queue. On failure AntiVamp retries up to **5 attempts** with a fixed backoff schedule — **1m → 5m → 30m → 2h → 12h** — after which the delivery moves to a **dead-letter** state. Dead deliveries remain in history and can still be **replayed** manually (a replay reuses the same delivery id).

| Action                   | Endpoint                                   |
| ------------------------ | ------------------------------------------ |
| List deliveries          | `GET /v1/webhooks/deliveries`              |
| Replay a delivery        | `POST /v1/webhooks/deliveries/{id}/replay` |
| Send a signed test event | `POST /v1/webhooks/test`                   |
| Update / rotate secret   | `PATCH /v1/webhooks/{id}`                  |
| Delete an endpoint       | `DELETE /v1/webhooks/{id}`                 |

Retries and replays reuse the same delivery `id`, so idempotent processing by `id` is what keeps duplicates harmless.

`PATCH` and `DELETE` on `/v1/webhooks/{id}` return `404 webhook_not_found` when the id does not exist **or belongs to another partner** — a delete against someone else's endpoint never reports success.

## Event types

Subscribe to specific events at registration, or omit `events` to receive all of them:

| Event                      | Fires when                                                                                                                           |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `reservation.created`      | A reservation is confirmed for a name + ticker pair                                                                                  |
| `reservation.expiring`     | A reservation is approaching its expiry                                                                                              |
| `reservation.expired`      | A reservation window ended without a launch                                                                                          |
| `identity.protected`       | An identity entered a protected state                                                                                                |
| `identity.extended`        | A protection window was extended                                                                                                     |
| `identity.blocked_attempt` | A launch attempt was blocked against a protected identity                                                                            |
| `launch.authorized`        | A launch was validated for the authorized wallet                                                                                     |
| `launch.blocked`           | A launch validation returned `block`                                                                                                 |
| `launch.reported`          | A partner reported a successful launch                                                                                               |
| `token.bonded`             | A bond event applied the first market-cap lock                                                                                       |
| `milestone.verified`       | A milestone event applied the extended lock                                                                                          |
| `identity.cleared`         | A guardian cleared a prior block                                                                                                     |
| `chain.degraded`           | A chain's data path degraded (fail-closed posture)                                                                                   |
| `revenue.accrued`          | Your partner share accrued after on-chain confirmation — see [Partner Program & Revenue Sharing](/for-launchpads/partner-program.md) |

{% hint style="info" %}
📡 View the machine-readable endpoint reference at [AntiVamp API](https://antivamp.io/api).
{% endhint %}

***

## Continue exploring

* ♻️ [Implement Idempotency](/for-launchpads/idempotency.md) — the same discipline for your outbound calls
* 📈 [Report Bonding & Milestones](/for-launchpads/report-milestones.md) — the events that trigger `token.bonded` / `milestone.verified`
* ✅ [Production Checklist](/for-launchpads/production-checklist.md) — webhook verification is a go-live gate
* 📦 [SDK Reference](/developers/sdk.md) — `verifyWebhook`
* 🆘 [Partner Troubleshooting](/for-launchpads/troubleshooting.md) — debugging delivery failures


---

# 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://docs.antivamp.io/for-launchpads/process-webhooks.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.
