Quickstart
Go from zero to a delivered, signed webhook in a few minutes. No DNS, no infrastructure.
Zero setup
A new organization is live immediately on the shared ingest domain (<ingest-domain> — a placeholder; the real name is config-driven) — both your webhook URLs and email aliases work right away, with TLS and DKIM already in place. Bringing your own domain is optional (see Custom domains).
1. Get an API key
Create an organization, then copy a key from Settings → API Keys in the console. Keys are scoped (read, write, admin).
export EK_KEY="ek_live_xxxxxxxxxxxxxxxx"2. Create a destination
A destination is where delivered events go — an HTTPS URL or a queue. Define it once; reference it by id everywhere.
curl -X POST https://api.emithook.com/v1/destinations \
-H "Authorization: Bearer $EK_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "acme-orders",
"type": "https",
"url": "https://api.acme.in/hooks/orders"
}'// → 201 Created — pending validation
{ "id": "dst_01JX9...", "name": "acme-orders", "validation": "pending" }A destination is created pending and must pass three checks — schema, credentials, and a connectivity test — before it can receive traffic (validation becomes valid). For queue destinations, the console's guided flow hands you the exact IAM/queue policy to grant. See Concepts → Destinations.
3. Send your first event
curl -X POST https://api.emithook.com/v1/send \
-H "Authorization: Bearer $EK_KEY" \
-H "Idempotency-Key: inv_001" \
-H "Content-Type: application/json" \
-d '{
"destination": "dst_01JX9...",
"event_type": "invoice.created",
"payload": { "id": "INV-2026-001", "amount": 4999, "currency": "INR" }
}'// → 202 Accepted
{ "message_id": "msg_01JX9..." }The event is now signed, queued, and delivered with automatic retries. Watch it land in Delivery Logs in the console, or tail it from the CLI:
npm i -g @emithook/cli
emithook logs tail --destination acme-orders4. Verify the signature (receiver side)
Every outbound delivery is signed with the open Standard Webhooks scheme (webhook-id, webhook-timestamp, webhook-signature). Verify it with any off-the-shelf library:
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.WHSEC); // whsec_… from the destination
app.post("/hooks/orders", (req, res) => {
const event = wh.verify(req.rawBody, req.headers); // throws if invalid
handle(event);
res.sendStatus(200);
});Bring your own domain (optional)
Want webhooks on your own hostname or email on your own domain? Add it under Domains — Emithook issues the DNS records (CNAME for webhooks via Cloudflare for SaaS, MX + SPF/DKIM/DMARC for email via SES) and verifies automatically. Until then, everything runs on the shared ingest domain.
Next steps
- Core concepts — endpoints, destinations, signing, retries.
- Receive a Shopify webhook — a full inbound walkthrough.
- API reference — every endpoint, with a Postman collection.