Idempotency

Retry a create safely after a timeout or a network error.

Every POST that creates something accepts an Idempotency-Key header: 8 to 255 characters, ideally a UUID v4. Send one on every create, and send the same key when you retry. A retried create then never makes a second resource.

curl -X POST https://api.vojo-media.com/v1/screens \
  -H "Authorization: Bearer $VOJO_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2b9e-4d3a-4e8b-9f2a-1c7d5e3b8a40" \
  -d '{ "name": "Lobby North", "size_inches": 55 }'

What a retry returns

You send You get
The same key and body, within 24 hours The stored response (same status, same id) with Idempotent-Replayed: true. Nothing new is created.
The same key with a different body, or on a different endpoint 409 idempotency_key_reused. Use a new key for a new request.
The same key while the first request is still running 409 idempotency_request_in_progress. Wait, then retry with the same key.

If your connection drops during a create, the request carries on. Retry with the same key: you'll get idempotency_request_in_progress until it finishes, then its stored response.

Which responses are stored

  • A 5xx isn't stored, so retrying with the same key runs the request again.
  • A 409 or 429 isn't stored either.
  • Other 4xx responses, such as a 422, are stored and replayed. Fix the request and use a new key.

Keys belong to your secret key and organisation, so another integration using the same value never sees your response.

Replays show the past

A replay returns exactly what the original request returned, even if the resource has changed since. To see the current state, GET the resource.

A replayed POST /v1/webhook-endpoints returns the original signing secret, even if you've rolled the secret or deleted the endpoint since.

POST /v1/wrappers is the exception. Its replay returns the wrapper as GET /v1/wrappers/{wrapper_id} shows it, with the same id and nothing re-wrapped. For delivery_mode: "inline" that means html is null, because the inline document embeds the whole creative and Vojo doesn't keep it. If you need the file on a retry, use delivery_mode: "archive", whose url is replayed, or wrap again with a new key. If the wrapper has been deleted since, the replay returns 404.