◷ openchronology

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.

object
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

TimelineDocument
  • format "openchronology" required
  • version 1 required
  • title string required · at most 300 characters
  • description string required · at most 20000 characters
  • events array of Moment required

    Its moments; IDs unique.

  • durations array of Duration
  • relationships array of Relationship
  • presentation TimePresentation
  • plugins array of object · at most 32 items

    Installed plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.

    • manifest object required

      The plugin’s manifest (apiVersion 1).

    • enabled boolean required
    • settings object

      Values 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.

  • tags array of string · at most 40 items

    The timeline’s tags: lowercased, without commas or control characters.

  • assets object

    Copies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.

  • comparison SavedComparison

Responses

201

The new timeline.

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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.

object
  • usedBytes integer
  • quotaBytes integer or null

    Null 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

  • id Uuid in path required

    The timeline's ID.

Responses

200

The timeline.

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • revision Revision required

    The revision the request was made on: the timeline’s current revision.

  • document TimelineDocument required

Responses

200

The timeline as saved.

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Responses

200

Deleted.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Responses

200

Its revision.

object
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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • visibility "private" | "public"
  • allowPrivateForks boolean

    Whether those with access may fork it while it is private.

  • retention string or null · at most 200 characters

    How 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.

  • keepHistory boolean
  • labels array of "nudity" | "violence" | "disturbing"

    What the owner marks it as containing. Moderators’ labels stay.

  • slug string or null

    Its 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Responses

200

Its members, by username.

object
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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • username string required

    Case is ignored.

  • role "viewer" | "contributor" | "writer" | "editor" required

    editor is taken as writer.

Responses

200

Done.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • username string required

Responses

200

Done.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • download "1" in query

    With 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

  • id Uuid in path required

    The timeline's ID.

  • name string in path required

    The file name to save it as.

Responses

200

The document.

TimelineDocument
  • format "openchronology" required
  • version 1 required
  • title string required · at most 300 characters
  • description string required · at most 20000 characters
  • events array of Moment required

    Its moments; IDs unique.

  • durations array of Duration
  • relationships array of Relationship
  • presentation TimePresentation
  • plugins array of object · at most 32 items

    Installed plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.

    • manifest object required

      The plugin’s manifest (apiVersion 1).

    • enabled boolean required
    • settings object

      Values 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.

  • tags array of string · at most 40 items

    The timeline’s tags: lowercased, without commas or control characters.

  • assets object

    Copies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.

  • comparison SavedComparison
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

  • id Uuid in path required

    The timeline's ID.

Responses

200

The SQLite file.

application/vnd.openchronology.sqlite
string
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

  • id Uuid in path required

    The 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • direction "last" | "first" in query

    Which end to read.

Responses

200

Its times.

object
  • revision Revision
  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • times array of Rational · at most 8 items
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

  • id Uuid in path required

    The timeline's ID.

Request body

TimelineChanges
  • revision Revision required

    The revision the request was made on: the timeline’s current revision.

  • settings TimelineSettings required
  • changes array of object required

    Changed moments: each the moment wanted, or null to delete it. IDs unique.

    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • event Moment or null required
  • durationChanges array of object

    Changed durations: each the duration wanted, or null to delete it.

    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • duration Duration or null required
  • relationshipChanges array of object · at most 5000 items

    Links to add (related: true) or remove (related: false).

  • base SaveBase

Responses

200

The timeline as saved.

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • revision Revision required

    The revision the request was made on: the timeline’s current revision.

  • lower Rational required

    Exact stored coordinate; at most upper.

  • upper Rational required

Responses

200

What was deleted, and the timeline afterwards.

object
  • removed object
    • moments integer
    • durations integer
  • more boolean

    Whether the range holds more to delete.

  • timeline TimelineMetadata
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • revision Revision required

    The revision the request was made on: the timeline’s current revision.

  • mapping TimeMapping required
  • filter ViewFilter

    Without it, everything moves.

Responses

200

How many events (moments and durations) moved, and the timeline as saved.

object
application/x-ndjson
string

JSON 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

This sends a real request to this server, as you.

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.sqlite
string
application/octet-stream
string

Responses

200

The file’s document.

object
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

TimelineDocument
  • format "openchronology" required
  • version 1 required
  • title string required · at most 300 characters
  • description string required · at most 20000 characters
  • events array of Moment required

    Its moments; IDs unique.

  • durations array of Duration
  • relationships array of Relationship
  • presentation TimePresentation
  • plugins array of object · at most 32 items

    Installed plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.

    • manifest object required

      The plugin’s manifest (apiVersion 1).

    • enabled boolean required
    • settings object

      Values 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.

  • tags array of string · at most 40 items

    The timeline’s tags: lowercased, without commas or control characters.

  • assets object

    Copies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.

  • comparison SavedComparison

Responses

200

The SQLite file.

application/vnd.openchronology.sqlite
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.

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

This sends a real request to this server, as you.

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

  • timelines string in query required

    One to eight timeline IDs, separated by commas.

Responses

200

The event stream.

text/event-stream
string
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

  • url string (uri) in query required

    The link: /timelines/<id> or /<owner>/<slug or id>, optionally followed by /moments/<id> or /durations/<id>, or a link fragment.

  • format "json" in query

    Only json is available.

  • maxwidth integer in query

    The widest it may be; at most 800 is given.

  • maxheight integer in query

    The tallest it may be; at most 480 is given.

Responses

200

The embed.

OEmbed
  • version "1.0"
  • type "rich"
  • provider_name string
  • provider_url string (uri)
  • title string
  • author_name string

    The owner’s username.

  • author_url string (uri)
  • html string

    An <iframe> of the timeline’s embed page.

  • width integer · ≥ 200, ≤ 800
  • height integer · ≥ 160, ≤ 480
  • thumbnail_url string (uri)

    Left out for a timeline with sensitive-content labels.

  • thumbnail_width 1200
  • thumbnail_height 630
  • cache_age 3600
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

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

  • id Uuid in path required

    The timeline's ID.

Request body

CopyRequest
  • revision Revision required

    The timeline’s current revision; 409 when it has changed since.

Responses

201

The new fork’s metadata (without time bounds).

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

CopyRequest
  • revision Revision required

    The timeline’s current revision; 409 when it has changed since.

Responses

201

The new copy’s metadata (without time bounds).

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • revision Revision required

    The fork’s current revision.

Responses

200

The fork’s metadata after syncing.

TimelineMetadata
  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • revision string · matches ^\d{1,20}$

    If given, the revision expected: 409 when the timeline has moved on.

Responses

200

OK.

BrowserFork
  • document TimelineDocument required
  • source object required

    What was copied.

  • limits object required

    The limits a browser copy is held to.

    • events 5000
    • bytes 4194304
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • page integer in query

    The page, from 1.

Responses

200

OK.

