Visena Dokumentasjon
Partner API

Ressurs

Document changes

Arkivets journal over registrerte endringshendelser for dokumenter og mapper — eieravgrenset, bare framover, aldri beskåret. Ett endepunkt, og den eneste leseveien i Partner-API-et der en sletting er synlig.

Endepunktreferansen under står på engelsk i begge språktrærne. Den gjengir API-kontrakten ordrett, og det finnes ingen generator å bygge den på nytt fra, så en oversatt kopi ville drevet fra API-et første gang et endepunkt endres.

Endepunkter

Ett endepunkt. Det er skrivebeskyttet; ingenting på denne siden skriver.

Dette endepunktet kan i tillegg svare med fellesfeilene — 401, 403, 404 (ukjent instans) og 500. De er dokumentert én gang, under Feil og feilsøking.

Hva strømmen er

En side fra denne strømmen er en liste over endringshendelser, ikke en liste over dokumenter. Hver hendelse forteller hva plattformen registrerte da en endring ble lagret: operasjonen, feltet den gjaldt, hvem som gjorde den, når den ble registrert, og filnavnene eller mappestiene på hver side av den. Ingenting på en side sier hvordan et dokument ser ut nå — det leser du fra dokumentet selv. Hendelsene kommer i den rekkefølgen de ble registrert, journalen beskjæres aldri, og pagineringen går bare framover.

Det er dette som skiller den fra GET /document/timeline, og grunnen til at begge finnes. Tidslinja er bare oppsett og oppdatering og ordnes på det sammenslåtte endret-eller-opprettet-tidsstempelet: den rapporterer et dokument som dukket opp eller ble omdøpt, og sier ingenting som helst om et som ble slettet. Denne strømmen registrerer slettingen. Det er den eneste leseveien i Partner-API-et der en sletting er synlig, og det er den som står bak en nattlig endringsstrøm inn i et rapporteringslager.

Et komplett bilde av arkivet trenger tre kilder, ikke én. Oppsett og oppdateringer kommer fra dokument-tidslinja, slettinger fra denne strømmen, og endringer i plassering, innhold og beskrivelse fra en jevnlig øyeblikksbilde-sammenlikning per eier som du kjører selv. Lister, paginering og synk går gjennom den tredelingen; grensene for fullstendighet under endepunktet nedenfor sier hvilke sammenslåtte skrivinger som registrerer bare én hendelse, og hvilke endringer som ikke registrerer noe i det hele tatt.

Rekkefølge og gjenopptak er én og samme sak her. Sidene kommer i den sekvensen hendelsene ble registrert i, og du går framover ved å sende tilbake nextCursor som forrige side ga deg. changed er et rapportert tidsstempel, ikke en posisjon: det er et klokkeøyeblikk på noen løp og en oppgitt opprettelsestid på andre, så det er ikke monotont med rekkefølgen strømmen paginerer på, og det er aldri et vannmerke å gjenoppta fra. Lagre cursoren, ikke tidsstempelet. limit godtar 1 til 1000, og er 100 når du utelater den.

GET /document/changes
# First page. entityType and entityId are required; limit is 1..1000, default 100.
curl "https://api.visena.example/acme/api/v1/en/document/changes?entityType=Company&entityId=bQ4wR8&limit=200" \
  -H "Authorization: Bearer $TOKEN"

# Next page: hand back nextCursor from the previous response. Never "changed".
curl "https://api.visena.example/acme/api/v1/en/document/changes?entityType=Company&entityId=bQ4wR8&limit=200&cursor=$NEXT_CURSOR" \
  -H "Authorization: Bearer $TOKEN"

# A response with no nextCursor is the end of the feed as it stands. Keep the
# last cursor you were given and re-issue it on the next poll.

Strømmen er eieravgrenset, og leveringen er minst én gang. entityType og entityId er påkrevd — det finnes ingen oppramsing på tvers av hele organisasjonen — så en poller holder én cursor per eier den følger, og fjerner duplikater i det den leser. En side som kommer tilbake uten nextCursor har nådd enden av strømmen slik den står nå: ta vare på den siste cursoren du fikk, og send den på nytt ved neste polling — det er slik en nattlig jobb tar opp tråden akkurat der den slapp. Regn aldri fraværet av en hendelse på en side som bevis for at ingen endring skjedde.

Å lese en hendelse

operation sier hva som skjedde, på det nivået journalen registrerer det: DOCUMENT_INSERT, DOCUMENT_UPDATE, DOCUMENT_DELETE, FOLDER_INSERT, FOLDER_UPDATE og FOLDER_DELETE. De to *_DELETE-operasjonene er signalet denne strømmen finnes for. changedField avgrenser det nærmere: FILE_NAME, FOLDER, FILE_CONTENT, FOLDER_NAME og FOLDER_PARENT er verdiene som er sett så langt, kolonnen begrenser ingenting, og en ukjent verdi skal behandles som ugjennomsiktig og ikke som en feil.

documentId står på en dokumenthendelse og mangler på en mappehendelse, så forgren på operation framfor å ta for gitt at feltet er der. previousFolderPath og folderPath er mappenavn fra rot til blad, og et tomt array betyr eierens rotnivå. Det registreres én hendelse per plassering, så flere hendelser med samme documentId for én logisk endring er som forventet: knytt bokføringen din til cursoren, aldri til documentId.

