Idempotency
A network failure leaves a client unsure whether a write happened. Send an Idempotency-Key header and retry with the same value: MASK writes once and answers every retry with the first answer.
The rules#
- The value is 1 to 128 visible ASCII characters (
!to~, no spaces); anything else is 400validation_failed. - It is required on
POST /integration/events(400idempotency_requiredwithout it) and accepted on every other write. Use your own event id (erp-clock-88123): retries of the same event then carry the same key by construction. - A retry within 24 hours, from the same API key, with the same idempotency key and the same request, gets the stored status and body back with
Idempotent-Replayed: true, and nothing is written again. "The same request" is the method, the route, the path and the JSON body; key order and fields MASK does not read make no difference. - The same
Idempotency-Keywith a different request is 422idempotency_mismatch. - A retry while the first request is still running is 409
idempotency_in_progresswithRetry-After: 1. A first attempt that never finishes is treated as failed after a few minutes, and the next retry runs the write. - Only successes (2xx) are stored. A refused request (400, 403, 404, 409) stores nothing: fix it and resend with the same key, or use a new one.
- A replay is authorised again: the key must still have the scope and the institution, and the employee or event must still be visible to it (otherwise the current 403 or 404). It then returns the original body, as it was at the first call, for example the memberships as they were then; read the resource for its current state.
- A replay costs a rate-limit token like any request.
Example#
curl -si -X POST "$MASK/integration/events" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-H 'Idempotency-Key: erp-clock-88123' \
-d '{"employeeId":24,"institutionId":1,"eventCode":"clock_in","eventTime":1793802122,"note":"Gate 2 (ERP event 88123)"}'
# sent twice: the second answer is the first one again
HTTP/1.1 201
X-Request-Id: ed62e396-23e7-43ba-b535-a7e7ec0de702
Idempotent-Replayed: true
Content-Type: application/json
{"id":7605,"employeeId":24,"institutionId":1,"businessDate":"2026-11-04","eventCode":"clock_in","eventTime":1793802122,"source":"api","status":"active","anomalies":[],"note":"Gate 2 (ERP event 88123)","createdAt":1793812922}
The same header with a changed body:
{
"status": "error",
"code": "idempotency_mismatch",
"message": "This Idempotency-Key was already used for a different request",
"requestId": "e19ce9ce-3245-4a55-8fe1-ed3885a44e4b"
}