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

# Webhooks

> Signed events for new orders, prescriptions and stock, and how to verify them.

GO JOE sends every event to your account's webhook URL (HTTPS, public host).
Signatures follow the [Standard Webhooks](https://www.standardwebhooks.com)
spec, so you can use the official library for your language.

## Headers

| Header | Meaning |
| - | - |
| `webhook-id` | Event id. Same on every retry. De-duplicate on it. |
| `webhook-timestamp` | Unix seconds when this attempt was signed. |
| `webhook-signature` | `v1,<base64 HMAC-SHA256>` of `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the base64-decoded part of your `whsec_…` secret. |

Reject a timestamp more than 5 minutes off, and compare signatures in constant time.

## Verify (Node.js, no library)

```js theme={null}
import { createHmac, timingSafeEqual } from 'node:crypto'

function verify(secret, headers, rawBody) {
  const id = headers['webhook-id'], ts = headers['webhook-timestamp']
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
  const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64')
  const expected = 'v1,' + createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest('base64')
  return headers['webhook-signature'].split(' ').some((sig) =>
    sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
}
```

## Delivery rules

* Answer `2xx` within 10 seconds; do the real work afterwards (queue it).
* Redirects are not followed.
* Failed deliveries are retried after 1, 2, 5, 10 and 30 minutes, then hourly, for 24 hours.
* After 24 hours of failures GO JOE's team is alerted. The events stay in
  `GET /events` for 30 days, so you can always catch up.
* Events can arrive out of order. Always fetch the order for the current state;
  the event only tells you *that* something changed.

## Event types

| Type | What to do |
| - | - |
| `order.created` | New order. Fetch it, download the prescription, accept it. |
| `order.prescription_signed` | Download the prescription again; file the signed version. |
| `order.prescription_replaced` | A new Vorab-Rezept replaces the previous one. Download again. |
| `order.status_changed` | Status changed (also GO JOE courier moves). Refresh. |
| `order.updated` | Delivery address or time changed. Refresh. |
| `order.cancelled` | Stop. Do not dispense. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.