Skip to content

Create a webhook endpoint

The webhook_endpoints.create operation: POST /api/v1/webhook_endpoints in the REST API and the webhook_endpoints_create tool in the MCP server.

POST/api/v1/webhook_endpoints

Creates an endpoint that receives the brand's events in the request's mode: Ownrecord POSTs each event it subscribes to as JSON, signed with the Ownrecord-Signature header (see the webhooks concept page).

  • events lists event types from the catalogue that are delivered to webhooks, or ["*"] for all of them, including types added later.
  • url must be a public https URL. In development and test (dev gate open), http://localhost works too.
  • The response contains the signing secret in secret. It is shown only once: it is stored encrypted and can't be read again. Rotate it with webhook_endpoints.rotate_secret if you lose it.

A brand can have at most 16 endpoints per mode. Send a test event with webhook_endpoints.test.

At a glance

  • REST: POST /api/v1/webhook_endpoints
  • MCP tool: webhook_endpoints_create
  • Operation ID: webhook_endpoints.create
  • Scope: Brand
  • Permission: webhooks:admin
  • Risk tier: security
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the webhooks:admin scope
  • Since: M4

Request

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
urlstringYesThe https URL Ownrecord POSTs events to, e.g. https://example.com/webhooks/ownrecord.
eventsarray of stringYesEvent types to receive (from the event catalogue), or ["*"] for every event of the brand.
descriptionstringNo
enabledbooleanNoStart receiving events at once (default) or create it disabled.
metadataobjectNoYour own key-value pairs (at most 50 keys). On updates the whole set is replaced.

Response

201 Created with a JSON object:

FieldTypeDescription
idwe_… ID
object"webhook_endpoint"
brandIdbrd_… ID
livemodeboolean
urlstring
descriptionstring or null
eventsarray of string
enabledboolean
disabledReasonone of manual, failing or null
disabledAtdate-time or null
failingSincedate-time or null
secretRotatedAtdate-time or null
previousSecretExpiresAtdate-time or null
metadataobject
createdAtdate-time
updatedAtdate-time
secretstring

Examples

An endpoint for order fulfilment

HTTP
POST /api/v1/webhook_endpoints
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "url": "https://example.com/webhooks/ownrecord",
  "events": [
    "customer.created",
    "checkout.session.completed"
  ],
  "description": "Order fulfilment"
}

Response (201):

JSON
{
  "id": "we_01m4tx5nj8emwbyf7y9vcf47z0",
  "object": "webhook_endpoint",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "url": "https://example.com/webhooks/ownrecord",
  "description": "Order fulfilment",
  "events": ["customer.created", "checkout.session.completed"],
  "enabled": true,
  "disabledReason": null,
  "disabledAt": null,
  "failingSince": null,
  "secretRotatedAt": null,
  "previousSecretExpiresAt": null,
  "metadata": {},
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z",
  "secret": "whsec_ExampleOnlyNotARealSigningSecret0000000"
}

Every event of the brand

HTTP
POST /api/v1/webhook_endpoints
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "url": "https://example.com/webhooks/all",
  "events": [
    "*"
  ]
}

Response (201):

JSON
{
  "id": "we_01m4tx5nj8emwbyf7y9vcf47z0",
  "object": "webhook_endpoint",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "url": "https://example.com/webhooks/all",
  "description": null,
  "events": ["*"],
  "enabled": true,
  "disabledReason": null,
  "disabledAt": null,
  "failingSince": null,
  "secretRotatedAt": null,
  "previousSecretExpiresAt": null,
  "metadata": {},
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z",
  "secret": "whsec_ExampleOnlyNotARealSigningSecret0000000"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400A field is missing or malformed.Fix the fields listed in details.issues and send the request again.
webhook_url_not_allowed400The URL isn't https, or points at localhost, a private network or another refused address.Use a public https URL without a user name, password or #fragment, e.g. https://example.com/webhooks. In development, http://localhost works while the dev gate is open.
webhook_event_type_invalid400An event type isn't in the catalogue or isn't delivered to brand webhook endpoints.List event types from the event catalogue that are delivered to webhooks (docs: reference → events), or "*" for all of them.
webhook_endpoint_limit_reached400The brand already has 16 endpoints in this mode.Delete an endpoint you no longer use, or subscribe an existing endpoint to more event types.
permission_denied403You can't manage this brand's webhooks.Ask an organization owner or admin for a role or scope that allows this action.
livemode_not_allowed403You have no live-mode access, so you can't manage live webhooks.Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, resource_not_found, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.