Webhooks

Webhooks

Manage a workspace's webhook endpoints with a key that holds webhook:write — every fl_live_… key holds it (API keys are full access); an MCP access token never can. For the event catalogue, payload shapes and how to verify a delivery's signature, see Webhooks.

Creating or rotating an endpoint's secret is the only time the response includes secret (whsec_…) — store it then, it is never returned again.
Webhooks

GET /v1/webhooks

GET/v1/webhooksscope: webhook:write

List the workspace's webhook endpoints. Never includes the signing secret.

curl https://buildonce.app/v1/webhooks \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Response
{
  "items": [ {
      "id": "whe_4hd9s0k2mq7z",
      "url": "https://example.com/hooks/buildonce",
      "description": "Production server",
      "events": ["render.completed", "template.updated"],
      "enabled": true,
      "disabledReason": null,
      "disabledAt": null,
      "failureCount": 0,
      "createdAt": "2026-08-01T12:00:00.000Z",
      "updatedAt": "2026-08-01T12:00:00.000Z"
    } /* … */ ]
}
Webhooks

POST /v1/webhooks

POST/v1/webhooksscope: webhook:write

Create an endpoint. Up to 10 per workspace (403 WEBHOOK_ENDPOINT_LIMIT beyond that).

ParamTypeNotes
urlstring (required)https only, 1–2048 chars. Rejected if it resolves to a private/internal address (WEBHOOK_URL_BLOCKED).
descriptionstringUp to 200 chars.
eventsstring[] (required)One or more event names from the catalogue — at least one, no duplicates.
curl -X POST https://buildonce.app/v1/webhooks \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/buildonce",
    "description": "Production server",
    "events": ["render.completed", "template.updated"]
  }'
Response
{
  "id": "whe_4hd9s0k2mq7z",
  "url": "https://example.com/hooks/buildonce",
  "description": "Production server",
  "events": ["render.completed", "template.updated"],
  "enabled": true,
  "disabledReason": null,
  "disabledAt": null,
  "failureCount": 0,
  "createdAt": "2026-08-01T12:00:00.000Z",
  "updatedAt": "2026-08-01T12:00:00.000Z",
  "secret": "whsec_zx3k…9fq1"
}
Webhooks

GET /v1/webhooks/:endpointId

GET/v1/webhooks/:endpointIdscope: webhook:write

Get one webhook endpoint. Never includes the signing secret.

curl https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Response
{
  "id": "whe_4hd9s0k2mq7z",
  "url": "https://example.com/hooks/buildonce",
  "description": "Production server",
  "events": ["render.completed", "template.updated"],
  "enabled": true,
  "disabledReason": null,
  "disabledAt": null,
  "failureCount": 0,
  "createdAt": "2026-08-01T12:00:00.000Z",
  "updatedAt": "2026-08-01T12:00:00.000Z"
}
Webhooks

PATCH /v1/webhooks/:endpointId

PATCH/v1/webhooks/:endpointIdscope: webhook:write

Change the URL, description, subscribed events, or turn the endpoint on/off.

ParamTypeNotes
urlstringSame validation as create.
descriptionstringAn empty string clears it.
eventsstring[]Replaces the full subscribed set.
enabledbooleanSetting true clears an auto-disable and resets the failure count. Setting false records a reason and marks waiting deliveries dead.
curl -X PATCH https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "events": ["render.completed", "render.failed"] }'
Response
{
  "id": "whe_4hd9s0k2mq7z",
  "url": "https://example.com/hooks/buildonce",
  "description": "Production server",
  "events": ["render.completed", "template.updated"],
  "enabled": true,
  "disabledReason": null,
  "disabledAt": null,
  "failureCount": 0,
  "createdAt": "2026-08-01T12:00:00.000Z",
  "updatedAt": "2026-08-01T12:00:00.000Z"
}
Webhooks

DELETE /v1/webhooks/:endpointId

DELETE/v1/webhooks/:endpointIdscope: webhook:write

Delete an endpoint and its delivery log.

curl -X DELETE https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Webhooks

POST /v1/webhooks/:endpointId/rotate-secret

POST/v1/webhooks/:endpointId/rotate-secretscope: webhook:write

Replace the signing secret. The new one is shown once, in this response only — switch your verification code to it before the old secret stops being useful.

curl -X POST https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z/rotate-secret \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Response
{
  "id": "whe_4hd9s0k2mq7z",
  "secret": "whsec_pq8m…2zt7"
}
Webhooks

POST /v1/webhooks/:endpointId/test

POST/v1/webhooks/:endpointId/testscope: webhook:write

Send a signed webhook.test event now, one attempt, no retry. Throttled to 10/min per caller.

curl -X POST https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z/test \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Response
{
  "id": "whd_6tq2k9m4xa1b",
  "event": "render.completed",
  "eventId": "evt_8m2kq4x7tb1c",
  "status": "succeeded",
  "attempt": 1,
  "nextAttemptAt": null,
  "responseStatus": 200,
  "responseBody": "ok",
  "error": null,
  "durationMs": 143,
  "deliveredAt": "2026-09-28T12:05:00.400Z",
  "createdAt": "2026-09-28T12:05:00.000Z"
}
Webhooks

GET /v1/webhooks/:endpointId/deliveries

GET/v1/webhooks/:endpointId/deliveriesscope: webhook:write

One endpoint's delivery log, newest first — includes payload, response and timing for each attempt.

ParamTypeNotes
pagenumberDefaults to 1.
limitnumberDefaults to 20, max 100.
status"pending" | "succeeded" | "failed" | "dead"Restrict to one delivery status.
curl "https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z/deliveries?status=failed" \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Response
{
  "items": [ {
      "id": "whd_6tq2k9m4xa1b",
      "event": "render.completed",
      "eventId": "evt_8m2kq4x7tb1c",
      "status": "succeeded",
      "attempt": 1,
      "nextAttemptAt": null,
      "responseStatus": 200,
      "responseBody": "ok",
      "error": null,
      "durationMs": 143,
      "deliveredAt": "2026-09-28T12:05:00.400Z",
      "createdAt": "2026-09-28T12:05:00.000Z"
    } /* … */ ],
  "total": 214,
  "page": 1,
  "limit": 20
}
Webhooks

POST /v1/webhooks/:endpointId/deliveries/:deliveryId/redeliver

POST/v1/webhooks/:endpointId/deliveries/:deliveryId/redeliverscope: webhook:write

Send a delivery again — same delivery id, same signed bytes — as a fresh run of retries. Throttled to 10/min per caller.

curl -X POST https://buildonce.app/v1/webhooks/whe_4hd9s0k2mq7z/deliveries/whd_6tq2k9m4xa1b/redeliver \
  -H "Authorization: Bearer fl_live_YOUR_API_KEY"
Answers 409 WEBHOOK_ENDPOINT_DISABLED while the endpoint is off — turn it back on first.
Webhooks

Errors

ParamTypeNotes
403 WEBHOOK_ENDPOINT_LIMITThe workspace already has 10 endpoints.
404 WEBHOOK_ENDPOINT_NOT_FOUNDUnknown id, or it belongs to another workspace.
400 WEBHOOK_URL_BLOCKEDThe URL is not https, carries credentials, or resolves to a private/internal address.
409 WEBHOOK_ENDPOINT_DISABLEDRedeliver was called while the endpoint is turned off.

Was this page helpful?