> ## Documentation Index
> Fetch the complete documentation index at: https://docs.komerza.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Store Webhooks

> Receive order events on your own server, with signed payloads, delivery logs and retries

Store webhooks push order events from Komerza to your server as they happen - so you can sync orders into your own database, trigger fulfilment in an external system, or notify your team. They are managed in the dashboard under **Developers → Webhooks**.

<Note>
  Webhooks are **not** the same thing as [Dynamic
  Delivery](/guides/dynamic-delivery). A webhook notifies you that something
  happened; dynamic delivery asks your server for the content to deliver, and
  its response is sent to the customer. Use dynamic delivery to generate goods,
  and webhooks to observe orders.
</Note>

## Events

<ParamField query="order.created" type="event">
  A new order was created.
</ParamField>

<ParamField query="order.pending" type="event">
  Payment was received or detected and is settling.
</ParamField>

<ParamField query="order.completed" type="event">
  The order was delivered. Also fires for manual and re-deliveries.
</ParamField>

<ParamField query="order.cancelled" type="event">
  The order was cancelled or expired.
</ParamField>

<ParamField query="order.refunded" type="event">
  The order was refunded. Also emitted when an order enters the Disputed state.
</ParamField>

## Payload

Each delivery is a JSON envelope containing the event name, the order data, a `messageId` and a timestamp:

```json theme={null}
{
  "event": "order.completed",
  "messageId": "0f2b0b2c-1c2f-4b7f-9e2a-8f2b1c9d4e77",
  "timestamp": "2026-07-31T14:02:11Z",
  "data": {
    "id": "...",
    "status": "Delivered"
  }
}
```

<Tip>
  Use `messageId` for idempotency. Retries re-send the original payload, so a
  handler that stores processed message IDs will never double-process an order.
</Tip>

## Verifying the signature

Every request is signed with an HMAC signature in the **`X-Signature`** header. Verify it against your webhook's signing secret before trusting the payload - an unverified endpoint will accept anything anyone posts to it.

The verification approach is the same as for dynamic delivery: compute an HMAC-SHA256 of the raw request body using your secret, hex-encode it, and compare against the header. Full code samples for Node.js, Python and PHP are in the [Dynamic Delivery guide](/guides/dynamic-delivery#signature-verification).

<Warning>
  Compare the **raw** request body, exactly as received. Parsing and
  re-serialising the JSON before hashing changes the bytes and the signature
  will never match.
</Warning>

## Creating a webhook

<Steps>
  <Step title="Open Developers → Webhooks">
    Each webhook is scoped to one or more of your stores. You can have up to
    **25 webhooks per user**.
  </Step>

  <Step title="Enter your endpoint URL">
    The URL must be HTTP or HTTPS. URLs that resolve to private or reserved
    addresses are blocked - the log entry reads "Blocked: webhook URL resolved
    to a private or reserved address."
  </Step>

  <Step title="Copy the signing secret">
    The signing secret is shown **exactly once**, at creation: "Copy your
    signing secret below - it won't be shown again." There is no way to view it
    later.
  </Step>
</Steps>

<Warning>
  If you lose the signing secret, you cannot recover or rotate it - create a new
  webhook to get a fresh secret. Deleting a webhook also **deletes all of its
  logs**.
</Warning>

## Delivery logs

Each webhook has its own execution log. You can filter by status (Success 2xx / Failed 4xx-5xx) and date range, and search by log ID, order ID, or a fragment of the URL.

Failed deliveries record a readable reason - TLS or certificate failure, DNS failure, connection refused, or timeout. Each entry also records its attempt/retry number, so you can watch a failed delivery being retried.

**Resend** on any log entry re-sends the original payload using the webhook's current URL and secret.

### Paused delivery

If your endpoint fails repeatedly, delivery is temporarily paused and entries appear with response code **-1**:

> Delivery is temporarily paused because this endpoint has failed repeatedly. Delivery will resume automatically once it starts responding.

Fix the endpoint and delivery resumes on its own - there is nothing to re-enable in the dashboard.

### Per-order logs

On any order's detail page, the **Webhook Execution Logs** card shows the most recent 100 deliveries for that specific order (date, URL, status code, attempt/retry number, response) - useful when debugging one order rather than a whole endpoint.

## Endpoint best practices

<AccordionGroup>
  <Accordion title="Respond 2xx quickly, then do the work">
    Acknowledge the delivery immediately and process asynchronously. Slow
    handlers time out and get retried, which looks like duplicate events.
  </Accordion>

  <Accordion title="Be idempotent">
    Retries, manual **Resend**, and re-deliveries all mean the same order can
    arrive more than once. Key your processing on `messageId` or the order ID.
  </Accordion>

  <Accordion title="Verify before trusting">
    Check the `X-Signature` header on every request, and return 401 when it does
    not match.
  </Accordion>

  <Accordion title="Don't treat webhooks as your only source of truth">
    Endpoints go down. Reconcile periodically against the [Orders
    API](/api-reference/endpoint/orders/get-list) rather than assuming every
    event arrived.
  </Accordion>
</AccordionGroup>

<Note>
  Discord notifications are configured in **Store Settings → Notifications**,
  not on the Webhooks page.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks API" icon="code" href="/api-reference/endpoint/webhooks/create">
    Create, update and inspect webhooks programmatically.
  </Card>

  <Card title="Webhook Logs API" icon="list" href="/api-reference/endpoint/webhooks/get-logs">
    Read delivery logs and resend deliveries.
  </Card>

  <Card title="Dynamic Delivery" icon="bolt" href="/guides/dynamic-delivery">
    Generate delivery content on demand from your own server.
  </Card>

  <Card title="Managing Orders" icon="receipt" href="/guides/orders">
    What each order event means operationally.
  </Card>
</CardGroup>
