API reference

Human-readable reference for the Outemit REST API. Auth with Bearer sk_test_ or sk_live_. Base URL https://outemit.dev.

Fire real test requests with a key in the playground.

Open playgroundOpen raw OpenAPI

Authentication

Authenticate with a Bearer API key. Keys are livemode-scoped: sk_test_... for Test and sk_live_... for Live. Base URL https://outemit.dev.

Authorization
Authorization: Bearer sk_test_...

Common headers

HeaderRequiredDescription
AuthorizationYesBearer sk_test_... or sk_live_...
Content-TypeOn JSON bodiesapplication/json
Idempotency-KeyRecommended on emitDedupes POST /api/v1/messages

Idempotency

On create message, pass Idempotency-Key (header preferred). Identical keys within the retention window return the original message and delivery ids instead of creating duplicates.

Error envelope

Errors use a consistent JSON envelope. Include request_id when contacting support.

  • 400 validation / invalid body
  • 401 missing or invalid API key
  • 404 resource missing in this environment
  • 409 conflict (for example duplicate uid)
  • 429 rate limited
  • 5xx transient; retry emits with Idempotency-Key
Error
{
  "error": {
    "code": "invalid_request",
    "message": "app_id is required",
    "request_id": "req_..."
  }
}

Messages

List messages

GET/api/v1/messages

Returns up to 50 recent messages for the API key organization (livemode-scoped). Payload bytes live in object storage; this list returns metadata.

Response fields

FieldTypeDescription
objectstringAlways "list"
dataMessage[]Recent messages, newest first

Errors

  • 401·Missing or invalid API key
bash
curl -X GET https://outemit.dev/api/v1/messages \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "object": "list",
  "data": [
    {
      "id": "evt_01HABC",
      "event_type": "invoice.paid",
      "app_id": "app_01HXYZ",
      "created_at": "2026-09-05T12:00:00.000Z"
    }
  ]
}

Create a message

POST/api/v1/messages

Accept a payload for an application, persist the immutable message, and fan out deliveries to subscribed endpoints. Safe to retry with the Idempotency-Key header.

Headers

NameTypeRequiredDescription
Idempotency-KeystringNoDedupes identical emit calls within the retention window

Request body

NameTypeRequiredDescription
app_idstringYesTarget application (app_...)
event_typestringYesCatalog name such as invoice.paid
payloadobjectYesJSON object delivered to receivers
idempotency_keystringNoOptional body alias for Idempotency-Key

Response fields

FieldTypeDescription
idstringMessage id (evt_...)
event_typestring
app_idstring
delivery_idsstring[]Deliveries enqueued for this emit
idempotentbooleanTrue when this was a replay of a prior emit

Errors

  • 400·Invalid body or unknown event_type
  • 401·Missing or invalid API key
  • 404·Application not found in this environment
  • 429·Rate limited
bash
curl -X POST https://outemit.dev/api/v1/messages \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: demo-1" \
  -H "Content-Type: application/json" \
  -d '{ "app_id": "app_01HXYZ", "event_type": "invoice.paid", "payload": { "id": "inv_1", "amount": 4900 }}'
Response
{
  "id": "evt_01HABC",
  "event_type": "invoice.paid",
  "app_id": "app_01HXYZ",
  "delivery_ids": ["dlv_01HDEF"],
  "idempotent": false
}

Retrieve a message

GET/api/v1/messages/{id}

Fetch message metadata. Payload bytes live in object storage; this returns ids, type, and timestamps.

Path parameters

NameTypeRequiredDescription
idstringYesMessage id (evt_...)

Response fields

FieldTypeDescription
idstring
event_typestring
app_idstring
created_atstringISO-8601 timestamp

Errors

  • 401·Unauthorized
  • 404·Message not found
bash
curl -X GET https://outemit.dev/api/v1/messages/evt_01HABC \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "id": "evt_01HABC",
  "event_type": "invoice.paid",
  "app_id": "app_01HXYZ",
  "created_at": "2026-09-05T12:00:00.000Z"
}