List recorded document and folder changes (cursor-paginated)

GET /{instanceName}/api/v1/{locale}/document/changes

Owner-scoped feed of recorded document and folder change events — the only partner read path on which a hard deletion is observable. Ordered by recorded INSERTION sequence and paged forward-only: pass the opaque cursor from a previous page's nextCursor, or omit it for the first page. There is no backward cursor and no links.prev. entityType+entityId are REQUIRED — there is no org-wide enumeration. entityType accepts Company, Person, Project and Room (a document share room); Room is a READ owner of this feed ONLY and stays rejected with 400 on every other document operation. No total is available and none will be added: the journal carries no index beyond its primary key and is never pruned, so a count would be a sequential scan of an ever-growing table on every request.

Requires the platform read scope, enforced globally for every safe method; a bearer token that was not granted it is refused with 403 and no rows are disclosed.

Delivery is AT-LEAST-ONCE. A consumer MUST overlap its polling window and de-duplicate events, and MUST NOT treat the absence of an event from a page as proof that no change occurred. Resumption is by cursor only: the reported changed timestamp is NEVER a resumption watermark, because it is the wall-clock moment of the change on some lanes and a caller-supplied creation time on others, and is therefore not monotonic with the insertion order this feed pages on.

An entityId that does not resolve to an existing entity of the declared type is 422. For entityType=Room a room the calling credential's person neither owns nor is a recorded member of — and an expired room read by anyone but its owner — is the SAME 422 with the same message shape, deliberately indistinguishable from a nonexistent room so the feed cannot be used as an existence oracle for room ids.

Completeness limits, published rather than hidden. Only ONE change is recorded when several are saved together: a rename combined with a move or a content replacement records the rename only. Documents that are not archived into a folder record nothing at all, in any direction. Document description and MIME-type changes are never recorded. A folder rename or reparent records the folder change only, never any change to the documents it contains. A relocation records only the gaining owner's side. One event is recorded per PLACEMENT, so several events bearing the same documentId for one logical change are expected — consumers key on the cursor, not on documentId. entityType=Project is NARROWER than GET /document/timeline: the owner predicate is flat, so a change in a sub-project's, phase's or activity's folder does not appear in the parent project's feed — poll this endpoint once per sub-owner you know of for full coverage of a project tree.

Room-specific statements. A room's feed is COMPLETE under the flat owner predicate — a room needs no owner expansion, unlike a project. A documentId on a pointer placement denotes a document whose primary copy belongs to a different owner, because a room commonly holds pointers rather than copies. A rename or a content replacement of such a document reaches the room only as a secondary record of the change to that primary copy. A room's feed MUST be polled while the room still exists: the events recorded by the room's own deletion are no longer retrievable once the room is gone.

Parametere

Parameter Plassering Type Beskrivelse
entityType required query string, one of Company Person Project Room Owning entity type.
entityId required query string Masked id of the owning record.
cursor query string Opaque page cursor from the previous response's links.next; omit for the first page.
limit query integer Maximum items to return per page.

Svar

Status Beskrivelse
200 A page of change events with its next cursor and links.
DocumentChangeCursorListResponse · application/json
400 Missing required entityType/entityId, unrecognised entityType, invalid or foreign cursor, limit below 1 or above 1000, or an id is not a valid id.
403 The bearer token was not granted the platform read scope.
422 The referenced entityId does not exist for the given entityType; for entityType=Room, also a room the calling identity is not entitled to, with the same message shape.

Eksempel

curl
curl "https://api.visena.example/acme/api/v1/en/document/changes?entityType=Company&entityId=bQ4wR8" \
  -H "Authorization: Bearer $TOKEN"

Objektstrukturer

Svarkroppene som brukes over, i den rekkefølgen de først refereres.

DocumentChangeCursorListResponse

Felt Type Beskrivelse
items array of DocumentChangeDto The change events on this page, in recorded insertion order.
nextCursor string Opaque cursor for the next page; absent when the feed is exhausted.
links DocumentListLinks

DocumentChangeDto

The change events on this page, in recorded insertion order.

Felt Type Beskrivelse
operation string The recorded operation.
changedField string Which field the change concerns. Open vocabulary — observed values are FILE_NAME, FOLDER, FILE_CONTENT, FOLDER_NAME and FOLDER_PARENT; treat an unknown value as opaque.
changed string (date-time) When the change was recorded (UTC). Not the paging key — it is not monotonic with insertion order.
changedBy string (masked id)
documentId string (masked id)
previousFileName string Previous file name, when the change recorded one.
fileName string New file name, when the change recorded one.
size object Blob size in bytes, when the change recorded one.
previousFolderPath array of string Previous folder path, root to leaf, internal root sentinel removed; empty means root level.
folderPath array of string New folder path, root to leaf, internal root sentinel removed; empty means root level.

RFC 8288 navigation links: self, and next when more events remain.

Felt Type Beskrivelse
self string URL of the current page.
first string URL of the first page (offset endpoint).
prev string URL of the previous page, if any.
next string URL of the next page, if any.
last string URL of the last page (offset endpoint).