> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qirtaas.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Documents API

> The /v1 contract: document endpoints behind the SDK, for direct calls or a custom backend.

Everything the SDK does runs over a small, **frozen `/v1` HTTP contract**
(changes are additive only). You normally never call it yourself — the editor,
renderer, and [client methods](/sdk/client#client-methods) wrap it — but it is
documented here for two audiences:

* hosts that want to hit an endpoint directly (e.g. server-side cleanup), and
* self-hosters implementing their own backend against the contract — see
  [Self-hosting](/backend/self-hosting).

All endpoints are relative to your `apiUrl`, e.g.
`https://api.qirtaas.io/v1/documents/`. Unless noted, requests are authorized
with an embed token: `Authorization: Bearer <token>` (see
[Authentication](/backend/authentication)), and scoped to that token's
identity — you can only see and touch your own documents.

## Document shape

```json theme={null}
{
  "id": "b1f2c3d4-…",
  "title": "My Document",
  "content": { "type": "doc", "content": [ … ] },
  "status": "CREATED",
  "created_at": "2026-07-01T10:00:00Z",
  "updated_at": "2026-07-04T09:30:00Z"
}
```

`content` is TipTap JSON. `title` is **derived server-side** from the first
words of the content. `id`, `status`, and the timestamps are read-only.

## Endpoints

### `GET /v1/documents/`

List the caller's documents (without `content`):
`[{ id, title, status, created_at, updated_at }, …]`. The
[client](/sdk/client)'s `listDocuments` wraps this.

### `POST /v1/documents/`

Create a document.

<ParamField body="content" type="Json">
  TipTap JSON. The title is derived from it.
</ParamField>

Returns `201` with the full document. Errors:
`403 { "error": "document_limit_reached" }` when the identity is at its
document cap, `413 { "error": "document_too_large" }` when the serialized
content exceeds the size limit.

### `GET /v1/documents/{id}/`

Fetch one document, `content` included. Two auth forms:

* `Authorization: Bearer <embed token>` — own-document read.
* `?sig=<hmac>&exp=<unix>` — identity-less cross-user read, authorized purely
  by a valid [signature](/backend/authentication#signatures-cross-user-reads).
  Invalid or expired: `403 { "error": "invalid_signature" }`.

### `PATCH /v1/documents/{id}/`

Update `content` (autosave uses this). Same `document_too_large` guard as
create.

### `DELETE /v1/documents/{id}/`

Delete the document. The [client](/sdk/client)'s `deleteDocument` wraps this.

### `GET /v1/documents/{id}/share/`

Read the document's sharing state (embed-token authed, owner only):
`{ "is_shared": boolean, "share_token": string | null }`. The token is `null`
while sharing is off. The [client](/sdk/client)'s `getShareInfo` wraps this.

### `PATCH /v1/documents/{id}/share/`

Turn public sharing on or off (embed-token authed, owner only).

<ParamField body="is_shared" type="boolean">
  `true` mints an opaque share token for the document (or returns the existing
  one); `false` revokes it.
</ParamField>

Returns the same `{ is_shared, share_token }` shape. The token is the
credential for the public read below and for the renderer's `shareToken`
mode. The [client](/sdk/client)'s `setSharing` wraps this.

### `GET /v1/documents/shared/{token}/`

Public read of an explicitly shared document by its share token — no auth.
Returns `{ id, title, content }`.

## Images

The editor manages document images through
`POST /v1/documents/images/upload/`,
`POST /v1/documents/images/{id}/confirm/`, and
`GET /v1/documents/images/{id}/url/` (upload → confirm on save → resolve a
display URL, embed-token authed; the URL endpoint also accepts signature auth
for renderer reads).

## Content endpoints

Quran and hadith search data come from `/v1/quran/…` and
`/v1/hadith/…`. The data itself can be pulled from QuranFoundation APIs.
You are responsible to keep the data in-sync with any revisions.
