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.