Idempotency & retries
Network errors and timeouts happen. When a request times out, you can't tell whether Helthjem received it. This page explains how to retry safely, especially for bookings.
Why it matters for bookings
POST /parcels/v1/bookings creates a real shipment. If a booking request times out and you simply send it again, you can end up with two shipments for one order: two labels, two deliveries and two invoice lines.
To prevent this, send an idempotency-key header with every booking request.
The idempotency-key header
If Helthjem receives a second booking request with the same idempotency-key within {N hours} of a successful booking, it returns the original response and does not create a new shipment.
curl -X POST "https://api.pre.helthjem.no/parcels/v1/bookings" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "idempotency-key: 3f1b2c9e-8a7d-4e21-9c55-0a1b2c3d4e5f" \
-d @booking.json
Choosing a key
- Use a value that is unique per shipment you intend to create. A UUID works well.
- Keep it to 40 characters or fewer. Longer keys are rejected with
400anderrorKey: over.max.length.of.idempotency.key. - Store the key with your order before you send the request, so that a crash or restart reuses the same key.
- Don't reuse a key for a different shipment. If one order needs two separate shipments, use two keys.
- If you change the request body, for example to fix a validation error, use a new key.
Without a key, every request is new
If you don't send an idempotency-key, each request is treated as a new booking. A retry after a timeout can create a duplicate shipment, which you then need to cancel.
When to retry
| Response | Retry? | What to do |
|---|---|---|
| Timeout, connection reset or no response | ✅ Yes | Retry with the same key. The booking may or may not exist; the key makes the retry safe. |
5xx |
✅ Yes | Retry with the same key, with exponential backoff, e.g. after 1 s, 2 s, 4 s and 8 s. Stop after about 5 attempts. |
401 |
✅ After refreshing the token | Request a new token, then retry with the same key. |
400, 403, 404 |
❌ No | The request itself is wrong. Fix it first, and use a new key if you change the body. |
Retrying other endpoints
| Endpoint | Safe to retry? |
|---|---|
GET labels and tracking |
Yes. They don't change anything. |
POST Single Address Check, pickup dates, nearby service points |
Yes. They only read data, even though they use POST. |
POST /auth/oauth2/v1/token |
Yes. Each call issues a new token. |
DELETE cancel a booking |
Yes in effect. Cancelling a booking that is already cancelled returns an error that you can treat as success. |
Your own shipmentId as a second safeguard
If you set your own shipmentId in the booking request, Helthjem rejects a second booking with the same value (400, errorKey: shipment.id.already.exists). Treat this error as "already booked" rather than as a failure. See Identifiers.
