{"openapi":"3.1.0","info":{"title":"PageRush API","version":"2.0.0","description":"Render PDFs from Typst templates and JSON data. Store a template once (its main.typ plus any other files it uses), then render it with data. Every version of a template is immutable; renders use the live version unless they ask for another.\n\nThe render's `data` is available to the template as a virtual `data.json` file at the project root: read it with `#let data = json(\"data.json\")`.\n\nWithout `callback_url` the PDF is returned in the response body. With `callback_url` the request returns 202 and the PDF is POSTed to your URL, signed, when it is ready.\n\nLimits: source plus files up to 1.5 MB per version and 50 files; data up to 2 MB per render (1 MB with callback_url)."},"servers":[{"url":"https://pagerush.dev"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Project API key (pk_live_...)"}},"schemas":{"CreateTemplateRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"source":{"description":"The template's main.typ. Send this or `document`.","type":"string","minLength":1},"document":{"description":"A template from the visual editor. Send this or `source`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}},"files":{"default":[],"description":"Other files the template imports or reads, with paths relative to main.typ.","maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":200,"pattern":"^(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))[\\w.-]+(?:\\/[\\w.-]+)*$"},"content":{"type":"string"},"encoding":{"default":"utf8","description":"`utf8` for text files (.typ, .csv, .svg), `base64` for binary files (images, fonts).","type":"string","enum":["utf8","base64"]}},"required":["path","content"],"additionalProperties":false}},"sample_data":{"description":"Example data for test renders in the dashboard. Not used by API renders.","anyOf":[{"$ref":"#/$defs/__schema1"},{"type":"null"}]},"typst_version":{"description":"Typst release to render this version with. Defaults to 0.15.1 for a new template, and to the previous version's for a new version, so an upgrade never changes existing PDFs.","type":"string","enum":["0.15.1"]}},"required":["name"],"additionalProperties":false,"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]},"__schema1":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema1"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema1"}}]}}},"CreateVersionRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"source":{"description":"The template's main.typ. Send this or `document`.","type":"string","minLength":1},"document":{"description":"A template from the visual editor. Send this or `source`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}},"files":{"default":[],"description":"Other files the template imports or reads, with paths relative to main.typ.","maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":200,"pattern":"^(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))[\\w.-]+(?:\\/[\\w.-]+)*$"},"content":{"type":"string"},"encoding":{"default":"utf8","description":"`utf8` for text files (.typ, .csv, .svg), `base64` for binary files (images, fonts).","type":"string","enum":["utf8","base64"]}},"required":["path","content"],"additionalProperties":false}},"sample_data":{"description":"Example data for test renders in the dashboard. Not used by API renders.","anyOf":[{"$ref":"#/$defs/__schema1"},{"type":"null"}]},"typst_version":{"description":"Typst release to render this version with. Defaults to 0.15.1 for a new template, and to the previous version's for a new version, so an upgrade never changes existing PDFs.","type":"string","enum":["0.15.1"]},"publish":{"default":true,"description":"Make this version the live one that renders use by default.","type":"boolean"}},"additionalProperties":false,"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]},"__schema1":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema1"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema1"}}]}}},"PublishRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"version":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["version"],"additionalProperties":false},"RenderRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"data":{"description":"Any JSON value. The template reads it with #let data = json(\"data.json\").","anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}],"$ref":"#/$defs/__schema0"},"version":{"description":"Render this version instead of the live one (e.g. to test a draft).","type":"integer","minimum":1,"maximum":9007199254740991},"callback_url":{"description":"Queue the render and POST the PDF to this public https URL, signed, when it is ready.","type":"string","maxLength":4096,"format":"uri"},"metadata":{"description":"Up to 20 string pairs, echoed on the job and in the callback; at most 4096 bytes as JSON.","type":"object","propertyNames":{"type":"string","maxLength":64},"additionalProperties":{"type":"string","maxLength":512}},"delete_after_download":{"description":"Delete the PDF as soon as you have it instead of keeping it for 24 hours: sync responses are not stored, and async PDFs are deleted once the callback is delivered or the file is downloaded. Defaults to the project's setting.","type":"boolean"},"filename":{"description":"File name used in Content-Disposition. Defaults to the template name.","type":"string","maxLength":200,"pattern":"^[\\w\\-. ]+$"}},"required":["data"],"additionalProperties":false,"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]}}},"Template":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"live_version":{"type":["integer","null"],"description":"The version renders use unless they ask for one. Null until a version is published."},"latest_version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"versions":{"type":"array","description":"Newest first. Only on GET /v1/templates/{id}.","items":{"type":"object","properties":{"version":{"type":"integer"},"live":{"type":"boolean"},"bytes":{"type":"integer","description":"Stored size of the source and files."},"file_count":{"type":"integer"},"has_sample_data":{"type":"boolean"},"typst_version":{"type":"string","description":"Typst release this version renders with."},"created_at":{"type":"string","format":"date-time"}}}}}},"TemplateVersion":{"type":"object","properties":{"version":{"type":"integer"},"source":{"type":"string","description":"The version's main.typ."},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"encoding":{"type":"string","enum":["utf8","base64"]}}}},"sample_data":{"description":"Example data for dashboard test renders, or null."},"typst_version":{"type":"string","description":"Typst release this version renders with."},"created_at":{"type":"string","format":"date-time"}}},"TemplateWithVersion":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"},"version":{"$ref":"#/components/schemas/TemplateVersion"}}},"Job":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued","rendering","succeeded","failed"]},"mode":{"type":"string","enum":["sync","async"]},"region":{"type":"string","enum":["in"],"description":"The region the job rendered in, and its PDF is stored in: the project's region."},"template_id":{"type":["string","null"],"description":"Null once the template has been deleted."},"template_version":{"type":["integer","null"],"description":"The template version that was rendered."},"engine":{"type":["string","null"],"description":"The compiler that produced the PDF."},"bytes":{"type":["integer","null"]},"duration_ms":{"type":["integer","null"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}},"delivery":{"type":["object","null"],"properties":{"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer"},"error":{"type":["string","null"]}}},"metadata":{"type":["object","null"],"additionalProperties":{"type":"string"}},"download_url":{"type":["string","null"],"description":"Signed link to the stored PDF, valid for up to 1 hour. Every successful PDF is kept for 24 hours; fetch the job again for a fresh link. Null once the file has expired, or has been delivered or downloaded when delete_after_download is set."},"delete_after_download":{"type":"boolean","description":"Whether the PDF is deleted once delivered or downloaded instead of kept for 24 hours."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}}},"Problem":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"integer"},"code":{"type":"string","description":"Stable machine-readable error code"},"detail":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}}}},"request_id":{"type":"string"}},"required":["type","title","status","code"]}}},"paths":{"/v1/templates":{"get":{"operationId":"listTemplates","summary":"List the project's templates","description":"Newest first, a page at a time. Pass the previous page's next_cursor as cursor for the next page.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"next_cursor from the previous page"}],"responses":{"200":{"description":"Templates, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"next_cursor":{"type":["string","null"],"description":"Cursor for the next page; null on the last page."}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"operationId":"createTemplate","summary":"Create a template (its version 1 goes live)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateWithVersion"}}}},"400":{"description":"Invalid template (bad paths, too large, too many files)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getTemplate","summary":"Get a template and its version history","responses":{"200":{"description":"The template, with `versions`","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"}}}}}},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"operationId":"renameTemplate","summary":"Rename a template","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}}}},"responses":{"200":{"description":"Renamed"},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"operationId":"deleteTemplate","summary":"Delete a template and all its versions","responses":{"204":{"description":"Deleted"},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/versions":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"createTemplateVersion","summary":"Add a version (live by default)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVersionRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateWithVersion"}}}},"400":{"description":"Invalid template content","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/versions/{version}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer"}}],"get":{"operationId":"getTemplateVersion","summary":"Get one version's source, files and sample data","responses":{"200":{"description":"The version","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"$ref":"#/components/schemas/TemplateVersion"}}}}}},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/publish":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"publishTemplateVersion","summary":"Make a version the live one (also how you roll back)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishRequest"}}}},"responses":{"200":{"description":"Published"},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/render":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"renderTemplate","summary":"Render a template with data to PDF","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Safely retry a request without rendering or charging twice."},{"name":"Prefer","in":"header","schema":{"type":"string","enum":["respond-async"]},"description":"If the compile service is temporarily overloaded, return 202 with a queued job instead of 503."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderRequest"}}}},"responses":{"200":{"description":"The PDF. Headers: X-Job-Id (fetch the job again later), X-Template-Version, X-Render-Engine.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"202":{"description":"Accepted; delivered to callback_url when ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"Invalid request, or invalid data (INVALID_DATA)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Quota exhausted and no credits","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Template not found (TEMPLATE_NOT_FOUND), or not in this key's project","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The template has no live version (TEMPLATE_NOT_PUBLISHED), or an idempotency conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"410":{"description":"Idempotent replay of a request whose PDF is no longer stored (expired or delete_after_download)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The template failed to compile with this data (TEMPLATE_COMPILE_FAILED, Typst diagnostics in `errors`), or ran too long (RENDER_TIMEOUT)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate or concurrency limit","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Temporary: the render service couldn't be reached (RENDER_UNAVAILABLE); retry after Retry-After seconds when present","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get a job's status and download link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}}}