Replay a message

POST/api/v1/messages/{id}/replay

Re-run the message through the pipeline for currently subscribed endpoints. Creates NEW delivery rows. Distinct from retry on a delivery.

Path parameters

NameTypeRequiredDescription
idstringYesMessage id (evt_...)

Response fields

FieldTypeDescription
message_idstring
delivery_idsstring[]New deliveries created by this replay
statusstringTypically "enqueued"

Errors

  • 401·Unauthorized
  • 404·Message not found
bash
curl -X POST https://outemit.dev/api/v1/messages/evt_01HABC/replay \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "message_id": "evt_01HABC",
  "delivery_ids": ["dlv_01HNEW"],
  "status": "enqueued"
}

Send a test message

POST/api/v1/messages/send-test

Test-only helper. Emits a sample event through the real pipeline. Prefer POST /api/v1/messages in production.

Request body

NameTypeRequiredDescription
app_idstringYes
event_typestringNoDefaults to invoice.paid
payloadobjectNo

Errors

  • 400·Invalid body
  • 401·Unauthorized
  • 404·Application not found
bash
curl -X POST https://outemit.dev/api/v1/messages/send-test \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "app_id": "app_01HXYZ", "event_type": "invoice.paid"}'
Response
{
  "id": "evt_01HTEST",
  "object": "message",
  "status": "accepted",
  "event_type": "invoice.paid",
  "app_id": "app_01HXYZ",
  "delivery_ids": ["dlv_01H"],
  "note": "Sample event accepted into the delivery pipeline."
}

Applications

List applications

GET/api/v1/applications

List applications (customer tenants) in the API key environment (test or live).

Response fields

FieldTypeDescription
dataApplication[]

Errors

  • 401·Unauthorized
bash
curl -X GET https://outemit.dev/api/v1/applications \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "data": [
    {
      "id": "app_01HXYZ",
      "name": "Acme",
      "uid": "acme",
      "created_at": "2026-09-01T00:00:00.000Z"
    }
  ]
}

Create an application

POST/api/v1/applications

Create an application for one customer tenant that will receive webhooks.

Request body

NameTypeRequiredDescription
namestringYes
uidstringNoStable external id for your system

Response fields

FieldTypeDescription
idstring
namestring
uidstring
portal_pathstringShort path into the customer portal

Errors

  • 400·Missing name
  • 401·Unauthorized
  • 409·uid already exists
bash
curl -X POST https://outemit.dev/api/v1/applications \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme", "uid": "acme" }'
Response
{
  "id": "app_01HXYZ",
  "name": "Acme",
  "uid": "acme",
  "portal_path": "/p/app_01HXYZ"
}

Endpoints

List endpoints

GET/api/v1/endpoints

List endpoints for the environment.

Response fields

FieldTypeDescription
dataEndpoint[]

Errors

  • 401·Unauthorized
bash
curl -X GET https://outemit.dev/api/v1/endpoints \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "data": [
    {
      "id": "ep_01H",
      "app_id": "app_01HXYZ",
      "url": "https://example.com/hooks",
      "status": "active",
      "event_types": ["invoice.paid"]
    }
  ]
}

Create an endpoint

POST/api/v1/endpoints

Create an endpoint. Live requires HTTPS. Test allows localhost. Response includes signing_secret once (whsec_). Store it immediately.

Request body

NameTypeRequiredDescription
app_idstringYes
urlstringYesReceiver URL
descriptionstringNo
event_typesstring[]NoSubscribe to these catalog names

Response fields

FieldTypeDescription
idstring
app_idstring
urlstring
signing_secretstringShown once; store securely
statusstringactive | disabled | failing

Errors

  • 400·Invalid URL or missing app_id
  • 401·Unauthorized
  • 404·Application not found
