e-bon
e-bon.ro
API reference

Webhooks

REST endpoints for managing webhook subscriptions — create, list, update, delete, rotate signing secrets, send test deliveries, and inspect delivery history.

Webhooks

The Webhooks API lets you subscribe an external HTTPS endpoint to events that happen inside e-bon — receipts being created, commands completing, devices going online or offline, reports being generated, etc. Every endpoint in this group lives under /api/v1/org/webhooks and is administrative: it manages the subscription, not the delivery payloads themselves. Once a subscription is in place, e-bon dispatches each matching event to your URL with an HMAC-SHA256 signature in the X-E-Bon-Signature header.

Unlike most of the API reference, webhook management routes are not API-key authenticated. They sit behind the Portal JWT middleware (jwtAuth) and additionally require the calling user to have the Owner or Admin role on the organization. There is no API-key scope that grants access to webhook administration — generate a Portal session token (POST /api/v1/auth/login) and use it as Authorization: Bearer <jwt>. See Authentication › JWT authentication.

The error envelope, rate limits and pagination conventions are documented once on API overview; only the per-endpoint error codes are listed in full on this page.

Event types

Subscriptions list one or more event types from this fixed set:

EventFired when…
receipt.createdA receipt has been persisted via POST /receipts.
receipt.failedRecording a receipt failed.
command.completedA fiscal command finished successfully on the AMEF.
command.failedA fiscal command was rejected by the AMEF.
command.timeoutA fiscal command did not get a reply within the timeout window.
device.onlineA device's WebSocket connection came up.
device.offlineA device's WebSocket connection dropped.
report.generatedAn X / Z / JE / MF report has been stored.
webhook.testSent only by the Send test delivery endpoint below.

GET /api/v1/org/webhooks

Lists all webhook subscriptions for the organization. Secrets are never returned by this endpoint — the raw signing secret is shown only at create time and on rotation.

  • Auth: Portal JWT, role Owner or Admin.

Response (200 OK)

{
  "webhooks": [
    {
      "id": "wh_abc123",
      "orgId": "acme_corp",
      "url": "https://hooks.example.com/e-bon",
      "description": "Accounting integration",
      "events": ["receipt.created", "report.generated"],
      "enabled": true,
      "failureCount": 0,
      "lastDeliveryAt": "2026-04-09T08:09:55.000Z",
      "lastDeliveryStatus": "success",
      "createdAt": "2026-03-01T12:00:00.000Z",
      "updatedAt": "2026-04-09T08:09:55.000Z",
      "createdBy": "user_xyz"
    }
  ]
}

Example

curl https://api.e-bon.ro/api/v1/org/webhooks \
  -H "Authorization: Bearer <portal-jwt>"

Error codes

  • UNAUTHORIZED (401) — missing or invalid JWT.
  • FORBIDDEN (403) — caller does not have Owner or Admin role.

The full HTTP catalogue is on API overview › HTTP error code catalogue.

POST /api/v1/org/webhooks

Creates a new webhook subscription. The raw signing secret is returned only once in the secret field of the response — store it immediately in your secret manager. There is no endpoint that returns the secret again.

  • Auth: Portal JWT, role Owner or Admin.

Request body

FieldTypeRequiredNotes
urlstringyesMust be a valid HTTPS URL (the server rejects any non-https:// URL).
descriptionstringnoFree-text label, ≤ 500 chars.
eventsstringyesAt least one event type from the table above.
enabledbooleannoDefaults to true. Set to false to create a subscription that does not yet receive deliveries.

Response (201 Created)

{
  "webhook": {
    "id": "wh_abc123",
    "orgId": "acme_corp",
    "url": "https://hooks.example.com/e-bon",
    "description": "Accounting integration",
    "events": ["receipt.created", "report.generated"],
    "enabled": true,
    "failureCount": 0,
    "createdAt": "2026-04-09T08:10:00.000Z",
    "createdBy": "user_xyz",
    "secret": "whsec_8f3a9d…"
  }
}

Example

curl -X POST https://api.e-bon.ro/api/v1/org/webhooks \
  -H "Authorization: Bearer <portal-jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/e-bon",
    "description": "Accounting integration",
    "events": ["receipt.created", "report.generated"]
  }'

Error codes

  • VALIDATION_ERROR (400) — body failed Zod validation (non-HTTPS URL, missing/empty events, description over 500 chars, unknown event type).
  • UNAUTHORIZED (401) — missing or invalid JWT.
  • FORBIDDEN (403) — caller does not have Owner or Admin role.

GET /api/v1/org/webhooks/{id}

Returns a single webhook subscription by ID. Secret is never returned.

  • Auth: Portal JWT, role Owner or Admin.

Path parameters

ParameterTypeNotes
idstringWebhook subscription ID.

Response (200 OK)

