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

# Webhook events and payloads

> Register a webhook with the OTO API, see what each of the three event types sends, verify HMAC-SHA256 signatures, and build an endpoint that holds up.

A webhook turns the integration around. Instead of asking OTO what happened every few minutes, you host a URL and OTO tells you.

## The three event types

| Type | Fires when | Use it for |
| - | - | - |
| `orderStatus` | An order's status changes — processing, delivered, returned and everything between. | Keeping your own system, and your customer, current. This is the default. |
| `shipmentError` | A shipment fails to be created with the carrier. | Catching the orders that would otherwise sit still. Carries the carrier's own message. |
| `newOrders` | An order arrives in OTO. | Pushing orders onward into a different WMS. |

> [!TIP]
>
> **Subscribe to shipmentError even if you subscribe to nothing else**
>
> A failed booking is silent by nature: the order does not move, and no status change fires because nothing changed.
>
> The payload names the cause — an `errorCode`, and the carrier's own words in `deliveryCompanyResponse`, typically something like a missing city or postcode. Those are fixable in seconds if someone knows, and invisible for days if nobody does.

## Registering one

`POST /rest/v2/webhook` Starter+

| Field | Required | What it does |
| - | - | - |
| `url` | Yes | Your endpoint. |
| `method` | Yes | `POST` or `PUT`. |
| `webhookType` | No | One of the three above. Defaults to `orderStatus` and `newOrders`. |
| `secretKey` | No | The shared secret the payload signature is computed with. |
| `authorizationKey` | No | A token sent with the request so your endpoint can reject anything else. |
| `timestampFormat` | No | The timestamp format you want, e.g. `yyyy-MM-dd HH:mm:ss`. |
| `orderPrefix` | No | A prefix to strip from order IDs before sending, if OTO's IDs carry one your system does not expect. |

`GET` lists your subscriptions, `PUT` updates one by `id`, and `DELETE` removes it. All at the same path.

## What arrives

An `orderStatus` payload carries the order and its new state, the carrier and driver where there is one, the tracking number and URL, a link to the AWB, and a `timestamp` in **UTC**.

A `shipmentError` payload carries the `orderId`, an `errorCode`, OTO's `errorMessage` and the carrier's raw `deliveryCompanyResponse`.

A `newOrders` payload carries the whole order — address, items, weight, totals, payment method, sales channel and warehouse.

## Verifying that it came from OTO

Every payload carries a `signature`: an **HMAC-SHA256** over a colon-joined string, base64 encoded, using the `secretKey` you registered.

| Event type | Signed string |
| - | - |
| `orderStatus` | `orderId:status:timestamp` |
| `shipmentError` | `orderId:errorCode:timestamp` |

> [!WARNING]
>
> **Verify the signature, and reject stale timestamps**
>
> Your webhook URL is reachable by anyone who learns it. Without verification, anyone who does can tell your system an order was delivered.
>
> Recompute the HMAC over the signed string and compare it with a constant-time comparison. Then check the timestamp is recent — a valid signature on an old payload is a replay, and marking yesterday's order delivered again is the mildest thing it can do.

## Building an endpoint that holds up

* **Answer immediately.** Return 200 as soon as you have the payload, and do the work afterwards. A slow endpoint looks like a broken one.
* **Expect duplicates.** Deliveries can repeat. Key on `orderId` plus status plus timestamp and make reprocessing harmless.
* **Expect them out of order.** Network timing does not respect your state machine. Never move an order backwards because an older event arrived late.
* **Log the raw body before parsing it.** When an integration misbehaves at 2am, the payload you did not keep is the one you needed.

## Related

* [Authentication](https://docs.tryoto.com/developers/authentication.md) — tokens and the sandbox.
* [Status and tracking updates](https://docs.tryoto.com/modules/sales-channels/updates.md) — the same events, pushed to a sales channel instead.
* [Endpoint index](https://docs.tryoto.com/developers/rest-api-reference.md) — everything else.


## Related topics

- [Webhooks for real-time updates](https://docs.tryoto.com/integrations/webhooks.md)
- [OTO API overview](https://docs.tryoto.com/developers/overview.md)
- [Security & compliance](https://docs.tryoto.com/platform/security-and-compliance.md)


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