HistoryPage
  • revisions array of HistoryRevision required · at most 20 items
  • page integer required · ≥ 1
  • more boolean required

    Whether there is a next page.

  • keepHistory boolean required

    Whether 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

  • id Uuid in path required

    The timeline's ID.

  • saved Uuid in path required

    The saved revision’s ID (from the history list).

  • download "1" in query

    1 to download the document as an .ochx file.

Responses

200

The saved document; with download=1, the bare document as an .ochx attachment (Content-Disposition set).

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

  • id Uuid in path required

    The timeline's ID.

  • page integer in query

    The page, from 1.

Responses

200

OK.

ProposalPage
  • proposals array of ProposalSummary required
  • total integer required · ≥ 0
  • page integer required · ≥ 1
  • pages integer 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

  • id Uuid in path required

    The timeline's ID.

Request body

Responses

201

The pull request opened.

Proposal
  • id Uuid
  • timeline_id Uuid
  • author_id Uuid
  • author string

    The author’s username.

  • title string
  • body string

    Its description, as plain text.

  • status "open" | "merged" | "rejected" | "closed"
  • revision Revision

    The pull request’s own revision: send it with updates and resolutions.

  • base_revision Revision

    The timeline revision it is based on.

  • base_revision_id Uuid

    The saved revision it is based on.

  • source_revision_id Uuid

    The saved revision it proposes.

  • source_timeline_id Uuid or null

    The fork it came from, if any.

  • from_fork boolean
  • resolved_by Uuid or null
  • merged_revision Revision or null

    The timeline revision its merge made.

  • merged_revision_id Uuid or null
  • created_at string (date-time)
  • updated_at string (date-time)
  • changes ProposalChanges
  • canMerge boolean
  • canUpdate boolean
  • canClose boolean
  • upstreamRevision Revision

    The timeline’s current revision: a rebase is needed when it differs from base_revision.

  • source object or null

    The source fork, when it came from one the caller can read.

    • id Uuid
    • title string
    • head_revision_id Uuid
    • canWrite boolean
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

Request body

object
  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12

Responses

200

OK.

ProposalPage
  • proposals array of ProposalSummary required
  • total integer required · ≥ 0
  • page integer required · ≥ 1
  • pages integer 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Responses

200

OK.

Proposal
  • id Uuid
  • timeline_id Uuid
  • author_id Uuid
  • author string

    The author’s username.

  • title string
  • body string

    Its description, as plain text.

  • status "open" | "merged" | "rejected" | "closed"
  • revision Revision

    The pull request’s own revision: send it with updates and resolutions.

  • base_revision Revision

    The timeline revision it is based on.

  • base_revision_id Uuid

    The saved revision it is based on.

  • source_revision_id Uuid

    The saved revision it proposes.

  • source_timeline_id Uuid or null

    The fork it came from, if any.

  • from_fork boolean
  • resolved_by Uuid or null
  • merged_revision Revision or null

    The timeline revision its merge made.

  • merged_revision_id Uuid or null
  • created_at string (date-time)
  • updated_at string (date-time)
  • changes ProposalChanges
  • canMerge boolean
  • canUpdate boolean
  • canClose boolean
  • upstreamRevision Revision

    The timeline’s current revision: a rebase is needed when it differs from base_revision.

  • source object or null

    The source fork, when it came from one the caller can read.

    • id Uuid
    • title string
    • head_revision_id Uuid
    • canWrite boolean
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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Request body

Responses

200

The pull request updated.

Proposal
  • id Uuid
  • timeline_id Uuid
  • author_id Uuid
  • author string

    The author’s username.

  • title string
  • body string

    Its description, as plain text.

  • status "open" | "merged" | "rejected" | "closed"
  • revision Revision

    The pull request’s own revision: send it with updates and resolutions.

  • base_revision Revision

    The timeline revision it is based on.

  • base_revision_id Uuid

    The saved revision it is based on.

  • source_revision_id Uuid

    The saved revision it proposes.

  • source_timeline_id Uuid or null

    The fork it came from, if any.

  • from_fork boolean
  • resolved_by Uuid or null
  • merged_revision Revision or null

    The timeline revision its merge made.

  • merged_revision_id Uuid or null
  • created_at string (date-time)
  • updated_at string (date-time)
  • changes ProposalChanges
  • canMerge boolean
  • canUpdate boolean
  • canClose boolean
  • upstreamRevision Revision

    The timeline’s current revision: a rebase is needed when it differs from base_revision.

  • source object or null

    The source fork, when it came from one the caller can read.

    • id Uuid
    • title string
    • head_revision_id Uuid
    • canWrite boolean
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Responses

200

The proposed timeline.

object
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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Request body

object
  • action "merge" | "reject" | "close" | "rebase" required
  • revision Revision required

    The pull request’s revision as last read (not the timeline’s).

Responses

200

The pull request after the action.

Proposal
  • id Uuid
  • timeline_id Uuid
  • author_id Uuid
  • author string

    The author’s username.

  • title string
  • body string

    Its description, as plain text.

  • status "open" | "merged" | "rejected" | "closed"
  • revision Revision

    The pull request’s own revision: send it with updates and resolutions.

  • base_revision Revision

    The timeline revision it is based on.

  • base_revision_id Uuid

    The saved revision it is based on.

  • source_revision_id Uuid

    The saved revision it proposes.

  • source_timeline_id Uuid or null

    The fork it came from, if any.

  • from_fork boolean
  • resolved_by Uuid or null
  • merged_revision Revision or null

    The timeline revision its merge made.

  • merged_revision_id Uuid or null
  • created_at string (date-time)
  • updated_at string (date-time)
  • changes ProposalChanges
  • canMerge boolean
  • canUpdate boolean
  • canClose boolean
  • upstreamRevision Revision

    The timeline’s current revision: a rebase is needed when it differs from base_revision.

  • source object or null

    The source fork, when it came from one the caller can read.

    • id Uuid
    • title string
    • head_revision_id Uuid
    • canWrite boolean
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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

  • after string in query

    Return comments after this comment ID (0 for the first page).

Responses

200

OK.

ProposalCommentPage
  • comments array of ProposalComment required · at most 50 items
  • next string or null required

    Send as after for 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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Request body

object
  • body string required · at least 1 characters, at most 20000 characters

    The comment: 1–20,000 characters, not only spaces. Kept trimmed.

Responses

201

The comment was added.

object
  • id string 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

Request body

object
  • after string · matches ^[0-9]{1,18}$, default "0"

    Return comments after this comment ID.

Responses

200

OK.

ProposalCommentPage
  • comments array of ProposalComment required · at most 50 items
  • next string or null required

    Send as after for 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The timeline's ID.

  • proposal Uuid in path required

    The pull request’s ID.

  • comment string in path required

    The comment’s ID.

Responses

200

Deleted.

Ok
  • ok true
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

This sends a real request to this server, as you.

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.

