Docs

Getting started

Six steps from sign-up to verifying signatures on the receiving side.

1. Sign up

Sign up at https://app.webhookadmin.com/signup with your email address, Google or GitHub. With email, we send you a sign-in link that is valid for 15 minutes.

On your first sign-in, create an organization (your company or team). Plans, billing and members belong to the organization.

2. Project

Create one project per sending service. Each project has two environments: production and test.

EnvironmentAPI keyMessages
Productionsk_live_…Count toward your monthly limit and billing
Testsk_test_…Not counted

3. API key

Create keys per environment under “API keys” in the dashboard. The key is shown once, when you create it. Choose from five scopes.

ScopeAllows
messages:sendSending messages
messages:retryRetrying deliveries
logs:readReading logs, consumers and endpoints
endpoints:writeCreating, updating and deleting endpoints; rotating signing secrets
consumers:writeCreating consumers

Keys expire after 30 days, 90 days, 1 year or never. Owners and admins get an email 7 days before a key expires.

The samples on this page read the key from the WEBHOOK_ADMIN_API_KEY environment variable.

export WEBHOOK_ADMIN_API_KEY=sk_test_…

4. Consumer and endpoint

A consumer is the company or user who receives your webhooks. Set external_id to the ID you use for that customer in your service.

curl https://api.webhookadmin.com/v1/consumers \
  -H "Authorization: Bearer $WEBHOOK_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "external_id": "cus_1024", "name": "Acme Inc." }'

Register the URL that receives webhooks as an endpoint of that consumer. The secret in the response (the signing secret, starting with whsec_) is returned only here. The receiver uses it to verify signatures.

curl https://api.webhookadmin.com/v1/endpoints \
  -H "Authorization: Bearer $WEBHOOK_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "consumer_id": "con_…",
    "url": "https://example.com/webhooks",
    "event_types": ["invoice.paid"]
  }'
  • URLs must use https on port 443 or 8443. URLs with a raw IP address and names that resolve to private addresses are rejected.
  • Leave out event_types to receive every event.
  • Set fixed_ip: true to deliver from the static source IP 209.71.107.233. Ask the receiver to allow this IP.

5. Send

Send the consumer’s external_id, the event type and the payload to POST /v1/messages. Every endpoint of that consumer that accepts the event receives it.

curl https://api.webhookadmin.com/v1/messages \
  -H "Authorization: Bearer $WEBHOOK_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv_88-paid" \
  -d '{
    "consumer": "cus_1024",
    "event_type": "invoice.paid",
    "payload": { "invoice_id": "inv_88", "amount": 128000 }
  }'
Response
HTTP/1.1 202 Accepted

{ "id": "msg_…", "deliveries": 1 }
  • Requests with the same Idempotency-Key return the first id for 24 hours and create no second message.
  • If no consumer has that external_id, one is created on the spot (with no endpoints, so deliveries is 0).
  • Check delivery under “Logs” in the dashboard or with GET /v1/messages/{id}.

6. Verify the signature

Every delivery is signed in the Standard Webhooks format, so receivers can verify it with the official libraries. Headers and the signing scheme are described in Signature verification.

npm install standardwebhooks express
Node.js (Express)
import express from 'express';
import { Webhook } from 'standardwebhooks';

const wh = new Webhook(process.env.WEBHOOK_SECRET); // whsec_…
const app = express();

// Verify against the raw body, before any JSON parsing
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = wh.verify(req.body, req.headers);
    console.log(event.type, event.data);
    res.sendStatus(200);
  } catch {
    res.sendStatus(400);
  }
});

app.listen(3000);

Set WEBHOOK_SECRET to the whsec_… you received in step 4.