Skip to main content

Webhook Endpoint & Deliveries

Set up the endpoint TensorRail delivers webhooks to, and inspect or retry deliveries programmatically.

New accounts receive no webhooks until an endpoint is configured

A new account has no webhook endpoint configured. Events still occur — payments succeed, refunds resolve — but nothing is delivered anywhere until you set a URL. Configuring your endpoint is the first integration step after your first test payment.

1. Configure your endpoint

In the dashboard, go to Developers → Webhooks, set your endpoint URL, and reveal your signing secret.

Requirements for the URL:

  • Public HTTPS only. Plain http://, private/internal addresses, and localhost are rejected (webhook_url must be a public https endpoint).
  • It must answer 2xx within 30 seconds (the delivery timeout) — though you should respond in well under a second and do any heavy work asynchronously. See delivery and retries.

Endpoint changes go through PUT /v1/webhooks/config and secret rotation through POST /v1/webhooks/config/rotate-secret on the Reporting API — but both are dashboard operator actions requiring a signed-in session with fresh two-factor verification. An API key calling them receives 401 ERR_1019: a leaked key must not be able to redirect your webhook traffic or swap your signing secret. The rotated secret is shown once; update your verifier within 30 minutes of rotating, because in-flight retries signed with the old secret will fail verification on your side.

Stopping delivery

To stop delivery, clear the endpoint URL: Developers → Webhooks, empty the field, and save. It is the same PUT /v1/webhooks/config call as any endpoint change — session plus two-factor, not an API key — with a blank (or null) webhook_url:

{ "webhook_details": { "webhook_url": "" } }

The response carries "delivery_stopped": true when the call stopped delivery, and GET /v1/webhooks/config then reads back webhook_url: null.

Nothing is lost while delivery is stopped: TensorRail still records every event, so GET /v1/webhooks/deliveries keeps listing them and each one can be retried once you set an endpoint again. Delivery stays stopped until you do.

Omitting webhook_url from the body entirely means "leave it as it is", which is not the same thing — only a present-but-blank value stops delivery.

2. Read your configuration

GET /v1/webhooks/config — scope webhooks:read. Works with your API key.

curl "https://api.tensorrail.com/v1/webhooks/config" \
-H "Authorization: Bearer rail_full_live_xxx"

The response contains your profile's webhook_details (including webhook_url) plus a payment_response_hash_key_set boolean that tells you whether a signing secret is configured. The signing secret's value is never returned by any read endpoint — it is shown only when (re)generated in the dashboard.

webhook_url is null when no endpoint is configured — either because you have not set one yet, or because you stopped delivery.

3. Inspect deliveries

GET /v1/webhooks/deliveries — scope webhooks:read

Lists recent webhook events for your account. Query parameters: limit (default 50, max 100) and event_type (e.g. payment_succeeded). History covers up to 90 days.

event_type takes one event name from the event catalog; a name that is not in it is rejected with 400.

curl "https://api.tensorrail.com/v1/webhooks/deliveries?limit=20&event_type=payment_succeeded" \
-H "Authorization: Bearer rail_full_live_xxx"

GET /v1/webhooks/deliveries/{event_id}/attempts — scope webhooks:read

Returns the full attempt chain for one event. Each entry carries event_id, event_type, event_class, object_id, is_delivery_successful, initial_attempt_id, and created.

There is no separate "attempt kind" field: an entry whose initial_attempt_id equals its own event_id is the first delivery, and every other entry in the chain is a retry of that first attempt. Order the chain by created to read it in sequence, and use is_delivery_successful to find the attempt that landed.

curl "https://api.tensorrail.com/v1/webhooks/deliveries/evt_1a2b3c/attempts" \
-H "Authorization: Bearer rail_full_live_xxx"

4. Retry a delivery

POST /v1/webhooks/deliveries/{event_id}/retry — scope webhooks:write. Works with your API key.

Manually re-sends one event to your endpoint — useful after fixing a bug on your side or after the automatic retry schedule was exhausted.

The dashboard button is test-mode only

Developers → Webhooks shows a Retry control, and it is disabled in live mode. That is deliberate, not a fault: re-driving a live delivery is a live-key action, and the dashboard session is view-only against live data. In live mode, use this endpoint with your live secret key. ::: The re-delivery is signed like any other and appears in the attempt chain as a further entry sharing the original's initial_attempt_id.

curl -X POST "https://api.tensorrail.com/v1/webhooks/deliveries/evt_1a2b3c/retry" \
-H "Authorization: Bearer rail_full_live_xxx"

Remember that your handler must be idempotent: a manual retry of an already-processed event will arrive with the same event_id.

Endpoint summary

EndpointAuthScope
GET /v1/webhooks/configAPI key or dashboard sessionwebhooks:read
PUT /v1/webhooks/configDashboard session + two-factorwebhooks:write
POST /v1/webhooks/config/rotate-secretDashboard session + two-factorwebhooks:write
GET /v1/webhooks/deliveriesAPI key or dashboard sessionwebhooks:read
GET /v1/webhooks/deliveries/{event_id}/attemptsAPI key or dashboard sessionwebhooks:read
POST /v1/webhooks/deliveries/{event_id}/retryAPI key or dashboard sessionwebhooks:write