Session
  • server boolean required

    Whether the server has storage. Without it, only browser timelines work.

  • dashboard true required
  • user SessionUser or null required
  • csrf string or null required · matches ^[a-f0-9]{64}$

    Signed in: the session’s CSRF token, sent as X-CSRF-Token with every change. Signed out: the sign-in token (also the oc_login cookie), sent the same way by sign-in requests. Null without server storage.

  • providers array of SignInProvider required

    The sign-in providers this server offers.

  • security object

    Which account-security features the server offers (it needs email and an encryption key configured). Absent without server storage.

    • email boolean
    • mfa boolean
    • registration boolean
  • challenge "mfa" | "email" | null

    A sign-in step this browser has pending (mfa: a two-factor code; email: an email address to confirm), or null.

  • fileExchange boolean required

    Whether the server converts SQLite (.och) timeline files.

  • fileLimit integer

    The largest .och file the server converts, in bytes (TIMELINE_FILE_BYTES, 64 MiB by default).

  • compareLimit integer

    How many timelines this account (or a guest) may compare at once.

  • entryLimit integer or null

    How 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.

Ok
  • ok true
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

This sends a real request to this server, as you.

POST /api/auth/logout Sign out

Ends this session. No body.

Who: Signed in, with the CSRF token

Responses

200

Signed out.

Ok
  • ok true
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

This sends a real request to this server, as you.

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 header

    Send desktop from the desktop app: the sign-in then returns a session token (a bearer credential) instead of setting the session cookie.

  • X-Challenge string in header

    The 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

SignInRequest
  • username string 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.

  • password string required · at least 1 characters, at most 1024 characters

    The 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

This sends a real request to this server, as you.

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-Challenge string in header

    The 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

RegistrationRequest
  • username string 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…).

  • email string (email) required · at most 254 characters

    An email address (trimmed and lowercased).

  • password string required · at least 15 characters, at most 1024 characters

    A 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.

  • passwordConfirmation string required

    The new password again; it must match.

  • birthYear integer required · ≥ 1900

    Year 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.

Registered
  • message string required
  • verificationRequired true 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

This sends a real request to this server, as you.

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

object
  • code string required

    With 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

This sends a real request to this server, as you.

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-Challenge string in header

    The 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

object
  • email string (email) required · at most 254 characters

    An email address (trimmed and lowercased).

  • birthYear integer · ≥ 1900

    Year 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.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

Responses

200

Confirmation sent.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

object
  • token string required · matches ^[a-f0-9]{64}$

    The token from the confirmation link.

Responses

200

Confirmed.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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-Challenge string in header

    The 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

object
  • email string (email) required · at most 254 characters

    An email address (trimmed and lowercased).

Responses

200

A link is sent if the account is eligible.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

object
  • token string required · matches ^[a-f0-9]{64}$

    The token from the reset link.

  • password string required · at least 15 characters, at most 1024 characters

    A 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.

  • passwordConfirmation string required

    The new password again; it must match.

Responses

200

Password reset.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

  • provider SignInProvider in path required

    The sign-in provider. Only providers this server configures work (see providers in GET /api/session).

Request body

