Skip to content

REST API Reference

The relay's REST surface — the wire spec any client needs to be compatible with a relay (OSS) deployment. Generated straight from the relay's own OpenAPI spec, so it can't drift silently.

REST + WebSocket surface for the DocuShark relay. Source of truth for any
client wanting to be wire-compatible with relay (OSS) deployments.

The relay is a pure OIDC resource server: it validates RS256 bearer
tokens minted by an external issuer and never mints them itself. There
is no password / login surface — user lifecycle lives at the issuer.

All authenticated endpoints expect a bearer token (Authorization: Bearer <jwt>) verified per token-format.md.

Servers

http://localhost:9876Default self-hosted relay
https://{region}.relay.example.comTemplated deployment (any operator-controlled hostname)

health

Liveness + readiness.

Operations


Liveness probe

GET
/health

Responses

Relay is alive.

text/plain
JSON
"ok"

Playground

Samples


List documents visible to the caller

GET
/api/docs

Lists the workspace's documents the caller may read — those they own,
are explicitly shared on (sharedWith), or (as a workspace owner)
manage. This is the default posture
(permissions.enforce_private_docs, on unless disabled). A relay
configured with that setting off returns every document in the caller's
workspace instead. Access is always scoped to the workspace resolved
from the token's wsp claim.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Documents the caller has access to.

application/json
JSON
[
  
{
  
  
"id": "string",
  
  
"title": "string",
  
  
"updated_at": "string",
  
  
"owner_id": "string",
  
  
"workspace_id": "string",
  
  
"is_relay_document": true,
  
  
"collectionId": "string",
  
  
"sizeBytes": 0
  
}
]

Playground

Server
Authorization

Samples


Fetch a document by id

GET
/api/docs/{id}

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Document.

application/json
JSON
{
  
"id": "string",
  
"version": 0,
  
"additionalProperties": "string"
}

Playground

Server
Authorization

Samples


Save (create or replace) a document

PUT
/api/docs/{id}

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Parameters

Query Parameters

expectedVersion

Optimistic-concurrency guard; 409 if it doesn't match the stored serverVersion.

Type
integer
Format
"int64"
overrideTombstone

Deliberately re-create a tombstoned (deleted) id (JP-375). Without it,
saving a tombstoned id is refused with 410. Gated to the document's
original owner or a workspace admin.

Type
boolean

Request Body

application/json
JSON
{
  
"id": "string",
  
"version": 0,
  
"additionalProperties": "string"
}

Responses

Saved.

application/json
JSON
{
  
"id": "string",
  
"title": "string",
  
"updated_at": "string",
  
"owner_id": "string",
  
"workspace_id": "string",
  
"is_relay_document": true,
  
"collectionId": "string",
  
"sizeBytes": 0
}

Playground

Server
Authorization
Variables
Key
Value
Body

Samples


Delete a document

DELETE
/api/docs/{id}

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Deleted.

Playground

Server
Authorization

Samples


Issue a share link for a document

POST
/api/docs/{id}/share

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"expires_at": "string"
}

Responses

Share link issued.

application/json
JSON
{
  
"token": "string",
  
"url": "string",
  
"expires_at": "string"
}

Playground

Server
Authorization
Body

Samples


Transfer ownership of a document

POST
/api/docs/{id}/transfer

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"to_user_id": "string"
}

Responses

Ownership transferred.

Playground

Server
Authorization
Body

Samples


Set or clear a document's collection membership

PUT
/api/docs/{id}/collection

Assigns the document to a single collection (or clears it with
collectionId: null). Write-scoped like a save. Membership rides the
document body's collectionId and surfaces in DocumentMetadata.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"collectionId": "string"
}

Responses

Membership updated.

Playground

Server
Authorization
Body

Samples


List a document's recovery points

GET
/api/docs/{id}/recovery

