Webhook Endpoint & Deliveries
Set up the endpoint TensorRail delivers webhooks to, and inspect or retry deliveries programmatically.
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
2xxwithin 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.
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
| Endpoint | Auth | Scope |
|---|---|---|
GET /v1/webhooks/config | API key or dashboard session | webhooks:read |
PUT /v1/webhooks/config | Dashboard session + two-factor | webhooks:write |
POST /v1/webhooks/config/rotate-secret | Dashboard session + two-factor | webhooks:write |
GET /v1/webhooks/deliveries | API key or dashboard session | webhooks:read |
GET /v1/webhooks/deliveries/{event_id}/attempts | API key or dashboard session | webhooks:read |
POST /v1/webhooks/deliveries/{event_id}/retry | API key or dashboard session | webhooks:write |
Related
- Webhooks: event catalog, signature verification, retry schedule
- Authentication: the scope table
- Reporting API: base URL and auth
- Troubleshooting