{
  "openapi": "3.1.0",
  "info": {
    "title": "PaperClerk API",
    "version": "1.0.0",
    "summary": "Generate documents from approved templates.",
    "description": "PaperClerk turns a document a team sends again and again into a saved template with typed placeholders. This API lists those templates, reads their placeholder inventory, generates immutable documents from them by sending values keyed by placeholder key (`client_name`, derived from the label when the template is first saved and stable when the label is reworded), and hands back each generated document's Markdown and its PDF, which is rendered once on PaperClerk's servers.\n\nThe API is read + generate only: it cannot create, edit or delete templates. Authentication is a Bearer token that opens exactly one workspace: a PaperClerk API key (`pc_…`, created under Connections inside the workspace by an owner or admin, acting with admin-level access to that workspace) or an OAuth access token from the MCP connector flow, bound to the workspace chosen at consent. Every error is `{ \"error\": { \"code\", \"message\", \"detail\"? } }`.",
    "contact": {
      "name": "PaperClerk",
      "email": "hello@usepaperclerk.com",
      "url": "https://usepaperclerk.com/docs/api"
    }
  },
  "servers": [
    {
      "url": "https://usepaperclerk.com/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Templates",
      "description": "Saved templates you can generate from."
    },
    {
      "name": "Documents",
      "description": "Generated documents and their PDFs."
    }
  ],
  "paths": {
    "/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "operationId": "listTemplates",
        "summary": "List templates",
        "description": "Saved templates the key's workspace can generate from, most recently updated first. When `truncated` is true, narrow with `search` rather than paging.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Only templates whose title contains this text (case-insensitive)."
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "The templates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/list-templates"
        }
      }
    },
    "/templates/{id}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "operationId": "getTemplate",
        "summary": "Get a template",
        "description": "One template: its saved version as Markdown (with `{{Label}}` tokens where a placeholder is blank) and the placeholder inventory — each placeholder's `key` (what `values` is keyed by) and `label` (the human name), its type, options, format, default, description, automatic slots and repeating groups: everything a form or a field mapping is drawn from.",
        "parameters": [
          {
            "$ref": "#/components/parameters/templateId"
          }
        ],
        "responses": {
          "200": {
            "description": "The template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/TemplateNotSaved"
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/get-template"
        }
      }
    },
    "/templates/{id}/generations": {
      "post": {
        "tags": [
          "Documents"
        ],
        "operationId": "generateDocument",
        "summary": "Generate a document",
        "description": "Create an immutable document from a template: the saved version with `values` applied. Keys of `values` are placeholder KEYS exactly as `GET /templates/{id}` returns them in `placeholders[].key` (a placeholder's label is accepted too, for callers written before keys existed). A placeholder used more than once in the document is filled everywhere; keys you omit keep the template's defaults; `\"\"` clears a placeholder. A repeating group (`groups[]`) takes an array of instance objects keyed by the group's field keys (`groups[].fields[].key`) — its template row is cloned once per entry; an omitted group keeps the single authored row; `[]` removes the section. Automatic placeholders (`auto: true`) are filled by PaperClerk and anything sent for them is ignored.\n\nRetries are safe without any extra header: a request identical to one sent in the last 10 minutes (same template, values, title and key) answers the document the first request produced, with HTTP 200 and `replayed: true` instead of 201, so a timeout and retry never generate twice or draw an auto-number twice. To decide yourself what counts as the same request, send an `Idempotency-Key` header (remembered 24 hours; a retry carrying it replays whatever the body). The PDF is rendered on PaperClerk's servers right after the document is created; `pdf_status` starts at `pending` and `GET /generations/{id}/pdf` renders on demand if you ask before it lands.",
        "parameters": [
          {
            "$ref": "#/components/parameters/templateId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Optional. Your own key for what counts as the same request, remembered 24 hours. Without it, an identical request within 10 minutes is treated as a retry on its own."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              },
              "example": {
                "title": "Invoice — Maple & Fern, September",
                "values": {
                  "client_name": "Maple & Fern Ltd.",
                  "payment_terms": "Net 15",
                  "due_date": "10/15/2026",
                  "line_items": [
                    {
                      "item": "Brand identity system",
                      "quantity": "1",
                      "amount": "4800"
                    },
                    {
                      "item": "Brand guidelines document",
                      "quantity": "1",
                      "amount": "1200"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The generated document. `Location` carries its page URL.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "The document's page in PaperClerk."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "200": {
            "description": "A replay: this request, or one carrying the same Idempotency-Key, already generated a document. The body carries `replayed: true`.",
            "headers": {
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`template_not_saved` — the template has no saved version yet; or `idempotency_in_flight` — the same request is still being processed, retry in a moment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large` — the body is over 1 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The values do not fit the template: `unknown_placeholder`, `unknown_group_field`, `invalid_option`, `invalid_number` or `invalid_values`. The message names the placeholder by key and, where it helps, the valid keys or options.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/generate"
        }
      }
    },
    "/generations": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "listGenerations",
        "summary": "List generated documents",
        "description": "The workspace's generated documents, newest first. Filters are combined with AND. Page with `cursor`: pass `next_cursor` back while `has_more` is true — it is a keyset cursor, so a page never skips or repeats a document however the filters are set.",
        "parameters": [
          {
            "name": "template",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Only documents generated from this template."
          },
          {
            "name": "created_by",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Only documents generated by this user."
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "app",
                "api"
              ]
            },
            "description": "`app` for documents generated in PaperClerk, `api` for the API and the MCP connector."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only documents created at or after this instant (ISO 8601; a date alone means midnight UTC)."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only documents created before this instant — the window is half-open, `[from, to)`."
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Only documents whose title contains this text."
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The `next_cursor` of the previous page."
          }
        ],
        "responses": {
          "200": {
            "description": "One page of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerationList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/list-generations"
        }
      }
    },
    "/generations/{id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "getGeneration",
        "summary": "Get a generated document",
        "description": "One generated document: its Markdown with the values baked in, its page URL, and where its PDF stands.",
        "parameters": [
          {
            "$ref": "#/components/parameters/generationId"
          }
        ],
        "responses": {
          "200": {
            "description": "The document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/get-generation"
        }
      }
    },
    "/generations/{id}/pdf": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "getGenerationPdf",
        "summary": "Get the PDF",
        "description": "The document's PDF, rendered once on PaperClerk's servers, as a short-lived download URL. If nothing is stored yet the call renders it on demand and answers when done (a few seconds); if another render is already in flight it answers 202 — ask again shortly. The URL expires after `expires_in` seconds; request a fresh one rather than storing it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/generationId"
          },
          {
            "name": "download",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Make the URL an attachment named after the document."
          },
          {
            "name": "redirect",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Answer a 302 to the URL instead of JSON."
          }
        ],
        "responses": {
          "200": {
            "description": "The file is ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfReady"
                }
              }
            }
          },
          "202": {
            "description": "A render is in flight; ask again in a moment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "rendering"
                      ]
                    }
                  },
                  "required": [
                    "status"
                  ]
                }
              }
            }
          },
          "302": {
            "description": "With `redirect=1`: the file's URL in `Location`."
          },
          "400": {
            "$ref": "#/components/responses/Validation"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "description": "`pdf_render_failed` — the render failed; asking again retries it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`pdf_unavailable` — rendering is not configured on this deployment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://usepaperclerk.com/docs/api/get-pdf"
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A PaperClerk API key (`pc_…`, created under Connections inside a workspace by an owner or admin; it acts with admin-level access to that workspace only) or an OAuth access token from the MCP connector flow, bound to the workspace chosen at consent. Revoking a key takes effect immediately, and so does its creator losing their admin role."
      }
    },
    "parameters": {
      "templateId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "The template's id."
      },
      "generationId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "The generated document's id."
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 50
        },
        "description": "Page size."
      }
    },
    "responses": {
      "Validation": {
        "description": "`validation` — a parameter or the body is malformed; `detail` names it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "`unauthorized` — no bearer, or not a valid one.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "`not_found` — no such record, or you do not have access.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TemplateNotSaved": {
        "description": "`template_not_saved` — the template has no saved version yet.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "SubscriptionRequired": {
        "description": "`subscription_required` — the workspace has no active plan; an owner or admin can choose one at https://usepaperclerk.com/app/billing.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "A stable machine-readable code.",
                "examples": [
                  "unknown_placeholder"
                ]
              },
              "message": {
                "type": "string",
                "description": "What went wrong and, where it helps, what to send instead."
              },
              "detail": {
                "type": "string",
                "description": "The parameter, header or value the error is about, when there is one."
              }
            }
          }
        }
      },
      "TemplateSummary": {
        "type": "object",
        "required": [
          "id",
          "title",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "folder_path": {
            "type": "string",
            "description": "Where the template is filed, `Parent / Child`; empty at the root."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TemplateList": {
        "type": "object",
        "required": [
          "workspace",
          "templates",
          "total",
          "truncated"
        ],
        "properties": {
          "workspace": {
            "type": [
              "string",
              "null"
            ],
            "description": "The connected workspace's name; a key opens exactly one."
          },
          "templates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateSummary"
            }
          },
          "total": {
            "type": "integer",
            "description": "How many templates match, whatever `limit` was."
          },
          "truncated": {
            "type": "boolean",
            "description": "True when `total` exceeds the page; narrow with `search`."
          }
        }
      },
      "Placeholder": {
        "type": "object",
        "required": [
          "label",
          "key",
          "count",
          "value",
          "type"
        ],
        "properties": {
          "label": {
            "type": "string",
            "description": "The human name the document shows; also accepted as a `values` key."
          },
          "key": {
            "type": "string",
            "description": "The key to send in `values` — lowercase letters, digits and underscores (`client_name`), derived from the label when the template is first saved, stable when the label is reworded, and changeable by the template's author."
          },
          "count": {
            "type": "integer",
            "description": "How many places in the document this placeholder fills."
          },
          "value": {
            "type": "string",
            "description": "The template's default value; empty when blank."
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "select",
              "number",
              "date",
              "today",
              "counter"
            ]
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`select` only: the value must be exactly one of these, or \"\"."
          },
          "format": {
            "type": "string",
            "description": "`number`: an example such as `1,234.56` — send a plain number and it is written in this shape. `date`: the reference date 2026-08-27 written the expected way — send dates in that shape. Automatic slots: how the server writes them."
          },
          "description": {
            "type": "string",
            "description": "The author's fill instructions."
          },
          "auto": {
            "type": "boolean",
            "description": "True for `today` and `counter`: filled by PaperClerk at generation; anything sent is ignored."
          },
          "start": {
            "type": "integer",
            "description": "`counter` only: the first number drawn."
          }
        }
      },
      "GroupField": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Placeholder"
          },
          {
            "type": "object",
            "properties": {
              "default": {
                "type": "string",
                "description": "The authored row's value for this field."
              }
            }
          }
        ]
      },
      "Group": {
        "type": "object",
        "required": [
          "label",
          "key",
          "fields"
        ],
        "properties": {
          "label": {
            "type": "string",
            "description": "The human name of the repeating section."
          },
          "key": {
            "type": "string",
            "description": "The key to send in `values`, whose value is an array of instance objects."
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupField"
            },
            "description": "Exactly the fields an instance object may carry, each keyed by its `key`."
          }
        }
      },
      "Template": {
        "type": "object",
        "required": [
          "id",
          "title",
          "markdown",
          "placeholders",
          "groups",
          "generation_count",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "markdown": {
            "type": "string",
            "description": "The saved version; a blank placeholder appears as `{{Label}}`."
          },
          "html": {
            "type": "string",
            "description": "A paper-true HTML preview of the saved version."
          },
          "html_truncated": {
            "type": "boolean"
          },
          "placeholders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Placeholder"
            },
            "description": "Top-level placeholders, one entry per placeholder."
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Group"
            },
            "description": "Repeating groups."
          },
          "generation_count": {
            "type": "integer"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GenerateRequest": {
        "type": "object",
        "properties": {
          "values": {
            "type": "object",
            "description": "Placeholder key → value (string); repeating-group key → array of instance objects (field key → string). Labels are accepted in place of keys.",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  }
                }
              ]
            }
          },
          "title": {
            "type": "string",
            "maxLength": 200,
            "description": "A name for the document; default `<template title> #<n>`."
          }
        }
      },
      "GenerationSummary": {
        "type": "object",
        "required": [
          "id",
          "title",
          "generation_number",
          "source",
          "created_at",
          "pdf_status",
          "pdf_url",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "template_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Null once the template has been deleted; the document survives."
          },
          "template_title": {
            "type": "string",
            "description": "The template's title at generation time."
          },
          "title": {
            "type": "string"
          },
          "generation_number": {
            "type": "integer",
            "description": "The document's number within its template."
          },
          "source": {
            "type": "string",
            "enum": [
              "app",
              "api"
            ]
          },
          "source_version": {
            "type": "integer",
            "description": "Which saved version of the template it was generated from."
          },
          "created_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "created_by_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The person's display name; null when the workspace no longer shares it."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "pdf_status": {
            "type": "string",
            "enum": [
              "pending",
              "rendering",
              "ready",
              "failed"
            ]
          },
          "pdf_url": {
            "type": "string",
            "format": "uri",
            "description": "`GET` it with the same bearer."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The document's page in PaperClerk."
          }
        }
      },
      "GenerationList": {
        "type": "object",
        "required": [
          "generations",
          "total",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "generations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GenerationSummary"
            }
          },
          "total": {
            "type": "integer",
            "description": "How many documents match the filters, whatever `limit` was."
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass back as `cursor` for the next page."
          }
        }
      },
      "Generation": {
        "type": "object",
        "required": [
          "id",
          "title",
          "generation_number",
          "source",
          "created_at",
          "markdown",
          "url",
          "pdf_status",
          "pdf_url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "template_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "generation_number": {
            "type": "integer"
          },
          "source": {
            "type": "string",
            "enum": [
              "app",
              "api"
            ]
          },
          "source_version": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "markdown": {
            "type": "string",
            "description": "The document with its values baked in; a placeholder left blank appears as `{{Label}}`."
          },
          "html": {
            "type": "string"
          },
          "html_truncated": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "pdf_status": {
            "type": "string",
            "enum": [
              "pending",
              "rendering",
              "ready",
              "failed"
            ]
          },
          "pdf_url": {
            "type": "string",
            "format": "uri"
          },
          "replayed": {
            "type": "boolean",
            "description": "Present and true when this answer is a replay of a request already generated."
          }
        }
      },
      "PdfReady": {
        "type": "object",
        "required": [
          "status",
          "url",
          "expires_in"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ready"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "A signed download URL."
          },
          "pages": {
            "type": [
              "integer",
              "null"
            ]
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until `url` stops working."
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "API reference: overview, guides, and individual endpoint pages",
    "url": "https://usepaperclerk.com/docs/api"
  }
}