{
  "webhook": {
    "id": "wh_abc123",
    "orgId": "acme_corp",
    "url": "https://hooks.example.com/e-bon",
    "description": "Accounting integration",
    "events": ["receipt.created", "report.generated"],
    "enabled": true,
    "failureCount": 0,
    "createdAt": "2026-03-01T12:00:00.000Z"
  }
}

Example

curl https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123 \
  -H "Authorization: Bearer <portal-jwt>"

Error codes

PATCH /api/v1/org/webhooks/{id}

Updates one or more fields on an existing webhook. At least one field must be provided. Re-enabling a previously disabled webhook (enabled: true) also resets failureCount to 0.

  • Auth: Portal JWT, role Owner or Admin.

Request body

FieldTypeNotes
urlstringMust be HTTPS if provided.
descriptionstring≤ 500 chars.
eventsstringAt least one event type from the table above.
enabledbooleanToggle deliveries on/off.

Response (200 OK)

Same shape as GET /api/v1/org/webhooks/{id} — the updated record without the secret.

Example

curl -X PATCH https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123 \
  -H "Authorization: Bearer <portal-jwt>" \
  -H "Content-Type: application/json" \
  -d '{ "events": ["receipt.created"], "enabled": true }'

Error codes

  • VALIDATION_ERROR (400) — body failed Zod validation, or empty body (no fields to update).
  • NOT_FOUND (404) — no webhook with that ID in your organization.
  • UNAUTHORIZED / FORBIDDEN — see Authentication › Auth errors.

DELETE /api/v1/org/webhooks/{id}

Permanently deletes a webhook subscription and every delivery record stored in its deliveries subcollection. Returns 204 No Content on success.

  • Auth: Portal JWT, role Owner or Admin.

Example

curl -X DELETE https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123 \
  -H "Authorization: Bearer <portal-jwt>"

Error codes

POST /api/v1/org/webhooks/{id}/rotate-secret

Generates a fresh signing secret for the webhook and replaces the previous one. The new secret is returned only once in the response — store it before the request finishes.

  • Auth: Portal JWT, role Owner or Admin.

Response (200 OK)

{
  "secret": "whsec_NEW_VALUE…"
}

Example

curl -X POST https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123/rotate-secret \
  -H "Authorization: Bearer <portal-jwt>"
Rotation is immediate. Any in-flight delivery signed with the old secret will still validate on the receiving side until you cut over — coordinate the secret change with the consumer that verifies signatures.

Error codes

POST /api/v1/org/webhooks/{id}/test

Fires a synchronous test delivery with event type webhook.test to the webhook's URL. Returns the created delivery record (with the attempted HTTP status, response body fragment and any error message) so you can debug your endpoint without waiting for a real event.

  • Auth: Portal JWT, role Owner or Admin.
  • Side effect: persists a delivery record under webhooks/{id}/deliveries.

Response (200 OK)

{
  "delivery": {
    "id": "del_test_abc",
    "webhookId": "wh_abc123",
    "orgId": "acme_corp",
    "eventType": "webhook.test",
    "payload": {
      "id": "evt_…",
      "type": "webhook.test",
      "createdAt": "2026-04-09T08:10:00.000Z",
      "orgId": "acme_corp",
      "data": { "test": true, "message": "This is a test event from e-bon." }
    },
    "status": "success",
    "attempt": 1,
    "httpStatus": 200,
    "createdAt": "2026-04-09T08:10:00.000Z",
    "attemptedAt": "2026-04-09T08:10:00.500Z"
  }
}

Example

curl -X POST https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123/test \
  -H "Authorization: Bearer <portal-jwt>"

Error codes

GET /api/v1/org/webhooks/{id}/deliveries

Returns recent delivery attempts for the webhook, newest-first. Each delivery includes the dispatched payload, the attempt counter, the HTTP status returned by your endpoint, the response body fragment, and any error message captured by the retry sweeper.

  • Auth: Portal JWT, role Owner or Admin.

Query parameters

ParameterTypeDefaultNotes
limitinteger50Page size, 1200.
statusstringOne of pending, success, failed.

Response (200 OK)

{
  "deliveries": [
    {
      "id": "del_abc123",
      "webhookId": "wh_abc123",
      "orgId": "acme_corp",
      "eventType": "receipt.created",
      "payload": { "id": "evt_…", "type": "receipt.created" },
      "status": "success",
      "attempt": 1,
      "httpStatus": 200,
      "createdAt": "2026-04-09T08:09:55.000Z",
      "attemptedAt": "2026-04-09T08:09:55.300Z"
    }
  ]
}

Example

curl "https://api.e-bon.ro/api/v1/org/webhooks/wh_abc123/deliveries?status=failed&limit=20" \
  -H "Authorization: Bearer <portal-jwt>"

Error codes

  • VALIDATION_ERROR (400) — bad query (limit > 200, unknown status value).
  • NOT_FOUND (404) — no webhook with that ID in your organization.
  • UNAUTHORIZED / FORBIDDEN — see Authentication › Auth errors.

See also