Skip to content

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:

PatternUse it whenHow it resolves
Direct sendOne-off / system-to-system push, no event mapping.POST /v1/send names a registered destination id or a validated HTTPS URL.
Static fan-outAn 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:

bash
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" }
  }'
json
// → 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):

typeBrokerFIFO within a groupDelivery countConformance
sqsAWS SQSFIFO queues (MessageGroupId)ApproximateReceiveCountCI (ElasticMQ)
natsNATS JetStreamstream orderJetStream redelivery countCI
redisRedis Streamsstream orderXCLAIM delivery countCI
amqpRabbitMQqueue orderquorum-queue x-delivery-countCI (RabbitMQ)
kafkaApache Kafkaper-key partition orderadapter-tracked per offsetCI (Redpanda)
pubsubGoogle Pub/Submessage ordering (orderingKey)deliveryAttempt (via DLQ policy)CI (emulator)
azureAzure Service Busqueue orderdeliveryCountconformance-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:

bash
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" } }'
json
// → 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.

Receiving side (your customers)

Every delivery is signed with Standard Webhooks, so your customers verify with any off-the-shelf library — verifying against the raw body. See signing.

Next

Apache-2.0 licensed · a Finnoto product