Create a webhook endpoint
The response includes the endpoint's signing `secret`. Registers a URL that receives signed events. The URL must be `https://` on a public host and carry no credentials; private, loopback, link-local and internal addresses are refused with `INVALID_REQUEST_BODY`, including hosts whose DNS answers with one. An endpoint created without `event_types` receives every event type. Each mode allows 16 endpoints (`409 LIMIT_REACHED`). Store the `secret` when you read it here: no other response repeats it except `GET /webhooks/{id}/secret`. Send `Idempotency-Key` so a retried request does not add a second endpoint — a replayed response has the secret stripped out, since a stored response must not keep it.
The response includes the endpoint's signing secret.
Registers a URL that receives signed events. The URL must be https:// on a public host and carry no credentials; private, loopback, link-local and internal addresses are refused with INVALID_REQUEST_BODY, including hosts whose DNS answers with one. An endpoint created without event_types receives every event type. Each mode allows 16 endpoints (409 LIMIT_REACHED).
Store the secret when you read it here: no other response repeats it except GET /webhooks/{id}/secret. Send Idempotency-Key so a retried request does not add a second endpoint — a replayed response has the secret stripped out, since a stored response must not keep it.
Authorization
secretKey Your secret key: sk_live_… or sk_test_….
In: header
Header Parameters
Retrying with the same key returns the first response instead of creating a duplicate. 1 to 255 printable ASCII characters (INVALID_IDEMPOTENCY_KEY otherwise), remembered for 24 hours per key's merchant and mode. A replayed answer carries idempotent-replayed: true. The same key with a different body is refused with 422 IDEMPOTENCY_KEY_REUSED; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. A request that failed with a 5xx is not remembered, so it can simply be retried.
length <= 255Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
curl -X POST "https://example.com/webhooks" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.example/webhooks/utopia", "description": "Order fulfilment", "event_types": [ "payment.succeeded", "refund.succeeded" ] }'{ "object": "webhook", "webhook_id": "wh_0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b", "url": "https://your-app.example/webhooks/utopia", "description": "Order fulfilment", "event_types": [ "payment.succeeded", "refund.succeeded" ], "disabled": false, "livemode": true, "created_at": "2026-09-10T08:30:00.000Z", "secret": "whsec_8ZPqvj0oNn4cKcGbHkA6uRGyXwZ1TtQ2"}Update a customer PATCH
Changes a customer's name, email, phone number or metadata. Fields you leave out keep their values, and `metadata` replaces what was stored rather than merging into it. The new email must be free in this merchant and mode (`409 CUSTOMER_EXISTS`). Payments and subscriptions already taken keep the name, email and phone number they were paid with; they are not rewritten.
Delete a webhook endpoint DELETE
Deletes the endpoint, along with the deliveries still queued for it, and answers `{ "object": "webhook", "webhook_id", "deleted": true }`. This cannot be undone and the signing secret cannot be recovered afterwards: to stop deliveries and keep both, update the endpoint with `disabled: true` instead. The events themselves are kept and stay readable under `/events`.