Skip to main content
The Documents API is the programmatic surface behind Document OS. It has two layers:
  • Authenticated routes — bearer-token, org-scoped. Used by the in-app Document OS UI and your own integrations.
  • Public routes — unauthenticated, used by the signer page and the clickwrap consent widget.
All authenticated endpoints follow the same conventions as the rest of the Winnerr API. See API Introduction for base URLs, bearer-token forwarding, and standard 401 behavior.

Authentication

Authenticated routes expect the session bearer token forwarded by apps/app:
Every authenticated route is org-scoped—you can only read and write documents that belong to your organization. Public routes (/api/public/sign/:token and /api/public/clickwrap/:agreementId) require no auth. The capability is the token or agreement ID embedded in the URL.

Document usage

GET /api/documents/usage

Returns the current calendar-month document usage for the organization. Response:
Generation is never blocked by the meter—going over included triggers overage billing, not a hard gate.

AI draft

POST /api/documents/draft

Generate a Zod-validated canonical draft from a natural-language prompt. The AI proposes; a human reviews in the wizard before generation. The response is a pre-filled canonical suitable for wizard pre-fill, never a completed document. Requires the AI gateway to be configured (@repo/ai + a chat model in models.json). Request body:
Response (success):
Response (failure, 422):

E-signature

POST /api/documents/:id/signature

Create and send a signature envelope for a generated document. The document must be in GENERATED status. Signing parties are derived automatically from the document’s canonical data (for typed OREA packs); you may adjust them in the request. Returns per-signer signing URLs. The raw tokens appear only in the url fields of the response—they are never stored or logged. Deliver them to the signers; do not log them yourself. Path parameters: Request body:
Response (201):
Error (409 cannot_send_for_signature): Returned when the document is not in GENERATED status, has no signing parties, or is not a typed OREA pack.

GET /api/documents/:id/signatures

List all signature envelopes for a document. Never exposes token hashes. Response:

GET /api/signatures/:envelopeId

Fetch the current status of a specific envelope, including per-signer status. Path parameters: Response: Same shape as a single item from the envelopes array above. Error (404): Returned when the envelope does not exist in the caller’s organization.

DELETE /api/signatures/:envelopeId

Void a signature envelope. Records a voided event with the given reason. Query parameters: Response:
Error (409 cannot_void): Returned when the envelope is already in a terminal status (completed, declined, voided, expired).

Public signer endpoint

GET /api/public/sign/:token

Open the document for the signer identified by the token. Records an opened event. Returns the signer’s view of the document if the token is valid and non-terminal. Rate limit: 60 requests per IP per minute. Response (active):
Response (404, any bad/terminal/expired token):
A uniform gone response is returned for unknown tokens, expired links, already-signed links, and voided envelopes—no information is disclosed about the reason.

POST /api/public/sign/:token

Advance the signer through the signing flow. The action field controls which step is executed. Rate limit: 30 requests per IP per minute. Request body:
Actions: Response (success):
For sign, also includes:
Error (409 invalid_state): Returned when the action is out of order (e.g. sign without prior consent).
Response (404): Uniform { "state": "gone" } for unknown/expired/terminal tokens.

Obligations

GET /api/documents/obligations

Return upcoming and overdue obligations across the organization, soonest first. Org-scoped. Query parameters: Response:

GET /api/documents/search

Search the organization’s documents by natural language. Returns ranked document IDs. Requires the AI gateway to be configured (embedding model). Query parameters: Response:
An empty q returns { "hits": [] } without calling the AI gateway. Without the gateway configured, all queries return an empty hits array.

Clickwrap (Click)

POST /api/clickwrap

Publish (upsert) a clickwrap agreement. If the body text has not changed since the last call with the same key, the call is idempotent. Changing the body creates a new version (new versionHash). Request body:
Response (201):
Embed the id in the consent widget URL: https://app.winnerr.ai/consent/<id>.

GET /api/clickwrap/:agreementId/acceptances

List acceptance evidence for an agreement. Returns the most recent 200 acceptances, newest first. Org-scoped. Path parameters: Response:

Public clickwrap endpoints

GET /api/public/clickwrap/:agreementId

Fetch the agreement text for the consent widget. Used by the public /consent/:agreementId page. Rate limit: 120 requests per IP per minute. Response:
Response (404): { "state": "gone" } — agreement does not exist or is not active.

POST /api/public/clickwrap/:agreementId

Record an immutable acceptance. Body is optional. Rate limit: 60 requests per IP per minute. Request body (optional):
Response:
Response (404): { "state": "gone" } — agreement does not exist or is not active.

Events emitted

The Document OS routes emit the following events on the internal event bus: