OpenChronology HTTP API
Version v0.5.0 · 92 operations · OpenAPI description (JSON), for Swagger UI, Postman, Insomnia or code generators
The API the web app, the desktop app and the command-line tools use. Requests and responses are JSON unless an operation says otherwise.
Signing in. Browsers use the session cookie that signing in sets, and send the session's CSRF token (the csrf of GET /api/session) as X-CSRF-Token with every change. The desktop app sends its session token as a bearer token, with the same CSRF header. For automation, make an API key in Account → API keys and send it as Authorization: Bearer och_key_…: keys reach the timeline endpoints only, with the timelines:read or timelines:write scope, and need no CSRF token.
Errors answer with a status code and {"error": "…"}, a message for people. A 428 asks for human verification first: answer the challenge it carries and send its token as X-Challenge.
Revisions. A timeline's revision changes with every save. Saves send the revision they were made on; one made on an older revision merges with what was saved since, or answers 409 with what conflicts.
Exact times. Times are exact rational numbers in coordinates, written as text ("86400/1", "-3/2"); how they read as dates is the timeline's presentation.
Timelines
Server timelines: listing, creating, reading their metadata, saving whole documents, settings, members and deleting. API keys reach these with the timelines:read or timelines:write scope, and are rate-limited per key (120 requests a minute by default).
GET /api/timelines List your timelines
The timelines the caller owns or is a member of, most recently updated first (at most 100). Timelines moderators restricted are listed only for their owner.
Who: Signed in · API keys (timelines:read)
Responses
- 200
Your timelines.
objecttimelinesarray of TimelineListItem
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines Create a timeline
Creates a private timeline from a document (at most 16 MiB of JSON), owned by the caller. Accounts that may not supply data (read-only accounts) are refused with 403.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Request body
format"openchronology" requiredversion1 requiredtitlestring required · at most 300 charactersdescriptionstring required · at most 20000 characterseventsarray of Moment requiredIts moments; IDs unique.
durationsarray of Durationrelationshipsarray of RelationshippresentationTimePresentationpluginsarray of object · at most 32 itemsInstalled plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.
manifestobject requiredThe plugin’s manifest (apiVersion 1).
enabledboolean requiredsettingsobjectValues of the timeline-wide settings its manifest declares (such as the timeline’s background image address, or its theme’s colors and fonts), by key. Values for undeclared settings are dropped.
tagsarray of string · at most 40 itemsThe timeline’s tags: lowercased, without commas or control characters.
assetsobjectCopies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.
comparisonSavedComparison
Responses
- 201
The new timeline.
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/timelines/usage Get your storage use
The storage the account (or the API key’s owner) uses and may use, so that importers can check that an import fits before writing.
Who: Signed in · API keys (timelines:read)
Responses
- 200
Storage used and allowed.
objectusedBytesintegerquotaBytesinteger or nullNull when no quota applies.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id} Get a timeline’s metadata
Its metadata, the caller’s permissions, and the times of its first and last moments. Available while a copy is being prepared.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Responses
- 200
The timeline.
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 429
Too many requests. Wait, then try again.
Try it
PUT /api/timelines/{id} Save a whole document
Replaces the timeline’s content with a document (at most 16 MiB of JSON), for writers. A revision other than the current one is refused with 409: fetch the timeline again and reconcile. For large timelines, save only what changed (PUT /api/timelines/{id}/changes).
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe revision the request was made on: the timeline’s current
revision.documentTimelineDocument required
Responses
- 200
The timeline as saved.
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
DELETE /api/timelines/{id} Delete a timeline
Deletes the timeline and its saved history, for its owner (or an administrator).
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Responses
- 200
Deleted.
Okoktrue
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/revision Get a timeline’s current revision
A cheap check of whether a timeline was saved since it was read.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Responses
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 429
Too many requests. Wait, then try again.
Try it
PATCH /api/timelines/{id}/settings Change a timeline’s settings
For its owner (or an administrator): any of its visibility, private forking policy, retention period, whether it keeps saved history, sensitive-content labels and address. Turning saved history off deletes past revisions at once, apart from those forks and pull requests still use. A timeline goes public only if moderators have not restricted it, it is not a copy of a private timeline, and (for a comparison) all its sources are public. Changing anything but the address saves a new revision.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
visibility"private" | "public"allowPrivateForksbooleanWhether those with access may fork it while it is private.
retentionstring or null · at most 200 charactersHow long to keep moments, as the timeline’s display writes durations (such as
1 year): at least an hour, at most 1,000 years. It needs a calendar (Gregorian) display. Null or empty keeps everything. What falls outside it is deleted for good.keepHistorybooleanlabelsarray of "nudity" | "violence" | "disturbing"What the owner marks it as containing. Moderators’ labels stay.
slugstring or nullIts address,
/<owner>/<slug>: 1–64 lowercase letters, digits, hyphens or underscores, starting with a letter or digit (trimmed and lowercased first). Null or empty removes it. Its former slug keeps leading to it until another of the owner’s timelines takes it.
Responses
- 200
The timeline with its new settings.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/members List a timeline’s members
For its owner (or an administrator).
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Responses
- 200
Its members, by username.
objectmembersarray of TimelineMember
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/members Add a member or change their role
For its owner (or an administrator). Viewers read a private timeline, contributors may also propose changes, writers may also save.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
usernamestring requiredCase is ignored.
role"viewer" | "contributor" | "writer" | "editor" requirededitoris taken aswriter.
Responses
- 200
Done.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
Try it
DELETE /api/timelines/{id}/members Remove a member
For its owner (or an administrator). The body names the member.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
usernamestring required
Responses
- 200
Done.
Okoktrue
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
Try it
Timeline data
Reading a timeline’s moments, durations and relationships a window at a time, downloading it whole, and changing parts of it: sparse saves, deleting a range, shifting and scaling times.
GET /api/timelines/{id}/document Download a timeline whole
Its metadata and whole document, streamed as it is read (moments by ID, durations by start). With download=1, the document alone, as an .ochx file named after its title. Guests get public timelines only, through the browser fork limits (5,000 entries, 4 MiB) and its rate limit; larger timelines are read a window at a time with POST /api/timelines/{id}/query.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
download"1" in queryWith
1: the document alone, as an attachment.
Responses
- 200
The timeline and its document; with
download=1, the document alone.TimelineWithDocument or TimelineDocument- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/export/{name}.ochx Download a timeline as an .ochx file
The document alone, streamed, as an attachment named by the end of the address (so browsers that name downloads after their address name it too). For signed-in callers.
Who: Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
namestring in path requiredThe file name to save it as.
Responses
- 200
The document.
TimelineDocumentformat"openchronology" requiredversion1 requiredtitlestring required · at most 300 charactersdescriptionstring required · at most 20000 characterseventsarray of Moment requiredIts moments; IDs unique.
durationsarray of Durationrelationshipsarray of RelationshippresentationTimePresentationpluginsarray of object · at most 32 itemsInstalled plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.
manifestobject requiredThe plugin’s manifest (apiVersion 1).
enabledboolean requiredsettingsobjectValues of the timeline-wide settings its manifest declares (such as the timeline’s background image address, or its theme’s colors and fonts), by key. Values for undeclared settings are dropped.
tagsarray of string · at most 40 itemsThe timeline’s tags: lowercased, without commas or control characters.
assetsobjectCopies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.
comparisonSavedComparison
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/file Download a timeline as a SQLite file
The timeline as a desktop .och file (at most the server’s file limit, 64 MiB by default; 413 beyond it), for signed-in callers; ten a minute per client address. Comparisons cannot be downloaded: download their sources.
Who: Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Responses
- 200
The SQLite file.
application/vnd.openchronology.sqlitestring- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 422
Converting it took too long.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/timelines/{id}/query Read part of a timeline
Reads a bounded part of a timeline, by kind: moments in a range a page at a time, an overview of a range for drawing it, durations in a range, one event, the entities related to one, a search of its moments and durations, or the tags it uses. A read, so API keys need only timelines:read and sessions no CSRF token. Comparisons are read through their sources (409).
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
Responses
- 200
What the query reads.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/timelines/{id}/recent Get a timeline’s latest times
The last (or first) eight distinct times its moments have, latest (or earliest) first: for following a timeline that grows at one end.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
direction"last" | "first" in queryWhich end to read.
Responses
- 200
Its times.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
PUT /api/timelines/{id}/changes Save what changed
A sparse save, for writers: the settings and only the changed moments, durations and relationships (at most 5,000 events, and 5,000 relationships, per request; at most 16 MiB). Small changes apply in place. Without base, a stale revision is refused with 409; with it, the save merges onto what was saved since, and conflicts answer 409 with conflicts. A save the server stops as too slow answers 503: send fewer changes at a time.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe revision the request was made on: the timeline’s current
revision.settingsTimelineSettings requiredchangesarray of object requiredChanged moments: each the moment wanted, or null to delete it. IDs unique.
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$eventMoment or null required
durationChangesarray of objectChanged durations: each the duration wanted, or null to delete it.
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$durationDuration or null required
relationshipChangesarray of object · at most 5000 itemsLinks to add (
related: true) or remove (related: false).baseSaveBase
Responses
- 200
The timeline as saved.
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/timelines/{id}/delete-range Delete everything in a range
Deletes every moment from lower to upper (both included) and the durations wholly inside, as one save, for writers. Durations that followed a deleted moment keep its time; links of deleted entities go. At most 200,000 moments at a time: more: true means send it again for the rest.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
Responses
- 200
What was deleted, and the timeline afterwards.
objectremovedobjectmomentsintegerdurationsinteger
morebooleanWhether the range holds more to delete.
timelineTimelineMetadata
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/timelines/{id}/map-times Shift and scale times
Shifts and scales the times of every event, or of those a filter selects, for good, as one save, for writers. A duration’s fixed ends are mapped; ends that follow a moment move with it. A stale revision and comparisons are refused with 409. Other saves wait until it finishes; it carries on if the client goes away. With Accept: application/x-ndjson, the reply streams JSON lines as it works: {"progress": …} ({"reading": true}, {"done", "total"}, or {"rebuilding": stage, "done", "total"}), then {"result": …}, or {"error": {"status", "message"}} for a failure once streaming. Without it, the reply is the result alone.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe revision the request was made on: the timeline’s current
revision.mappingTimeMapping requiredfilterViewFilterWithout it, everything moves.
Responses
- 200
How many events (moments and durations) moved, and the timeline as saved.
objectmovedobjectmomentsintegerdurationsinteger
timelineTimelineMetadata
application/x-ndjsonstringJSON lines: progress, then the result or an error.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Files
Converting between .ochx documents (JSON) and the desktop app’s SQLite .och files, which are at most the server’s file limit (TIMELINE_FILE_BYTES, 64 MiB by default; the session’s fileLimit). Only signed-in browser and desktop sessions may convert; API keys may not.
POST /api/files/import Read a SQLite timeline file
Converts a desktop .och SQLite file (at most the server’s file limit, 64 MiB by default; 413 beyond it) to a document, without saving anything. Ten conversions a minute per account; two at once per server.
Who: Signed in, with the CSRF token
Request body
application/vnd.openchronology.sqliteapplication/octet-streamResponses
- 200
The file’s document.
objectdocumentTimelineDocument
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 415
The body is not a SQLite timeline file.
- 422
Converting it took too long.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
POST /api/files/export Write a SQLite timeline file
Converts a document (at most 16 MiB of JSON) to a desktop .och SQLite file (at most the server’s file limit, 64 MiB by default; 413 beyond it), keeping the images it embeds. Ten conversions a minute per account; two at once per server.
Who: Signed in, with the CSRF token
Request body
format"openchronology" requiredversion1 requiredtitlestring required · at most 300 charactersdescriptionstring required · at most 20000 characterseventsarray of Moment requiredIts moments; IDs unique.
durationsarray of Durationrelationshipsarray of RelationshippresentationTimePresentationpluginsarray of object · at most 32 itemsInstalled plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.
manifestobject requiredThe plugin’s manifest (apiVersion 1).
enabledboolean requiredsettingsobjectValues of the timeline-wide settings its manifest declares (such as the timeline’s background image address, or its theme’s colors and fonts), by key. Values for undeclared settings are dropped.
tagsarray of string · at most 40 itemsThe timeline’s tags: lowercased, without commas or control characters.
assetsobjectCopies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.
comparisonSavedComparison
Responses
- 200
The SQLite file.
application/vnd.openchronology.sqlitestring- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON (
Content-Type: application/json).- 422
Converting it took too long.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Live updates
Learning when timelines are saved, as a server-sent event stream.
GET /api/live Follow timelines’ revisions
A server-sent event stream of the revisions of one to eight timelines the caller may read. Each starts with a revision event per timeline, then one each time it is saved: event: revision with {"id", "revision"}. If the caller’s access to one changes, or their session does, an event: access with {"error"} (and the timeline’s id) ends the stream: connect again. A comment line every 25 seconds keeps it open. API keys and other origins are refused.
Who: Anyone · Signed in
Parameters
timelinesstring in query requiredOne to eight timeline IDs, separated by commas.
Responses
- 200
The event stream.
text/event-streamstring- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 503
The server’s storage, or a service it needs, is unavailable.
Embeds
oEmbed for public timelines, so a pasted timeline link can show the timeline.
GET /api/oembed Get the oEmbed of a timeline link
For a link to a public timeline on this site (its page, or one of its moments’ or durations’), the HTML to embed it. Cached for an hour; open to other origins.
Who: Anyone · Signed in
Parameters
urlstring (uri) in query requiredThe link:
/timelines/<id>or/<owner>/<slug or id>, optionally followed by/moments/<id>or/durations/<id>, or a link fragment.format"json" in queryOnly
jsonis available.maxwidthinteger in queryThe widest it may be; at most 800 is given.
maxheightinteger in queryThe tallest it may be; at most 480 is given.
Responses
- 200
The embed.
OEmbedversion"1.0"type"rich"provider_namestringprovider_urlstring (uri)titlestringauthor_namestringThe owner’s username.
author_urlstring (uri)htmlstringAn
<iframe>of the timeline’s embed page.widthinteger · ≥ 200, ≤ 800heightinteger · ≥ 160, ≤ 480thumbnail_urlstring (uri)Left out for a timeline with sensitive-content labels.
thumbnail_width1200thumbnail_height630cache_age3600
- 400
The request is malformed or a value is not allowed.
- 404
Not found, or not visible to this account.
- 501
Not the json format, or less room than 200 × 160.
Try it
Search
Finding public, shared and starred timelines, and starring them. Browsing ranks by account standing (docs/browsing.md).
POST /api/timelines/search Search and browse timelines
Lists timelines a page at a time. With no search text, owner or starredBy, the public scope browses: public timelines of established accounts, and featured ones; readers who are not signed in, or whose accounts may be under 18, browse no labelled timelines. Text search uses PostgreSQL full-text search (websearch_to_tsquery, so quoted phrases and -exclusions work) over titles, tags, descriptions and moment text, and finds every account’s public timelines, established accounts’ first. A POST, so it counts as a read for API keys.
Who: Anyone · Signed in · API keys (timelines:read)
Request body
searchstring · at most 300 characters, default ""Words to find, in web-search syntax (quoted phrases,
-exclusions). Empty to browse.tagstring · at most 64 characters, default ""Only timelines with this tag (matched exactly, lowercased).
ownerstring · at most 64 characters, default ""Only timelines owned by this username.
starredBystring · at most 64 characters, default ""Only timelines this username starred (their public favorites; none for an account that may be under 18). Only with the
publicscope.scope"public" | "mine" | "visible" | "starred" · default "public"public: public timelines.mine: the caller’s own.visible: public ones and those shared with the caller.starred: those the caller starred. All butpublicneed sign-in.sort"featured" | "stars" | "popularity" | "trending" | "alphabetical" | "age" | "relevance"The order:
relevanceby default when there issearchtext, otherwisefeatured(featured first, then recently updated).popularityandtrending(last 30 days) weigh stars and forks by the standing of who gave them;ageis newest first. Ties go to the most recently updated.pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12
Responses
- 200
OK.
TimelineSearchPagetimelinesarray of TimelineSearchResult requiredtotalinteger required · ≥ 0How many timelines match in all.
pageinteger required · ≥ 1limitinteger required · ≥ 1pagesinteger required · ≥ 0
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/star Star or unstar a timeline
Stars (or unstars) a timeline the account can read. Starring twice, or unstarring an unstarred timeline, changes nothing. The timeline’s popularity and its owner’s standing are updated at once.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
starredboolean requiredTrue to star, false to unstar.
Responses
- 200
OK.
objectstarredboolean requiredstar_countstring required · matches ^\d+$How many accounts have starred it now, as a decimal string.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
Forks and history
Forks, duplicates and syncs, and a timeline’s saved history: the checkpoints each save records, with their parents.
POST /api/timelines/{id}/fork Fork a timeline
Copies the timeline’s saved head into a new timeline owned by the caller, linked to it as upstream so it can sync and propose pull requests. The fork starts private, and stays private when upstream is private. Its saved history and index read through to upstream’s instead of being copied, so it opens at once; a large copy may answer with preparing true while the rest of its index is copied. Anyone signed in may fork a public timeline; a private one needs its owner, or the owner’s *Allow invited readers to fork* setting.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe timeline’s current revision; 409 when it has changed since.
Responses
- 201
The new fork’s metadata (without time bounds).
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/duplicate Duplicate a timeline
Like a fork, but the copy has no upstream link or merge ancestry: an independent timeline owned by the caller. It shares saved history with its source the same way.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe timeline’s current revision; 409 when it has changed since.
Responses
- 201
The new copy’s metadata (without time bounds).
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/sync Sync a fork with its upstream
Merges what upstream saved since its latest common ancestor with the fork into the fork, entity by entity, and records a sync checkpoint with both parents. Does nothing when upstream is already an ancestor. Refused with 409 when the fork has no upstream, the revision is stale, the two have several equally good common ancestors, fields conflict (listed in conflicts), or upstream no longer keeps the revision they last shared. A public fork cannot sync a private upstream.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionRevision requiredThe fork’s current revision.
Responses
- 200
The fork’s metadata after syncing.
TimelineMetadataidUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/browser-fork Copy a public timeline to edit in the browser
Returns a public timeline’s saved head whole, for an editor to keep as an in-memory draft rather than on the server. Only timelines of at most 5,000 entries (stack entries included) and 4 MiB qualify; larger ones are refused with 413, and nothing is truncated. Comparisons are refused with 409. At most four copies are made at once (429 when busy), and copies are rate limited by address. Anyone may copy one, guests included: it reads, and keeps nothing on the server.
Who: Anyone · Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
revisionstring · matches ^\d{1,20}$If given, the revision expected: 409 when the timeline has moved on.
Responses
- 200
OK.
BrowserForkdocumentTimelineDocument requiredsourceobject requiredWhat was copied.
limitsobject requiredThe limits a browser copy is held to.
events5000bytes4194304
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/history List saved revisions
A page of the timeline’s saved checkpoints, newest first, twenty per page. A past revision whose content is not kept (the timeline stopped keeping saved history) is listed with available false.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
pageinteger in queryThe page, from 1.
Responses
- 200
OK.
HistoryPagerevisionsarray of HistoryRevision required · at most 20 itemspageinteger required · ≥ 1moreboolean requiredWhether there is a next page.
keepHistoryboolean requiredWhether the timeline keeps saved history.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/history/{saved} Read a saved revision
The timeline as it was saved at that checkpoint, streamed as {"document": …}. With download=1 it is the bare document, sent as an attachment named timeline-<saved>.ochx. Only this timeline’s checkpoints are found; one whose content is not kept answers 409.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
savedUuid in path requiredThe saved revision’s ID (from the history list).
download"1" in query1to download the document as an.ochxfile.
Responses
- 200
The saved document; with
download=1, the bare document as an.ochxattachment (Content-Dispositionset).object or TimelineDocument- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
Pull requests
Pull requests (proposals): changes offered to a timeline from a fork or as a whole document, reviewed against saved revisions, merged or rejected by its writers, and discussed in comments.
GET /api/timelines/{id}/proposals List pull requests
The timeline’s pull requests, newest first, twelve per page. POST …/proposals/search takes the same request as a body, with a chosen page size.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
pageinteger in queryThe page, from 1.
Responses
- 200
OK.
ProposalPageproposalsarray of ProposalSummary requiredtotalinteger required · ≥ 0pageinteger required · ≥ 1pagesinteger required · ≥ 0
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/proposals Open a pull request
Offers changes to the timeline, either from a saved revision of one of its forks (sourceTimelineId and sourceRevisionId; needs write access to the fork) or as a whole proposed document made on its current revision (baseRevision and document). The proposal is pinned to those revisions: later saves to the fork do not change it. Needs contributor access, or any signed-in account on a public timeline. Both the timeline and the fork must keep saved history. An author may have at most 100 open pull requests per timeline. New accounts may first be asked for human verification (428). Answers with the pull request, as GET does.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
Responses
- 201
The pull request opened.
ProposalidUuidtimeline_idUuidauthor_idUuidauthorstringThe author’s username.
titlestringbodystringIts description, as plain text.
status"open" | "merged" | "rejected" | "closed"revisionRevisionThe pull request’s own revision: send it with updates and resolutions.
base_revisionRevisionThe timeline revision it is based on.
base_revision_idUuidThe saved revision it is based on.
source_revision_idUuidThe saved revision it proposes.
source_timeline_idUuid or nullThe fork it came from, if any.
from_forkbooleanresolved_byUuid or nullmerged_revisionRevision or nullThe timeline revision its merge made.
merged_revision_idUuid or nullcreated_atstring (date-time)updated_atstring (date-time)changesProposalChangescanMergebooleancanUpdatebooleancanClosebooleanupstreamRevisionRevisionThe timeline’s current revision: a rebase is needed when it differs from
base_revision.sourceobject or nullThe source fork, when it came from one the caller can read.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/proposals/search List pull requests, a page at a time
The timeline’s pull requests, newest first. A POST so the desktop app can send it without a query string; it counts as a read for API keys.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
Request body
pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12
Responses
- 200
OK.
ProposalPageproposalsarray of ProposalSummary requiredtotalinteger required · ≥ 0pageinteger required · ≥ 1pagesinteger required · ≥ 0
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/proposals/{proposal} Get a pull request
The pull request with its pinned revisions, a summary of what it changes (computed from saved history), and what the caller may do with it.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Responses
- 200
OK.
ProposalidUuidtimeline_idUuidauthor_idUuidauthorstringThe author’s username.
titlestringbodystringIts description, as plain text.
status"open" | "merged" | "rejected" | "closed"revisionRevisionThe pull request’s own revision: send it with updates and resolutions.
base_revisionRevisionThe timeline revision it is based on.
base_revision_idUuidThe saved revision it is based on.
source_revision_idUuidThe saved revision it proposes.
source_timeline_idUuid or nullThe fork it came from, if any.
from_forkbooleanresolved_byUuid or nullmerged_revisionRevision or nullThe timeline revision its merge made.
merged_revision_idUuid or nullcreated_atstring (date-time)updated_atstring (date-time)changesProposalChangescanMergebooleancanUpdatebooleancanClosebooleanupstreamRevisionRevisionThe timeline’s current revision: a rebase is needed when it differs from
base_revision.sourceobject or nullThe source fork, when it came from one the caller can read.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
PUT /api/timelines/{id}/proposals/{proposal} Update a pull request
Replaces an open pull request’s title, description and proposed changes: a new saved revision of the same fork, or a new proposed document on the same base. Only its author, while still allowed to contribute, may. revision is the pull request’s revision as last read; a stale one answers 409. To move a document proposal onto a newer upstream revision, rebase it instead.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Request body
Responses
- 200
The pull request updated.
ProposalidUuidtimeline_idUuidauthor_idUuidauthorstringThe author’s username.
titlestringbodystringIts description, as plain text.
status"open" | "merged" | "rejected" | "closed"revisionRevisionThe pull request’s own revision: send it with updates and resolutions.
base_revisionRevisionThe timeline revision it is based on.
base_revision_idUuidThe saved revision it is based on.
source_revision_idUuidThe saved revision it proposes.
source_timeline_idUuid or nullThe fork it came from, if any.
from_forkbooleanresolved_byUuid or nullmerged_revisionRevision or nullThe timeline revision its merge made.
merged_revision_idUuid or nullcreated_atstring (date-time)updated_atstring (date-time)changesProposalChangescanMergebooleancanUpdatebooleancanClosebooleanupstreamRevisionRevisionThe timeline’s current revision: a rebase is needed when it differs from
base_revision.sourceobject or nullThe source fork, when it came from one the caller can read.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/proposals/{proposal}/document Get the proposed timeline
The pull request’s proposed timeline, whole, to view, edit or export. 409 when its revision is no longer kept.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Responses
- 200
The proposed timeline.
objectdocumentTimelineDocument required
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/proposals/{proposal}/resolve Merge, reject, close or rebase a pull request
merge applies the pull request’s changes to the timeline, entity by entity, as a new revision; reject declines it; both need write access. close withdraws it, by its author or a writer. rebase (author only) remakes it on the timeline’s current revision, keeping it open; a document pull request must be rebased before it can merge once upstream has changed. Fields changed on both sides refuse a merge or rebase with 409 and conflicts (field names such as moment example.metadata.title); nothing is saved. A resolved pull request cannot be reopened.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Request body
action"merge" | "reject" | "close" | "rebase" requiredrevisionRevision requiredThe pull request’s revision as last read (not the timeline’s).
Responses
- 200
The pull request after the action.
ProposalidUuidtimeline_idUuidauthor_idUuidauthorstringThe author’s username.
titlestringbodystringIts description, as plain text.
status"open" | "merged" | "rejected" | "closed"revisionRevisionThe pull request’s own revision: send it with updates and resolutions.
base_revisionRevisionThe timeline revision it is based on.
base_revision_idUuidThe saved revision it is based on.
source_revision_idUuidThe saved revision it proposes.
source_timeline_idUuid or nullThe fork it came from, if any.
from_forkbooleanresolved_byUuid or nullmerged_revisionRevision or nullThe timeline revision its merge made.
merged_revision_idUuid or nullcreated_atstring (date-time)updated_atstring (date-time)changesProposalChangescanMergebooleancanUpdatebooleancanClosebooleanupstreamRevisionRevisionThe timeline’s current revision: a rebase is needed when it differs from
base_revision.sourceobject or nullThe source fork, when it came from one the caller can read.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
GET /api/timelines/{id}/proposals/{proposal}/comments List comments on a pull request
Comments oldest first, fifty at a time. Pass the previous page’s next as after for the next page.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
afterstring in queryReturn comments after this comment ID (
0for the first page).
Responses
- 200
OK.
ProposalCommentPagecommentsarray of ProposalComment required · at most 50 itemsnextstring or null requiredSend as
afterfor the next page; null on the last.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/proposals/{proposal}/comments Comment on a pull request
Adds a plain-text comment. Anyone signed in who can read the timeline may comment, on open and resolved pull requests alike. New accounts may first be asked for human verification (428).
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Request body
bodystring required · at least 1 characters, at most 20000 charactersThe comment: 1–20,000 characters, not only spaces. Kept trimmed.
Responses
- 201
The comment was added.
objectidstring required · matches ^\d+$The new comment’s ID.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
Try it
POST /api/timelines/{id}/proposals/{proposal}/comments/search List comments on a pull request, as a POST
The same as GET …/comments, with after in the body, for the desktop app. Counts as a read for API keys.
Who: Anyone · Signed in · API keys (timelines:read)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
Request body
afterstring · matches ^[0-9]{1,18}$, default "0"Return comments after this comment ID.
Responses
- 200
OK.
ProposalCommentPagecommentsarray of ProposalComment required · at most 50 itemsnextstring or null requiredSend as
afterfor the next page; null on the last.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
Try it
DELETE /api/timelines/{id}/proposals/{proposal}/comments/{comment} Delete your comment
Deletes one of the caller’s own comments, at any time.
Who: Signed in, with the CSRF token · API keys (timelines:write)
Parameters
idUuid in path requiredThe timeline's ID.
proposalUuid in path requiredThe pull request’s ID.
commentstring in path requiredThe comment’s ID.
Responses
- 200
Deleted.
Okoktrue
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 429
Too many requests. Wait, then try again.
Try it
Session
Who is signed in, the CSRF token, and what this server offers; signing out. Cookie names take the __Host- prefix (and Secure) when the server is on HTTPS.
GET /api/session Get the session
Who is signed in (or user: null), the CSRF token to send with changes, and what this server offers. When nobody is signed in, csrf is the sign-in token, set as the oc_login cookie too: signing in, registering and the other steps before a session send it as X-CSRF-Token.
Who: Anyone · Signed in
Responses
- 200
The session.
Sessionserverboolean requiredWhether the server has storage. Without it, only browser timelines work.
dashboardtrue requireduserSessionUser or null requiredcsrfstring or null required · matches ^[a-f0-9]{64}$Signed in: the session’s CSRF token, sent as
X-CSRF-Tokenwith every change. Signed out: the sign-in token (also theoc_logincookie), sent the same way by sign-in requests. Null without server storage.providersarray of SignInProvider requiredThe sign-in providers this server offers.
securityobjectWhich account-security features the server offers (it needs email and an encryption key configured). Absent without server storage.
emailbooleanmfabooleanregistrationboolean
challenge"mfa" | "email" | nullA sign-in step this browser has pending (
mfa: a two-factor code;email: an email address to confirm), or null.fileExchangeboolean requiredWhether the server converts SQLite (.och) timeline files.
fileLimitintegerThe largest .och file the server converts, in bytes (
TIMELINE_FILE_BYTES, 64 MiB by default).compareLimitintegerHow many timelines this account (or a guest) may compare at once.
entryLimitinteger or nullHow many moments (and durations, relationships) a timeline may hold; null for no limit.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
Try it
POST /api/auth/revoke-others Sign out every other session
Signs out the account’s other browser and desktop sessions at once, keeping this one. API keys are not affected. No body.
Who: Signed in, with the CSRF token
Responses
- 200
Signed out.
Okoktrue
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/logout Sign out
Ends this session. No body.
Who: Signed in, with the CSRF token
Responses
- 200
Signed out.
Okoktrue
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Sign-in
Signing in with a password, a sign-in provider (Google, GitHub, Facebook) or, for the desktop app, a browser; registering; two-factor and email steps; confirming emails and resetting passwords. Sign-in, social starts and device approvals are limited to ten attempts a minute per client address (429). API keys cannot reach these endpoints (403).
POST /api/auth/login Sign in with a password
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
A signed-in browser gets the session cookie; the desktop app (X-OC-Client: desktop) gets a session token instead. Signing in replaces the caller’s previous session.
When the account needs another step, the answer is a SignInStep instead, with the oc_challenge cookie (five minutes): mfa asks for POST /api/auth/mfa/complete, email for POST /api/auth/email/enroll.
After three failures in fifteen minutes from the client address or for the account, it asks for human verification (428) instead of locking the account. Ten attempts a minute per client address and per account (429).
Who: Signed in, with the CSRF token
Parameters
X-OC-Client"desktop" in headerSend
desktopfrom the desktop app: the sign-in then returns a sessiontoken(a bearer credential) instead of setting the session cookie.X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
usernamestring required · matches ^[A-Za-z0-9][A-Za-z0-9_-]{2,31}$3–32 letters, digits,
_or-, starting with a letter or digit; lowercased by the server.passwordstring required · at least 1 characters, at most 1024 charactersThe password.
Responses
- 200
Signed in, or the next step.
SignedIn or SignInStep- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/register Register
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Makes a pending registration and emails a confirmation, which POST /api/auth/email/verify accepts in this browser within 24 hours; the account exists only then, and no session is made here. The answer is the same whether or not the username or email is taken. Always asks for human verification (428). Unavailable (503) until the server has email and an encryption key configured.
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
usernamestring required · matches ^[A-Za-z0-9][A-Za-z0-9_-]{2,31}$3–32 letters, digits,
_or-, starting with a letter or digit; lowercased by the server. Names of the site’s own pages are taken, as are names that would pass for the site or its staff (root,moderator,admin1,open_chronology…).emailstring (email) required · at most 254 charactersAn email address (trimmed and lowercased).
passwordstring required · at least 15 characters, at most 1024 charactersA password or passphrase of 15–1024 characters. Predictable ones, and ones found in known breaches (checked against Have I Been Pwned by the first five characters of its SHA-1), are refused.
passwordConfirmationstring requiredThe new password again; it must match.
birthYearinteger required · ≥ 1900Year of birth. Accounts are for people 13 and older: anyone who may be younger than 13 by the end of this year is refused (403), and the browser is refused again for a day.
Responses
- 200
Registration pending its email confirmation.
Registeredmessagestring requiredverificationRequiredtrue required
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/mfa/complete Finish signing in with a two-factor code
The mfa step of a sign-in: send an authenticator or recovery code. Needs the oc_challenge cookie the sign-in set, in the same browser (oc_login), within five minutes; five wrong codes close the step, and signing in starts again.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Signs in as the sign-in began: a browser session cookie, or a desktop token.
Who: Signed in, with the CSRF token
Request body
codestring requiredWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Signed in.
any- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/email/enroll Give an email address to confirm
The email step of a sign-in: an account without a confirmed email address (such as one new from a sign-in provider) gives one, and confirms it with the emailed link (POST /api/auth/email/verify) before it can sign in. Needs the oc_challenge cookie of that step. A new account gives its year of birth here too; one under 13 is closed.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Always asks for human verification (428), since it sends email to an address the requester types. The answer is the same whether or not another account has the address.
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
emailstring (email) required · at most 254 charactersAn email address (trimmed and lowercased).
birthYearinteger · ≥ 1900Year of birth. Accounts are for people 13 and older: anyone who may be younger than 13 by the end of this year is refused (403), and the browser is refused again for a day. Required when the account has no year of birth yet.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Confirmation sent.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/email/verify Confirm an email address
Accepts the token from an emailed confirmation link (/login#verify=…): it completes a registration (making the account), confirms an email address given at sign-in, or completes an email change. It works only in the browser that asked for it (its oc_verify cookie), within 24 hours.
Confirming signs the account out everywhere; sign in afterwards.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Who: Signed in, with the CSRF token
Request body
tokenstring required · matches ^[a-f0-9]{64}$The token from the confirmation link.
Responses
- 200
Confirmed.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/password/forgot Ask for a password reset link
Emails a reset link (/login#reset=…, valid 30 minutes, once) to an account with that confirmed address and a password. The answer is the same for every address.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Always asks for human verification (428). Limited per client address and per email address (429).
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
emailstring (email) required · at most 254 charactersAn email address (trimmed and lowercased).
Responses
- 200
A link is sent if the account is eligible.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/password/reset Reset a password
Sets a new password with the token from a reset link. It signs the account out everywhere, revokes its API keys and pending desktop approvals, and does not turn two-factor authentication off.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Who: Signed in, with the CSRF token
Request body
tokenstring required · matches ^[a-f0-9]{64}$The token from the reset link.
passwordstring required · at least 15 characters, at most 1024 charactersA password or passphrase of 15–1024 characters. Predictable ones, and ones found in known breaches (checked against Have I Been Pwned by the first five characters of its SHA-1), are refused.
passwordConfirmationstring requiredThe new password again; it must match.
Responses
- 200
Password reset.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/{provider}/start Start signing in with a provider
Begins signing in with Google, GitHub or Facebook, or with link: true, linking one to the signed-in account (which needs a sign-in within the last five minutes). Send the browser to the url returned; the provider returns it to GET /api/auth/{provider}/callback within ten minutes.
Before signing in, send X-CSRF-Token equal to the sign-in token: the csrf that GET /api/session returns along with its oc_login cookie (valid ten minutes). A caller that is already signed in sends its session’s CSRF token instead.
Who: Signed in, with the CSRF token
Parameters
providerSignInProvider in path requiredThe sign-in provider. Only providers this server configures work (see
providersinGET /api/session).
Request body
returnTostring · default "/"Where to return after:
/,/editor,/account,/plugins,/timelines/<id>, or a desktop approval page (/connect/desktop/<code>,/#desktop/<code>).linkbooleanLink the provider to the signed-in account instead of signing in. Needs a session signed in within the last five minutes.
Responses
- 200
Where to send the browser.
objecturlstring (uri) requiredThe provider’s authorization page, to send the browser to.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/auth/{provider}/callback Return from a provider
Where the provider sends the browser back: not called directly. It needs the oc_oauth cookie of the browser that started, and is used once.
It answers with a redirect (303): to the return location when signed in, linked or cancelled (?auth_cancelled=1), or to /login?step=mfa|email&returnTo=… when the sign-in needs another step. Signing in replaces the browser’s previous session. A failure answers with a JSON error instead.
Who: Anyone
Parameters
providerSignInProvider in path requiredThe sign-in provider. Only providers this server configures work (see
providersinGET /api/session).statestring in query requiredThe state the sign-in started with.
codestring in queryThe provider’s authorization code.
errorstring in querySet by the provider when the person cancelled or it refused.
Responses
- 303
Back to the site.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 502
The provider could not be reached or did not verify the identity.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/device/start Start signing in the desktop app through a browser
The desktop app’s Sign in using your browser: it shows userCode and opens verificationUri, where a signed-in browser approves it (POST /api/auth/device/approve), then polls POST /api/auth/device/poll with deviceCode, which it keeps to itself. The request expires in ten minutes. Send an empty JSON object.
Who: Anyone
Request body
Responses
- 200
The pending desktop sign-in.
DeviceSignIndeviceCodestring required · matches ^[a-f0-9]{64}$The desktop app’s secret for polling. Keep it out of the browser.
userCodestring required · matches ^[A-Z2-9]{10}$The code the desktop app shows, to match in the browser.
verificationUristring (uri) requiredThe page that approves it:
<origin>/connect/desktop/<userCode>.interval3 requiredSeconds between polls, at least.
expiresIn600 requiredSeconds until it expires.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/device/poll Check on a desktop sign-in
Answers {pending: true} until a browser approves, then a desktop session token, once. Poll at most every three seconds: a faster poll, an expired request or a used one is refused (400).
Who: Anyone
Request body
deviceCodestring required · matches ^[a-f0-9]{64}$The
deviceCodefromPOST /api/auth/device/start.
Responses
- 200
Still waiting, or signed in (with
token).object or SignedIn- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/device/approve Approve a desktop sign-in
Approves the desktop app showing userCode, signing it in to this account. Needs a sign-in within the last five minutes.
Who: Signed in, with the CSRF token
Request body
userCodestring required · matches ^[A-Z2-9]{10}$The ten-character code the desktop app shows.
Responses
- 200
Approved.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Account security
Two-factor authentication, recovery codes, password and email changes, and unlinking sign-in providers. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
POST /api/auth/mfa/setup Start setting up two-factor authentication
Gives a new authenticator key, to enter in an authenticator app; POST /api/auth/mfa/enable turns it on within ten minutes, from this session. Needs a confirmed email address. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
Responses
- 200
The authenticator key.
TwoFactorSetupsecretstring required · matches ^[A-Z2-7]+$The authenticator key, in base32.
uristring requiredThe same key as an
otpauth://totp/…link (SHA-1, six digits, 30 seconds).
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/mfa/enable Turn on two-factor authentication
Confirms the key from POST /api/auth/mfa/setup with a code from the authenticator, and gives ten recovery codes, shown only once. Signs out the account’s other sessions. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestring required · matches ^\d{6}$A code from the authenticator just set up.
Responses
- 200
Turned on.
RecoveryCodesmessagestring requiredrecoveryCodesarray of string required · at least 10 items, at most 10 itemsTen one-time recovery codes, shown only once. Store them offline.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/mfa/disable Turn off two-factor authentication
Turns two-factor authentication off and removes the recovery codes. Signs out the account’s other sessions. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Turned off.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/mfa/recovery Replace the recovery codes
Gives ten new recovery codes, shown only once; the old ones stop working. Signs out the account’s other sessions. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
The new recovery codes.
RecoveryCodesmessagestring requiredrecoveryCodesarray of string required · at least 10 items, at most 10 itemsTen one-time recovery codes, shown only once. Store them offline.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/password/change Change the password
Sets a new password (or a first one, for an account made with a sign-in provider). Signs the account out everywhere, this session included, and revokes its API keys. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
newPasswordstring required · at least 15 characters, at most 1024 charactersA password or passphrase of 15–1024 characters. Predictable ones, and ones found in known breaches (checked against Have I Been Pwned by the first five characters of its SHA-1), are refused.
passwordConfirmationstring requiredThe new password again; it must match.
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Changed; sign in again.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/email/change Change the email address
Emails a confirmation to the new address, which POST /api/auth/email/verify accepts in this browser within 24 hours; the old address is told and stays until then. Confirming signs the account out everywhere. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
emailstring (email) required · at most 254 charactersAn email address (trimmed and lowercased).
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Confirmation sent.
AccountMessagemessagestring requiredWhat happened, for people.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/identities/unlink Unlink a sign-in provider
Removes a provider from the ways to sign in to this account. An account keeps at least one: a password or another provider (409). Linking is POST /api/auth/{provider}/start with link: true. Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
providerSignInProvider requiredpasswordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Unlinked.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
API keys
Keys for automation, which reach the timeline endpoints only. Managed from a signed-in session; API keys cannot manage keys (403).
GET /api/auth/api-keys List API keys
The account’s API keys, newest first (at most 100), revoked and expired ones included.
Who: Signed in
Responses
- 200
The keys.
objectkeysarray of ApiKey required
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/api-keys Make an API key
Makes a key for the timeline endpoints with the scopes asked for. The key itself is returned only here: copy it now. An account has at most 100 keys, counting revoked ones (409). Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
namestring required · at least 1 characters, at most 80 charactersTrimmed; not blank.
scopesarray of ApiKeyScope · at least 1 items, at most 2 items, default ["timelines:read"]daysinteger · ≥ 1, ≤ 365, default 90Days until it expires.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 201
The new key.
CreatedApiKeyidUuid requiredtokenstring required · matches ^och_key_[a-f0-9]{32}_[a-f0-9]{64}$The key, sent as
Authorization: Bearer …. Shown only now; the server keeps only its hash.messagestring required
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/auth/api-keys/{id} Revoke an API key
Stops the key working; it stays listed, as revoked. No body.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe API key’s ID.
Responses
- 200
Revoked.
Okoktrue
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
DELETE /api/auth/api-keys/{id} Delete an API key
Removes the key, which stops working.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe API key’s ID.
Responses
- 200
Deleted.
Okoktrue
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Account
The account’s profile, security overview, storage, sessions, and deleting it.
PATCH /api/auth/profile Change the profile
Changes the avatar or whether sensitive content shows without a warning. Accounts of people under 18 always see the warnings (403).
Who: Signed in, with the CSRF token
Request body
avatarUrlstring · at most 350000 charactersAn HTTPS image URL (at most 2048 characters), a
data:image/png|jpeg|webp;base64,…image (at most 256 KiB), or empty to remove it.showSensitivebooleanShow sensitive content without a warning. Adults only.
Responses
- 200
Changed.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/auth/account Get the account
The account’s security settings, profile, storage, API keys, linked sign-in providers and active sessions.
Who: Signed in
Responses
- 200
The account.
Accountsecurityobject requiredemailstring or nullemail_verified_atstring or null (date-time)mfa_enabledbooleanhas_passwordbooleanrecovery_remainingintegerRecovery codes not yet used.
profileobject requiredavatarUrlstringminorbooleanshowSensitiveboolean
usageAccountUsage requiredkeysarray of ApiKey requiredidentitiesarray of SignInProvider requiredThe sign-in providers linked to the account.
sessionsarray of AccountSession required
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
DELETE /api/auth/account Delete the account
Deletes the account and what it owns: its timelines (with their history, pull requests and comments), the pull requests and comments it wrote on others’ timelines, its plugins and suites, stars, memberships, API keys, sign-in methods and sessions. What it already merged into others’ timelines stays theirs. It cannot be undone. The last active administrator cannot delete their account (409). Like every security change, it needs a live session, the current password when the account has one (else 401) or, for an account without a password, a sign-in within the last five minutes (else 403), and, with two-factor authentication on, a fresh code from the authenticator or a recovery code (else 401).
Who: Signed in, with the CSRF token
Request body
confirmstring requiredThe account’s username, to confirm.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
Responses
- 200
Deleted.
AccountDeletedoktrue requiredtimelinesinteger requiredHow many timelines were deleted with it.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Plugins
The plugin library: official plugins and suites, those the operator adds, and those accounts publish. Anyone can search and read it.
GET /api/plugins Search the plugin library
The newest version of each plugin whose name, description or ID contains the search. Works without server storage, with the official and operator’s plugins alone. Plugins moderators restricted are left out.
Who: Anyone · Signed in
Parameters
searchstring in queryText that names, descriptions or IDs contain, without regard to case.
pageinteger in queryThe page, from 1.
limitinteger in queryHow many on a page.
sort"popularity" | "alphabetical" | "age" in queryThe order: by how many public timelines use the plugin, by name, or newest first. Without server storage, always by name.
Responses
- 200
A page of plugins.
PluginPageapiVersion1 requiredpluginsarray of Plugin requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
- 400
The request is malformed or a value is not allowed.
Try it
POST /api/plugins/search Search the plugin library with a JSON body
As GET /api/plugins, with the search in the body (at most 4 KiB). The desktop app uses it.
Who: Anyone · Signed in
Request body
searchstring · at most 200 characters, default ""pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12sort"popularity" | "alphabetical" | "age" · default "popularity"Without server storage, always by name.
Responses
- 200
A page of plugins.
PluginPageapiVersion1 requiredpluginsarray of Plugin requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.
Try it
GET /api/plugins/{id}/{version} Read a version of a plugin
One version of a plugin, old versions included. A plugin moderators restricted is not found.
Who: Anyone · Signed in
Parameters
idstring in path requiredThe plugin’s ID.
versionstring in path requiredThe plugin’s version.
Responses
- 200
The plugin’s definition.
PluginapiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published plugins’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstring required · at least 1 characters, at most 2000 charactersfieldsarray of PluginField required · at most 8 itemsEach with a different metadata key.
markerobjectkind"image" | "color" | "shape" | "heading" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
hoverobjectkind"card" required
summaryobjectkind"radial" required
notesobjectkind"markdown" required
backgroundobjectAn image behind the timeline where a duration lies.
kind"image" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
targetsarray of "moments" | "durations" · at least 1 itemsWhat the plugin applies to; omitted, moments (and durations for colors and cards).
sourcestring · at least 1 characters, at most 16384 charactersThe plugin’s script, in the bounded plugin language.
- 400
The request is malformed or a value is not allowed.
- 404
Not found, or not visible to this account.
Try it
POST /api/plugins/publish Publish a plugin
Publishes a version of a plugin to the library, where anyone can find it at once. It needs a script, which the server compiles in its sandbox (never running it) and refuses with 400 when it does not compile. The ID is put in the account’s namespace, u-<account ID without hyphens>-<slug> with a slug of at most 29 characters; keep the returned ID and increase version to publish an update. Versions cannot be replaced. An account may publish at most 200 versions, and ten publications (plugins and suites together) a minute. Accounts other than administrators answer a human-verification challenge first. Read-only accounts cannot publish.
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
The plugin’s definition, at most 32 KiB.
Responses
- 201
Published: the definition as stored, with its namespaced ID.
PluginapiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published plugins’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstring required · at least 1 characters, at most 2000 charactersfieldsarray of PluginField required · at most 8 itemsEach with a different metadata key.
markerobjectkind"image" | "color" | "shape" | "heading" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
hoverobjectkind"card" required
summaryobjectkind"radial" required
notesobjectkind"markdown" required
backgroundobjectAn image behind the timeline where a duration lies.
kind"image" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
targetsarray of "moments" | "durations" · at least 1 itemsWhat the plugin applies to; omitted, moments (and durations for colors and cards).
sourcestring · at least 1 characters, at most 16384 charactersThe plugin’s script, in the bounded plugin language.
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/plugins/suites Search the plugin suites
The newest version of each suite whose name, description, ID or plugins’ names contain the search, by name. Works without server storage, with the official suites alone. Suites moderators restricted are left out.
Who: Anyone · Signed in
Parameters
searchstring in queryText that names, descriptions or IDs contain, without regard to case.
pageinteger in queryThe page, from 1.
limitinteger in queryHow many on a page.
Responses
- 200
A page of suites.
PluginSuitePageapiVersion1 requiredsuitesarray of PluginSuite requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
- 400
The request is malformed or a value is not allowed.
Try it
POST /api/plugins/suites/search Search the plugin suites with a JSON body
As GET /api/plugins/suites, with the search in the body (at most 4 KiB).
Who: Anyone · Signed in
Request body
searchstring · at most 200 characters, default ""pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12
Responses
- 200
A page of suites.
PluginSuitePageapiVersion1 requiredsuitesarray of PluginSuite requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.
Try it
GET /api/plugins/suites/{id}/{version} Read a version of a plugin suite
One version of a suite, with its plugins’ full definitions.
Who: Anyone · Signed in
Parameters
idstring in path requiredThe suite’s ID.
versionstring in path requiredThe suite’s version.
Responses
- 200
The suite.
PluginSuiteapiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published suites’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstringLonger descriptions are cut to 2,000 characters. Always present in answers.
pluginsarray of Plugin required · at least 1 items, at most 32 itemsEach plugin once (by ID).
- 400
The request is malformed or a value is not allowed.
- 404
Not found, or not visible to this account.
Try it
POST /api/plugins/suites/publish Publish a plugin suite
Publishes a version of a suite, as plugins are published: namespaced as u-<account ID without hyphens>-<slug> (slug of at most 29 characters), immutable versions, at most 200 versions per account, ten publications a minute, and a human-verification challenge for accounts other than administrators. Every scripted plugin in it, other than the official ones, must compile.
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
The suite, with its plugins’ definitions; the request at most 256 KiB.
apiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published suites’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstringLonger descriptions are cut to 2,000 characters. Always present in answers.
pluginsarray of Plugin required · at least 1 items, at most 32 itemsEach plugin once (by ID).
Responses
- 201
Published: the suite as stored, with its namespaced ID.
PluginSuiteapiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published suites’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstringLonger descriptions are cut to 2,000 characters. Always present in answers.
pluginsarray of Plugin required · at least 1 items, at most 32 itemsEach plugin once (by ID).
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Reports and moderation
Reporting content to the site’s administrators, and the decisions about what an account owns (see docs/moderation.md).
POST /api/reports Report something to the administrators
Reports a timeline, an event (moment or duration) in one, a comment on a pull request, a published plugin or suite, or an account, which the reporter must be able to see (404 otherwise). Reports of the same thing gather in one case; reporting the same thing again replaces the account’s earlier report. One’s own things cannot be reported (400). Signed-out readers can report, sending the sign-in token from GET /api/session as the CSRF token, and answer a human-verification challenge first. Limited to ten reports a minute per account, or per address when signed out. The owner is never told who reported.
Who: Signed in, with the CSRF token
Parameters
X-Challengestring in headerThe answer to the challenge a 428 carried: base64url of the JSON of a
HumanChallengeAnswer. Each answer works once, for the action it was issued for, within ten minutes.
Request body
The report, at most 8 KiB.
targetReportTarget requiredcategoryReportCategory requireddetailsstring · at most 2000 charactersMore about what is wrong.
Responses
- 201
Reported.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 428
Human verification is needed first: answer the challenge and send its token in
X-Challenge.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/moderation List moderation decisions about what you own
The restrictions and labels in force, and those lifted, on things the account owns: the latest 50, newest first.
Who: Signed in
Responses
- 200
The decisions.
objectdecisionsarray of ModerationDecision required
- 401
Sign in first.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
POST /api/moderation/{id}/appeal Ask for a review of a moderation decision
The owner’s one request for a review of a restriction or labels in force on what they own. It appears in the administrators’ queue, who then uphold or lift the decision. Limited to ten requests a minute.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe case’s ID.
Request body
The request, at most 8 KiB.
appealstring required · at least 1 characters, at most 2000 charactersWhy the decision should be reviewed.
Responses
- 200
Asked.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
A review was already asked for.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/admin/reports List reported cases for review
For administrators only. A page of 25 cases. open lists cases awaiting a decision and decisions whose owner asked for a review, those reporting child abuse or other illegal content first, then the oldest; restricted lists decisions in force (restrictions and labels); closed lists dismissed cases and lifted decisions, newest first.
Who: Signed in
Parameters
view"open" | "restricted" | "closed" in queryWhich cases (anything else means
open).pageinteger in queryThe page of 25, from 1 (out-of-range pages are clamped to 1–10,000).
Responses
- 200
A page of cases.
ReportCasePageview"open" | "restricted" | "closed" requiredpageinteger requiredtotalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of ReportCase required · at most 25 items
- 403
Not signed in as an active administrator.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
PATCH /api/admin/reports/{id} Decide a reported case
For administrators only. dismiss closes an open case; restrict makes a timeline private, hides a comment, plugin or suite (and refuses its new versions) or suspends an account; label adds content labels to a reported timeline; uphold keeps a decision whose owner asked for a review; lift undoes a restriction or labels at any time. restrict and label need a reason, given to the owner. The owner and signed-in reporters with a confirmed email are told by email. For administrators only, and confirmed: the body carries the current password (an account without one, as a social-only sign-in, must instead have signed in within the last five minutes; 403 otherwise) and, with two-factor authentication on, a fresh authenticator or recovery code (401 when either is wrong). Each change is recorded in the administration audit. Limited to ten changes a minute per administrator.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe case’s ID.
Request body
The decision, at most 8 KiB.
action"restrict" | "label" | "dismiss" | "uphold" | "lift" requiredrestrict,labelanddismissdecide an open case;upholdanswers a request for review;liftundoes a decision in force. Only timelines are labelled.reasonstring · at most 2000 charactersThe statement of reasons for the owner; required to restrict or label.
labelsarray of ContentLabel · at least 1 itemsTo label: what the timeline contains.
passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
Responses
- 200
Decided.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
The case was already decided, no review was asked for, nothing is in force, what was reported no longer exists, or it would suspend the last active administrator.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Administration
Site administration: accounts, timelines, the default storage quota and the review of reports. For administrators only.
GET /api/admin/users List accounts
For administrators only. A page of 25 accounts whose username or email contains the search, by username, with each one’s storage, trust and standing, and the site’s settings.
Who: Signed in
Parameters
searchstring in queryText to look for, without regard to case (longer text is cut to 200 characters).
pageinteger in queryThe page of 25, from 1 (out-of-range pages are clamped to 1–10,000).
Responses
- 200
A page of accounts.
AdminUserPagetotalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of AdminUser required · at most 25 itemspageinteger requiredsettingsobject requireddefault_quota_bytesstring · matches ^\d+$The storage quota of accounts without their own, in bytes.
default_quota_from_envbooleanWhether the environment file sets the default quota (
DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.
- 403
Not signed in as an active administrator.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
PATCH /api/admin/users/{id} Change an account
Makes an account an administrator or not, suspends or restores it, sets its storage quota or exemption from quotas, or marks it trusted or untrusted. Suspending an account, or demoting an administrator, ends its sessions, API keys and device sign-ins. The last active administrator cannot be suspended or demoted (409). For administrators only, and confirmed: the body carries the current password (an account without one, as a social-only sign-in, must instead have signed in within the last five minutes; 403 otherwise) and, with two-factor authentication on, a fresh authenticator or recovery code (401 when either is wrong). Each change is recorded in the administration audit. Limited to ten changes a minute per administrator.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe account’s ID.
Request body
The changes, at most 8 KiB.
is_adminbooleanis_disabledbooleanSuspends (true) or restores (false) it.
quota_bypassbooleanquota_bytesstring or integer or nullA size from 0 to 10 TB: a byte count (
104857600) or a size with a unit (500MiB,2GB,1.5GiB). At most 32 characters. Null for the site’s default.trust"trusted" | "untrusted" | nullTrusted accounts have full standing; untrusted none; null decides by its record.
passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
Responses
- 200
Changed.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/admin/timelines List timelines
For administrators only. A page of 25 timelines, of every account and visibility, whose title or owner’s username contains the search, by title; and the site’s settings.
Who: Signed in
Parameters
searchstring in queryText to look for, without regard to case (longer text is cut to 200 characters).
pageinteger in queryThe page of 25, from 1 (out-of-range pages are clamped to 1–10,000).
Responses
- 200
A page of timelines.
AdminTimelinePagetotalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of AdminTimeline required · at most 25 itemspageinteger requiredsettingsobject requireddefault_quota_bytesstring · matches ^\d+$The storage quota of accounts without their own, in bytes.
default_quota_from_envbooleanWhether the environment file sets the default quota (
DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.
- 403
Not signed in as an active administrator.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
PATCH /api/admin/timelines/{id} Change or delete a timeline
Makes a timeline public or private, features it on the site or not, or deletes it with its history ("delete": true, which ignores the other changes). A timeline moderators restricted cannot be made public until the restriction is lifted (409); nor can one holding private upstream data, or a comparison of timelines that are not all public (403). For administrators only, and confirmed: the body carries the current password (an account without one, as a social-only sign-in, must instead have signed in within the last five minutes; 403 otherwise) and, with two-factor authentication on, a fresh authenticator or recovery code (401 when either is wrong). Each change is recorded in the administration audit. Limited to ten changes a minute per administrator.
Who: Signed in, with the CSRF token
Parameters
idUuid in path requiredThe timeline’s ID.
Request body
The changes, at most 8 KiB.
visibility"public" | "private"featuredbooleandeletebooleantruedeletes the timeline and its history.passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
Responses
- 200
Changed.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 404
Not found, or not visible to this account.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
GET /api/admin/settings Read the site settings
For administrators only. The same answer as GET /api/admin/users (a page of accounts, with the same parameters), whose settings are the site’s settings.
Who: Signed in
Parameters
searchstring in queryText to look for, without regard to case (longer text is cut to 200 characters).
pageinteger in queryThe page of 25, from 1 (out-of-range pages are clamped to 1–10,000).
Responses
- 200
A page of accounts, and the site’s settings.
AdminUserPagetotalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of AdminUser required · at most 25 itemspageinteger requiredsettingsobject requireddefault_quota_bytesstring · matches ^\d+$The storage quota of accounts without their own, in bytes.
default_quota_from_envbooleanWhether the environment file sets the default quota (
DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.
- 403
Not signed in as an active administrator.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
PATCH /api/admin/settings Change the default storage quota
Sets the storage quota of accounts without their own. When the environment file sets it (DEFAULT_USER_STORAGE_BYTES), it is changed there instead (409). For administrators only, and confirmed: the body carries the current password (an account without one, as a social-only sign-in, must instead have signed in within the last five minutes; 403 otherwise) and, with two-factor authentication on, a fresh authenticator or recovery code (401 when either is wrong). Each change is recorded in the administration audit. Limited to ten changes a minute per administrator.
Who: Signed in, with the CSRF token
Request body
The change, at most 8 KiB.
default_quota_bytesstring or integer requiredA size from 0 to 10 TB: a byte count (
104857600) or a size with a unit (500MiB,2GB,1.5GiB). At most 32 characters.passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
Responses
- 200
Changed.
Okoktrue
- 400
The request is malformed or a value is not allowed.
- 401
Sign in first.
- 403
Not allowed: the CSRF token is missing or stale, the account lacks the role, or an API key lacks the scope.
- 409
It conflicts with the current state, such as a stale revision.
- 413
Too large, or over the account’s storage.
- 415
The body is not JSON: send
Content-Type: application/json.- 429
Too many requests. Wait, then try again.
- 503
The server’s storage, or a service it needs, is unavailable.
Try it
Server
The server itself.
GET /healthz Check the server’s health
Whether the server is up and, when it has PostgreSQL, whether its database answers and has the current schema. For load balancers and monitors.
Who: Anyone
Responses
- 200
The server is healthy.
Healthstatus"ok" requiredstorage"postgresql" | "browser" requiredpostgresqlwhen the server has a database;browserwhen it has none and timelines are kept in the browser.
- 503
The database does not answer, or lacks the current schema.
Try it
GET /api/openapi.json Get this API’s description
This document: the HTTP API in OpenAPI 3.1, for Swagger UI, Postman, code generators and the reference at /docs/api. Any site may read it.
Who: Anyone
Responses
- 200
The OpenAPI description.
object
Try it
Schemas
Error object
errorstring requiredWhat went wrong, for people.
challengeHumanChallengeWith 428: the human-verification challenge to answer.
conflictsarray of anyWith 409 from a save, merge or sync: what conflicts with what was saved meanwhile (at most 100). Saves name each conflicting entity; merges and syncs name fields, such as
moment x.metadata.title.conflictCountintegerWith
conflicts: how many there are.
Uuid string (uuid)
Revision string
A timeline's revision, as a decimal string. Saves send the revision they were made on.
Rational string
An exact time or number: an integer or fraction (-3/2), in coordinates.
Ok object
oktrue
EntityMetadata object
What an event (a moment or a duration) says. The core reads title, description, tags and content_labels; plugins keep their own fields here, stored as given.
titlestringdescriptionstringNotes, in Markdown.
tagsarray of string · at most 40 itemsTags, lowercased and trimmed when valid (1–64 characters, no commas or control characters, at most 40). Anything else is kept as ordinary metadata.
content_labelsarray of "nudity" | "violence" | "disturbing"Sensitive-content labels: readers are warned and its images blurred.
Moment object
A point event (a moment).
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$Unique among the timeline’s moments.
timestring requiredAn exact time in coordinates: a rational (
-3/2), a finite decimal (1.25), or an ISO 8601 timestamp (one with aT), which is read as Unix seconds. Stored and returned as a canonical rational.metadataEntityMetadata required
DurationEndpoint string or object
An exact time, or {"moment": "<id>"} to follow that moment’s time.
Duration object
A span of time. Either end may be a fixed time or follow a moment; anchors must name moments of the timeline.
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$Unique among the timeline’s durations.
startDurationEndpoint requiredendDurationEndpoint requiredmetadataEntityMetadataAs a moment’s;
{}when left out. It may not containdurations.
DurationBand any
A duration placed on the timeline: its definition with both ends resolved.
EntityRef object or object
A moment or a duration. Their IDs are separate, so a reference names the kind.
Relationship object
An undirected link between two different entities. Stored once, in canonical order; both must exist.
EdgeBand object
A relationship placed on the timeline, as an arc between its ends’ times.
TimePresentation object
How the timeline’s coordinates read: as numbers, units or calendar dates.
version1 requiredmode"rational" | "float" | "scientific" | "si" | "gregorian" | "custom" requiredsignificantDigitsinteger required · ≥ 1, ≤ 30unitstring required · at most 80 charactersscalestring required · at most 8192 charactersStored coordinates per displayed unit: a positive exact number.
originstring required · at most 8192 charactersThe stored coordinate of displayed zero.
offsetMinutesinteger required · ≥ -1439, ≤ 1439adaptiveLabelsbooleanrulerobjectRuler tick policy.
sourcestringFor
custom: its source code. The server checks its syntax and never runs it.
SavedComparison object
A saved comparison: a read-only live view of two to eight timelines. It stores no events of its own.
sourcesarray of Uuid required · at least 2 items, at most 8 itemscombinedboolean requiredOne combined track, or a track per source.
ViewFilter object or object
A separation: the entities with any of the tags (any) or none of them (none); or an entity and its relations, directly or through any number of links, or everything else.
TimelineDocument object
An OpenChronology document, as in an .ochx file. Each kind of entry (moments, durations, relationships) is limited to the server’s entry limit, 200,000 by default. Unknown fields are dropped. The server stores no copies of images: it drops assets when it saves, and keeps them only in exports.
format"openchronology" requiredversion1 requiredtitlestring required · at most 300 charactersdescriptionstring required · at most 20000 characterseventsarray of Moment requiredIts moments; IDs unique.
durationsarray of Durationrelationshipsarray of RelationshippresentationTimePresentationpluginsarray of object · at most 32 itemsInstalled plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.
manifestobject requiredThe plugin’s manifest (apiVersion 1).
enabledboolean requiredsettingsobjectValues of the timeline-wide settings its manifest declares (such as the timeline’s background image address, or its theme’s colors and fonts), by key. Values for undeclared settings are dropped.
tagsarray of string · at most 40 itemsThe timeline’s tags: lowercased, without commas or control characters.
assetsobjectCopies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.
comparisonSavedComparison
TimelineSettings object
A timeline’s settings, as a document without its entries: what a sparse save keeps or changes.
format"openchronology" requiredversion1 requiredtitlestring required · at most 300 charactersdescriptionstring required · at most 20000 characterspresentationTimePresentationpluginsarray of object · at most 32 itemstagsarray of string · at most 40 itemsassetsobject
TimelineMetadata object
A timeline as the caller may see it, with what they may do. It also carries internal fields of the server’s index (such as root, index_version, duration_root, edge_root), which clients should ignore.
idUuidowner_idUuidownerstringIts owner’s username.
slugstring or nullIts address is
/<owner>/<slug>; without one,/<owner>/<id>.titlestringdescriptionstringvisibility"private" | "public"revisionRevisionevent_countstring · matches ^\d+$How many moments it has.
event_generationstring · matches ^\d+$A count, as a decimal string.
star_countstring · matches ^\d+$A count, as a decimal string.
starredbooleanWhether the caller starred it.
role"admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | nullThe caller’s role; null for a public timeline they have none in.
presentationTimePresentation or nullpluginsarray or nulltagsarray or nullassetsobject or nullcomparisonSavedComparison or nullfeaturedbooleanupstream_idstring or null (uuid)The timeline this was forked from.
fork_base_revision_idstring or null (uuid)head_revision_idstring or null (uuid)allow_private_forksbooleanpublication_restrictedbooleanA copy of a private timeline, which must stay private.
storage_bytesstring · matches ^\d+$A count, as a decimal string.
created_atstring or null (date-time)updated_atstring (date-time)retention_secondsstring or nullHow long it keeps moments, in seconds as an exact rational; null for always.
retention_applied_atstring or null (date-time)retention_removedstring or nullkeep_historybooleanWhether it keeps saved history.
history_sincestring or nullcontent_labelsarray of stringmoderator_labelsarray of stringlabelsarray of "nudity" | "violence" | "disturbing"Its sensitive-content labels: its owner’s and moderators’.
moderationobject or nullWhen moderators restricted it (seen only by its owner and administrators).
caseUuidreasonstringdecided_atstring (date-time)appealed_atstring or null (date-time)appeal_outcomestring or null
preparingbooleanA copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).
canWritebooleanMay save it.
canEditbooleanMay edit a copy of it (to save or propose).
canProposebooleanMay open pull requests on it.
canSharebooleanMay manage its settings, members and deletion.
canForkbooleanfirstRational or nullWith
GET /api/timelines/{id}: its earliest moment’s time.lastRational or nullWith
GET /api/timelines/{id}: its latest moment’s time.
TimelineListItem object
A timeline the caller owns or is a member of.
TimelineWithDocument object
A timeline’s metadata and its whole document.
timelineTimelineMetadatadocumentTimelineDocument
TimelineSettingsResult any
The timeline after a settings change.
TimelineMember object
usernamestringrole"viewer" | "contributor" | "writer" | "editor"editoris an older name forwriter.
TimelineQuery object or object or object or object or object or object or object or object
A bounded read of a timeline, by kind. With revision, a timeline saved since answers 409. A filter (for events, durations and overview) reads a separation of the timeline, built on first use.
TimelineQueryResult object or object or object or object or object or object or object or object
What the query kind reads. Each carries the timeline’s revision.
TimelineChanges object
A sparse save: the settings, and only the moments, durations and relationships that changed. At most 5,000 changed events (moments and durations together), and 5,000 relationships.
revisionRevision requiredThe revision the request was made on: the timeline’s current
revision.settingsTimelineSettings requiredchangesarray of object requiredChanged moments: each the moment wanted, or null to delete it. IDs unique.
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$eventMoment or null required
durationChangesarray of objectChanged durations: each the duration wanted, or null to delete it.
idstring required · matches ^[A-Za-z0-9_.:-]{1,128}$durationDuration or null required
relationshipChangesarray of object · at most 5000 itemsLinks to add (
related: true) or remove (related: false).baseSaveBase
SaveBase object
What the edits were made on, so that a save on an older revision merges with what was saved since (field by field). With it, the save is checked against it even on the latest revision; a change or setting left out of it applies as sent. Conflicts answer 409 with conflicts, {kind: "moment" | "duration" | "setting", id, title}, and save nothing.
settingsobjectThe settings as loaded: any of these.
titleanydescriptionanytagsanypresentationanypluginsanyassetsany
momentsarray of object · at most 5000 itemsidstring required · matches ^[A-Za-z0-9_.:-]{1,128}$eventobject or null requiredAs loaded; null for one added.
durationsarray of object · at most 5000 itemsidstring required · matches ^[A-Za-z0-9_.:-]{1,128}$durationobject or null requiredAs loaded; null for one added.
TimeMapping object
Each time becomes (time − around) × scale + around + offset, exactly. Numbers are exact rationals or finite decimals as text (at most 4,000 characters).
scalestring requiredPositive.
offsetstring requiredaroundstring · default "0"The point to scale around.
OEmbed object
An oEmbed 1.0 rich response.
version"1.0"type"rich"provider_namestringprovider_urlstring (uri)titlestringauthor_namestringThe owner’s username.
author_urlstring (uri)htmlstringAn
<iframe>of the timeline’s embed page.widthinteger · ≥ 200, ≤ 800heightinteger · ≥ 160, ≤ 480thumbnail_urlstring (uri)Left out for a timeline with sensitive-content labels.
thumbnail_width1200thumbnail_height630cache_age3600
TimelineSearchRequest object
searchstring · at most 300 characters, default ""Words to find, in web-search syntax (quoted phrases,
-exclusions). Empty to browse.tagstring · at most 64 characters, default ""Only timelines with this tag (matched exactly, lowercased).
ownerstring · at most 64 characters, default ""Only timelines owned by this username.
starredBystring · at most 64 characters, default ""Only timelines this username starred (their public favorites; none for an account that may be under 18). Only with the
publicscope.scope"public" | "mine" | "visible" | "starred" · default "public"public: public timelines.mine: the caller’s own.visible: public ones and those shared with the caller.starred: those the caller starred. All butpublicneed sign-in.sort"featured" | "stars" | "popularity" | "trending" | "alphabetical" | "age" | "relevance"The order:
relevanceby default when there issearchtext, otherwisefeatured(featured first, then recently updated).popularityandtrending(last 30 days) weigh stars and forks by the standing of who gave them;ageis newest first. Ties go to the most recently updated.pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12
TimelineSearchResult object
A timeline found by a search: what a result card shows.
idUuidslugstring or nullIts address under its owner (
/<owner>/<slug>), if it has one.titlestringdescriptionstringtagsarray of stringvisibility"public" | "private"ownerstringThe owner’s username.
revisioninteger · ≥ 1A timeline revision, as a number (lists send it as a JSON number).
event_countinteger · ≥ 0How many moments it has.
comparisonobject or nullSet when it is a comparison of other timelines (a read-only live view).
star_countstring · matches ^\d+$Stars, as a decimal string.
starredbooleanWhether the caller starred it.
popularitystringIts popularity score (docs/browsing.md), as a decimal string.
featuredbooleanlabelsarray of stringIts sensitive-content labels, its owner’s and moderators’.
ranknumberIts text-search rank; 0 without search text.
created_atstring (date-time)updated_atstring (date-time)
TimelineSearchPage object
timelinesarray of TimelineSearchResult requiredtotalinteger required · ≥ 0How many timelines match in all.
pageinteger required · ≥ 1limitinteger required · ≥ 1pagesinteger required · ≥ 0
CopyRequest object
revisionRevision requiredThe timeline’s current revision; 409 when it has changed since.
BrowserFork object
documentTimelineDocument requiredsourceobject requiredWhat was copied.
limitsobject requiredThe limits a browser copy is held to.
events5000bytes4194304
HistoryRevision object
A saved checkpoint of a timeline.
idUuidThe saved revision’s ID.
numberstring · matches ^\d+$Its number in this timeline’s history; numbers can have gaps.
kind"baseline" | "save" | "fork" | "duplicate" | "sync" | "merge" | "proposal" | "rebase"What recorded it.
authorstring or nullWho saved it, by username.
created_atstring (date-time)parentsarray of Uuid · at most 2 itemsIts parent revisions: none, one, or two for a sync or merge.
availablebooleanWhether its content can be read: false for a past one not kept.
HistoryPage object
revisionsarray of HistoryRevision required · at most 20 itemspageinteger required · ≥ 1moreboolean requiredWhether there is a next page.
keepHistoryboolean requiredWhether the timeline keeps saved history.
ProposalSummary object
A pull request as lists show it.
idUuidtitlestringstatus"open" | "merged" | "rejected" | "closed"authorstringThe author’s username.
base_revisioninteger · ≥ 1The timeline revision it was made on.
revisioninteger · ≥ 1The pull request’s own revision.
created_atstring (date-time)updated_atstring (date-time)
ProposalPage object
proposalsarray of ProposalSummary requiredtotalinteger required · ≥ 0pageinteger required · ≥ 1pagesinteger required · ≥ 0
ProposalChanges object
What a pull request changes from its base, computed from saved history. When either revision is no longer kept, nothing is counted and unavailable says why.
settingsarray of stringThe timeline settings it changes (such as
title,tags).momentsobjectaddedinteger · ≥ 0removedinteger · ≥ 0changedinteger · ≥ 0
durationsobjectaddedinteger · ≥ 0removedinteger · ≥ 0changedinteger · ≥ 0
relationshipsobjectaddedinteger · ≥ 0removedinteger · ≥ 0
examplesarray of objectThe first thirty moments of each kind of change.
change"added" | "removed" | "changed"beforeMoment or nullafterMoment or null
unavailablestringWhy nothing could be counted.
Proposal object
A pull request, with what it changes and what the caller may do with it.
idUuidtimeline_idUuidauthor_idUuidauthorstringThe author’s username.
titlestringbodystringIts description, as plain text.
status"open" | "merged" | "rejected" | "closed"revisionRevisionThe pull request’s own revision: send it with updates and resolutions.
base_revisionRevisionThe timeline revision it is based on.
base_revision_idUuidThe saved revision it is based on.
source_revision_idUuidThe saved revision it proposes.
source_timeline_idUuid or nullThe fork it came from, if any.
from_forkbooleanresolved_byUuid or nullmerged_revisionRevision or nullThe timeline revision its merge made.
merged_revision_idUuid or nullcreated_atstring (date-time)updated_atstring (date-time)changesProposalChangescanMergebooleancanUpdatebooleancanClosebooleanupstreamRevisionRevisionThe timeline’s current revision: a rebase is needed when it differs from
base_revision.sourceobject or nullThe source fork, when it came from one the caller can read.
ProposalInput object or object
A pull request from a saved revision of a fork of this timeline, or as a whole proposed document.
ProposalUpdate any
What opening a pull request takes, plus revision, the pull request’s revision as last read. A fork pull request names the same fork; a document one keeps its baseRevision.
ProposalComment object
idstring · matches ^\d+$authorstringThe author’s username.
bodystringThe comment, as plain text; empty when moderators removed it.
removedbooleanWhether moderators removed it.
minebooleanWhether the caller wrote it (and so may delete it).
created_atstring (date-time)
ProposalCommentPage object
commentsarray of ProposalComment required · at most 50 itemsnextstring or null requiredSend as
afterfor the next page; null on the last.
Session object
serverboolean requiredWhether the server has storage. Without it, only browser timelines work.
dashboardtrue requireduserSessionUser or null requiredcsrfstring or null required · matches ^[a-f0-9]{64}$Signed in: the session’s CSRF token, sent as
X-CSRF-Tokenwith every change. Signed out: the sign-in token (also theoc_logincookie), sent the same way by sign-in requests. Null without server storage.providersarray of SignInProvider requiredThe sign-in providers this server offers.
securityobjectWhich account-security features the server offers (it needs email and an encryption key configured). Absent without server storage.
emailbooleanmfabooleanregistrationboolean
challenge"mfa" | "email" | nullA sign-in step this browser has pending (
mfa: a two-factor code;email: an email address to confirm), or null.fileExchangeboolean requiredWhether the server converts SQLite (.och) timeline files.
fileLimitintegerThe largest .och file the server converts, in bytes (
TIMELINE_FILE_BYTES, 64 MiB by default).compareLimitintegerHow many timelines this account (or a guest) may compare at once.
entryLimitinteger or nullHow many moments (and durations, relationships) a timeline may hold; null for no limit.
SessionUser object
idUuid requiredusernamestring requiredisAdminbooleanavatarUrlstringAn HTTPS or data: image URL, or empty.
minorbooleanWhether the account may be under 18, by its year of birth.
showSensitivebooleanWhether sensitive content shows without a warning (never for minors).
SignInProvider "google" | "github" | "facebook"
SignInRequest object
usernamestring required · matches ^[A-Za-z0-9][A-Za-z0-9_-]{2,31}$3–32 letters, digits,
_or-, starting with a letter or digit; lowercased by the server.passwordstring required · at least 1 characters, at most 1024 charactersThe password.
SignedIn object
userobject requiredidUuid requiredusernamestring required
csrfstring required · matches ^[a-f0-9]{64}$The new session’s CSRF token, to send as
X-CSRF-Tokenwith changes.tokenstring · matches ^[a-f0-9]{64}$Desktop sign-ins only: the session token, sent as
Authorization: Bearer …. A browser gets the session cookie instead.
SignInStep object
challenge"mfa" | "email" requiredmfa: send a two-factor code toPOST /api/auth/mfa/complete.email: confirm an email address withPOST /api/auth/email/enroll.messagestring required
RegistrationRequest object
usernamestring required · matches ^[A-Za-z0-9][A-Za-z0-9_-]{2,31}$3–32 letters, digits,
_or-, starting with a letter or digit; lowercased by the server. Names of the site’s own pages are taken, as are names that would pass for the site or its staff (root,moderator,admin1,open_chronology…).emailstring (email) required · at most 254 charactersAn email address (trimmed and lowercased).
passwordstring required · at least 15 characters, at most 1024 charactersA password or passphrase of 15–1024 characters. Predictable ones, and ones found in known breaches (checked against Have I Been Pwned by the first five characters of its SHA-1), are refused.
passwordConfirmationstring requiredThe new password again; it must match.
birthYearinteger required · ≥ 1900Year of birth. Accounts are for people 13 and older: anyone who may be younger than 13 by the end of this year is refused (403), and the browser is refused again for a day.
Registered object
messagestring requiredverificationRequiredtrue required
AccountMessage object
messagestring requiredWhat happened, for people.
SecurityConfirmation object
What confirms a security change.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
TwoFactorSetup object
secretstring required · matches ^[A-Z2-7]+$The authenticator key, in base32.
uristring requiredThe same key as an
otpauth://totp/…link (SHA-1, six digits, 30 seconds).
RecoveryCodes object
messagestring requiredrecoveryCodesarray of string required · at least 10 items, at most 10 itemsTen one-time recovery codes, shown only once. Store them offline.
ProviderStartRequest object
returnTostring · default "/"Where to return after:
/,/editor,/account,/plugins,/timelines/<id>, or a desktop approval page (/connect/desktop/<code>,/#desktop/<code>).linkbooleanLink the provider to the signed-in account instead of signing in. Needs a session signed in within the last five minutes.
DeviceSignIn object
deviceCodestring required · matches ^[a-f0-9]{64}$The desktop app’s secret for polling. Keep it out of the browser.
userCodestring required · matches ^[A-Z2-9]{10}$The code the desktop app shows, to match in the browser.
verificationUristring (uri) requiredThe page that approves it:
<origin>/connect/desktop/<userCode>.interval3 requiredSeconds between polls, at least.
expiresIn600 requiredSeconds until it expires.
ApiKey object
idUuid requirednamestring requiredprefixstring requiredThe key’s first 20 characters, to recognize it by.
scopesarray of ApiKeyScope requiredcreated_atstring (date-time) requiredexpires_atstring (date-time) requiredlast_used_atstring or null (date-time)revoked_atstring or null (date-time)
ApiKeyScope "timelines:read" | "timelines:write"
timelines:read for reads (GET, and POST searches and queries); timelines:write for changes.
NewApiKey object
namestring required · at least 1 characters, at most 80 charactersTrimmed; not blank.
scopesarray of ApiKeyScope · at least 1 items, at most 2 items, default ["timelines:read"]daysinteger · ≥ 1, ≤ 365, default 90Days until it expires.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
CreatedApiKey object
idUuid requiredtokenstring required · matches ^och_key_[a-f0-9]{32}_[a-f0-9]{64}$The key, sent as
Authorization: Bearer …. Shown only now; the server keeps only its hash.messagestring required
ProfileChange object
avatarUrlstring · at most 350000 charactersAn HTTPS image URL (at most 2048 characters), a
data:image/png|jpeg|webp;base64,…image (at most 256 KiB), or empty to remove it.showSensitivebooleanShow sensitive content without a warning. Adults only.
Account object
securityobject requiredemailstring or nullemail_verified_atstring or null (date-time)mfa_enabledbooleanhas_passwordbooleanrecovery_remainingintegerRecovery codes not yet used.
profileobject requiredavatarUrlstringminorbooleanshowSensitiveboolean
usageAccountUsage requiredkeysarray of ApiKey requiredidentitiesarray of SignInProvider requiredThe sign-in providers linked to the account.
sessionsarray of AccountSession required
AccountUsage object
Storage used and allowed.
used_bytesstring · matches ^\d+$Storage used. A decimal string.
quota_bytesstring or null · matches ^\d+$The account’s own storage limit, or null for the site default. A decimal string.
effective_quota_bytesstring · matches ^\d+$The storage limit that applies. A decimal string.
quota_bypassbooleanWhether the account has no storage limit.
is_adminbooleanis_disabledboolean
AccountSession object
idstring required · matches ^[a-f0-9]{64}$Identifies the session (a hash of its token, not the token).
kind"web" | "desktop" requiredcreated_atstring (date-time) requiredlast_seen_atstring (date-time) requiredcurrentboolean requiredWhether it is the session asking.
AccountDeletion object
confirmstring requiredThe account’s username, to confirm.
passwordstring · at most 1024 charactersThe current password, when the account has one (accounts made with a sign-in provider may not).
codestringWith two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.
AccountDeleted object
oktrue requiredtimelinesinteger requiredHow many timelines were deleted with it.
HumanChallenge object or object
The human-verification challenge a 428 carries (as challenge). Answer it and repeat the request with the answer in X-Challenge.
HumanChallengePurpose "register" | "email" | "sign-in" | "contribution" | "plugin" | "report"
The action a challenge is for; its answer works for that action only.
HumanChallengeAnswer object or object
An answer to a HumanChallenge, sent base64url-encoded as JSON in X-Challenge.
Health object
status"ok" requiredstorage"postgresql" | "browser" requiredpostgresqlwhen the server has a database;browserwhen it has none and timelines are kept in the browser.
PluginField object
kind"text" | "multiline" | "image-url" | "stack" | "color" | "shape" | "size" | "links" | "heading" | "font" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.labelstring required · at least 1 characters, at most 100 characters
Plugin object
A plugin’s definition (manifest): host components and an optional restricted script. Unknown properties are refused.
apiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published plugins’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstring required · at least 1 characters, at most 2000 charactersfieldsarray of PluginField required · at most 8 itemsEach with a different metadata key.
markerobjectkind"image" | "color" | "shape" | "heading" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
hoverobjectkind"card" required
summaryobjectkind"radial" required
notesobjectkind"markdown" required
backgroundobjectAn image behind the timeline where a duration lies.
kind"image" requiredmetadataKeystring required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$A metadata key; not
title,description,durations,tags,__proto__,prototypeorconstructor.
targetsarray of "moments" | "durations" · at least 1 itemsWhat the plugin applies to; omitted, moments (and durations for colors and cards).
sourcestring · at least 1 characters, at most 16384 charactersThe plugin’s script, in the bounded plugin language.
PluginPublication any
A plugin to publish: a definition with a script, at most 32 KiB serialized.
PluginSearch object
searchstring · at most 200 characters, default ""pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12sort"popularity" | "alphabetical" | "age" · default "popularity"Without server storage, always by name.
PluginPage object
apiVersion1 requiredpluginsarray of Plugin requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
PluginSuite object
A named package of plugins installed together, with their full definitions; at most 128 KiB serialized. Unknown properties are refused.
apiVersion1 requiredidstring required · matches ^[a-z][a-z0-9-]{0,63}$Published suites’ IDs are
u-<account>-<slug>.versioninteger required · ≥ 1, ≤ 9007199254740991namestring required · at least 1 characters, at most 100 charactersdescriptionstringLonger descriptions are cut to 2,000 characters. Always present in answers.
pluginsarray of Plugin required · at least 1 items, at most 32 itemsEach plugin once (by ID).
PluginSuiteSearch object
searchstring · at most 200 characters, default ""pageinteger · ≥ 1, ≤ 10000, default 1limitinteger · ≥ 1, ≤ 50, default 12
PluginSuitePage object
apiVersion1 requiredsuitesarray of PluginSuite requiredtotalinteger requiredHow many match.
pageinteger requiredlimitinteger requiredpagesinteger requiredHow many pages there are.
ReportCategory "child_abuse" | "illegal" | "sexual" | "violence" | "self_harm" | "harassment" | "spam" | "copyright" | "other"
What is wrong: child sexual abuse or exploitation; other illegal content; sexually explicit content; graphic violence or gore; promotes suicide or self-harm; harassment, threats or private information; spam or misleading; copyright infringement; something else.
ReportTarget object or object or object or object or object
What is reported.
ReportRequest object
targetReportTarget requiredcategoryReportCategory requireddetailsstring · at most 2000 charactersMore about what is wrong.
ContentLabel "nudity" | "violence" | "disturbing"
Nudity, graphic violence or disturbing content.
ModerationTarget object or null
What a case is about, as it is now; null once it is gone. Each kind has some of these.
ModerationDecision object
A decision about something the account owns.
idUuidtarget_kind"timeline" | "comment" | "plugin" | "suite" | "user"target_idstringstatus"restricted" | "labelled" | "lifted"labelsarray or nullContentLabelThe labels a
labeldecision added.reasonstring or nullThe statement of reasons.
decided_atstring or null (date-time)appealstring or nullThe owner’s request for a review.
appealed_atstring or null (date-time)appeal_outcome"upheld" | "lifted" | nullappeal_decided_atstring or null (date-time)targetModerationTargetpathstring or nullWhere what it is about is seen on the platform; null once it is gone.
AppealRequest object
appealstring required · at least 1 characters, at most 2000 charactersWhy the decision should be reviewed.
ReportCase object
A case: the reports of one thing, and its decision.
idUuidtarget_kind"timeline" | "comment" | "plugin" | "suite" | "user"target_idstringowner_idstring or null (uuid)The owner’s account ID; null once the account is gone.
ownerstring or nullThe owner’s username.
status"open" | "dismissed" | "restricted" | "labelled" | "lifted"created_atstring (date-time)reasonstring or nulllabelsarray or nullContentLabeldecided_bystring or null (uuid)The deciding administrator’s account ID.
decided_atstring or nullprevious_visibility"public" | "private" | nullA restricted timeline’s visibility before, restored when lifted.
appealstring or nullappealed_atstring or nullappeal_outcome"upheld" | "lifted" | nullappeal_decided_atstring or nulltargetModerationTargetpathstring or nullreport_countintegerurgentbooleanWhether a report says child abuse or other illegal content.
reportsarray of object · at most 20 itemsThe latest twenty reports, newest first.
categoryReportCategorydetailsstringentity_kind"moment" | "duration" | nullThe event (moment or duration) a timeline’s report names.
entity_idstring or nullcreated_atstring (date-time)reporterstring or nullThe reporter’s username; null when signed out.
ReportCasePage object
view"open" | "restricted" | "closed" requiredpageinteger requiredtotalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of ReportCase required · at most 25 items
ModerationDecisionRequest object
action"restrict" | "label" | "dismiss" | "uphold" | "lift" requiredrestrict,labelanddismissdecide an open case;upholdanswers a request for review;liftundoes a decision in force. Only timelines are labelled.reasonstring · at most 2000 charactersThe statement of reasons for the owner; required to restrict or label.
labelsarray of ContentLabel · at least 1 itemsTo label: what the timeline contains.
passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
AdminUser object
idUuidusernamestringemailstring or nullis_adminbooleanis_disabledbooleanWhether it is suspended.
quota_bypassbooleanWhether storage quotas do not apply to it.
quota_bytesinteger or nullIts own storage quota; null for the site’s default.
used_bytesintegercreated_atstring (date-time)trust"trusted" | "untrusted" | nullstandingnumber · ≥ 0, ≤ 1Its standing, which ranks its timelines and weighs its stars.
endorsersintegerAccounts that endorse it by stars or forks.
confirmedbooleanWhether it has a confirmed email or a social sign-in.
restrictedbooleanWhether a moderation restriction is in force on something it owns.
AdminUserPage object
totalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of AdminUser required · at most 25 itemspageinteger requiredsettingsobject requireddefault_quota_bytesstring · matches ^\d+$The storage quota of accounts without their own, in bytes.
default_quota_from_envbooleanWhether the environment file sets the default quota (
DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.
AdminTimeline object
idUuidtitlestringvisibility"public" | "private"featuredbooleanevent_countintegerownerstringThe owner’s username.
AdminTimelinePage object
totalstring required · matches ^\d+$A count, as a decimal string.
itemsarray of AdminTimeline required · at most 25 itemspageinteger requiredsettingsobject requireddefault_quota_bytesstring · matches ^\d+$The storage quota of accounts without their own, in bytes.
default_quota_from_envbooleanWhether the environment file sets the default quota (
DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.
AdminUserChange object
is_adminbooleanis_disabledbooleanSuspends (true) or restores (false) it.
quota_bypassbooleanquota_bytesstring or integer or nullA size from 0 to 10 TB: a byte count (
104857600) or a size with a unit (500MiB,2GB,1.5GiB). At most 32 characters. Null for the site’s default.trust"trusted" | "untrusted" | nullTrusted accounts have full standing; untrusted none; null decides by its record.
passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
AdminTimelineChange object
visibility"public" | "private"featuredbooleandeletebooleantruedeletes the timeline and its history.passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.
AdminSettingsChange object
default_quota_bytesstring or integer requiredA size from 0 to 10 TB: a byte count (
104857600) or a size with a unit (500MiB,2GB,1.5GiB). At most 32 characters.passwordstringThe administrator’s current password.
codestringA fresh authenticator or recovery code, when the administrator has two-factor authentication on.