Guide
Lister, paginering og synk
Hver samling kan leses på mer enn én måte, og forskjellen er ikke bekvemmelighet. Den avgjør om kopien din av dataene blir komplett.
Tre lesemodi
Alle rutene på denne siden har formen som er beskrevet i Å gjøre kall: /{instanceName}/api/v1/{locale}/person — entall, og uten partner/-ledd. Listevariantene henger på den samme stien. Velg én etter jobben du gjør, ikke etter hva som er raskest å skrive, for to av de tre vil stille og rolig gi deg et ufullstendig svar på et annet spørsmål.
| Modus | Rute | Rekkefølge | Ved samtidige endringer | Bruk den til |
|---|---|---|---|---|
| Offset-liste | GET /person |
den sort du ba om, indeksert med offset og limit |
posisjonene forskyver seg: rader kan hoppes over eller gjentas | en side et menneske ser på, engangsspørringer, alt som trenger et reelt totaltall |
| Cursor-liste | GET /person/cursor |
stigende entitets-id, som er innsettingsrekkefølgen | innsettingsstabil: en ny rad kan ikke fortrenge en du ikke har lest | ett konsistent uttrekk, gått gjennom fra start til slutt i én omgang |
| Tidslinje | GET /person/timeline |
stigende endringstid, fra en inklusiv since |
minst én gang: randrader gjentas, ingen faller ut | å gjenoppta en inkrementell synk, kjøring etter kjøring |
Ikke alle ressurser tilbyr alle tre. Person, Company, Project, Activity og Document har hele settet; de to malressursene har bare den vanlige offset-lista, og et mappetre for dokumenter returneres i sin helhet framfor sidevis. Tabellen API-flaten nederst på siden viser hvem som har hva.
Offset-lister
Standardvisningen av en samling: offset og limit inn i et sortert resultat, med et reelt totaltall og RFC 8288-navigasjonslenker i kroppen.
{
"totalItems": 143,
"totalPages": 8,
"page": 0,
"size": 20,
"items": [ { "id": "xK9mQ2", "firstName": "Kari", … }, … ],
"links": {
"self": "/acme/api/v1/en/person?offset=0&limit=20",
"first": "/acme/api/v1/en/person?offset=0&limit=20",
"next": "/acme/api/v1/en/person?offset=20&limit=20",
"last": "/acme/api/v1/en/person?offset=140&limit=20"
}
}
Følg links, ikke bygg URL-er selv. Hver lenke bevarer filtrene og sorteringen du sendte, og er en gyldig sti mot samme base-URL. Mangler next, er du på siste side. Person- og Company-lister tar også view=full, som gir hele posten for hver rad i stedet for det lette listeelementet, og setter taket for limit til 100.
Hvorfor en offset-løkke kan miste rader
En offset er en posisjon, ikke en rad. offset=20 betyr «hopp over de tjue første radene i resultatet slik det ser ut i det øyeblikket jeg spør» — og mellom det første kallet ditt og det andre kan resultatet endre form.
Si at en rad som sorterte foran sidegrensa din forlater resultatet: den slettes, deaktiveres ut av isActive-filteret ditt, eller endres slik at den sorterer senere. Alle rader bak den flytter seg nå én posisjon fram. Raden som skulle bli den første på side 2, glir opp i en posisjon side 1 alt har passert, og løkka di spør aldri om den posisjonen igjen — så den raden leveres aldri. Ingenting i svaret sier det: next peker fortsatt framover, og totalItems viser rett og slett ett lavere tall enn før. Den motsatte endringen — en rad som kommer til foran grensa — forskyver alt én posisjon bakover, og side 2 gir deg den siste raden fra side 1 en gang til.
offset=4 er fortsatt den samme posisjonen — den stiplede linja — men E har glidd over til venstre for den, og side 2 begynner på F. E leveres aldri, og ikke ett felt i svaret forteller det. En cursor spør om radene etter D i stedet for om den femte posisjonen, så den krysser linja og får med seg E.Offset-paginering er riktig for en side et menneske ser på, og for en spørring der du henter hele resultatet i ett svar. Den er feil løkke for et uttrekk eller en synk. En dublett kan du oppdage og forkaste; en oversprunget rad legger ikke igjen spor i svaret, i loggen eller i databasen din — du finner det ut måneder senere, av et totaltall som ikke stemmer. Må løkka være komplett, bruk cursor-lista.
Cursor-lister: ett konsistent uttrekk
GET /person/cursor paginerer med keyset over den monotone entitets-id-en, så den går gjennom samlingen i innsettingsrekkefølge og teller aldri posisjoner. Det finnes ikke noe totaltall — en keyset-side hopper over opptellingen. I stedet for en offset bærer hvert svar nextCursor og prevCursor, preget fra randradene i sida du nettopp fikk: nextCursor fra den siste raden, prevCursor fra den første. Det er nøyaktig det PersonCursorCodec og CompanyCursorCodec koder i partner-rest-service.
{
"items": [ { "id": "xK9mQ2", "firstName": "Kari", … }, … ],
"nextCursor": "MXxhfGNyZWF0ZWR8MjAyNi0…",
"prevCursor": "MXxifGNyZWF0ZWR8MjAyNi0…",
"links": {
"self": "/acme/api/v1/en/person/cursor?limit=100",
"next": "/acme/api/v1/en/person/cursor?cursor=MXxhfGNyZWF0ZWR8MjAyNi0…&limit=100"
}
}
En cursor er et ugjennomsiktig, URL-trygt token. Lagre det og send det tilbake ordrett; aldri tolk, rediger eller konstruer et. Ugjennomsiktig er ikke det samme som hemmelig — tokenet bærer ingen egen myndighet, og hva du får lese avgjøres fortsatt av bearer-tokenet ditt — men et token som ikke lar seg dekode, eller som er preget for en annen sorteringsnøkkel enn kallet bruker, avvises med 400.
Dette er det som gjør modusen innsettingsstabil: en rad som skrives mens du er halvveis gjennom gjennomgangen, får en id over grensa du står på, så den kan ikke skubbe en ulest rad bak deg. Filtre snevrer inn resultatet, men de bindes ikke inn i cursoren — så ikke endre dem underveis, for da sender du en cursor fra ett resultatsett inn i et annet.
- Start rent —
GET /person/cursor?limit=100, helt uten cursor. - Følg
links.next— den bærer alt den neste cursoren og filtrene dine. Ikke sett den sammen selv. - Stopp når
nextforsvinner — uttrekket er komplett.
Synk-semantikk. Dette er øyeblikksbilde-paginering — en stabil gjennomgang av de postene som finnes mens du går gjennom dem — og ikke et underlag du kan gjenoppta en synk fra. Entitets-id-en tildeles når en post skrives første gang, ikke når skrivingen committes, så tildelingsrekkefølge er ikke commit-rekkefølge: blir en side levert mens en post med lavere id ennå ikke er committet, leveres den posten aldri til denne gjennomgangen, og ingen senere side henter den inn. Gå gjennom den fra start til slutt for et engangsuttrekk. Skal noe holdes i synk, bruk tidslinja, som med sin upresishet gjentar rader i stedet for å droppe dem.
Tidslinjer: inkrementell synk
GET /person/timeline er mekanismen for inkrementell synk, og den er både tidsvinduet og cursor-paginert. since er en inklusiv nedre grense med åpen øvre ende, og sidene inne i vinduet går du gjennom med de samme ugjennomsiktige cursorene som i cursor-lista. Tidsstempler er UTC-øyeblikk med Z-forskyvning.
Tidslinjene for Person og Company lar deg velge hvilket tidsstempel du paginerer på, med key=created eller key=modified; en cursor preget for én nøkkel avvises med 400 på den andre. De øvrige har ikke valget: Project og Document paginerer på det sammenslåtte modified-eller-created-tidsstempelet, og Activity på siste endring, med fall tilbake til opprettelse.
# First run: one full export via /person/cursor, walked start to finish.
# Remember the highest "modified" value you saw. That is your watermark.
# Every run after that: ask for everything modified since a moment
# slightly behind the watermark, so the window overlaps.
curl "https://api.visena.example/acme/api/v1/en/person/timeline?key=modified&since=2026-08-20T01:59:00Z" \
-H "Authorization: Bearer $TOKEN"
# Walk links.next to the end. De-duplicate by person id, apply the
# changes, then store the new watermark.
Leveringen er minst én gang, så avdupliser på id. Søketidsstempelet leses tilbake med millisekundpresisjon fra en kolonne som lagres med mikrosekundpresisjon, så en post hvis nøkkelverdi har sifre under millisekundet kan komme igjen på neste side. Upresisheten gjentar rader og utelater aldri noen, og det er nettopp det som gjør et overlappende gjennomløp til å stole på: gjenoppta ved å sende kallet på nytt med since satt litt bak den siste verdien du så. Den nedre grensa er inklusiv, og det er det som gjør overlappet mulig å uttrykke i det hele tatt.
Ingen liste rapporterer en sletting. En slettet post slutter bare å vises — på offset-lista, cursor-lista og tidslinja likt — og en GDPR-sletting når en endringskonsument som en helt vanlig oppdatering framfor som en sletting. Å avstemme det som forsvinner er arbeid på din side: for poster betyr det en jevnlig full gjennomgang av cursor-lista, satt opp mot det du selv har. Dokumentarkivet er det ene unntaket, og det kommer nå.
Arkivets egen endringsstrøm
Dokumenter har de tre modusene som alt annet, og én til: GET /document/changes, en strøm av registrerte endringshendelser for dokumenter og mapper. Det er den eneste leseveien i Partner-API-et der en sletting er synlig, og det er dette landingssida mener med nattlige endringsstrømmer inn i rapporteringen din.
Den skiller seg fra en tidslinje på tre måter det er verdt å kjenne før du bygger på den. Den er eiereavgrenset: entityType og entityId er påkrevd, og det finnes ingen oppramsing på tvers av hele organisasjonen. Den paginerer bare framover: du sender nextCursor fra forrige side, og det finnes verken en cursor bakover eller en links.prev. Og den er ordnet etter registrert innsettingssekvens, som changed-tidsstempelet på hver hendelse ikke er monotont med — changed er et klokkeøyeblikk på noen løp og en oppgitt opprettelsestid på andre, så det er aldri et vannmerke å gjenoppta fra. Gjenoppta med cursor, og bare med cursor. Det finnes ikke noe totaltall heller, og det kommer ikke: journalen beskjæres aldri, så å telle den ville bety en sekvensiell gjennomgang av en stadig voksende tabell ved hvert kall.
# Owner-scoped: entityType and entityId are required, not optional.
curl "https://api.visena.example/acme/api/v1/en/document/changes?entityType=Company&entityId=bQ4wR8&limit=200" \
-H "Authorization: Bearer $TOKEN"
# Resume with nextCursor from the previous page — never with "changed".
Et komplett bilde av arkivet trenger tre kilder, ikke én. Dokument-tidslinja er bare oppsett og oppdatering: den rapporterer opprettelse, arkivering og omdøping, fordi omdøping er den eneste skrivingen Partner-API-et rekker som plattformen stempler modified på. Mappeflytting, erstatning av innhold og rene beskrivelsesendringer lar raden ligge og rapporteres ikke der. Slettinger vises bare på /document/changes. Så: tidslinja for oppsett og oppdatering, /document/changes for slettinger, og en jevnlig øyeblikksbilde-sammenlikning per eier for endringer i plassering, innhold og beskrivelse. Den tredje kilden er din side sitt ansvar, og ingenting i API-et minner deg på den.
Strømmen publiserer også sine egne grenser for fullstendighet — hvilke sammenslåtte skrivinger som bare registrerer én hendelse, hvilke endringer som ikke registrerer noe, og hvorfor strømmen for et prosjekt ikke dekker underprosjektene. Les dem i referansen for Document changes før du poller den.
Filtre og sortering
Filtre er vanlige spørringsparametere og kombineres fritt med alle lesemodusene. links i hvert svar bærer dem videre for deg, og det er den andre grunnen til å følge lenkene framfor å bygge dem opp igjen.
| Ressurs | Filtre | Sorteringsnøkler |
|---|---|---|
person |
query (navn, e-post og ansattnummer) · isActive · companyId · groupId · employeeNumber · externalReference · email |
created · modified · lastName |
company |
query (navn) · isActive · ownerGroupId · orgNumber · companyNumber · externalReference |
created · modified · name |
company-template |
isActive · shouldBeMonitored |
fast: name stigende |
project |
isActive · companyId |
created · modified · name |
project-template |
isActive · templateTypeId |
— |
activity |
projectId · companyId · responsibleId · statusId · isActive · query · dueBefore |
created · modified · name · dueDate |
document |
entityType + entityId (påkrevd) · query |
name · created · modified · modifiedOrCreated |
To ting å holde fast på. Dokumentlister er alltid avgrenset til én eiende post, så entityType og entityId er påkrevd framfor valgfrie — det finnes ingen oppramsing av dokumenter på tvers av organisasjonen. Og selskapsmaler er ordnet etter navn stigende, uten hensyn til store og små bokstaver, og har ingen sort-parameter i det hele tatt, fordi navn er det eneste feltet det kan sorteres på lenger inn.
Cursor- og tidslinjevariantene tar de samme filtrene som offset-søskenet sitt, men ingen sort: rekkefølgen deres er pagineringsnøkkelen, og det er hele poenget med dem.
API-flaten
Ni ressurser, lesemodusene hver av dem tilbyr, og hva du kan gjøre med den. Parametere, skjemaer og statuskoder per endepunkt ligger i referansen.
| Ressurs | Sti | Lesemodi | Hva du kan gjøre |
|---|---|---|---|
| Person | /person |
offset · cursor · timeline | Full CRUD · dublettsjekk · planlagt slettedato · GDPR-sletting, som er funksjonsstyrt per instans og svarer 202 når jobben legges i kø. |
| Company | /company |
offset · cursor · timeline | Full CRUD · dublettsjekk — et selskapsnummer eller organisasjonsnummer som alt er i bruk svarer 409 · sletting deaktiverer som standard, mode=delete er den harde. |
| Company template | /company-template |
bare offset | Skrivebeskyttet: liste og hent. |
| Project | /project |
offset · cursor · timeline | Full CRUD; opprettelse bygger fra en templateId, og sletting lukker framfor å fjerne. |
| Project template | /project-template |
bare offset | Skrivebeskyttet: liste og hent. Malene avgjør hvilke prosjekter du kan opprette. |
| Activity | /activity |
offset · cursor · timeline | Full CRUD · hører alltid til et prosjekt · sletting lukker som standard via den reversible hurtiglukkingen, mode=delete fjerner · status er skrivebeskyttet i skrivekropper. |
| Document | /document |
offset · cursor · timeline · changes | Multipart opplasting og nedlasting · redigering av metadata · flytting mellom mapper · alltid knyttet til en eiende post. Hver liste er eiereavgrenset. |
| Document folder | /document/folder |
hele treet, upaginert | Eierens mappetre som en flat liste, foreldre før barn: opprett, døp om, flytt, slett (en kaskade utenfor undertreet må bekreftes, ellers 409) · zip-nedlasting av et undertre. |
| Document changes | /document/changes |
cursor, bare framover | Skrivebeskyttet strøm av registrerte endringer på dokumenter og mapper. Den eneste leseveien der en sletting er synlig. |
Alle ressursene følger de samme konvensjonene — maskerte id-er, en Location-header ved opprettelse, merge-patch på PATCH, multipart bare for dokumentinnhold — og de er dekket i Å gjøre kall. Hver feil er et RFC 9457-problemdokument, dekket i Feil og feilsøking.