Recovery points are relay-captured document versions, newest first.
The relay captures them automatically: periodically while a document
is actively edited, when its last participant leaves (skipped if
nothing changed), and before a suspicious zeroing would overwrite
prior state (the JP-180 poison guard). Retention is a bounded
per-document ring. Read-scoped like GET /api/docs/{id}.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Recovery points, newest first.

application/json
JSON
{
  
"recoveryPoints": [
  
  
{
  
  
  
"id": "string",
  
  
  
"createdAt": 0,
  
  
  
"serverVersion": 0,
  
  
  
"sizeBytes": 0
  
  
}
  
]
}

Playground

Server
Authorization

Samples


Capture a recovery point now

POST
/api/docs/{id}/recovery/capture

Captures a recovery point immediately (JP-428) — backs the version
history UI's open-time refresh, so the timeline leads with current
state instead of the last periodic tick. A resident document is
flushed first so the point reflects "now"; state byte-identical to
the newest existing point dedupes to a no-op (captured: false).
Write-scoped like PUT /api/docs/{id}.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Capture result.

application/json
JSON
{
  
"captured": true
}

Playground

Server
Authorization

Samples


Fetch a recovery point's content (non-destructive)

GET
/api/docs/{id}/recovery/{pointId}

Returns the recovery point flattened to a document body, WITHOUT mutating
live state (JP-183) — backs "save/download to local". Read-scoped like
GET /api/docs/{id}.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Recovery point content as a document body.

application/json
JSON
{
  
"id": "string",
  
"version": 0,
  
"additionalProperties": "string"
}

Playground

Server
Authorization

Samples


Restore a recovery point as a new document

POST
/api/docs/{id}/recovery/{pointId}/restore

Writes the recovery point as a NEW document and deletes + tombstones the
source id (JP-183). Owner-scoped (it deletes the source). Connected
clients receive the source's Deleted event (and strand their copy to
Trash) and the new document's Created event.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Restored as a new document.

application/json
JSON
{
  
"newDocId": "string",
  
"serverVersion": 0
}

Playground

Server
Authorization

Samples


List the workspace's collection definitions

GET
/api/collections

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Collection definitions (id/name/colour/order), sorted by order,
plus the registry version for the optimistic-concurrency
handshake on PUT.

application/json
JSON
{
  
"collections": [
  
  
{
  
  
  
"id": "string",
  
  
  
"name": "string",
  
  
  
"color": "string",
  
  
  
"order": 0
  
  
}
  
],
  
"version": 0
}

Playground

Server
Authorization

Samples


Replace the workspace's collection definitions (wholesale)

PUT
/api/collections

The editor owns the definition set and replaces it whole. Definitions
are presentation metadata (name/colour/order), not membership — a
document's membership is set via PUT /api/docs/{id}/collection.
Duplicate ids are healed keep-first; structural violations (empty or
oversized name/id/colour, more than 200 collections) are rejected
with 400. When expectedVersion is present the write is conditional
on the current registry version — a mismatch returns 409 with the
current state so the caller can rebase; omitted, the write is an
unconditional replace (legacy clients).

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"collections": [
  
  
{
  
  
  
"id": "string",
  
  
  
"name": "string",
  
  
  
"color": "string",
  
  
  
"order": 0
  
  
}
  
],
  
"expectedVersion": 0
}

Responses

Definitions replaced.

application/json
JSON
{
  
"success": true,
  
"newVersion": 0
}

Playground

Server
Authorization
Body

Samples


List a collection's document-members (metadata only)

GET
/api/collections/{id}/documents

Returns the documents assigned to the collection in the caller's
workspace, as metadata only — never document bodies, Y.Doc state, or
blobs. A browse/list surface for the web collection view, not a
content-read channel. Workspace-scoped from the JWT; an unknown/foreign
collection id yields an empty list (no cross-tenant existence leak).

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Metadata for the collection's documents.

application/json
JSON
{
  
"documents": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"updated_at": "string",
  
  
  
"owner_id": "string",
  
  
  
"workspace_id": "string",
  
  
  
"is_relay_document": true,
  
  
  
"collectionId": "string",
  
  
  
"sizeBytes": 0
  
  
}
  
]
}