bash
curl -X POST https://outemit.dev/api/v1/endpoints \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "app_id": "app_01HXYZ", "url": "https://example.com/hooks", "event_types": ["invoice.paid", "invoice.failed"]}'
Response
{
  "id": "ep_01H",
  "app_id": "app_01HXYZ",
  "url": "https://example.com/hooks",
  "signing_secret": "whsec_...",
  "status": "active"
}

Rotate signing secret

POST/api/v1/endpoints/{id}/rotate-secret

Mint a new whsec_. Previous secret remains valid until previous_valid_until (dual-sign grace).

Path parameters

NameTypeRequiredDescription
idstringYesEndpoint id (ep_...)

Response fields

FieldTypeDescription
idstring
signing_secretstringNew secret, shown once
previous_valid_untilstringUntil when the old secret still verifies

Errors

  • 401·Unauthorized
  • 404·Endpoint not found
bash
curl -X POST https://outemit.dev/api/v1/endpoints/ep_01H/rotate-secret \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "id": "ep_01H",
  "signing_secret": "whsec_new...",
  "previous_valid_until": "2026-09-06T12:00:00.000Z"
}

Deliveries

Retrieve a delivery

GET/api/v1/deliveries/{id}

Returns delivery status and recent attempt summary. Public surface for status checks; retry is a separate POST.

Path parameters

NameTypeRequiredDescription
idstringYesDelivery id (dlv_...)

Response fields

FieldTypeDescription
idstring
objectstringAlways "delivery"
message_idstring
endpoint_idstring
statusstringpending | success | failed | disabled
attempt_countinteger
next_attempt_atstring | null

Errors

  • 401·Unauthorized
  • 404·Delivery not found
bash
curl -X GET https://outemit.dev/api/v1/deliveries/dlv_01HDEF \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "id": "dlv_01HDEF",
  "object": "delivery",
  "message_id": "evt_01HABC",
  "endpoint_id": "ep_01H",
  "status": "failed",
  "attempt_count": 2,
  "next_attempt_at": "2026-09-06T12:05:00.000Z"
}

Retry a delivery

POST/api/v1/deliveries/{id}/retry

Re-attempt the same delivery to the same endpoint. Adds a new attempt; does not create a new delivery. Distinct from message replay.

Path parameters

NameTypeRequiredDescription
idstringYesDelivery id (dlv_...)

Response fields

FieldTypeDescription
delivery_idstring
statusstring
attempt_numberinteger

Errors

  • 401·Unauthorized
  • 404·Delivery not found
bash
curl -X POST https://outemit.dev/api/v1/deliveries/dlv_01HDEF/retry \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "delivery_id": "dlv_01HDEF",
  "status": "enqueued",
  "attempt_number": 3
}

Event types

List event types

GET/api/v1/event-types

List the org event catalog used by the dashboard and customer portal.

Response fields

FieldTypeDescription
dataEventType[]

Errors

  • 401·Unauthorized
bash
curl -X GET https://outemit.dev/api/v1/event-types \
  -H "Authorization: Bearer sk_test_..."
Response
{
  "data": [
    {
      "name": "invoice.paid",
      "description": "Invoice settled successfully",
      "version": 1,
      "example_json": { "id": "inv_1", "amount": 4900 }
    }
  ]
}

API keys

Create an API key

POST/api/v1/api-keys

Creates an additional key for the same org and livemode as the Bearer key. The full key value is returned once. Use /api/v1/dev/bootstrap for the first key in local/dev.

Request body

NameTypeRequiredDescription
namestringNoLabel for the key

Response fields

FieldTypeDescription
idstring
objectstringAlways "api_key"
namestring
prefixstring
livemodeboolean
keystringPlaintext key, shown once

Errors

  • 401·Unauthorized
bash
curl -X POST https://outemit.dev/api/v1/api-keys \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "CI key" }'
Response
{
  "id": "key_01H",
  "object": "api_key",
  "name": "CI key",
  "prefix": "sk_test_",
  "livemode": false,
  "key": "sk_test_..."
}

Machine-readable contract: /openapi.yaml. Human reference above stays in sync with that spec.