# Create a webhook endpoint

Registers an endpoint and returns its signing secret **once**. Store the secret: it is needed to verify
the `X-Orderwerks-Signature` header on every delivery and cannot be read back. Rotate it with
`POST /v1/webhooks/{webhookGuid}/rotate-secret` if it is lost.
A business may register up to 10 endpoints. The endpoint must subscribe to at least one event or
workflow trigger.

Endpoint: POST /v1/webhooks
Version: 1.19
Security: ApiKey, ApiSecret, UserGuid, UserToken, SupplierGuid

## Security:

  - `ApiKey` (unknown)
    apiKey in header x-apiKey

  - `ApiSecret` (unknown)
    apiKey in header x-apiSecret

  - `UserGuid` (unknown)
    apiKey in header userGuid

  - `UserToken` (unknown)
    apiKey in header userToken

  - `SupplierGuid` (unknown)
    apiKey in header supplierGuid

## Request fields (application/json):

  - `name` (string)

  - `url` (string)
    Must be HTTPS, carry no credentials and resolve to a public address. Redirects are not followed. A query parameter named like a credential (`token`, `key`, ...) is accepted with a warning; prefer `headers`.

  - `active` (boolean)

  - `events` (array)
    Event types to subscribe to (from `GET /v1/webhook-events`). `workflow.fired` is not subscribable here; use `workflow_triggers`.

  - `workflow_triggers` (array)

  - `workflow_triggers.workflow_guid` (string, required)

  - `workflow_triggers.order_state_id` (integer, required)
    Order state id of the step (same ids as `Order.order_state_id`).

  - `headers` (object)
    Up to 10 static headers sent with every delivery (for example an `Authorization` header your receiver expects). Values are stored encrypted and never returned. On an update, omit to keep the current headers or send `{}` to clear them. Headers Orderwerks sets itself (`Content-Type`, `User-Agent`, `X-Orderwerks-*`) cannot be overridden.

## Response 201:

  - `201` (unknown)
    The endpoint and its signing secret.

## Response 201 fields (application/json):

  - `webhook` (object)
    An outbound webhook endpoint registered by the business. The signing secret is returned once, when the endpoint is created or its secret is rotated, and never again. Static header values are write-only; only their names are returned.

  - `webhook.guid` (string, required)

  - `webhook.name` (string, required)

  - `webhook.url` (string, required)
    HTTPS URL deliveries are posted to.

  - `webhook.active` (boolean, required)
    False pauses the endpoint; events that happen while it is paused are not queued.

  - `webhook.events` (array, required)
    Subscribed event types. See `GET /v1/webhook-events` for the list.

  - `webhook.workflow_triggers` (array, required)

  - `webhook.workflow_triggers.workflow_guid` (string, required)

  - `webhook.workflow_triggers.order_state_id` (integer, required)
    Order state id of the step (same ids as `Order.order_state_id`).

  - `webhook.header_names` (array)
    Names of the static headers sent with every delivery.

  - `webhook.api_version` (string, required)
    Payload version pinned when the endpoint was created (sent as `X-Orderwerks-Api-Version`).
    Example: 2026-10-27

  - `webhook.consecutive_failures` (integer)
    Failed attempts since the last 2xx. Any 2xx resets it; at 50 the endpoint is disabled.

  - `webhook.disabled_at` (string)
    Set when Orderwerks switched the endpoint off (failure streak or a `410 Gone`). Re-enable by updating `active` to true.

  - `webhook.disabled_reason` (string)

  - `webhook.last_delivery_at` (string)

  - `webhook.last_success_at` (string)

  - `webhook.previous_secret_expires_at` (string)
    While set, deliveries are also signed with the secret that was rotated out.

  - `webhook.created_at` (string)

  - `webhook.updated_at` (string)

  - `signing_secret` (string)
    Shown once.
    Example: whsec_1f0c9d4e6a2b8c7d5e3f1a0b9c8d7e6f5a4b3c2d1e0f9a8b

## Response 400:

  - `400` (unknown)
    Validation failed. `message` starts with a stable code, optionally followed by a detail: `WEBHOOK_NAME_REQUIRED`, `WEBHOOK_NAME_TOO_LONG`, `WEBHOOK_URL_SCHEME`, `WEBHOOK_URL_CREDENTIALS`, `WEBHOOK_URL_FRAGMENT`, `WEBHOOK_URL_PRIVATE_ADDRESS`, `WEBHOOK_URL_HOSTNAME`, `WEBHOOK_URL_UNRESOLVED`, `WEBHOOK_URL_SYNTAX`, `WEBHOOK_EVENTS_INVALID`, `WEBHOOK_WORKFLOW_TRIGGERS_INVALID`, `WEBHOOK_SUBSCRIPTION_REQUIRED`.

## Response 400 fields (application/json):

  - `message` (string, required)
    Human-readable error message.
    Example: Invalid Catalog GUID

  - `error` (string)
    Underlying error detail, when available.

  - `code` (string)
    Machine-readable code for specific failures (for example `INVALID_DELTA_CURSOR`).

## Response 401:

  - `401` (unknown)
    Missing or invalid credentials.

## Response 401 fields (application/json):

  - `message` (string, required)
    Human-readable error message.
    Example: Invalid Catalog GUID

  - `error` (string)
    Underlying error detail, when available.

  - `code` (string)
    Machine-readable code for specific failures (for example `INVALID_DELTA_CURSOR`).

## Response 403:

  - `403` (unknown)
    The credentials are valid but the user lacks the access level this endpoint requires.

## Response 403 fields (application/json):

  - `message` (string, required)
    Human-readable error message.
    Example: Invalid Catalog GUID

  - `error` (string)
    Underlying error detail, when available.

  - `code` (string)
    Machine-readable code for specific failures (for example `INVALID_DELTA_CURSOR`).

## Response 409:

  - `409` (unknown)
    The business already has 10 endpoints (`WEBHOOK_LIMIT_REACHED`).

## Response 409 fields (application/json):

  - `message` (string, required)
    Human-readable error message.
    Example: Invalid Catalog GUID

  - `error` (string)
    Underlying error detail, when available.

  - `code` (string)
    Machine-readable code for specific failures (for example `INVALID_DELTA_CURSOR`).