ProviderStartRequest
  • returnTo string · default "/"

    Where to return after: /, /editor, /account, /plugins, /timelines/<id>, or a desktop approval page (/connect/desktop/<code>, /#desktop/<code>).

  • link boolean

    Link 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.

object
  • url string (uri) required

    The 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

This sends a real request to this server, as you.

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

  • provider SignInProvider in path required

    The sign-in provider. Only providers this server configures work (see providers in GET /api/session).

  • state string in query required

    The state the sign-in started with.

  • code string in query

    The provider’s authorization code.

  • error string in query

    Set 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

object

Responses

200

The pending desktop sign-in.

DeviceSignIn
  • deviceCode string required · matches ^[a-f0-9]{64}$

    The desktop app’s secret for polling. Keep it out of the browser.

  • userCode string required · matches ^[A-Z2-9]{10}$

    The code the desktop app shows, to match in the browser.

  • verificationUri string (uri) required

    The page that approves it: <origin>/connect/desktop/<userCode>.

  • interval 3 required

    Seconds between polls, at least.

  • expiresIn 600 required

    Seconds 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

This sends a real request to this server, as you.

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

object
  • deviceCode string required · matches ^[a-f0-9]{64}$

    The deviceCode from POST /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

This sends a real request to this server, as you.

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

object
  • userCode string required · matches ^[A-Z2-9]{10}$

    The ten-character code the desktop app shows.

Responses

200

Approved.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

object
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

Responses

200

The authenticator key.

TwoFactorSetup
  • secret string required · matches ^[A-Z2-7]+$

    The authenticator key, in base32.

  • uri string required

    The 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

This sends a real request to this server, as you.

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

object
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string required · matches ^\d{6}$

    A code from the authenticator just set up.

Responses

200

Turned on.

RecoveryCodes
  • message string required
  • recoveryCodes array of string required · at least 10 items, at most 10 items

    Ten 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

This sends a real request to this server, as you.

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

SecurityConfirmation
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

Responses

200

Turned off.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

SecurityConfirmation
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With 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.

RecoveryCodes
  • message string required
  • recoveryCodes array of string required · at least 10 items, at most 10 items

    Ten 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

This sends a real request to this server, as you.

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

object
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • newPassword string required · at least 15 characters, at most 1024 characters

    A 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.

  • passwordConfirmation string required

    The new password again; it must match.

  • code string

    With 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.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

object
  • email string (email) required · at most 254 characters

    An email address (trimmed and lowercased).

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

Responses

200

Confirmation sent.

AccountMessage
  • message string required

    What 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

This sends a real request to this server, as you.

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

object
  • provider SignInProvider required
  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

Responses

200

Unlinked.

Ok
  • ok true
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

This sends a real request to this server, as you.

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.

object
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

NewApiKey
  • name string required · at least 1 characters, at most 80 characters

    Trimmed; not blank.

  • scopes array of ApiKeyScope · at least 1 items, at most 2 items, default ["timelines:read"]
  • days integer · ≥ 1, ≤ 365, default 90

    Days until it expires.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With 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.

CreatedApiKey
  • id Uuid required
  • token string 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.

  • message string 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

This sends a real request to this server, as you.

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

  • id Uuid in path required

    The API key’s ID.

Responses

200

Revoked.

Ok
  • ok true
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

This sends a real request to this server, as you.

DELETE /api/auth/api-keys/{id} Delete an API key

Removes the key, which stops working.

Who: Signed in, with the CSRF token

Parameters

  • id Uuid in path required

    The API key’s ID.

Responses

200

Deleted.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

ProfileChange
  • avatarUrl string · at most 350000 characters

    An HTTPS image URL (at most 2048 characters), a data:image/png|jpeg|webp;base64,… image (at most 256 KiB), or empty to remove it.

  • showSensitive boolean

    Show sensitive content without a warning. Adults only.

Responses

200

Changed.

Ok
  • ok true
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

This sends a real request to this server, as you.

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.

Account
  • security object required
    • email string or null
    • email_verified_at string or null (date-time)
    • mfa_enabled boolean
    • has_password boolean
    • recovery_remaining integer

      Recovery codes not yet used.

  • profile object required
    • avatarUrl string
    • minor boolean
    • showSensitive boolean
  • usage AccountUsage required
  • keys array of ApiKey required
  • identities array of SignInProvider required

    The sign-in providers linked to the account.

  • sessions array 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

AccountDeletion
  • confirm string required

    The account’s username, to confirm.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

Responses

200

Deleted.

AccountDeleted
  • ok true required
  • timelines integer required

    How 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

This sends a real request to this server, as you.

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

  • search string in query

    Text that names, descriptions or IDs contain, without regard to case.

  • page integer in query

    The page, from 1.

  • limit integer in query

    How many on a page.

  • sort "popularity" | "alphabetical" | "age" in query

    The 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.

PluginPage
  • apiVersion 1 required
  • plugins array of Plugin required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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

PluginSearch
  • search string · at most 200 characters, default ""
  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12
  • sort "popularity" | "alphabetical" | "age" · default "popularity"

    Without server storage, always by name.

Responses

200

A page of plugins.

PluginPage
  • apiVersion 1 required
  • plugins array of Plugin required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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

This sends a real request to this server, as you.

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

  • id string in path required

    The plugin’s ID.

  • version string in path required

    The plugin’s version.

Responses

200

The plugin’s definition.

Plugin
  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published plugins’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string required · at least 1 characters, at most 2000 characters
  • fields array of PluginField required · at most 8 items

    Each with a different metadata key.

  • marker object
    • kind "image" | "color" | "shape" | "heading" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • hover object
    • kind "card" required
  • summary object
    • kind "radial" required
  • notes object
    • kind "markdown" required
  • background object

    An image behind the timeline where a duration lies.

    • kind "image" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • targets array of "moments" | "durations" · at least 1 items

    What the plugin applies to; omitted, moments (and durations for colors and cards).

  • source string · at least 1 characters, at most 16384 characters

    The 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-Challenge string in header

    The 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.

Plugin
  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published plugins’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string required · at least 1 characters, at most 2000 characters
  • fields array of PluginField required · at most 8 items

    Each with a different metadata key.

  • marker object
    • kind "image" | "color" | "shape" | "heading" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • hover object
    • kind "card" required
  • summary object
    • kind "radial" required
  • notes object
    • kind "markdown" required
  • background object

    An image behind the timeline where a duration lies.

    • kind "image" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • targets array of "moments" | "durations" · at least 1 items

    What the plugin applies to; omitted, moments (and durations for colors and cards).

  • source string · at least 1 characters, at most 16384 characters

    The 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

This sends a real request to this server, as you.

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

  • search string in query

    Text that names, descriptions or IDs contain, without regard to case.

  • page integer in query

    The page, from 1.

  • limit integer in query

    How many on a page.

Responses

200

A page of suites.

PluginSuitePage
  • apiVersion 1 required
  • suites array of PluginSuite required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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

PluginSuiteSearch
  • search string · at most 200 characters, default ""
  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12

Responses

200

A page of suites.

PluginSuitePage
  • apiVersion 1 required
  • suites array of PluginSuite required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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

This sends a real request to this server, as you.

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

  • id string in path required

    The suite’s ID.

  • version string in path required

    The suite’s version.

Responses

200

The suite.

PluginSuite
  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published suites’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string

    Longer descriptions are cut to 2,000 characters. Always present in answers.

  • plugins array of Plugin required · at least 1 items, at most 32 items

    Each 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-Challenge string in header

    The 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.

PluginSuite
  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published suites’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string

    Longer descriptions are cut to 2,000 characters. Always present in answers.

  • plugins array of Plugin required · at least 1 items, at most 32 items

    Each plugin once (by ID).

Responses

201

Published: the suite as stored, with its namespaced ID.

PluginSuite
  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published suites’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string

    Longer descriptions are cut to 2,000 characters. Always present in answers.

  • plugins array of Plugin required · at least 1 items, at most 32 items

    Each 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

This sends a real request to this server, as you.

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-Challenge string in header

    The 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.

ReportRequest

Responses

201

Reported.

Ok
  • ok true
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

This sends a real request to this server, as you.

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.

object
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

  • id Uuid in path required

    The case’s ID.

Request body

The request, at most 8 KiB.

AppealRequest
  • appeal string required · at least 1 characters, at most 2000 characters

    Why the decision should be reviewed.

Responses

200

Asked.

Ok
  • ok true
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

This sends a real request to this server, as you.

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 query

    Which cases (anything else means open).

  • page integer in query

    The page of 25, from 1 (out-of-range pages are clamped to 1–10,000).

Responses

200

A page of cases.

ReportCasePage
  • view "open" | "restricted" | "closed" required
  • page integer required
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array 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

  • id Uuid in path required

    The case’s ID.

Request body

The decision, at most 8 KiB.

ModerationDecisionRequest
  • action "restrict" | "label" | "dismiss" | "uphold" | "lift" required

    restrict, label and dismiss decide an open case; uphold answers a request for review; lift undoes a decision in force. Only timelines are labelled.

  • reason string · at most 2000 characters

    The statement of reasons for the owner; required to restrict or label.

  • labels array of ContentLabel · at least 1 items

    To label: what the timeline contains.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

Responses

200

Decided.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • search string in query

    Text to look for, without regard to case (longer text is cut to 200 characters).

  • page integer in query

    The page of 25, from 1 (out-of-range pages are clamped to 1–10,000).

Responses

200

A page of accounts.

AdminUserPage
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of AdminUser required · at most 25 items
  • page integer required
  • settings object required
    • default_quota_bytes string · matches ^\d+$

      The storage quota of accounts without their own, in bytes.

    • default_quota_from_env boolean

      Whether 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

  • id Uuid in path required

    The account’s ID.

Request body

The changes, at most 8 KiB.

AdminUserChange
  • is_admin boolean
  • is_disabled boolean

    Suspends (true) or restores (false) it.

  • quota_bypass boolean
  • quota_bytes string or integer or null

    A 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" | null

    Trusted accounts have full standing; untrusted none; null decides by its record.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

Responses

200

Changed.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • search string in query

    Text to look for, without regard to case (longer text is cut to 200 characters).

  • page integer in query

    The page of 25, from 1 (out-of-range pages are clamped to 1–10,000).

Responses

200

A page of timelines.

AdminTimelinePage
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of AdminTimeline required · at most 25 items
  • page integer required
  • settings object required
    • default_quota_bytes string · matches ^\d+$

      The storage quota of accounts without their own, in bytes.

    • default_quota_from_env boolean

      Whether 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

  • id Uuid in path required

    The timeline’s ID.

Request body

The changes, at most 8 KiB.

AdminTimelineChange
  • visibility "public" | "private"
  • featured boolean
  • delete boolean

    true deletes the timeline and its history.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

Responses

200

Changed.

Ok
  • ok true
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

This sends a real request to this server, as you.

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

  • search string in query

    Text to look for, without regard to case (longer text is cut to 200 characters).

  • page integer in query

    The 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.

AdminUserPage
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of AdminUser required · at most 25 items
  • page integer required
  • settings object required
    • default_quota_bytes string · matches ^\d+$

      The storage quota of accounts without their own, in bytes.

    • default_quota_from_env boolean

      Whether 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.

AdminSettingsChange
  • default_quota_bytes string or integer required

    A size from 0 to 10 TB: a byte count (104857600) or a size with a unit (500MiB, 2GB, 1.5GiB). At most 32 characters.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

Responses

200

Changed.

Ok
  • ok true
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

This sends a real request to this server, as you.

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.

Health
  • status "ok" required
  • storage "postgresql" | "browser" required

    postgresql when the server has a database; browser when 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
  • error string required

    What went wrong, for people.

  • challenge HumanChallenge

    With 428: the human-verification challenge to answer.

  • conflicts array of any

    With 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.

  • conflictCount integer

    With 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
  • ok true
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.

  • title string
  • description string

    Notes, in Markdown.

  • tags array of string · at most 40 items

    Tags, lowercased and trimmed when valid (1–64 characters, no commas or control characters, at most 40). Anything else is kept as ordinary metadata.

  • content_labels array of "nudity" | "violence" | "disturbing"

    Sensitive-content labels: readers are warned and its images blurred.

Moment object

A point event (a moment).

  • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$

    Unique among the timeline’s moments.

  • time string required

    An exact time in coordinates: a rational (-3/2), a finite decimal (1.25), or an ISO 8601 timestamp (one with a T), which is read as Unix seconds. Stored and returned as a canonical rational.

  • metadata EntityMetadata 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.

  • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$

    Unique among the timeline’s durations.

  • start DurationEndpoint required
  • end DurationEndpoint required
  • metadata EntityMetadata

    As a moment’s; {} when left out. It may not contain durations.

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.

  • version 1 required
  • mode "rational" | "float" | "scientific" | "si" | "gregorian" | "custom" required
  • significantDigits integer required · ≥ 1, ≤ 30
  • unit string required · at most 80 characters
  • scale string required · at most 8192 characters

    Stored coordinates per displayed unit: a positive exact number.

  • origin string required · at most 8192 characters

    The stored coordinate of displayed zero.

  • offsetMinutes integer required · ≥ -1439, ≤ 1439
  • adaptiveLabels boolean
  • ruler object

    Ruler tick policy.

  • source string

    For 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.

  • sources array of Uuid required · at least 2 items, at most 8 items
  • combined boolean required

    One 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" required
  • version 1 required
  • title string required · at most 300 characters
  • description string required · at most 20000 characters
  • events array of Moment required

    Its moments; IDs unique.

  • durations array of Duration
  • relationships array of Relationship
  • presentation TimePresentation
  • plugins array of object · at most 32 items

    Installed plugins (at most 128 KiB in all), each with its manifest. Their scripts must compile.

    • manifest object required

      The plugin’s manifest (apiVersion 1).

    • enabled boolean required
    • settings object

      Values 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.

  • tags array of string · at most 40 items

    The timeline’s tags: lowercased, without commas or control characters.

  • assets object

    Copies of its images, by their HTTPS address: base64 data URIs of at most 2 MiB each and 8 MiB in all.

  • comparison SavedComparison
TimelineSettings object

A timeline’s settings, as a document without its entries: what a sparse save keeps or changes.

  • format "openchronology" required
  • version 1 required
  • title string required · at most 300 characters
  • description string required · at most 20000 characters
  • presentation TimePresentation
  • plugins array of object · at most 32 items
  • tags array of string · at most 40 items
  • assets object
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.

  • id Uuid
  • owner_id Uuid
  • owner string

    Its owner’s username.

  • slug string or null

    Its address is /<owner>/<slug>; without one, /<owner>/<id>.

  • title string
  • description string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    How many moments it has.

  • event_generation string · matches ^\d+$

    A count, as a decimal string.

  • star_count string · matches ^\d+$

    A count, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • role "admin" | "owner" | "writer" | "editor" | "contributor" | "viewer" | null

    The caller’s role; null for a public timeline they have none in.

  • presentation TimePresentation or null
  • plugins array or null
  • tags array or null
  • assets object or null
  • comparison SavedComparison or null
  • featured boolean
  • upstream_id string or null (uuid)

    The timeline this was forked from.

  • fork_base_revision_id string or null (uuid)
  • head_revision_id string or null (uuid)
  • allow_private_forks boolean
  • publication_restricted boolean

    A copy of a private timeline, which must stay private.

  • storage_bytes string · matches ^\d+$

    A count, as a decimal string.

  • created_at string or null (date-time)
  • updated_at string (date-time)
  • retention_seconds string or null

    How long it keeps moments, in seconds as an exact rational; null for always.

  • retention_applied_at string or null (date-time)
  • retention_removed string or null
  • keep_history boolean

    Whether it keeps saved history.

  • history_since string or null
  • content_labels array of string
  • moderator_labels array of string
  • labels array of "nudity" | "violence" | "disturbing"

    Its sensitive-content labels: its owner’s and moderators’.

  • moderation object or null

    When moderators restricted it (seen only by its owner and administrators).

    • case Uuid
    • reason string
    • decided_at string (date-time)
    • appealed_at string or null (date-time)
    • appeal_outcome string or null
  • preparing boolean

    A copy whose index is still being prepared: until it is ready, only its metadata, settings, sharing and deletion are available (others answer 409).

  • canWrite boolean

    May save it.

  • canEdit boolean

    May edit a copy of it (to save or propose).

  • canPropose boolean

    May open pull requests on it.

  • canShare boolean

    May manage its settings, members and deletion.

  • canFork boolean
  • first Rational or null

    With GET /api/timelines/{id}: its earliest moment’s time.

  • last Rational or null

    With GET /api/timelines/{id}: its latest moment’s time.

TimelineListItem object

A timeline the caller owns or is a member of.

  • id Uuid
  • slug string or null
  • title string
  • visibility "private" | "public"
  • revision Revision
  • event_count string · matches ^\d+$

    A count, as a decimal string.

  • owner string

    Its owner’s username.

  • role "owner" | "writer" | "editor" | "contributor" | "viewer"
TimelineWithDocument object

A timeline’s metadata and its whole document.

TimelineSettingsResult any

The timeline after a settings change.

TimelineMember object
  • username string
  • role "viewer" | "contributor" | "writer" | "editor"

    editor is an older name for writer.

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.

  • revision Revision required

    The revision the request was made on: the timeline’s current revision.

  • settings TimelineSettings required
  • changes array of object required

    Changed moments: each the moment wanted, or null to delete it. IDs unique.

    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • event Moment or null required
  • durationChanges array of object

    Changed durations: each the duration wanted, or null to delete it.

    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • duration Duration or null required
  • relationshipChanges array of object · at most 5000 items

    Links to add (related: true) or remove (related: false).

  • base SaveBase
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.

  • settings object

    The settings as loaded: any of these.

    • title any
    • description any
    • tags any
    • presentation any
    • plugins any
    • assets any
  • moments array of object · at most 5000 items
    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • event object or null required

      As loaded; null for one added.

  • durations array of object · at most 5000 items
    • id string required · matches ^[A-Za-z0-9_.:-]{1,128}$
    • duration object or null required

      As 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).

  • scale string required

    Positive.

  • offset string required
  • around string · default "0"

    The point to scale around.

