# Security best practices

> Keep API keys and webhook secrets safe, limit what each key can do, rotate both without downtime, and handle personal data carefully.

## API keys

An API key acts for your whole workspace: whoever holds a live key can book deliveries that are invoiced to you.

- **Server-side only.** Call the API from your backend. Never put a key into a website, mobile app, or desktop app, and never commit it to a repository.
- **Store it as a secret,** in your secret manager or deployment environment.
- **One key per system.** A separate key for the shop, the ERP, and each environment lets you revoke one without breaking the others.
- **Least privilege.** Give each key only the permissions it needs:

| Permission | Allows |
| --- | --- |
| `quotes:create` | Quote routes. |
| `deliveries:read` | Read deliveries, tracking, and proof of delivery. |
| `deliveries:write` | Create and cancel deliveries. |
| `webhooks:manage` | Create, change, test, and delete webhook endpoints. |
| `fleet_orders:create`, `fleet_orders:read` | Fleets only: push and read orders on your dispatch board. |

A missing permission answers `403 permission_denied`.

- **Expiry dates.** Give keys for temporary integrations or contractors an expiry date when you create them.

### Rotate a key

**1. Create the new key**

Create a second key with the same permissions in **Settings → API keys**.

**2. Deploy it**

Switch your system to the new key. Both keys work in parallel.

**3. Revoke the old key**

Once no request uses the old key anymore, revoke it. Requests with a revoked key answer `401 invalid_api_key`.

## Webhook secrets

- The signing secret (`whsec_…`) is returned once, when you create the endpoint. Store it like an API key.
- [Verify every request](https://maxmove.com/en/developers/docs/webhooks/verify-signatures): recompute the HMAC over the raw body, compare in constant time, and reject timestamps older than 5 minutes.
- Don't put secrets or tokens into the webhook URL. Maxmove signs every request, so the URL needs no protection of its own.

### Rotate a webhook secret

[`PATCH /v1/webhooks/{webhookId}`](https://api.maxmove.com/v1/docs#tag/webhooks/PATCH/v1/webhooks/{webhookId}) with `"rotate_secret": true` returns the new secret once. For the next 24 hours, every event carries two signatures in `webhook-signature`, one per secret, so your verifier accepts it with whichever secret is deployed. `previous_secret_expires_at` on the endpoint shows when the old secret stops signing. Deploy the new secret within that window. Standard Webhooks libraries already accept any matching signature in the header.

## Webhook URLs

Maxmove only sends webhooks to public HTTPS URLs. Private, local, and reserved addresses are rejected when you register the endpoint and checked again, including DNS, before every send.

## Personal data

Deliveries contain personal data: names, phone numbers, addresses, and proof-of-delivery photos and signatures.

- Store only what your process needs, and delete it on your usual retention schedule.
- Download proof-of-delivery files into storage with the same access rules as your other customer data. The download links expire quickly by design.
- Webhook payloads carry only the courier's name, because webhooks often end up in logs. Read the courier's photo, vehicle, and position from the tracking endpoint when needed.

## Report a security issue

Report security findings to Maxmove support at [support@maxmove.com](mailto:support@maxmove.com).

---

Source: https://maxmove.com/en/developers/docs/guides/security