Playground

Server
Authorization

Samples


Server-rendered PNG preview of a document

GET
/api/v1/docs/{id}/preview.png

Reserved. Implemented by future work that introduces a server-side
renderer (resvg + tiny-skia). Pre-rendered at save time and cached.

Responses

PNG bytes.

image/png

Playground

Samples


Server-rendered SVG preview of a document

GET
/api/v1/docs/{id}/preview.svg

Reserved. Vector form of the PNG preview. Cheaper to render.

Responses

SVG bytes.

image/svg+xml
JSON
"string"

Playground

Samples


Issue an anonymous read-only share-token

POST
/api/v1/docs/{id}/share-links

Reserved. Supersedes /api/docs/{id}/share (legacy) when the
share-link surface lands.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"expires_at": "string"
}

Responses

Share token issued.

application/json
JSON
{
  
"token": "string",
  
"url": "string",
  
"expires_at": "string"
}

Playground

Server
Authorization
Body

Samples


Download a blob

GET
/api/blobs/{hash}

On a filesystem backend the relay streams the bytes (200). On an
object-storage backend it ACL-checks the workspace and returns a 302
redirect to a short-lived presigned URL the client fetches directly.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Blob bytes (filesystem backend; content type per stored MIME).

application/octet-stream

Playground

Server
Authorization

Samples


Upload a blob through the relay (hash in path must match content)

POST
/api/blobs/{hash}

Proxies the bytes through the relay. This is the upload path for the
filesystem backend; object-storage backends use the presigned flow
(POST /api/v1/blobs/{hash}/upload-url then .../finalize) so bytes go
directly to storage.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/octet-stream
Format"binary"

Responses

Blob stored.

Playground

Server
Authorization
Body

Samples


Check whether a blob exists

HEAD
/api/blobs/{hash}

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Blob present.

Playground

Server
Authorization

Samples


Request a presigned upload (object-storage backend)

POST
/api/v1/blobs/{hash}/upload-url

Mint a short-lived presigned PUT so the client uploads blob bytes
directly to object storage, bypassing the relay; after the PUT, call
finalize. Returns { "exists": true } when the workspace already holds
the blob (skip upload + finalize). On a filesystem backend the relay
cannot presign and returns 409 — clients then fall back to the proxy
POST /api/blobs/{hash}.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"size": 0,
  
"mimeType": "string"
}

Responses

A presigned upload, or an already-exists marker for a dedup hit.

application/json
JSON
{
  
"exists": true
}

Playground

Server
Authorization
Body

Samples


Ingest a blob from a URL (server-side fetch)

POST
/api/v1/blobs/ingest-from-url

Fetch bytes from url (sending authorization verbatim as the
Authorization header), store them content-addressed for the caller's
workspace, and return the SHA-256 hash. Lets a trusted backend hand the
relay a reference instead of streaming the bytes through itself.

Disabled by default: returns 403 unless the operator configures a
host allowlist ([tenancy.limits] blob_ingest_allowed_hosts /
RELAY_BLOB_INGEST_ALLOWED_HOSTS). The allowlist (exact host or
*.suffix wildcard) is enforced on the initial URL and every redirect
hop
; only https is allowed and private/loopback IP-literal hosts are
rejected (SSRF protection). source/tags are opaque provenance
strings recorded for audit; the relay does not interpret them.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"url": "string",
  
"authorization": "string",
  
"mimeType": "string",
  
"source": "string",
  
"tags": [
  
  
"string"
  
]
}

Responses

Stored (or deduplicated) blob.

application/json
JSON
{
  
"hash": "string",
  
"size": 0,
  
"mimeType": "string"
}

Playground

Server
Authorization
Body

Samples


Finalize a presigned upload (object-storage backend)

POST
/api/v1/blobs/{hash}/finalize