OEmbed object

An oEmbed 1.0 rich response.

  • version "1.0"
  • type "rich"
  • provider_name string
  • provider_url string (uri)
  • title string
  • author_name string

    The owner’s username.

  • author_url string (uri)
  • html string

    An <iframe> of the timeline’s embed page.

  • width integer · ≥ 200, ≤ 800
  • height integer · ≥ 160, ≤ 480
  • thumbnail_url string (uri)

    Left out for a timeline with sensitive-content labels.

  • thumbnail_width 1200
  • thumbnail_height 630
  • cache_age 3600
TimelineSearchRequest object
  • search string · at most 300 characters, default ""

    Words to find, in web-search syntax (quoted phrases, -exclusions). Empty to browse.

  • tag string · at most 64 characters, default ""

    Only timelines with this tag (matched exactly, lowercased).

  • owner string · at most 64 characters, default ""

    Only timelines owned by this username.

  • starredBy string · 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 public scope.

  • 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 but public need sign-in.

  • sort "featured" | "stars" | "popularity" | "trending" | "alphabetical" | "age" | "relevance"

    The order: relevance by default when there is search text, otherwise featured (featured first, then recently updated). popularity and trending (last 30 days) weigh stars and forks by the standing of who gave them; age is newest first. Ties go to the most recently updated.

  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12
