Samme rækker som /events, men med den garanti en afstemning kan hvile på:
«Kalder du med markør X, får du hver hændelse med seq > X, i rækkefølge, uden dubletter og uden huller, til og med complete_through = Y.»
Gemmer du Y og kalder igen, begynder næste svar over Y. Ingen hændelse med seq ≤ Y kan blive synlig efter du har fået Y — rækkefølgen er commit-rækkefølgen, fordi nummeret tildeles under kontoens rækkelås. En tabt webhook bliver dermed en FORSINKELSE, ikke et TAB.
Forskellen fra /events — og hvorfor den findes. /events' cursor er et hændelses-id og udelades (null) når du er ajour; er du ajour eller har feedet tabt hændelsen, har du intet at gemme. /changes returnerer ALTID en markør, også på et tomt svar, og markøren er et tal der overlever at hændelsen selv forsvinder.
Hvad sker der når kaldet udebliver? Ingenting går tabt: markøren står stille, og næste kald leverer alt det mellemliggende. Der er ingen tidsfrist på et ubrugt kald.
Hvad hvis du mister markøren? Så er du på egen hånd — og det er et gyldigt svar, men det skal stå skrevet: der findes ingen «hvor var jeg»-genopretning. Du har to veje, og de koster hver sit: (a) kald uden cursor og genafspil feedet fra begyndelsen — korrekt, men hele historikken; (b) hent en frisk markør på GET /changes/cursor og genindlæs de ressourcer du har brug for via listekaldene — billigere, men du får ALDRIG de hændelser der ligger imellem.
Hvad hvis markøren er for gammel? 410 cursor_too_old, aldrig et afkortet svar. Serveren kender det højeste fjernede seq (accounts.events_pruned_through) og nægter at svare på en markør derunder, fordi svaret ville have et hul. I dag fjernes hændelser kun af POST /sandbox/reset; indføres en opbevaringsgrænse, er det den samme 410.
Hvad hvis markøren hører til en anden konto? 409 cursor_wrong_account. Markøren bærer kontoen, netop fordi et blot tal ville blive besvaret pænt og fuldstændigt på den forkerte konto — sandbox-markøren der følger med konfigurationen over i live er den typiske.
Hvad hvis markøren hører til en nøgle med et andet kreditor-skop? 409 cursor_wrong_scope (siden 17-09-2026). Markøren bærer et AFTRYK af nøglens kreditor-skop — ikke skopet selv, så markøren røber ikke hvad nøglen kan se. Uden det ville en markør hentet med en nøgle skopet til kreditor A og brugt med en nøgle skopet til B blive besvaret 200: B ville få sine hændelser OVER markøren, og alt B havde UNDER den ville være tavst væk for altid. Aftrykket er bundet til MÆNGDEN af kreditorer, ikke til rækkefølgen: to nøgler med samme kreditorer i forskellig orden deler markør.
Hvad hvis markøren hører til et andet filter? 409 cursor_wrong_filter (siden 18-09-2026). Markøren bærer også et aftryk af det filter (type/creditor_id) kaldet blev gjort med. Uden det ville en markør hentet med ?type=invoice.* og brugt uden filter (eller omvendt) blive besvaret 200 — og de hændelser der lå UNDER markøren og først matcher det nye filter, ville være tavst væk for altid. Egen kode, fordi «skiftet filter» og «forkert nøgle» er to forskellige rettelser i din log. De to stavemåder invoice.* og invoice. er SAMME filter og deler markør. Næste skridt: hent en frisk markør på GET /changes/cursor med SAMME filter som du kalder /changes med — eller før én markør pr. filter.
Hvad hvis markøren er fra før 17-09-2026? 409 cursor_missing_scope (før skop-aftrykket; to-delte markører mangler begge aftryk og får den ældste mangels kode). Er den fra 17.–18.-09-2026 (med skop-aftryk, uden filter-aftryk): 409 cursor_missing_filter. Markører fra ældre formater kan ikke afgøres gyldige og accepteres ikke — der er ingen overgangsordning, fordi et format uden aftryk der forbliver lovligt, er den dør fejlene ovenfor kommer ind ad igen. Næste skridt er det samme som ved de andre 409'ere: hent en frisk markør på GET /changes/cursor MED DEN NØGLE og MED DET FILTER du vil kalde med, og genindlæs det du mangler under den via listekaldene.
Hvad hvis markøren er FORUD for feedet? 409 cursor_ahead_of_feed — markøren hører til en anden konto eller et miljø der er gendannet fra backup. Et tomt svar ville ligne «ajour».
Huller i NUMRENE er ikke huller i feedet. Ruller en transaktion tilbage efter at have taget sit nummer, findes nummeret aldrig. Løftet er «ingen hændelse springes over», ikke «numrene er sammenhængende» — tæl ikke på sammenhæng.
Markøren hører til nøglens skop og til kaldets filter — og BEGGE håndhæves. En kreditor-begrænset nøgle ser kun sine egne hændelser; skopet afvises med 409 cursor_wrong_scope, filteret (siden 18-09-2026) med 409 cursor_wrong_filter. Kalder du med type=/creditor_id=, dækker markøren kun DET filter; vil du følge flere filtre, så før én markør pr. filter — de afviser hinanden i stedet for tavst at springe hændelser over.
⚠️ complete_through er feedets position, ikke dit højeste seq. Er du filtreret — af nøglens kreditor-skop eller af type=/creditor_id= — rykker markøren frem forbi de hændelser, filteret sorterede fra, når siden er fuldstændig. Tallet er derfor normalt HØJERE end den sidste hændelse i data, og det er præcis det, der gør et tomt svar til et fremskridt i stedet for en evig genscanning. Se GET /changes/cursor for konsekvensen.