Docs menu

Webhooks — API reference

Registering and testing delivery endpoints.

MethodPathSummary
GET/v1/webhooksList delivery endpoints
POST/v1/webhooksRegister a delivery endpoint
GET/v1/webhooks/{webhookId}Read one endpoint
PATCH/v1/webhooks/{webhookId}Edit an endpoint
DELETE/v1/webhooks/{webhookId}Delete an endpoint
POST/v1/webhooks/{webhookId}/rotate-secretIssue a new signing secret
POST/v1/webhooks/{webhookId}/testSend a test delivery
GET/v1/webhooks/{webhookId}/deliveriesDelivery log of one endpoint

Generated from openapi.yaml at build time. Base URL https://api.tenergy.me/v1, or https://api-nile.tenergy.me/v1 on Nile (Environments). Every request below is signed as in Authentication unless its Auth line says otherwise.

List delivery endpoints

GET /v1/webhooks · listWebhooks

Auth: API key (HMAC).

The secret is never returned here.

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
dataarray of object (WebhookEndpoint)yes
data[].idstringyes
data[].urlstring (uri)yes
data[].roleenum: primary, backupyes
data[].eventsarray of enum (13 values, WebhookEventType) | nullnull means all events.
data[].is_activebooleanyes
data[].last_delivery_atstring (date-time) | null
data[].last_delivery_statusinteger | null
data[].created_atstring (date-time)yes
data[].updated_atstring (date-time)
max_endpointsintegeryes
rolesarray of enum: primary, backup

Register a delivery endpoint

POST /v1/webhooks · createWebhook

Auth: API key (HMAC).

Returns a secret shown exactly once. It signs every delivery to this endpoint — store it now; if you lose it, rotate rather than re-register.

At most two endpoints per account: one primary and one backup. Delivery is not fan-out — every event goes to the primary, and moves to the backup only after the primary’s retries are exhausted. The first endpoint you create becomes primary.

URL requirements, enforced on create and on every edit: https only; must resolve to a public address (loopback, RFC 1918, link-local including 169.254.169.254 and other non-routable ranges are rejected); no credentials in the URL; at most 2048 characters.

Full event catalogue, payloads, signature scheme and retry schedule: Webhooks.

Request body

JSON (WebhookRequest), required.

FieldTypeRequiredDescription
urlstring (uri)yesHTTPS, publicly resolvable, no credentials.
roleenum: primary, backupOmit to take the first free role.
eventsarray of enum (13 values, WebhookEventType)Which events to deliver here. Omit to receive all of them — recommended, since new event types then start arriving without a registration change. Route by the event field and ignore types you do not handle yet.

Example request body, from the contract (illustrative values):

json
{
  "url": "https://acme.example/hooks/tenergy",
  "role": "primary",
  "events": ["order.confirmed","order.failed","balance.credited"]
}

Responses

StatusMeaning
201Created. secret is present only in this response.
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
409The request contradicts the current state of the object.
422Syntactically valid but semantically impossible.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
idstringyes
urlstring (uri)yes
roleenum: primary, backupyes
eventsarray of enum (13 values, WebhookEventType) | nullnull means all events.
is_activebooleanyes
last_delivery_atstring (date-time) | null
last_delivery_statusinteger | null
created_atstring (date-time)yes
updated_atstring (date-time)
secretstringyesSigning secret. Shown once, never returned by GET.

Read one endpoint

GET /v1/webhooks/{webhookId} · getWebhook

Auth: API key (HMAC).

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Response fields (WebhookEndpoint)

FieldTypeRequiredDescription
idstringyes
urlstring (uri)yes
roleenum: primary, backupyes
eventsarray of enum (13 values, WebhookEventType) | nullnull means all events.
is_activebooleanyes
last_delivery_atstring (date-time) | null
last_delivery_statusinteger | null
created_atstring (date-time)yes
updated_atstring (date-time)

Edit an endpoint

PATCH /v1/webhooks/{webhookId} · updateWebhook

Auth: API key (HMAC).

Change url, events, is_active and/or role. Sending {"role": "primary"} to the backup swaps the two roles in one transaction, so you are never left without a primary. A changed URL is re-validated. is_active: false pauses delivery without losing the endpoint; pausing the primary does not promote the backup — swap the roles if that is what you want.

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes

Request body

JSON (WebhookPatch), required.

FieldTypeRequiredDescription
urlstring (uri)
roleenum: primary, backup
eventsarray of enum (13 values, WebhookEventType) | null
is_activeboolean

Responses

StatusMeaning
200Updated
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
404No such object, or it belongs to another account. The two are not distinguished.
422Syntactically valid but semantically impossible.
500Something broke on our side.

Response fields (WebhookEndpoint)