TimelineSearchResult object

A timeline found by a search: what a result card shows.

  • id Uuid
  • slug string or null

    Its address under its owner (/<owner>/<slug>), if it has one.

  • title string
  • description string
  • tags array of string
  • visibility "public" | "private"
  • owner string

    The owner’s username.

  • revision integer · ≥ 1

    A timeline revision, as a number (lists send it as a JSON number).

  • event_count integer · ≥ 0

    How many moments it has.

  • comparison object or null

    Set when it is a comparison of other timelines (a read-only live view).

  • star_count string · matches ^\d+$

    Stars, as a decimal string.

  • starred boolean

    Whether the caller starred it.

  • popularity string

    Its popularity score (docs/browsing.md), as a decimal string.

  • featured boolean
  • labels array of string

    Its sensitive-content labels, its owner’s and moderators’.

  • rank number

    Its text-search rank; 0 without search text.

  • created_at string (date-time)
  • updated_at string (date-time)
TimelineSearchPage object
  • timelines array of TimelineSearchResult required
  • total integer required · ≥ 0

    How many timelines match in all.

  • page integer required · ≥ 1
  • limit integer required · ≥ 1
  • pages integer required · ≥ 0
CopyRequest object
  • revision Revision required

    The timeline’s current revision; 409 when it has changed since.

BrowserFork object
  • document TimelineDocument required
  • source object required

    What was copied.

  • limits object required

    The limits a browser copy is held to.

    • events 5000
    • bytes 4194304
HistoryRevision object

A saved checkpoint of a timeline.

  • id Uuid

    The saved revision’s ID.

  • number string · 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.

  • author string or null

    Who saved it, by username.

  • created_at string (date-time)
  • parents array of Uuid · at most 2 items

    Its parent revisions: none, one, or two for a sync or merge.

  • available boolean

    Whether its content can be read: false for a past one not kept.

HistoryPage object
  • revisions array of HistoryRevision required · at most 20 items
  • page integer required · ≥ 1
  • more boolean required

    Whether there is a next page.

  • keepHistory boolean required

    Whether the timeline keeps saved history.

ProposalSummary object

A pull request as lists show it.

  • id Uuid
  • title string
  • status "open" | "merged" | "rejected" | "closed"
  • author string

    The author’s username.

  • base_revision integer · ≥ 1

    The timeline revision it was made on.

  • revision integer · ≥ 1

    The pull request’s own revision.

  • created_at string (date-time)
  • updated_at string (date-time)
ProposalPage object
  • proposals array of ProposalSummary required
  • total integer required · ≥ 0
  • page integer required · ≥ 1
  • pages integer 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.

  • settings array of string

    The timeline settings it changes (such as title, tags).

  • moments object
    • added integer · ≥ 0
    • removed integer · ≥ 0
    • changed integer · ≥ 0
  • durations object
    • added integer · ≥ 0
    • removed integer · ≥ 0
    • changed integer · ≥ 0
  • relationships object
    • added integer · ≥ 0
    • removed integer · ≥ 0
  • examples array of object

    The first thirty moments of each kind of change.

    • change "added" | "removed" | "changed"
    • before Moment or null
    • after Moment or null
  • unavailable string

    Why nothing could be counted.

Proposal object

A pull request, with what it changes and what the caller may do with it.

  • id Uuid
  • timeline_id Uuid
  • author_id Uuid
  • author string

    The author’s username.

  • title string
  • body string

    Its description, as plain text.

  • status "open" | "merged" | "rejected" | "closed"
  • revision Revision

    The pull request’s own revision: send it with updates and resolutions.

  • base_revision Revision

    The timeline revision it is based on.

  • base_revision_id Uuid

    The saved revision it is based on.

  • source_revision_id Uuid

    The saved revision it proposes.

  • source_timeline_id Uuid or null

    The fork it came from, if any.

  • from_fork boolean
  • resolved_by Uuid or null
  • merged_revision Revision or null

    The timeline revision its merge made.

  • merged_revision_id Uuid or null
  • created_at string (date-time)
  • updated_at string (date-time)
  • changes ProposalChanges
  • canMerge boolean
  • canUpdate boolean
  • canClose boolean
  • upstreamRevision Revision

    The timeline’s current revision: a rebase is needed when it differs from base_revision.

  • source object or null

    The source fork, when it came from one the caller can read.

    • id Uuid
    • title string
    • head_revision_id Uuid
    • canWrite boolean
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
  • id string · matches ^\d+$
  • author string

    The author’s username.

  • body string

    The comment, as plain text; empty when moderators removed it.

  • removed boolean

    Whether moderators removed it.

  • mine boolean

    Whether the caller wrote it (and so may delete it).

  • created_at string (date-time)