Confirm a direct upload landed: the relay HEADs the object for its
authoritative size, re-checks the workspace quota (reclaiming the object
and returning 507 if over), then records the blob and grants the
workspace ACL.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"mimeType": "string"
}

Responses

Blob recorded.

application/json
JSON
{
  
"success": true,
  
"hash": "string",
  
"size": 0
}

Playground

Server
Authorization
Body

Samples


usage

Workspace storage usage + effective limits.


The calling workspace's storage usage + effective limits

GET
/api/v1/usage

Workspace-scoped from the validated bearer token — a caller can only
ever read its own numbers. Counts only; no document ids, no content.
storageBytes is the combined meter (docBytes + blobBytes); a
null quota/limit means unlimited / no ceiling.

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Usage snapshot.

application/json
JSON
{
  
"storageBytes": 0,
  
"docBytes": 0,
  
"blobBytes": 0,
  
"storageQuota": 0,
  
"maxDocBytes": 0,
  
"activeEditors": 0,
  
"editorLimit": 0
}

Playground

Server
Authorization

Samples


sync

WebSocket CRDT sync + awareness.

Operations


WebSocket upgrade for CRDT sync + awareness

GET
/ws

WebSocket endpoint multiplexing SYNC, AWARENESS, AUTH, AUTH_RESPONSE,
JOIN_DOC, DOC_EVENT, and ERROR frames. Protocol version negotiated
on connect — see relay/src/server/protocol.rs and the fixture set
at relay/tests/protocol-fixtures/.

Token verification follows token-format.md. Connections whose
token region does not match the relay's configured region are
rejected with a 403 close.

A JOIN_DOC frame is answered with an ERROR frame (the connection stays
open) when the document is unknown (ERR_UNKNOWN_DOC) or deleted
(ERR_DELETED). A JOIN_DOC for a document the caller may not read is
refused with ERR_VIEW_FORBIDDEN and the client is not joined — the
same owner/share rules the document listing applies. On a relay with
permissions.enforce_private_docs disabled, any authenticated member
of the workspace may join any of its documents.

Live edits are gated separately: a caller who may read but not write
(a view share, or the workspace viewer role) has its write-bearing
SYNC frames dropped with ERR_EDIT_FORBIDDEN while still receiving
state.

Parameters

Header Parameters

Sec-WebSocket-Protocol
Type
string

Responses

WebSocket upgrade.

Playground

Server
Headers

Samples


mcp

Model Context Protocol HTTP endpoint (bearer-auth'd).


MCP Server-Sent Events stream (keep-alive)

GET
/mcp

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

text/event-stream

Playground

Server
Authorization

Samples


MCP JSON-RPC request

POST
/mcp

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
}

Responses

JSON-RPC response.

Playground

Server
Authorization
Body

Samples


Close an MCP session

DELETE
/mcp

Authorizations

bearerAuth

App token verified per token-format.md: an OIDC-issued, RS256-signed
access token validated against the issuer's JWKS. The relay does not
mint or sign tokens.

Type
HTTP (bearer)

Responses

Closed.

Playground

Server
Authorization

Samples


internal

Server-to-server endpoints, called by the operator's auth control plane.
Not for client use.


Push a token revocation set update to the relay

POST
/api/v1/internal/revoke

Server-to-server. Called by the operator's auth control plane to
push revocations. Authenticated with the shared
revocation_push_bearer secret in relay.toml [auth]
(constant-time compared). See webhooks.md and revocation.md
for the protocol.

Authorizations

revocationBearer

Shared bearer secret between the auth control plane and the relay.
Rotated regularly. Not user-facing. See revocation.md.

Type
HTTP (bearer)

Request Body

application/json
JSON
{
  
"revocations": [
  
  
{
  
  
  
"jti": "string",
  
  
  
"revoked_at": "string"
  
  
}
  
]
}

Responses

Applied.

Playground

Server
Authorization
Body

Samples


Powered by VitePress OpenAPI

Released under the AGPL-3.0 License.