Maxmove LogoDocs

Webhook events

Register an HTTPS endpoint, choose delivery events, and read the signed event envelope Maxmove sends for every delivery change.

View as Markdown

Webhooks tell your system about every delivery change as it happens, so you don't need to poll. Maxmove sends a signed POST with a JSON body to your endpoint for each event.

Register an endpoint#

Register a public HTTPS URL with POST /v1/webhooks. The key needs the webhooks:manage permission. List the events you want in events, or leave it empty to receive all of them.

curl -X POST https://api.maxmove.com/v1/webhooks \
  -H "x-api-key: $MAXMOVE_KEY" -H "content-type: application/json" \
  -d '{
    "url": "https://shop.example.com/maxmove/webhooks",
    "events": ["delivery.status_updated", "delivery.delivered", "delivery.cancelled"]
  }'

The response contains the endpoint id (we_…) and the signing secret (whsec_…). The secret is shown only in this response. Store it to verify signatures.

  • The URL must be a public HTTPS URL. Private and reserved network targets are rejected with 400 invalid_webhook_url.
  • Endpoints belong to the mode of the key that registered them. An endpoint registered with a test key only receives test deliveries, and the other way round.
  • A workspace can register a limited number of endpoints per mode. Above that, registration answers 409 endpoint_limit_reached.

Events#

EventSent when
delivery.createdThe delivery was created. data.status is pending.
delivery.status_updatedThe status changed, for example to picked_up or in_transit.
delivery.courier_assignedA courier accepted the delivery.
delivery.courier_arrivedThe courier arrived at a waypoint: data.status is at_pickup or at_dropoff. At an intermediate stop, the status doesn't change.
delivery.eta_updatedThe schedule or the route changed, so the expected arrival moved.
delivery.pod_submittedThe courier submitted proof at pickup or dropoff.
delivery.deliveredThe delivery was completed. delivered_at is set.
delivery.cancelledThe delivery was cancelled by you or by Maxmove, also when no courier was found. cancelled_at is set.

Events are sent for deliveries created with POST /v1/deliveries. Fleet orders don't send webhook events.

The API reference lists the request Maxmove sends for each event type.

How to read events#

  • One event per status change. Each forward status change produces one event. delivery.eta_updated, delivery.pod_submitted, and delivery.courier_arrived at intermediate stops don't change the status.
  • Always read data.status. Statuses that have their own event (courier_assigned, at_pickup, at_dropoff, delivered, cancelled) can also arrive as delivery.status_updated, depending on how the underlying updates are ordered. Use data.status from any event as the current status, rather than the event type.
  • delivery.courier_arrived without a status change. At intermediate stops, the courier's arrival is reported, but data.status stays the same.
  • delivery.eta_updated carries no ETA. It tells you that the schedule or route changed. Read the new ETA from GET /v1/deliveries/{deliveryId}/tracking.
  • delivery.pod_submitted per checkpoint. It is sent once for proof at pickup and once for proof at dropoff, so up to twice per delivery. Fetch the files from GET /v1/deliveries/{deliveryId}/proof-of-delivery.

Event body#

{
  "id": "evt_4c1f9e2b7a3d8c5e6f0a1b2c3d4e5f60",
  "type": "delivery.status_updated",
  "version": "2026-10",
  "created_at": "2026-10-07T09:42:11Z",
  "data": { "id": "del_…", "status": "picked_up", "pickup": { … }, "dropoff": { … }, … }
}

data is the delivery as returned by GET /v1/deliveries/{deliveryId}, without the courier's phone number and position: data.courier carries only the courier's name.

version changes only with breaking payload changes. Additive changes, such as new fields in data, keep the version. Ignore fields you don't know. See Versioning.

Test your endpoint#

POST /v1/webhooks/{webhookId}/test sends a signed sample delivery.status_updated event to the endpoint. Its data.id is del_sample and data.test is true, so your handler can recognize and ignore it. Disabled endpoints answer 409 endpoint_disabled.

With a test key, every test delivery also sends real events as the Robocourier moves it along.

Manage endpoints#

TaskRequest
List endpointsGET /v1/webhooks
Change URL, events, or descriptionPATCH /v1/webhooks/{webhookId}
Pause or resumePATCH with "status": "disabled" or "status": "active"
Rotate the signing secretPATCH with "rotate_secret": true
Delete an endpointDELETE /v1/webhooks/{webhookId}

A disabled endpoint receives no new events. See Retries and replay for events that were already queued.

Did this answer your question?