Facebook Pixel
Fit'DistanceDocumentation
Open the app
On this page

Writes and idempotency

Write with POST /operations, retry without duplicates using Idempotency-Key and preview an effect with dry_run.

Every write goes through POST /operations/<name>. This page explains how to pick an operation, how to retry without creating a duplicate and how to preview an effect before producing it.

Find an operation

GET /operations lists the operations. The call is public: no key, no credit. It is the source of truth for each operation: its kind (kind), the scope it requires (scope), its sensitive scopes (sensitive), whether it can be previewed (confirmable) and its arguments (input_schema).

curl https://api.fitdistance.io/api/partner/v1/operations \
  | jq '.data[] | {name, kind, scope, confirmable}'

A name missing from this list gets a 404 OPERATION_NOT_EXPOSED, with no credit.

Call an operation

The JSON body is the object of arguments, plus an optional dry_run. This example requires students:write:

curl -X POST https://api.fitdistance.io/api/partner/v1/operations/students.note_create \
  -H "Authorization: Bearer $FITDISTANCE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: note-42-2026-10-25" \
  -d '{"studentId": 42, "content": "Good session"}'

The response always has three fields: data (the result, whose shape depends on the operation), message and dry_run.

{ "data": { "uid": "…", "studentId": 42 }, "message": "", "dry_run": false }

Retry without duplicates

A call that times out leaves a doubt: did the write happen? The Idempotency-Key header removes it. It is optional, but send it on every write.

  • Give a value that is unique per intended write, from 1 to 128 characters, such as a UUID. An empty or longer value gets a 400 VALIDATION.
  • Same key and same request, meaning the same operation and the same body: the write runs once. The replay returns the stored response with Idempotency-Replayed: true, and its credit is refunded.
  • Same key and a different request: 409 IDEMPOTENCY_MISMATCH, free.
  • Same request still running: the replay waits for its response, otherwise 409 CONFLICT, free. If the conflict lasts, a call was interrupted: check whether the write happened, then send a new key.

An Idempotency-Key belongs to the API key that sends it, and is kept for 24 to 48 hours. 5xx and 429 responses are never stored: the retry runs. The refusal of an operation (a 4xx) is stored like a successful response: after you fix the request, use a new Idempotency-Key. With no credit left, even a replay gets a 402.

Preview with dry_run

Add "dry_run": true to the body: the operation announces its effect without writing anything.

  • It is a strict boolean: the string "true" is refused with a 400 VALIDATION.
  • Only operations with confirmable: true can preview. For the others: 400 DRY_RUN_UNSUPPORTED, free, and nothing ran.
  • messaging.send previews only with threadUid. With studentId, it answers DRY_RUN_UNSUPPORTED, because finding the student's thread can create it.
  • A preview writes nothing and is never debited, except for nine operations that debit the preview and refund it when nothing is written (at zero credit, their dry_run answers 402). It requires the same scope as the real call.
{
  "data": null,
  "message": "<the effect described by the operation>",
  "dry_run": true
}

data is null and the effect is in message. The dry_run is part of the body: for the real write, use another Idempotency-Key.

The script in Write a script applies these rules, and each operation is described in the reference.

Next pageWebhooksReceive the events of your account on your server: create a webhook, verify the signature, answer fast, retries and GET /events to catch up.