Hvilke operationer kræver en nøgle?
POST journal, POST products og POST invoices kræver Idempotency-Key. Nøglen skal være 8–128 tegn, begynde med et bogstav eller tal og derefter kun indeholde bogstaver, tal, punktum, underscore, kolon eller bindestreg. journal/prepare kræver den ikke, fordi kontrollen ikke bogfører eller opretter et domæneobjekt.
Brug en stabil reference for den logiske operation, eksempelvis en UUID gemt sammen med en bestemt ordreversion. Generér ikke nøglen inde i retry-loopet. Genbrug heller ikke en fast nøgle som invoice-create til alle kunder og fakturaer. Nøglens betydning er én konkret tilsigtet operation med ét fast input.
Nøglens gyldighedsområde er app, organisation, operationstype og nøgle. To apps kan bruge samme tekst uden at dele resultat. En journalpostering og en produktoprettelse er forskellige operationstyper. En sandboxgeneration får egne syntetiske organisationsreferencer og dermed sin egen idempotenshistorik.
Samme input skal forblive samme input
Input valideres og normaliseres, før skrivningen udføres. Det normaliserede input gemmes sammen med resultatet. Ved genforsøg sammenlignes indholdet, ikke bodyens whitespace eller rækkefølgen af objektets nøgler. Rækkefølgen af posterings- og fakturalinjer er derimod en del af input og skal bevares.
Et felt, som blev udeladt og fik en dokumenteret standardværdi, kan normaliseres til samme input som en eksplicit standardværdi. Antag ikke, at alle semantisk lignende ændringer er ens: en ny dato, linjetekst eller et ændret beløb kan med rette give konflikt. Når forretningsindholdet ændres, skal klienten oprette en ny logisk operation og tage stilling til eventuel korrektion af den gamle.
Nøglen er ikke en autorisationsmekanisme. Et kald skal stadig have en gyldig app, scope, organisation og grant. Et tidligere resultat returneres ikke til et tilbagekaldt token. Et skifte til et nyt grant giver konflikt ved forsøg på at overtage samme nøgle, fordi den gamle kvittering ikke automatisk må gives til en anden adgangsbeslutning.
Samtidige requests og atomisk resultat
Skrivningen tager en transaktionsbundet lås på nøglens app-, organisations- og operationskontekst. Den kontrollerer derefter, om et resultat allerede findes. En unik constraint på samme kombination er et ekstra værn mod dubletter.
Det nye domæneobjekt, operationsresultatet, det eksterne resultatudsnit og eventuel webhook-outbox skrives i samme transaktion. Journalen delegeres til Hours' eksisterende bogføringsfunktion, og fakturakladden delegeres til Hours' eksisterende fakturafunktion. Der udføres ikke en løs sekvens med først en hovedbogsheader og derefter uafhængige linjekald.
Test integrationen med reelt samtidige requests og afbrudte klientforbindelser, og verificér antallet af domæneobjekter og operationer i sandbox.
Hvad gemmes ved fejl?
Input, der afvises før regnskabskernen, gemmer ingen kvittering. Det gælder alle 400-svar samt invalid_amount, journal_unbalanced og reference_not_allowed (422). Samme nøgle kan derfor genbruges med rettet input. En idempotensnøgle reserverer ikke en handling, som aldrig blev optaget.
En afvisning fra regnskabskernen (domain_rejected, for eksempel et lukket regnskabsår) gemmes som et afsluttet afvist resultat. Et genforsøg med samme nøgle og samme input afspiller denne afvisning. Samme nøgle med anden payload giver 409 idempotency_conflict. Ukendte databasefejl ruller hele transaktionen tilbage og efterlader ikke en falsk succeskvittering. Klienten må ikke afgøre commitstatus ud fra, om fejlteksten "ser midlertidig ud".
Der gives ikke en universel garanti om præcis én fysisk netværkslevering. Idempotensen afgrænser én domæneoperation på den beskrevne nøgle. Webhooks kan leveres flere gange; OAuth-refresh har særskilt replaybeskyttelse og følger ikke denne idempotenskontrakt.
Retry-algoritme hos integrationen
Gem operationens nøgle, normaliserbare input, målmiljø og lokal reference, før requesten sendes. Ved et klart 2xx-svar gemmes kvitteringen. Ved timeout eller en 5xx/503 med ukendt udfald beholdes nøglen og inputtet; vent med backoff og prøv den samme operation igen.
Ved idempotency_conflict skal du stoppe automatiske retries og sammenligne det input, klienten allerede har gemt. Ved idempotency_grant_changed kræves manuel afklaring af adgang og den tidligere operation. Opret ikke en ny nøgle for at skjule konflikten. Ved permanent inputfejl skal det faglige input rettes, ikke retries gøres hurtigere.
Brug ikke API'et til at rette en bogført postering ved at overskrive dens input. En bogført postering og en korrektion er forskellige faglige hændelser. Korrektions- og stornoendpoints findes ikke i partner-API'et; håndter en nødvendig korrektion gennem Hours' eksisterende, autoriserede proces.
Opbevaring og bevis
Idempotenshistorikken slettes ikke automatisk efter et fast antal timer. Historik, persondata, finansielle kontrolspor og pladsforbrug kræver en samlet retentionbeslutning, og en senere oprydningspolitik må ikke skabe et skjult vindue, hvor en gammel retry pludselig bogfører igen.
Ved fejlsøgning noteres request-id, operation-id, tidspunkt, miljø, apprevision og en lokal reference. Del ikke hele payloaden, når den ikke er nødvendig. Operationsdata indeholder input og skal behandles som beskyttede data; det er ikke en offentlig debuglog.