{
  "openapi": "3.1.0",
  "info": {
    "title": "Papermill API",
    "description": "Generate PDFs from Press documents, Markdown, JSON, and CSV. Full documentation is at https://docs.papermill.io/api/.",
    "version": "2.0.0",
    "contact": {
      "name": "Papermill Support",
      "email": "support@papermill.io",
      "url": "https://docs.papermill.io"
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["statusCode", "message", "timestamp"],
        "properties": {
          "statusCode": {
            "type": "integer",
            "description": "Repeats the HTTP status."
          },
          "message": {
            "type": "string",
            "description": "Human-readable description. May be reworded — branch on `data.code` instead."
          },
          "timestamp": {
            "type": "string",
            "description": "When the failure occurred."
          },
          "stackTrace": {
            "type": "array",
            "description": "Source locations responsible, on Press authoring errors.",
            "items": {
              "type": "object"
            }
          },
          "data": {
            "type": "object",
            "description": "Machine-readable detail. Present on known failure modes.",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable identifier for the failure mode.",
                "enum": [
                  "ERR_EMAIL_NOT_VERIFIED",
                  "ERR_ACCOUNT_DISABLED",
                  "ERR_QUOTA_EXCEEDED",
                  "ERR_DRAFT_QUOTA_EXCEEDED",
                  "ERR_RENDER_TIMEOUT",
                  "ERR_TEMPLATE_NOT_FOUND",
                  "ERR_TEMPLATE_EMPTY",
                  "ERR_RATE_LIMITED",
                  "ERR_SLUG_TAKEN",
                  "ERR_SLUG_INVALID",
                  "ERR_WORKSPACE_UNRESOLVED",
                  "ERR_KEY_REVOKED",
                  "ERR_KEY_EXPIRED"
                ]
              },
              "cap": {
                "type": "number",
                "description": "Page allowance, on quota failures."
              },
              "usage": {
                "type": "number",
                "description": "Pages used so far, on quota failures."
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your Papermill API key, sent as `Authorization: Bearer <key>`."
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your Papermill API key. Equivalent to the bearer form."
      }
    }
  },
  "paths": {
    "/v2/authcheck": {
      "get": {
        "operationId": "authcheck",
        "summary": "Verify an API key",
        "tags": ["Account"],
        "description": "Confirms the presented API key is usable and names the account it belongs to. Takes no parameters and no body.",
        "responses": {
          "200": {
            "description": "The key is usable.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "The key is usable.",
                  "type": "object",
                  "required": ["status"],
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "Confirmation naming the authenticated account."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing, unrecognised, revoked, or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The account is disabled, or the email address is unverified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Honour the `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v2/validate": {
      "post": {
        "operationId": "validate",
        "summary": "Validate a payload",
        "tags": ["Documents"],
        "description": "Reports syntax and semantic problems in a payload without rendering it. A 200 response does not mean the payload is valid — read `valid`. Takes the same body and content types as `POST /v2/pdf`.",
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "template_id",
            "required": false,
            "description": "The template to render or validate against. Required when the body is JSON, CSV, or Markdown; optional when the body is a complete Press document.",
            "examples": {
              "papermill-invoice": {
                "value": "papermill-invoice"
              },
              "papermill-modern-invoice": {
                "value": "papermill-modern-invoice"
              },
              "papermill-modern-letter": {
                "value": "papermill-modern-letter"
              },
              "papermill-modern-report": {
                "value": "papermill-modern-report"
              },
              "papermill-simple-report": {
                "value": "papermill-simple-report"
              }
            }
          },
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "flow",
            "required": false,
            "description": "With `Content-Type: text/markdown`, the template flow the body replaces. Defaults to `body`. Supplying it with any other content type is rejected rather than silently ignored."
          }
        ],
        "responses": {
          "200": {
            "description": "Validation findings, split by severity.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Validation findings, split by severity.",
                  "type": "object",
                  "required": ["valid", "errors", "warnings"],
                  "properties": {
                    "valid": {
                      "type": "boolean",
                      "description": "True when `errors` is empty."
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string",
                            "description": "What is wrong."
                          },
                          "source": {
                            "type": "object",
                            "description": "Where the finding sits. Absent when it cannot be tied to a position.",
                            "properties": {
                              "tagName": {
                                "type": "string",
                                "description": "The element the finding sits on."
                              },
                              "origin": {
                                "type": "string",
                                "enum": ["template", "payload"],
                                "description": "Which document the finding is in. Present only when `template_id` was supplied."
                              },
                              "lineStart": {
                                "type": "number",
                                "description": "First line of the element."
                              },
                              "lineEnd": {
                                "type": "number",
                                "description": "Last line of the element."
                              },
                              "columnStart": {
                                "type": "number",
                                "description": "First column of the element."
                              },
                              "columnEnd": {
                                "type": "number",
                                "description": "Last column of the element."
                              }
                            }
                          }
                        }
                      },
                      "description": "Findings that prevent rendering."
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string",
                            "description": "What is wrong."
                          },
                          "source": {
                            "type": "object",
                            "description": "Where the finding sits. Absent when it cannot be tied to a position.",
                            "properties": {
                              "tagName": {
                                "type": "string",
                                "description": "The element the finding sits on."
                              },
                              "origin": {
                                "type": "string",
                                "enum": ["template", "payload"],
                                "description": "Which document the finding is in. Present only when `template_id` was supplied."
                              },
                              "lineStart": {
                                "type": "number",
                                "description": "First line of the element."
                              },
                              "lineEnd": {
                                "type": "number",
                                "description": "Last line of the element."
                              },
                              "columnStart": {
                                "type": "number",
                                "description": "First column of the element."
                              },
                              "columnEnd": {
                                "type": "number",
                                "description": "Last column of the element."
                              }
                            }
                          }
                        }
                      },
                      "description": "Findings that do not prevent rendering."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the document is malformed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing, unrecognised, revoked, or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The account is disabled, or the email address is unverified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The `template_id` does not exist or is not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The request body exceeded 32 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "The `Content-Type` is not one Papermill accepts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Honour the `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "A complete Press document, or data to merge into `template_id`. How the body is read depends on the `Content-Type`: the XML types are a whole document, while JSON and CSV supply data and Markdown supplies flow content. Bodies are capped at 32 MB.",
          "required": true,
          "content": {
            "text/xml": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "application/xml": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "text/plain": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object"
              }
            },
            "text/csv": {
              "schema": {
                "type": "string"
              }
            },
            "text/markdown": {
              "schema": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "/v2/pdf": {
      "post": {
        "operationId": "generatePDF",
        "summary": "Render a PDF",
        "tags": ["Documents"],
        "description": "Renders a PDF from a complete Press document, or from data merged into the template named by `template_id`. The response body is the PDF itself.",
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "template_id",
            "required": false,
            "description": "The template to render or validate against. Required when the body is JSON, CSV, or Markdown; optional when the body is a complete Press document.",
            "examples": {
              "papermill-invoice": {
                "value": "papermill-invoice"
              },
              "papermill-modern-invoice": {
                "value": "papermill-modern-invoice"
              },
              "papermill-modern-letter": {
                "value": "papermill-modern-letter"
              },
              "papermill-modern-report": {
                "value": "papermill-modern-report"
              },
              "papermill-simple-report": {
                "value": "papermill-simple-report"
              }
            }
          },
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "flow",
            "required": false,
            "description": "With `Content-Type: text/markdown`, the template flow the body replaces. Defaults to `body`. Supplying it with any other content type is rejected rather than silently ignored."
          },
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "draft",
            "required": false,
            "description": "Set to `true` to render against your draft allowance instead of your production page allowance. Any other value renders against the production allowance."
          }
        ],
        "responses": {
          "200": {
            "description": "The rendered PDF.",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string",
                  "default": "application/pdf"
                }
              },
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "default": "inline; filename=\"example.pdf\""
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "description": "The rendered PDF.",
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "The request or the document is malformed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing, unrecognised, revoked, or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The page allowance for the billing period is used up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The account is disabled, or the email address is unverified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The `template_id` does not exist or is not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The request body exceeded 32 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "The `Content-Type` is not one Papermill accepts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Honour the `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "The render exceeded the time budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "A complete Press document, or data to merge into `template_id`. How the body is read depends on the `Content-Type`: the XML types are a whole document, while JSON and CSV supply data and Markdown supplies flow content. Bodies are capped at 32 MB.",
          "required": true,
          "content": {
            "text/xml": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "application/xml": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "text/plain": {
              "examples": {
                "Press": {
                  "summary": "A Press document",
                  "value": "<press>\n  <document format=\"A4\">\n    <page>Hello</page>\n  </document>\n</press>",
                  "lang": "xml",
                  "isAutogenerated": true
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object"
              }
            },
            "text/csv": {
              "schema": {
                "type": "string"
              }
            },
            "text/markdown": {
              "schema": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "/v2/account/usage": {
      "get": {
        "operationId": "accountUsage",
        "summary": "Read account usage",
        "tags": ["Account"],
        "description": "Reports page and request consumption for the current billing period. The period runs from your plan renewal day, so it is usually not a calendar month.",
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "date",
            "required": false,
            "description": "A date inside the billing period to report on. Defaults to the current period."
          }
        ],
        "responses": {
          "200": {
            "description": "Consumption for the billing period.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Consumption for the billing period.",
                  "type": "object",
                  "required": ["pagesGenerated", "apiCalls", "maxPagesGenerated", "startDate", "endDate"],
                  "properties": {
                    "pagesGenerated": {
                      "type": "number",
                      "description": "Production pages generated this period."
                    },
                    "apiCalls": {
                      "type": "number",
                      "description": "Requests made this period."
                    },
                    "maxPagesGenerated": {
                      "type": "number",
                      "description": "Production page allowance for the plan."
                    },
                    "startDate": {
                      "type": "string",
                      "description": "Start of the billing period."
                    },
                    "endDate": {
                      "type": "string",
                      "description": "End of the billing period."
                    },
                    "draft": {
                      "type": "object",
                      "description": "Draft consumption. Appears after the first draft render of the period.",
                      "properties": {
                        "pagesGenerated": {
                          "type": "number",
                          "description": "Draft pages generated this period."
                        },
                        "apiCalls": {
                          "type": "number",
                          "description": "Draft requests made this period."
                        }
                      }
                    },
                    "maxDraftPagesGenerated": {
                      "type": "number",
                      "description": "Draft page allowance, on plans that set one."
                    },
                    "overagePages": {
                      "type": "number",
                      "description": "Pages generated beyond the allowance."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing, unrecognised, revoked, or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The account is disabled, or the email address is unverified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Honour the `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://api.papermill.io",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    },
    {
      "ApiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Documents",
      "description": "Render and validate documents."
    },
    {
      "name": "Account",
      "description": "Verify credentials and read consumption."
    }
  ]
}
