HTTP API

Publish events over plain HTTPS: one endpoint, an idempotency key, and clear status codes.

Every SDK publishes through one HTTPS endpoint. Most applications use a generated client and never call it directly, but it is all you need from a language without an SDK, a script, or curl.

Publish an event

curl -X POST https://api.repost.sh/v1/messages \
  -H "Authorization: Bearer $REPOST_SEND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1001" \
  -d '{
    "type": "order.created",
    "customerId": "acme",
    "data": { "id": "order-1001", "currency": "EUR" }
  }'
FieldRequiredMeaning
typeYesThe event type, as deployed from your schema (order.created).
customerIdYesThe customer's externalId.
dataYesThe payload, shaped by the event's model.
timestampNoRFC 3339 (2026-07-02T12:00:00Z). Defaults to now.

Authentication is a Bearer token with the publish scope. The Idempotency-Key header (up to 255 characters) is optional but recommended; it is what makes retries safe.

A successful publish returns 202 Accepted with the message:

{
  "id": "msg_01JZX3NV7Q9WD9F2M6K4T8RSAB",
  "type": "order.created",
  "customerId": "acme",
  "timestamp": "2026-07-17T12:00:00.000Z"
}

202 means Repost has stored the event durably and will deliver it. Fan-out, signing, and retries happen after this point and are covered under delivery.

Idempotency

To make sure an event is sent exactly once even when your side crashes and retries, set an idempotency key that names the business fact, such as order-1001-created, rather than a random value per attempt. Repost remembers each key for 10 minutes. The key alone identifies the publish; the body is not compared:

  • The same key again within those 10 minutes answers 409 with the first message's id, and the body of the second call is discarded — changed bytes included.
  • The same key while the first publish is still in flight is held for up to 6 seconds and then answered the same way.
  • After 10 minutes the key is forgotten. The same key then publishes a new message with a new id, so a retry that arrives later than that delivers the event a second time.

A 409 names the message that already exists. Read the id and treat the call as done:

{ "error": "duplicate", "id": "msg_01JZX3NV7Q9WD9F2M6K4T8RSAB" }

With stable keys, queue redeliveries, crashed workers, and timeout-retry loops inside that window all collapse into a single delivered event. The SDKs already do this: they mint one key per send, reuse it across their own retries, and turn the 409 into the original result.

Status codes

StatusMeaningWhat to do
202Accepted.Done.
400Missing or invalid field, bad timestamp, oversized key, or invalid JSON.Fix the request.
401 / 403Bad token, or missing the publish scope for this environment.Fix credentials.
409This idempotency key already published; the body carries that message's id.Done. Use the id.
413Payload over 256 KiB (the same cap as the Receive webhook receiver).Send references instead of blobs.
429Environment rate limit (Retry-After: 1).Back off and retry.
503Temporarily unable to accept messages (Retry-After: 2).Retry with backoff, same key.

Retry 429, 503, and network failures, always with the same idempotency key. 409 is not a failure: the event is already published. The other errors indicate a problem in the request itself.

Continue