ProposalCommentPage object
  • comments array of ProposalComment required · at most 50 items
  • next string or null required

    Send as after for the next page; null on the last.

Session object
  • server boolean required

    Whether the server has storage. Without it, only browser timelines work.

  • dashboard true required
  • user SessionUser or null required
  • csrf string or null required · matches ^[a-f0-9]{64}$

    Signed in: the session’s CSRF token, sent as X-CSRF-Token with every change. Signed out: the sign-in token (also the oc_login cookie), sent the same way by sign-in requests. Null without server storage.

  • providers array of SignInProvider required

    The sign-in providers this server offers.

  • security object

    Which account-security features the server offers (it needs email and an encryption key configured). Absent without server storage.

    • email boolean
    • mfa boolean
    • registration boolean
  • challenge "mfa" | "email" | null

    A sign-in step this browser has pending (mfa: a two-factor code; email: an email address to confirm), or null.

  • fileExchange boolean required

    Whether the server converts SQLite (.och) timeline files.

  • fileLimit integer

    The largest .och file the server converts, in bytes (TIMELINE_FILE_BYTES, 64 MiB by default).

  • compareLimit integer

    How many timelines this account (or a guest) may compare at once.

  • entryLimit integer or null

    How many moments (and durations, relationships) a timeline may hold; null for no limit.

SessionUser object
  • id Uuid required
  • username string required
  • isAdmin boolean
  • avatarUrl string

    An HTTPS or data: image URL, or empty.

  • minor boolean

    Whether the account may be under 18, by its year of birth.

  • showSensitive boolean

    Whether sensitive content shows without a warning (never for minors).

SignInProvider "google" | "github" | "facebook"
SignInRequest object
  • username string 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.

  • password string required · at least 1 characters, at most 1024 characters

    The password.

SignedIn object
  • user object required
    • id Uuid required
    • username string required
  • csrf string required · matches ^[a-f0-9]{64}$

    The new session’s CSRF token, to send as X-CSRF-Token with changes.

  • token string · 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" required

    mfa: send a two-factor code to POST /api/auth/mfa/complete. email: confirm an email address with POST /api/auth/email/enroll.

  • message string required
RegistrationRequest object
  • username string 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…).

  • email string (email) required · at most 254 characters

    An email address (trimmed and lowercased).

  • password string required · at least 15 characters, at most 1024 characters

    A 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.

  • passwordConfirmation string required

    The new password again; it must match.

  • birthYear integer required · ≥ 1900

    Year 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
  • message string required
  • verificationRequired true required
AccountMessage object
  • message string required

    What happened, for people.

SecurityConfirmation object

What confirms a security change.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

TwoFactorSetup object
  • secret string required · matches ^[A-Z2-7]+$

    The authenticator key, in base32.

  • uri string required

    The same key as an otpauth://totp/… link (SHA-1, six digits, 30 seconds).

RecoveryCodes object
  • message string required
  • recoveryCodes array of string required · at least 10 items, at most 10 items

    Ten one-time recovery codes, shown only once. Store them offline.

