Send webhooks
Available — including the application/subscription model & the consumer portal.The Send side: emit your own events as webhooks-as-a-service. You don't run delivery infrastructure — Emithook signs, retries, circuit-breaks, logs, and archives every send through the same engine the relay uses. Only the ingress differs.
Three ways to resolve a destination
All three share signing, retry/backoff, the per-destination circuit breaker, SSRF protection, DLQ, and logs. They differ only in how the target is chosen:
| Pattern | Use it when | How it resolves |
|---|---|---|
| Direct send | One-off / system-to-system push, no event mapping. | POST /v1/send names a registered destination id or a validated HTTPS URL. |
| Static fan-out | An event always goes to the same place(s). | An event type → a fixed route set. |
| Per-tenant (applications) | A multi-tenant product where each customer wants their own URL/queue for the same event. | app_id = your end-customer's id; POST /v1/app/{id}/event resolves that tenant's endpoints. |
Direct send
The simplest path — one call delivers one payload:
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..." }Send Idempotency-Key so client retries can't double-deliver. See the Quickstart for the end-to-end version.
Queue and broker destinations
A destination doesn't have to be an HTTPS URL — it can be a message broker. The same engine (signing context, retry/backoff, per-destination circuit breaker, DLQ, logs) applies; only the final hop changes: instead of an HTTP POST, the event is published to the broker. One adapter class per broker implements the same QueuePort (publish and consume), so a broker can be both a delivery target and an ingestion source.
Every adapter passes the same shared QueuePort conformance suite (publish/receive, ack removes, nack redelivers with an incrementing delivery count, FIFO within a group, consume() auto-ack, health):
type | Broker | FIFO within a group | Delivery count | Conformance |
|---|---|---|---|---|
sqs | AWS SQS | FIFO queues (MessageGroupId) | ApproximateReceiveCount | CI (ElasticMQ) |
nats | NATS JetStream | stream order | JetStream redelivery count | CI |
redis | Redis Streams | stream order | XCLAIM delivery count | CI |
amqp | RabbitMQ | queue order | quorum-queue x-delivery-count | CI (RabbitMQ) |
kafka | Apache Kafka | per-key partition order | adapter-tracked per offset | CI (Redpanda) |
pubsub | Google Pub/Sub | message ordering (orderingKey) | deliveryAttempt (via DLQ policy) | CI (emulator) |
azure | Azure Service Bus | queue order | deliveryCount | conformance-ready — not CI-verified |
Azure Service Bus
The Azure adapter is implemented against the same contract and ships with the identical conformance suite, but there is no lightweight Service Bus emulator that supports dynamic queue creation, so the suite is gated on AZURE_SERVICEBUS_TEST_URL and skipped in CI. Point that variable at a real namespace to run the full contract end to end.
Broker connection details live in the destination's stored configuration, not in environment variables — only the self-host ingest/delivery backbone (QueuePort) is env-configured. See self-hosting.
The application / subscription model Available
Turn Emithook into "webhooks for your product." Register each of your end-customers as an Application (keyed by your own id), each holding endpoints (URL/queue + event-type filter + its own signing secret). Then fan out:
curl -X POST https://api.emithook.com/v1/app/cust_8f2a/event \
-H "Authorization: Bearer $EK_KEY" \
-d '{ "event_type": "invoice.created", "payload": { "id": "INV-1" } }'// → 202 Accepted — fanned out to every matching endpoint
{ "message_id": "msg_01JX9...", "fanout": 3 }Applications can be lazily auto-created on first send. The data model (Environment → Application → Endpoint, plus Message/Attempt/EventType) is defined in the glossary.
Consumer portal Available
Your end-customers manage their own endpoints, view delivery logs, replay failures, browse the event catalog, and rotate their secret — in an embeddable, white-label portal scoped to one application via a magic link, with no Emithook account. This is what offloads webhook support from your team to theirs.
Delivery envelope
Every delivery — to any destination (HTTPS, SQS, or another queue) — carries the original request, not just its body, so a consumer of a shared destination can tell who sent an event and why:
{
"url": "https://wh.emithook.com/acme-orders",
"method": "POST",
"headers": { "content-type": "application/json", "stripe-signature": "t=…,v1=…" },
"data": "{\"id\":\"evt_123\",\"amount\":4999}",
"received_at": "2026-07-21T00:25:52.943Z"
}datais the original body as a verbatim string —JSON.parse(data)to get the object. Keeping it exact means you can still verify the source's own signature (forwarded inheaders) against it.headersare the inbound headers, minus secrets we won't relay (authorization,cookie,set-cookie,proxy-authorization).urlis the full inbound URL — the key to routing on the consumer side when many webhooks fan into one destination.
url, headers, and data are values the source supplied — treat them as untrusted input, exactly as you would the raw body.
When a transform runs, the delivered payload is your transform's output with the original request attached under an original block (same five fields). original is a reserved key: if your transform output already has an original field, the platform's block replaces it.
Receiving side (your customers)
Every delivery is signed with Standard Webhooks, so your customers verify with any off-the-shelf library — against the exact delivered bytes as received (the envelope above), not a re-parsed copy. See signing.
Send transactional email
The Send side isn't only webhooks. The same accept → queue → deliver → retry → DLQ → replay engine sends transactional email through Amazon SES, with delivery-truth analytics (sent → delivered, bounce/complaint tracking, an org suppression list, per-message timelines). See Send email.
Next
- Send email — transactional email through the same engine.
- API conventions — idempotency, scopes, errors, retry schedule.
- Receive webhooks — the inbound half.
- API reference · MCP server