Export the site as a PDF
Exports the live site as a single PDF, rendering every page in navigation order. The export runs in the background: a new export returns 202, then poll GET /exports/pdf until downloadUrl is set.
If the latest completed export was built from the deployment that is live now, it is returned with 200, already carrying its downloadUrl, and nothing is rendered. Pass force to render again anyway.
One export runs per documentation at a time. Exports started through the API are limited to one every 5 minutes and 10 per 24 hours for each documentation; a request answered with an existing export does not count. Pages that cannot be rendered are left out of the PDF.
Requires editor or admin role, on the Standard, Professional or Enterprise plan.
curl -X POST "https://api.documentationai.app/api/v1/exports/pdf" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"force": false
}'
import requests
import json
url = "https://api.documentationai.app/api/v1/exports/pdf"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"force": false
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://api.documentationai.app/api/v1/exports/pdf", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"force": false
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"force": false
}`)
req, err := http.NewRequest("POST", "https://api.documentationai.app/api/v1/exports/pdf", bytes.NewBuffer(data))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://api.documentationai.app/api/v1/exports/pdf')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"force": false
}'
response = http.request(request)
puts response.body
{
"exportId": "6fa5a52d-d8b7-4b24-ac92-a55378f5eec4",
"status": "completed",
"progress": {
"completed": 130,
"total": 130
},
"fileSize": 38580135,
"downloadUrl": "https://exports.r2.cloudflarestorage.com/exports/org-.../documentation-export.pdf?X-Amz-Signature=...",
"downloadUrlExpiresAt": "2026-09-17T14:06:15.000Z",
"deploymentId": "64e41663-5ac8-422e-a941-00aff79963ed",
"source": "api",
"errorMessage": "example_string",
"createdAt": "2026-09-17T13:04:12.000Z",
"completedAt": "2026-09-17T13:06:15.000Z"
}
{
"exportId": "6fa5a52d-d8b7-4b24-ac92-a55378f5eec4",
"status": "completed",
"progress": {
"completed": 130,
"total": 130
},
"fileSize": 38580135,
"downloadUrl": "https://exports.r2.cloudflarestorage.com/exports/org-.../documentation-export.pdf?X-Amz-Signature=...",
"downloadUrlExpiresAt": "2026-09-17T14:06:15.000Z",
"deploymentId": "64e41663-5ac8-422e-a941-00aff79963ed",
"source": "api",
"errorMessage": "example_string",
"createdAt": "2026-09-17T13:04:12.000Z",
"completedAt": "2026-09-17T13:06:15.000Z"
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Forbidden",
"message": "You don't have permission to access this resource",
"code": 403
}
{
"error": "Not Found",
"message": "The requested resource was not found",
"code": 404
}
{
"error": "Conflict",
"message": "The request conflicts with the current state of the resource",
"code": 409,
"details": "Resource already exists"
}
{
"error": "Unprocessable Entity",
"message": "The request was well-formed but contains semantic errors",
"code": 422,
"details": [
{
"field": "password",
"message": "Password must be at least 8 characters long"
}
]
}
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please try again later",
"code": 429,
"retryAfter": 3600
}
{
"error": "Service Unavailable",
"message": "The service is temporarily unavailable. Please try again later",
"code": 503
}
/exports/pdf
Target server for requests. Edit to use your own host.
API key generated from the Documentation.AI dashboard (Settings → API Keys). Pass as Authorization: Bearer dai_...
Authorization: Bearer dai_...The media type of the request body
Render again even when an export of the current live deployment already exists. The cooldown and daily quota still apply.
Request Preview
Response
Response will appear here after sending the request
Authentication
Bearer token. API key generated from the Documentation.AI dashboard (Settings → API Keys). Pass as Authorization: Bearer dai_...
Body
Render again even when an export of the current live deployment already exists. The cooldown and daily quota still apply.
falseResponses
Identifies this export. Reads go through GET /exports/pdf, which always returns the current one.
pending and processing are in progress; completed, failed and cancelled are final.
pendingprocessingcompletedfailedcancelledSize of the PDF in bytes. Null until the export completes.
Temporary link for downloading the PDF directly from storage, with no API key. Null while the export runs, after it fails, and once a newer export replaces the file.
When downloadUrl stops working. Read the export again for a fresh link.
The live deployment this export rendered
Where the export was started
dashboardapiWhy the export failed. Null unless status is failed.
Null until the export completes