FieldTypeRequiredDescription
idstringyes
urlstring (uri)yes
roleenum: primary, backupyes
eventsarray of enum (13 values, WebhookEventType) | nullnull means all events.
is_activebooleanyes
last_delivery_atstring (date-time) | null
last_delivery_statusinteger | null
created_atstring (date-time)yes
updated_atstring (date-time)

Delete an endpoint

DELETE /v1/webhooks/{webhookId} · deleteWebhook

Auth: API key (HMAC).

Hard delete; frees the role. Undelivered events for this endpoint are dropped.

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes

Responses

StatusMeaning
204Deleted. No body.
401Missing, malformed or rejected credentials.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Issue a new signing secret

POST /v1/webhooks/{webhookId}/rotate-secret · rotateWebhookSecret

Auth: API key (HMAC).

Returns a new secret once. It takes effect immediately for subsequent deliveries; there is no overlap window, so deploy the new secret to your receiver before rotating, or accept a brief period where in-flight retries fail signature verification. Each endpoint has its own secret — rotating the primary’s does not touch the backup’s.

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes

Responses

StatusMeaning
200Rotated
401Missing, malformed or rejected credentials.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
idstringyes
secretstringyes

Send a test delivery

POST /v1/webhooks/{webhookId}/test · testWebhook

Auth: API key (HMAC).

Sends a synthetic event to the endpoint and reports what your server answered. The payload is signed exactly like a real one and carries "test": true at the top level, so a receiver that ignores unknown event types, or that checks the flag, will not act on it.

Test deliveries are not retried and do not appear in delivery history.

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes

Request body

JSON.

FieldTypeRequiredDescription
eventenum (13 values, WebhookEventType)Full catalogue with payloads in Webhooks. balance.credited for a deposit also carries asset (TRX|USDT), usdt_amount, rate (SUN per USDT after spread), rate_source, spread_bps, txid, sender, block_number; the USDT fields are null for TRX.

Responses

StatusMeaning
200The delivery was attempted; the result describes what happened.
401Missing, malformed or rejected credentials.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
deliveredbooleanyesTrue when your endpoint answered 2xx.
eventenum (13 values, WebhookEventType)yesFull catalogue with payloads in Webhooks. balance.credited for a deposit also carries asset (TRX|USDT), usdt_amount, rate (SUN per USDT after spread), rate_source, spread_bps, txid, sender, block_number; the USDT fields are null for TRX.
delivery_idstringyes
response_statusinteger | nullHTTP status your endpoint returned; null on connection failure.
response_body_excerptstring | nullFirst 512 bytes of your response, for debugging.
errorstring | nullTransport-level failure description, when delivered is false.
duration_msinteger

Delivery log of one endpoint

GET /v1/webhooks/{webhookId}/deliveries · listWebhookDeliveries

Auth: API key (HMAC).

Every event queued for this endpoint, newest first: which event, how many attempts, the state, the last HTTP status your server answered and when the next retry is due. Test deliveries are not listed. Scope webhooks.read, or a dashboard session with member role viewer. Another account’s endpoint answers 404.

Parameters

NameInTypeRequiredDescription
webhookIdpathstringyes
limitqueryinteger
cursorquerystringOpaque cursor from a previous response’s next_cursor.

Responses

StatusMeaning
200OK
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
dataarray of object (WebhookDelivery)yes
data[].idstringyes
data[].event_idstringyesThe id of the event envelope — your dedup key, stable across retries.
data[].eventenum (13 values, WebhookEventType)yesFull catalogue with payloads in Webhooks. balance.credited for a deposit also carries asset (TRX|USDT), usdt_amount, rate (SUN per USDT after spread), rate_source, spread_bps, txid, sender, block_number; the USDT fields are null for TRX.
data[].attemptintegeryesAttempts made so far.
data[].stateenum: pending, delivering, delivered, failed, deadyesfailed is retried at next_attempt_at; dead is not retried.
data[].response_statusinteger | nullyesHTTP status of the last attempt; null before one, or on a connection failure.
data[].errorstring | nullyesTransport failure of the last attempt.
data[].next_attempt_atstring (date-time) | nullyes
data[].delivered_atstring (date-time) | nullyes
data[].created_atstring (date-time)yes
data[].updated_atstring (date-time)yes
next_cursorstring | nullyes

Example 200 response, from the contract (illustrative values — live numbers come from the API):

json
{
  "data": [
    {
      "id": "dlv_01K5YA1B2C3D4E5F6G7H8J9K0M",
      "event_id": "evt_01K5YA1B2C3D4E5F6G7H8J9K0N",
      "event": "order.confirmed",
      "attempt": 2,
      "state": "failed",
      "response_status": 502,
      "error": null,
      "next_attempt_at": "2026-09-25T10:31:00.000Z",
      "delivered_at": null,
      "created_at": "2026-09-25T10:30:00.000Z",
      "updated_at": "2026-09-25T10:30:30.000Z"
    }
  ],
  "next_cursor": null
}

    ↑ ↓ to move · Enter to open · Esc to close