Sites API
The Sites API is the core of Pageflare. You upload a zip of your built site, poll until optimization is complete, then download the result.
Base URL
Section titled “Base URL”https://pageflare.dev/_apiAll requests require an Authorization: Bearer <your-token> header. See Authentication for details.
Status flow
Section titled “Status flow”queued → running → complete ↘ erroredAfter uploading, a site moves through these statuses:
| Status | Meaning |
|---|---|
queued | Upload received; job is waiting in the processing queue |
running | Optimization is actively in progress |
complete | Optimization finished successfully; download is available |
errored | Optimization failed; see the error field for details |
POST /sites
Section titled “POST /sites”Upload a zip archive of your built site for optimization.
Request
Section titled “Request”Multipart upload (zip + optional config together):
POST /_api/sitesContent-Type: multipart/form-dataAuthorization: Bearer <your-token>
file=<zip-binary>config={"minify_html":true,"minify_css":true}Raw upload (zip body only):
POST /_api/sitesContent-Type: application/octet-streamAuthorization: Bearer <your-token>
<zip-binary>Constraints:
- Maximum file size: 50 MB
config(optional): JSON string with optimization flags. Omitting it uses your account defaults.
Config fields:
| Field | Type | Default | Description |
|---|---|---|---|
minify_html | boolean | true | Collapse whitespace and remove comments from HTML |
minify_css | boolean | true | Minify inline and linked CSS |
minify_js | boolean | true | Minify inline and linked JavaScript |
js_defer | boolean | true | Add defer to non-critical script tags |
lazy_images | boolean | true | Add loading="lazy" to below-the-fold images |
img_dimensions | boolean | true | Inject missing width/height attributes on <img> tags |
font_swap | boolean | true | Add font-display: swap to @font-face rules |
self_host_fonts | boolean | false | Download and inline Google Fonts (Pro) |
critical_css | boolean | false | Extract and inline critical CSS (Pro) |
youtube_facades | boolean | false | Replace YouTube embeds with click-to-load facades (Pro) |
Response
Section titled “Response”201 Created
{ "id": "site_abc123"}Use the returned id to poll for status and to download the result.
Try it
Section titled “Try it”Click Send to make a request
Errors
Section titled “Errors”| Status | Meaning |
|---|---|
400 Bad Request | Missing or invalid zip file, or malformed config JSON |
401 Unauthorized | Invalid or missing token |
413 Content Too Large | File exceeds the 50 MB limit |
GET /sites/:id
Section titled “GET /sites/:id”Poll for the status of an optimization job.
Request
Section titled “Request”GET /_api/sites/site_abc123Authorization: Bearer <your-token>Response
Section titled “Response”200 OK
{ "id": "site_abc123", "status": "complete", "fileCount": 42, "bytesIn": 524288, "bytesOut": 327680, "bytesSaved": 196608, "error": null, "createdAt": "2026-03-12T10:30:00.000Z", "completedAt": "2026-03-12T10:30:12.000Z"}Response fields:
| Field | Type | Description |
|---|---|---|
id | string | Site identifier |
status | string | One of queued, running, complete, errored |
fileCount | number | null | Number of files processed (available when complete) |
bytesIn | number | null | Total input size in bytes |
bytesOut | number | null | Total output size in bytes |
bytesSaved | number | null | Bytes saved (bytesIn - bytesOut) |
error | string | null | Error message if status is errored, otherwise null |
createdAt | string | ISO 8601 timestamp of when the job was created |
completedAt | string | null | ISO 8601 timestamp of completion, or null if still in progress |
Try it
Section titled “Try it”Click Send to make a request
Errors
Section titled “Errors”| Status | Meaning |
|---|---|
401 Unauthorized | Invalid or missing token |
404 Not Found | No site with the given ID |
GET /sites/:id/download
Section titled “GET /sites/:id/download”Download the optimized zip archive once a job has reached complete status.
Request
Section titled “Request”GET /_api/sites/site_abc123/downloadAuthorization: Bearer <your-token>Response
Section titled “Response”200 OK — binary zip stream
Content-Type: application/zipContent-Disposition: attachment; filename="site_abc123.zip"202 Accepted — if the job is still queued or running:
{ "status": "running"}Retry after a short delay when you receive 202.
Polling pattern
Section titled “Polling pattern”async function waitForOptimization(id, token) { const headers = { Authorization: `Bearer ${token}` }; while (true) { const res = await fetch(`/_api/sites/${id}`, { headers }); const data = await res.json(); if (data.status === 'complete') break; if (data.status === 'errored') throw new Error(data.error); await new Promise(r => setTimeout(r, 2000)); // wait 2 s } const download = await fetch(`/_api/sites/${id}/download`, { headers }); return download.blob();}Errors
Section titled “Errors”| Status | Meaning |
|---|---|
401 Unauthorized | Invalid or missing token |
404 Not Found | No site with the given ID |
500 Internal Server Error | Job errored; check status endpoint for details |