ProviderStartRequest object
  • returnTo string · default "/"

    Where to return after: /, /editor, /account, /plugins, /timelines/<id>, or a desktop approval page (/connect/desktop/<code>, /#desktop/<code>).

  • link boolean

    Link the provider to the signed-in account instead of signing in. Needs a session signed in within the last five minutes.

DeviceSignIn object
  • deviceCode string required · matches ^[a-f0-9]{64}$

    The desktop app’s secret for polling. Keep it out of the browser.

  • userCode string required · matches ^[A-Z2-9]{10}$

    The code the desktop app shows, to match in the browser.

  • verificationUri string (uri) required

    The page that approves it: <origin>/connect/desktop/<userCode>.

  • interval 3 required

    Seconds between polls, at least.

  • expiresIn 600 required

    Seconds until it expires.

ApiKey object
  • id Uuid required
  • name string required
  • prefix string required

    The key’s first 20 characters, to recognize it by.

  • scopes array of ApiKeyScope required
  • created_at string (date-time) required
  • expires_at string (date-time) required
  • last_used_at string or null (date-time)
  • revoked_at string 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
  • name string required · at least 1 characters, at most 80 characters

    Trimmed; not blank.

  • scopes array of ApiKeyScope · at least 1 items, at most 2 items, default ["timelines:read"]
  • days integer · ≥ 1, ≤ 365, default 90

    Days until it expires.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

CreatedApiKey object
  • id Uuid required
  • token string 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.

  • message string required
ProfileChange object
  • avatarUrl string · at most 350000 characters

    An HTTPS image URL (at most 2048 characters), a data:image/png|jpeg|webp;base64,… image (at most 256 KiB), or empty to remove it.

  • showSensitive boolean

    Show sensitive content without a warning. Adults only.

Account object
  • security object required
    • email string or null
    • email_verified_at string or null (date-time)
    • mfa_enabled boolean
    • has_password boolean
    • recovery_remaining integer

      Recovery codes not yet used.

  • profile object required
    • avatarUrl string
    • minor boolean
    • showSensitive boolean
  • usage AccountUsage required
  • keys array of ApiKey required
  • identities array of SignInProvider required

    The sign-in providers linked to the account.

  • sessions array of AccountSession required
AccountUsage object

Storage used and allowed.

  • used_bytes string · matches ^\d+$

    Storage used. A decimal string.

  • quota_bytes string or null · matches ^\d+$

    The account’s own storage limit, or null for the site default. A decimal string.

  • effective_quota_bytes string · matches ^\d+$

    The storage limit that applies. A decimal string.

  • quota_bypass boolean

    Whether the account has no storage limit.

  • is_admin boolean
  • is_disabled boolean
AccountSession object
  • id string required · matches ^[a-f0-9]{64}$

    Identifies the session (a hash of its token, not the token).

  • kind "web" | "desktop" required
  • created_at string (date-time) required
  • last_seen_at string (date-time) required
  • current boolean required

    Whether it is the session asking.

AccountDeletion object
  • confirm string required

    The account’s username, to confirm.

  • password string · at most 1024 characters

    The current password, when the account has one (accounts made with a sign-in provider may not).

  • code string

    With two-factor authentication on: a six-digit authenticator code, or a recovery code. Codes already used do not work again.

AccountDeleted object
  • ok true required
  • timelines integer required

    How 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" required
  • storage "postgresql" | "browser" required

    postgresql when the server has a database; browser when it has none and timelines are kept in the browser.

PluginField object
  • kind "text" | "multiline" | "image-url" | "stack" | "color" | "shape" | "size" | "links" | "heading" | "font" required
  • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

    A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • label string 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.

  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published plugins’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string required · at least 1 characters, at most 2000 characters
  • fields array of PluginField required · at most 8 items

    Each with a different metadata key.

  • marker object
    • kind "image" | "color" | "shape" | "heading" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • hover object
    • kind "card" required
  • summary object
    • kind "radial" required
  • notes object
    • kind "markdown" required
  • background object

    An image behind the timeline where a duration lies.

    • kind "image" required
    • metadataKey string required · matches ^[A-Za-z][A-Za-z0-9_-]{0,63}$

      A metadata key; not title, description, durations, tags, __proto__, prototype or constructor.

  • targets array of "moments" | "durations" · at least 1 items

    What the plugin applies to; omitted, moments (and durations for colors and cards).

  • source string · at least 1 characters, at most 16384 characters

    The 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
  • search string · at most 200 characters, default ""
  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12
  • sort "popularity" | "alphabetical" | "age" · default "popularity"

    Without server storage, always by name.

PluginPage object
  • apiVersion 1 required
  • plugins array of Plugin required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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.

  • apiVersion 1 required
  • id string required · matches ^[a-z][a-z0-9-]{0,63}$

    Published suites’ IDs are u-<account>-<slug>.

  • version integer required · ≥ 1, ≤ 9007199254740991
  • name string required · at least 1 characters, at most 100 characters
  • description string

    Longer descriptions are cut to 2,000 characters. Always present in answers.

  • plugins array of Plugin required · at least 1 items, at most 32 items

    Each plugin once (by ID).

PluginSuiteSearch object
  • search string · at most 200 characters, default ""
  • page integer · ≥ 1, ≤ 10000, default 1
  • limit integer · ≥ 1, ≤ 50, default 12
PluginSuitePage object
  • apiVersion 1 required
  • suites array of PluginSuite required
  • total integer required

    How many match.

  • page integer required
  • limit integer required
  • pages integer required

    How 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
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.

  • title string

    A timeline’s, plugin’s or suite’s name, a pull request’s title, or @username.

  • text string

    A comment’s text (its first 500 characters).

  • timeline Uuid

    A comment’s timeline.

  • proposal Uuid

    A comment’s pull request.

  • username string

    An account’s username.

ModerationDecision object

A decision about something the account owns.

  • id Uuid
  • target_kind "timeline" | "comment" | "plugin" | "suite" | "user"
  • target_id string
  • status "restricted" | "labelled" | "lifted"
  • labels array or nullContentLabel

    The labels a label decision added.

  • reason string or null

    The statement of reasons.

  • decided_at string or null (date-time)
  • appeal string or null

    The owner’s request for a review.

  • appealed_at string or null (date-time)
  • appeal_outcome "upheld" | "lifted" | null
  • appeal_decided_at string or null (date-time)
  • target ModerationTarget
  • path string or null

    Where what it is about is seen on the platform; null once it is gone.

AppealRequest object
  • appeal string required · at least 1 characters, at most 2000 characters

    Why the decision should be reviewed.

ReportCase object

A case: the reports of one thing, and its decision.

  • id Uuid
  • target_kind "timeline" | "comment" | "plugin" | "suite" | "user"
  • target_id string
  • owner_id string or null (uuid)

    The owner’s account ID; null once the account is gone.

  • owner string or null

    The owner’s username.

  • status "open" | "dismissed" | "restricted" | "labelled" | "lifted"
  • created_at string (date-time)
  • reason string or null
  • labels array or nullContentLabel
  • decided_by string or null (uuid)

    The deciding administrator’s account ID.

  • decided_at string or null
  • previous_visibility "public" | "private" | null

    A restricted timeline’s visibility before, restored when lifted.

  • appeal string or null
  • appealed_at string or null
  • appeal_outcome "upheld" | "lifted" | null
  • appeal_decided_at string or null
  • target ModerationTarget
  • path string or null
  • report_count integer
  • urgent boolean

    Whether a report says child abuse or other illegal content.

  • reports array of object · at most 20 items

    The latest twenty reports, newest first.

    • category ReportCategory
    • details string
    • entity_kind "moment" | "duration" | null

      The event (moment or duration) a timeline’s report names.

    • entity_id string or null
    • created_at string (date-time)
    • reporter string or null

      The reporter’s username; null when signed out.

ReportCasePage object
  • view "open" | "restricted" | "closed" required
  • page integer required
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of ReportCase required · at most 25 items
ModerationDecisionRequest object
  • action "restrict" | "label" | "dismiss" | "uphold" | "lift" required

    restrict, label and dismiss decide an open case; uphold answers a request for review; lift undoes a decision in force. Only timelines are labelled.

  • reason string · at most 2000 characters

    The statement of reasons for the owner; required to restrict or label.

  • labels array of ContentLabel · at least 1 items

    To label: what the timeline contains.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

AdminUser object
  • id Uuid
  • username string
  • email string or null
  • is_admin boolean
  • is_disabled boolean

    Whether it is suspended.

  • quota_bypass boolean

    Whether storage quotas do not apply to it.

  • quota_bytes integer or null

    Its own storage quota; null for the site’s default.

  • used_bytes integer
  • created_at string (date-time)
  • trust "trusted" | "untrusted" | null
  • standing number · ≥ 0, ≤ 1

    Its standing, which ranks its timelines and weighs its stars.

  • endorsers integer

    Accounts that endorse it by stars or forks.

  • confirmed boolean

    Whether it has a confirmed email or a social sign-in.

  • restricted boolean

    Whether a moderation restriction is in force on something it owns.

AdminUserPage object
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of AdminUser required · at most 25 items
  • page integer required
  • settings object required
    • default_quota_bytes string · matches ^\d+$

      The storage quota of accounts without their own, in bytes.

    • default_quota_from_env boolean

      Whether the environment file sets the default quota (DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.

AdminTimeline object
  • id Uuid
  • title string
  • visibility "public" | "private"
  • featured boolean
  • event_count integer
  • owner string

    The owner’s username.

AdminTimelinePage object
  • total string required · matches ^\d+$

    A count, as a decimal string.

  • items array of AdminTimeline required · at most 25 items
  • page integer required
  • settings object required
    • default_quota_bytes string · matches ^\d+$

      The storage quota of accounts without their own, in bytes.

    • default_quota_from_env boolean

      Whether the environment file sets the default quota (DEFAULT_USER_STORAGE_BYTES), so it cannot be changed here.

AdminUserChange object
  • is_admin boolean
  • is_disabled boolean

    Suspends (true) or restores (false) it.

  • quota_bypass boolean
  • quota_bytes string or integer or null

    A 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" | null

    Trusted accounts have full standing; untrusted none; null decides by its record.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

AdminTimelineChange object
  • visibility "public" | "private"
  • featured boolean
  • delete boolean

    true deletes the timeline and its history.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.

AdminSettingsChange object
  • default_quota_bytes string or integer required

    A size from 0 to 10 TB: a byte count (104857600) or a size with a unit (500MiB, 2GB, 1.5GiB). At most 32 characters.

  • password string

    The administrator’s current password.

  • code string

    A fresh authenticator or recovery code, when the administrator has two-factor authentication on.