Documents API reference
REST API for creating, reading, updating, and deleting documents with API key authentication.
Updated · Reviewed by Jacob
Answer first
Authenticated clients call /api/documents with a Bearer API key (gryz_…). Anonymous publishes use POST /api/documents from the web UI with Turnstile — not the same as MCP OAuth.
Base URL: https://www.gryz.ai
Authentication
Authorization: Bearer gryz_YOUR_KEY_HERECreate keys at /account/api-keys/. Requires Starter tier or above.
POST /api/documents/
Create a document.
Body (JSON):
{
"content": "# Hello",
"content_type": "markdown",
"title": "Optional title",
"visibility": "public"
}Responses:
201—{ "slug": "...", "url": "..." }400— validation error401— missing or invalid API key413— over tier size limit429— rate limited
GET /api/documents/
List documents for the authenticated user. Supports pagination query params.
GET /api/documents/[slug]/
Fetch a single document you own.
PATCH /api/documents/[slug]/
Update content, title, visibility, or expiry.
DELETE /api/documents/[slug]/
Permanently delete a document you own.
Editing part of a document
These routes change one part of a document without resending the rest, and keep a history of every change. They take a Bearer API key (or a signed-in web session), act on documents you own, and share their rules, size limits, and error codes with the document editing MCP tools. They are available while the mcp_document_edit feature is on; when it is off the routes answer 404. PATCH /api/documents/[slug]/ is unchanged.
Every document has a revision such as r12. Send it as if_match to refuse a write when the document has changed since you read it.
POST /api/documents/[slug]/append/
Add text to the end (or start) of a Markdown, CSV, or Mermaid document.
curl -X POST https://www.gryz.ai/api/documents/my-log/append/ \
-H "Authorization: Bearer gryz_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"content": "## 2026-10-07\n\nShipped the thing.", "if_match": "r12"}'Body: content (required), position (end or start), if_match, on_conflict (fail or merge), idempotency_key.
200—{ "slug", "url", "revision", "changed", "replayed", "bytes_delta", "history_trimmed" }400— empty content, or a document type that cannot be appended to (type_not_supported_for_append)403— not your document, or the owner limited assistants (agent_access_read_only,agent_access_suggest_only)409—revision_conflict: the document changed sinceif_match; the response includescurrent_revision. Nothing was written.413—size_over_tier_limit: the result would pass your plan's size limit. Nothing was written.422— content screening rejected the added text
POST /api/documents/[slug]/edit/
Apply up to 25 operations together as one new version, or change nothing.
curl -X POST https://www.gryz.ai/api/documents/my-plan/edit/ \
-H "Authorization: Bearer gryz_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"operations": [{"op": "set_checkbox", "text": "write docs", "checked": true}], "dry_run": true}'Body: operations (required; replace_text, insert_before_heading, insert_after_heading, replace_section, delete_section, append_table_row, set_checkbox), if_match, on_conflict, dry_run, idempotency_key. The operations are described in the MCP tools reference.
200— the same fields as append plusoperations(what each did),diff(a compact before and after),merged,merged_over, anddry_run. A dry run writes nothing.400— an invalid operation. The response names it (operation_index) and itscode, such asmatch_not_foundorheading_ambiguous. No operation in the batch was applied.409—revision_conflict(ormerge_conflictwithconflicting_sectionswhenon_conflictismergeand the same section changed)410—revision_expired: the version named byif_matchis no longer kept; the response includesoldest_available_revision413,403,422— as for append
GET /api/documents/[slug]/revisions/
List the saved versions, newest first, without their text. Query: limit (1–50), before (a revision, to page back).
curl "https://www.gryz.ai/api/documents/my-plan/revisions/?limit=10" \
-H "Authorization: Bearer gryz_YOUR_KEY_HERE"200—{ "current_revision", "revisions": [{ "revision", "actor", "tool", "summary", "bytes_delta", "created_at" }], "next_before", "history_trimmed" }
GET /api/documents/[slug]/revisions/[rev]/
What one version changed compared with the one before it, as a compact diff. [rev] is r12 or 12. 404 or 410 when the version is no longer kept. The response includes has_parent: it is false for the first saved version and for a version whose earlier version was removed, and then diff is empty because there is nothing to compare with.
POST /api/documents/[slug]/revisions/[rev]/restore/
Bring a version back as a new version. History is never rewritten. Optional body: if_match, idempotency_key.
curl -X POST https://www.gryz.ai/api/documents/my-plan/revisions/r9/restore/ \
-H "Authorization: Bearer gryz_YOUR_KEY_HERE"200—{ "revision", "restored_from", "changed" }410— that version is no longer kept413— the version is larger than your plan allows today
Suggestions and assistant permissions (web only)
POST /api/documents/[slug]/suggestions/[id]/ (body { "action": "accept" } or { "action": "reject" }) and PUT /api/documents/[slug]/agent-access/ (body { "agent_access": "direct" | "suggest" | "read_only" }) are for the signed-in owner in the web app only. They do not accept API keys, so an assistant cannot approve its own suggestion or widen its own access. They need the document_suggestions feature. Accepting returns { "revision" }, or 409 with suggestion_stale when the document changed too much, or agent_access_read_only when the document is now read only for assistants.
Errors use the shape below, with extra fields such as retryable, remedy, and current_revision where they help.
Rate limits
Publish endpoints enforce per-identity sliding-window limits. When exceeded, the API returns 429 with Retry-After.
Error shape
{
"error": "Human-readable message",
"code": "OPTIONAL_CODE"
}For assistant-driven workflows, compare the MCP tools. For browser and API publishing constraints, see Choose publishing options.