Guides

Webhooks

Webhooks send your server a signed POST request for every followed event. They follow the Standard Webhooks specification, whose official library verifies the signatures.
  1. In the console, on the Webhooks screen, register an endpoint: URL, mode and followed events (owner and admins only).
  2. Copy the signing secret (whsec_…), shown only once.
  3. Verify every signature and respond 2xx within 10 seconds.
  4. Validate with Send a test.
Endpoint rules:
  • HTTPS URL on port 443, without credentials or fragment. The host must resolve to public IP addresses, at registration and on every delivery.
  • Mode set at creation: a test endpoint receives the events of test keys; a live endpoint, those of live keys and of the balance.
  • 20 endpoints at most per organization, both modes included.
  • An event that no active endpoint of the right mode follows is not produced, nor caught up later.
typeTrigger
generation.succeededGeneration completed successfully.
generation.failedGeneration failed, refunded.
generation.canceledGeneration canceled, refunded.
balance.lowBalance below the auto recharge threshold, or below €5.00 excluding tax without it, at each crossing.
balance.recharge_failedAuto recharge payment refused, or 3 recharges reached within 24 hours: auto recharge now disabled.
balance.expiringPart of the balance expires within 30 days (once per top-up or granted credit).
Balance events are always live mode (see Billing).
Every delivery carries Content-Type: application/json and User-Agent: RenderThink-Webhooks/1.0:
json
{
"id": "evt_4Kp9WmT2xQr7LbN3vZc8Hd",
"type": "balance.low",
"created_at": 1791453648,
"livemode": true,
"data": {
"object": {
"object": "balance",
"amount": 420,
"currency": "eur",
"unit": "cents",
"low_balance_threshold": 500
}
}
}
FieldTypeDescription
idstringevt_…, equal to the webhook-id header.
typestringEvent type.
created_atintegerUnix timestamp in seconds.
livemodebooleanfalse in test mode.
data.objectobjectThe generation, as GET /v1/generations/{id} returns it, or the balance (balance).
  • The generation is read again for every delivery: its output[].url are valid for 15 minutes from the delivery.
  • The balance, in cents excluding tax, carries amount and, depending on the event, low_balance_threshold, failed_recharge (amount, auto_recharge_enabled) or expiring (amount, expires_at).
  • Ignore unknown fields: new fields can be added, in events as in API responses.
webhook-signature is v1, followed by the base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body}, computed with the endpoint secret; during a secret change, two signatures separated by a space. The library verifies the signature and refuses a webhook-timestamp more than 5 minutes off. Verify the raw body, before parsing the JSON. Without the library, compare signatures in constant time (crypto.timingSafeEqual, hmac.compare_digest), never with ==. RENDERTHINK_WEBHOOK_SECRET holds the full secret, whsec_ prefix included.
// npm install standardwebhooks express
import express from 'express'
import { Webhook } from 'standardwebhooks'
​
const webhook = new Webhook(process.env.RENDERTHINK_WEBHOOK_SECRET)
const app = express()
​
app.post(
'/webhooks/renderthink',
express.raw({ type: 'application/json' }),
(req, res) => {
let event
try {
event = webhook.verify(req.body, req.headers)
} catch {
return res.sendStatus(400)
}
res.sendStatus(204)
handleEvent(event)
},
)
​
app.listen(3000)
Respond 2xx within 10 seconds, then process the event. Any other status, a redirect (never followed), a timeout or a failed connection counts as a failure.
A failed delivery is retried automatically, at increasing intervals, for 72 hours after the event, about 16 attempts in all.
AttemptDelay after the previous failure
230 seconds
31 minute
42 minutes
5 to 12Twice the previous delay: 4 min, 8 min, 16 min, 32 min, 1h04, 2h08, 4h16, 8h32
13 and later12 hours
  • Delays vary by up to 10%. A Retry-After header in your response is honored, up to 12 hours.
  • After 72 hours, the event is no longer resent automatically; it stays in the console's delivery log.
  • An event may arrive more than once, with the same webhook-id: ignore an identifier already processed, still responding 2xx. Order is not guaranteed: rely on created_at.
  • After 72 hours of failures without any success, or on a 410 Gone response, the endpoint is disabled, its scheduled deliveries canceled, and the owner and admins receive an email. Once enabled again, it only receives new events.
Each endpoint has a delivery log, kept for 30 days, and can be disabled or enabled again by hand.
  • Resend sends a delivery once more, with the same webhook-id.
  • Send a test sends a sample event of a followed type, with fictitious identifiers and no image.
  • Change the secret shows the new secret once. For 24 hours, every delivery carries both signatures. A second change within that delay removes the first secret at once.
Resend and test: active endpoint required, never retried.