Documentation

EventInbox Documentation

Quickstart — your first webhook in 5 minutes

  1. Sign up at app.eventinbox.pro and create a workspace.
  2. Create an endpoint (dashboard → Endpoints → New): give it a name and the destination URL where you want events delivered. You get an ingest URL of the form:
    https://api.eventinbox.pro/in/{workspace-slug}/{endpoint-name}
  3. Send your first event — POST any JSON to that ingest URL:
    curl -X POST https://api.eventinbox.pro/in/your-workspace/your-endpoint \
      -H "Content-Type: application/json" \
      -H "x-ei-event-type: payment.succeeded" \
      -d '{"id":"pi_123","amount":4200}'
    Response (202):
    {"event_id":"...","delivery_id":"...","status":"accepted","received_at":"..."}
  4. Watch it deliver — open the dashboard. The event flows through the worker, gets signed, and is delivered to your endpoint with automatic retries on failure. Or click "Send test event" on any endpoint to fire a sample through the pipeline.

Core concepts

  • Event — a JSON payload you POST to an ingest URL. EventInbox stores it and creates a delivery.
  • Endpoint — a destination URL that receives your events, with its own signing secret and retry config (default: 12 attempts, 5 max concurrency, 10s timeout).
  • Delivery — one event being sent to one endpoint. Tracks status (pending/processing/delivered/failed), attempt count, and the next retry time.
  • Attempt — a single HTTP POST to your endpoint, recording response status, duration, and any error.

Delivery & retries

Every event is delivered at-least-once. On failure (non-2xx response, timeout, or connection error), EventInbox retries with exponential backoff — up to 12 attempts over roughly 72 hours by default. After the final attempt the delivery is marked failed and moves to the dead-letter queue, where you can replay it anytime from the dashboard. Configure max_attempts and timeout_seconds per endpoint.

Verifying webhook signatures

EventInbox signs every delivery using the Standard Webhooks specification (standardwebhooks.com) — the same scheme used by OpenAI, Stripe, and others. Each delivery includes three headers:

  • webhook-id — unique delivery id
  • webhook-timestamp — unix timestamp
  • webhook-signature — base64 HMAC-SHA256 over {id}.{timestamp}.{payload}

Verify with the official library — no EventInbox SDK required:

Node

import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.WEBHOOK_SECRET); // your endpoint's whsec_ secret
const payload = wh.verify(rawBody, {
  "webhook-id": req.headers["webhook-id"],
  "webhook-timestamp": req.headers["webhook-timestamp"],
  "webhook-signature": req.headers["webhook-signature"],
});

Python

from standardwebhooks import Webhook
wh = Webhook(webhook_secret)  # your endpoint's whsec_ secret
payload = wh.verify(raw_body, headers)

Go

import standardwebhooks "github.com/standard-webhooks/standard-webhooks/libraries/go"
wh, _ := standardwebhooks.NewWebhook(webhookSecret)
err := wh.Verify(payload, headers)

The legacy x-ei-* headers are still sent for backward compatibility.

API reference

  • Base URL: https://api.eventinbox.pro
  • Auth: Bearer JWT (from signin) OR an API key in the x-api-key header.

Ingress (no auth)

  • POST /in/{workspace}/{endpoint} — send an event. Optional headers x-ei-event-type, x-ei-idempotency-key. Returns 202.

Endpoints

  • GET /api/v1/endpoints — list
  • POST /api/v1/endpoints — create (name, destination_url, optional max_attempts, max_concurrency, timeout_seconds)
  • GET|PUT|DELETE /api/v1/endpoints/{id}
  • POST /api/v1/endpoints/{id}/enable | /disable | /rotate-secret | /test-event

Events

  • GET /api/v1/events (filters: event_type, endpoint_id, status, limit)
  • GET /api/v1/events/{id}
  • POST /api/v1/events/{id}/replay

Deliveries

  • GET /api/v1/deliveries (filters: status, endpoint_id, limit)
  • GET /api/v1/deliveries/{id}
  • GET /api/v1/deliveries/{id}/attempts
  • POST /api/v1/deliveries/{id}/replay

Settings

  • GET|POST /api/v1/settings/api-keys
  • DELETE /api/v1/settings/api-keys/{id}