EmitHQ

API Reference

Base URL: https://api.emithq.com
Authentication: Authorization: Bearer emhq_your_key
All :appId and :epId params accept either UUID or user-defined uid.

Authentication

All API requests require a Bearer token. Use your emhq_ API key.

POST/api/v1/auth/keys201

Create a new API key (requires org:admin role via Clerk session)

Request body:
{ "name": "production-key" }
Response:
{ "data": { "id": "...", "key": "emhq_...", "name": "production-key" } }
GET/api/v1/auth/keys200

List active API keys (metadata only, no key values)

Response:
{ "data": [{ "id": "...", "name": "...", "lastUsedAt": "..." }] }
DELETE/api/v1/auth/keys/:keyId200

Revoke an API key (soft-delete)

Response:
{ "data": { "id": "...", "revoked": true } }

Messages

Send webhook events for delivery to all matching endpoints.

POST/api/v1/app/:appId/msg202

Send a webhook event. Persisted before queueing. Returns 202.

Request body:
{ "eventType": "invoice.paid", "payload": { ... }, "eventId": "evt_unique" }
Response:
{ "data": { "id": "msg_...", "eventType": "invoice.paid", "createdAt": "..." } }
GET/api/v1/app/:appId/msg200

List messages with optional filters: eventType, since, until. Cursor-paginated.

Response:
{ "data": [...], "iterator": "cursor", "done": false }
GET/api/v1/app/:appId/msg/:msgId200

Get a single message with all delivery attempts.

Response:
{ "data": { "id": "...", "payload": {...}, "attempts": [...] } }

Endpoints

CRUD for webhook delivery destinations. Each endpoint has its own signing secret.

POST/api/v1/app/:appId/endpoint201

Create an endpoint. Signing secret returned once.

Request body:
{ "url": "https://example.com/hook", "eventTypeFilter": ["invoice.paid"] }
Response:
{ "data": { "id": "...", "signingSecret": "whsec_...", ... } }
GET/api/v1/app/:appId/endpoint200

List endpoints. Cursor-paginated. Excludes soft-deleted.

Response:
{ "data": [...], "iterator": "cursor", "done": false }
GET/api/v1/app/:appId/endpoint/:epId200

Get a single endpoint. Signing secret is masked.

PUT/api/v1/app/:appId/endpoint/:epId200

Update an endpoint. Setting disabled:false re-enables and resets circuit breaker.

Request body:
{ "url": "https://new-url.com/hook", "disabled": false }
DELETE/api/v1/app/:appId/endpoint/:epId200

Soft-delete an endpoint.

Response:
{ "data": { "id": "...", "deleted": true } }
POST/api/v1/app/:appId/endpoint/:epId/test200

Send a test webhook to verify endpoint connectivity.

Response:
{ "data": { "success": true, "statusCode": 200, "responseTimeMs": 42 } }

Replay & DLQ

Retry failed deliveries and manage the dead-letter queue.

POST/api/v1/app/:appId/msg/:msgId/retry200

Replay all failed/exhausted delivery attempts for a message.

Response:
{ "data": { "replayed": 2, "attempts": [...] } }
POST/api/v1/app/:appId/msg/:msgId/attempt/:attemptId/retry200

Replay a single delivery attempt.

Response:
{ "data": { "attemptId": "...", "jobId": "..." } }
GET/api/v1/app/:appId/dlq200

List exhausted delivery attempts (dead-letter queue). Cursor-paginated.

Response:
{ "data": [...], "iterator": "cursor", "done": false }

Dashboard & Stats

Read-only endpoints for monitoring and observability.

GET/api/v1/app/:appId/stats200

Overview stats: events today, success rate, active endpoints, pending retries.

Response:
{ "data": { "eventsToday": 142, "successRate": 98.5, "activeEndpoints": 5, "pendingRetries": 3 } }
GET/api/v1/app/:appId/endpoint-health200

Per-endpoint health: success rate, avg latency, failure count, last delivery.

Response:
{ "data": [{ "url": "...", "successRate": 99.1, "avgLatencyMs": 142, ... }] }

Transform Preview

Test payload transformations without persisting anything.

POST/api/v1/transform/preview200

Preview a transformation rule against a sample payload.

Request body:
{ "payload": { ... }, "rules": [{ "sourcePath": "$.data.email", "targetField": "email" }] }
Response:
{ "data": { "original": { ... }, "transformed": { "email": "..." } } }