Naar de inhoud
Documentatie
Nederlands
De applicatie openen

Idempotentie

Een schrijfbewerking opnieuw afspelen zonder dubbel record dankzij X-Client-Mutation-Id, en een wijziging beschermen met de optimistische vergrendeling X-Base-Version.

Een netwerk kan uitvallen tussen het versturen van uw request en het ontvangen van het antwoord. U weet dan niet of de factuur is aangemaakt. Idempotentie beantwoordt die vraag: u verstuurt dezelfde request opnieuw met dezelfde sleutel, en NovaFisko garandeert dat ze maar één keer wordt uitgevoerd.

De sleutel X-Client-Mutation-Id

Voeg de header X-Client-Mutation-Id toe aan elke schrijfrequest (POST, PUT, PATCH, DELETE) die betrekking heeft op een dossier, dus onder companies/{company}.

curl -X POST https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries/invoice \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Client-Mutation-Id: 0b0f7a52-63f4-4f1f-8a43-0d4f6b0b8a10" \
  -d '{
    "journal_id": 3,
    "third_party_id": 41,
    "entry_date": "2026-10-02",
    "reference": "F-2026-0918",
    "lines": [{"account": "604000", "amount": "1250.00", "vat_code": "A21"}]
  }'

Regels

Regel Detail
Formaat Vrije string van 1 tot 64 tekens. Een UUID versie 4 is perfect geschikt
Bereik De sleutel is uniek per dossier
Opslag Alleen de geslaagde antwoorden (status 2xx) worden opgeslagen
Betrokken requests POST, PUT, PATCH, DELETE onder companies/{company}
Uitzondering sync/push beheert zijn eigen idempotentie, mutatie per mutatie

Een lege sleutel of een sleutel van meer dan 64 tekens wordt genegeerd: de request wordt normaal uitgevoerd, zonder bescherming.

Eerste verzending

De request wordt uitgevoerd. Als ze slaagt, slaat NovaFisko de status en de body van het antwoord op.

HTTP/1.1 201 Created
X-Operation-Id: 5d0f6a7e-2f0b-4a35-9b56-7f1f3c1f4c22

Herhaling

Als u dezelfde sleutel opnieuw verstuurt voor hetzelfde dossier, wordt er niets uitgevoerd. U ontvangt de opgeslagen body, met de status 200 en een header die de herhaling aangeeft.

HTTP/1.1 200 OK
X-Idempotent-Replay: 1
Content-Type: application/json
Let op

Een herhaling antwoordt altijd 200, ook als de oorspronkelijke request 201 of 204 had geantwoord. Beschouw elke 2xx-status als een succes en controleer X-Idempotent-Replay als u beide gevallen moet onderscheiden.

Wat niet wordt opgeslagen

Een request die mislukt (4xx, 5xx) wordt niet opgeslagen. U kunt de gegevens corrigeren en dezelfde sleutel opnieuw versturen, of het ongewijzigd opnieuw proberen na een fout 500 of 503.

De opgeslagen body is beperkt tot 500 kB. Daarboven geeft de herhaling 200 terug met een body null: de bewerking heeft wel degelijk plaatsgevonden, lees de resource opnieuw om de toestand ervan te kennen.

De sleutel goed kiezen

  • Genereer de sleutel vóór de eerste verzending en sla hem samen met de bewerking op in uw systeem.
  • Een sleutel staat voor een intentie, niet voor een poging: alle pogingen van dezelfde bewerking delen dezelfde sleutel.
  • Hergebruik nooit een sleutel voor een andere bewerking. De server vergelijkt de body's niet: hij zou het resultaat van de eerste teruggeven.

Een deterministische sleutel werkt zeer goed wanneer uw systeem al een stabiele identificator heeft:

// One key per business operation, stable across retries
$key = substr(hash('sha256', 'erp-atelier:purchase-invoice:'.$invoice->id), 0, 64);

Voorbeeld van een retry-lus

import { randomUUID } from "node:crypto";

async function postOnce(url, body, token) {
  const mutationId = randomUUID(); // generated once, reused on every retry
  for (let attempt = 0; attempt < 5; attempt++) {
    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
          Accept: "application/json",
          "X-Client-Mutation-Id": mutationId,
        },
        body: JSON.stringify(body),
      });
      if (response.status === 429 || response.status >= 500) {
        const wait = Number(response.headers.get("Retry-After") ?? 2 ** attempt);
        await new Promise((resolve) => setTimeout(resolve, wait * 1000));
        continue;
      }
      return {
        replayed: response.headers.get("X-Idempotent-Replay") === "1",
        status: response.status,
        data: await response.json(),
      };
    } catch (networkError) {
      await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 1000));
    }
  }
  throw new Error("NovaFisko API unreachable");
}

Optimistische vergrendeling met X-Base-Version

Idempotentie beschermt tegen uw eigen dubbels. De optimistische vergrendeling beschermt tegen de wijzigingen van anderen: ze voorkomt dat u een wijziging overschrijft die tussen uw lees- en uw schrijfbewerking is gemaakt.

Elke resource die door de geschiedenis wordt gevolgd, toont een geheel getal version. Stuur de waarde die u hebt gelezen mee in de header X-Base-Version van een PATCH, een PUT of een DELETE.

curl -X PATCH https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/third-parties/41 \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Base-Version: 3" \
  -d '{"email": "compta@brasserie-collines.example"}'

Als de versie op de server nog altijd 3 is, wordt de wijziging toegepast. Als iemand de derde intussen heeft gewijzigd, wordt er niets aangeraakt en antwoordt de API 409:

{
  "message": "Cet enregistrement a été modifié entre-temps.",
  "code": "conflict",
  "server_version": 5,
  "server_data": {
    "id": 41,
    "type": "supplier",
    "name": "Brasserie des Collines SA",
    "email": "facturation@brasserie-collines.example",
    "version": 5
  }
}

Om het conflict op te lossen: vergelijk server_data met uw waarden, beslis wat moet worden behouden en verstuur de request opnieuw met X-Base-Version: 5.

Punt Gedrag
Activering Alleen als de header aanwezig en numeriek is
Methodes PATCH, PUT, DELETE. Genegeerd bij POST
Vergelijking Conflict als de versie op de server strikt hoger is dan de uwe
Betrokken resource Het record dat door de URL wordt aangeduid (nooit het dossier zelf)
Opmerking

De versiecontrole gaat vóór de idempotente herhaling. Combineer beide headers gerust: X-Base-Version beschermt het gegeven, X-Client-Mutation-Id beschermt de poging.

En voor offline batches

POST sync/push past dezelfde principes toe op een batch mutaties: elke mutatie draagt haar client_mutation_id en, als u dat wenst, haar base_version. Een al verwerkte mutatie komt terug met de status duplicate en haar oorspronkelijke resultaat. Conflicten worden er veld per veld samengevoegd in plaats van geweigerd. Zie Continu synchroniseren.

Zie ook