Register an endpoint
POST/v1/webhooks
scope webhooks.manage
The signing secret is returned ONCE. Verify every delivery: X-Biklo-Signature is t=<timestamp>,v1=hmac_sha256(timestamp + "." + raw_body, secret) — the same scheme Stripe uses. An empty events list means every event.
Request body#
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | Where we POST the events. Must parse as an absolute URL (invalid_url, 400) and must be HTTPS in production (https_required, 400) — event payloads carry order ids and status. Registering the same URL twice on one integration returns endpoint_exists (409).Not supported Plain |
events | array | optional | Which events to send. An empty or missing array means EVERY event, including ones added after you register — that is the recommended setting, and the only one that keeps working as the API grows. Listing names explicitly freezes the subscription to those names. An unrecognised name is rejected with unknown_event (400), which names the offenders. GET /v1/webhooks returns available_events for the authoritative list.Accepts |
headers | array|object | optional | Extra request headers to send with every delivery to this endpoint. Either shape works: a list of {name, value} as shown, or a plain object {"X-Api-Key": "value"}. For a receiver behind an API gateway that checks a key of its own before routing the request. At most 5, names must be valid HTTP tokens, values at most 500 characters; anything else is invalid_header (400). Stored encrypted and never returned — GET /v1/webhooks shows the names and the first four characters only. This is NOT authentication: a fixed header value says nothing about the body it arrived with, so verify X-Biklo-Signature regardless.Not supported |
headers[]. | string | optional | The header name, e.g. X-Api-Key. A valid HTTP token: letters, digits and -. |
headers[]. | string | optional | What to send. Stored encrypted, never returned, and never written to a delivery record. |
Example
{
"url": "https://erp.example.com/hooks/biklo",
"events": [
"order.created",
"order.status_changed"
],
"headers": [
{
"name": "X-Api-Key",
"value": "the value your gateway expects"
}
]
}Response#
| Field | Type | Description |
|---|---|---|
id | integer | The new endpoint id. |
url | string | Where we will POST events. |
events | string[] | What it is subscribed to. |
is_active | boolean | true on creation. |
headers | array | The custom headers you registered, as {name, preview}. The values are never returned, not even here, so keep your own record of them. |
headers[]. | string | The header name we send. |
headers[]. | string | The first four characters of the value, then dots. Enough to tell two credentials apart, useless to anyone who does not already have it. |
secret | string | The signing secret, shown HERE AND NOWHERE ELSE. Store it now — it cannot be retrieved later, only replaced by deleting the endpoint and creating another. Every delivery is signed with it, and verifying that signature is what makes a webhook trustworthy. |
secret_note | string | A reminder that the secret appears once. |
Example
{
"id": 1,
"url": "https://erp.example.com/hooks/biklo",
"events": [
"order.created",
"order.status_changed"
],
"is_active": true,
"headers": [
{
"name": "X-Api-Key",
"preview": "the ••••••••"
}
],
"secret": "whsec_…",
"secret_note": "Shown once."
}