Pilio API Documentation
Use permanent API keys to create asynchronous image processing, PDF watermark removal, and GPT Image 2 tasks. API calls reuse your existing Pilio credits and task limits.
Basics
Authentication
Send your API key with every request. You can use either header form.
Authorization: Bearer pilio_sk_your_key_here
# or
X-API-Key: pilio_sk_your_key_here- Base URL
https://pilio.ai- Content-Type
application/json
5-minute quickstart
This flow creates an upload file, uploads the binary to a presigned URL, creates an async task, then polls for the result.
# 1) Create upload file records. This example explicitly chooses simple upload.
# Read data.items[0].id and data.items[0].upload_url.
curl -X POST "https://pilio.ai/v1/files/batch-create" -H "Authorization: Bearer pilio_sk_your_key_here" -H "Content-Type: application/json" -d '{"files":[{"nanoid":"V1StGXR8_Z5jdHi6B-myT","name":"reference.png","type":"png","size":1024}],"upload_mode":"simple","storage_intent":"temporary"}'
# 2) Upload the file to the presigned URL. Do not send your Pilio API key here.
# After a simple upload_url upload succeeds, go to step 3. Do not call /v1/files/:id/complete.
curl -X PUT "<upload_url>" -H "Content-Type: image/png" --data-binary @reference.png
# 3) Create an image watermark removal task with the file ID
curl -X POST "https://pilio.ai/v1/images/remove-watermark" -H "Authorization: Bearer pilio_sk_your_key_here" -H "Content-Type: application/json" -d '{"image_file_id":"<file_id>","mode":"auto"}'
# 4) Poll task status until status is Succeeded or Failed
curl -H "Authorization: Bearer pilio_sk_your_key_here" "https://pilio.ai/v1/tasks/<task_id>/status"
# 5) Fetch the result and download data.files[0].download_url
curl -H "Authorization: Bearer pilio_sk_your_key_here" "https://pilio.ai/v1/tasks/<task_id>/result"Response envelope
Every Pilio API response uses the same outer envelope. Check both the HTTP status and code.
{
"code": 200,
"message": "success",
"data": { ... }
}File upload and download
Image editing and image/PDF processing endpoints receive file IDs, not raw multipart file bodies. Create upload records first, upload to the returned URL, then pass the file ID to a task endpoint.
upload_mode=simpleexplicitly chooses one-file upload. Whenupload_urlis returned, PUT the file binary to that URL and do not call complete.upload_mode=multipartexplicitly chooses multipart upload. Whenupload_urlsis returned, PUT each part in order, collect eachETag, then call complete.upload_mode=autolets the server choose by file size. Client code should follow the returned field instead of guessing the upload path.- Do not send the Pilio API key to presigned upload or download URLs.
Main flow boundaries
batch-createonly creates file records and upload URLs. It does not upload file content.- Returned
upload_url: run onePUT, then create the task withitems[].id. Do not call/v1/files/:id/complete. - Returned
upload_urls: after all partPUTrequests succeed, call/v1/files/:id/complete, then create the task withitems[].id. - Task creation accepts file IDs such as
image_file_id,image_file_ids, orpdf_file_id. Do not passnanoid,upload_url,upload_urls, orupload_id. - If upload URLs expire or multipart state is lost, call
batch-createagain to get fresh upload URLs.
POST/v1/files/batch-create
Create file upload records and return either a simple upload_url or multipart upload_urls based on upload_mode and file size.
Request example
{
"files": [
{
"nanoid": "V1StGXR8_Z5jdHi6B-myT",
"name": "reference.png",
"type": "png",
"size": 1024
}
],
"upload_mode": "simple",
"storage_intent": "temporary"
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
files | SourceFile[] | yes | Files to create upload credentials for; at least one item. |
files[].nanoid | string | yes | Client-generated 21-character nanoid for matching returned file records to local files. |
files[].name | string | yes | Original file name, up to 300 characters; extension must match type. |
files[].type | enum | yes | File extension type, such as jpg, jpeg, png, webp, or pdf. |
files[].size | integer | no | File size in bytes; auto mode uses it to choose upload_url or upload_urls. |
upload_mode | enum | no | auto, simple, or multipart. simple returns upload_url; multipart returns upload_urls; auto lets the server choose by size. |
storage_intent | enum | no | temporary or permanent; image/PDF processing inputs usually use temporary. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
total | integer | yes | Number of file records created. |
items | File[] | yes | File records; pass the returned id as image_file_id, image_file_ids, or pdf_file_id. |
items[].id | string | yes | File ID. |
items[].nanoid | string | yes | The nanoid from your request, useful for client-side matching. |
items[].status | FileStatus | yes | Initially Pending; finish the presigned PUT upload before creating a task with this file ID. |
items[].upload_url | string | yes for simple upload | Presigned URL for a single PUT upload. Do not call complete when this field is returned. |
items[].upload_urls | UploadPart[] | yes for multipart upload | Presigned URLs for multipart PUT uploads. Upload every part, then call complete. |
items[].upload_id | string | yes for multipart upload | Object storage multipart upload ID, mainly for troubleshooting; complete only needs parts. |
POST/v1/files/:id/complete
Complete a multipart upload (optional). Call this only when batch-create returns upload_urls; do not call it for simple upload_url uploads.
Request example
{
"parts": [
{ "part_number": 1, "etag": ""etag-from-upload-response"" }
]
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
id | string(path) | yes for multipart upload | File ID returned as items[].id by batch-create; do not call this endpoint for simple upload_url uploads. |
parts | CompletedPart[] | yes for multipart upload | Successfully uploaded parts; part numbers must be continuous and start at 1. |
parts[].part_number | integer | yes for multipart upload | Part number, starting at 1. |
parts[].etag | string | yes for multipart upload | ETag response header returned by object storage after each part upload. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
data | null/object | no | Success means the multipart object has been merged; simple upload_url uploads do not need this endpoint. |
Task polling
Creation endpoints return immediately with a task ID. Poll status_url until the task reaches Succeeded or Failed, then read result files from result_url.
{
"code": 200,
"message": "success",
"data": {
"task_id": "2048...",
"status": "Processing",
"status_url": "/v1/tasks/2048.../status",
"result_url": "/v1/tasks/2048.../result",
"created_at": "2026-04-25T12:00:00Z"
}
}GET/v1/tasks/:id/status
Query task status. :id is the task_id returned by a creation endpoint.
Request example
No request body.Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
id | string(path) | yes | Task ID. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Task ID. |
status | TaskStatus | yes | Pending, Processing, Succeeded, or Failed. |
error_type | string | no | Failure category, usually present only when the task failed. |
error_message | string | no | Failure message, usually present only when the task failed. |
created_at | string(date-time) | no | Task creation time. |
updated_at | string(date-time) | no | Last update time. |
result_url | string | no | URL for reading task results. |
GET/v1/tasks/:id/result
Query task results. Successful tasks return downloadable files.
Request example
No request body.Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
id | string(path) | yes | Task ID. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Task ID. |
status | TaskStatus | yes | If the task has not succeeded yet, files may be empty. |
error_type | string | no | Failure category. |
error_message | string | no | Failure message. |
files | ResultFile[] | no | One or more output files. |
zip_file | ResultFile | no | May be present for batched output. |
Shared schemas
TaskStatus
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
Pending | TaskStatus | yes | Created and waiting for worker scheduling. |
Processing | TaskStatus | yes | The task is running; keep polling status_url. |
Succeeded | TaskStatus | yes | The task finished successfully; call result_url for output files. |
Failed | TaskStatus | yes | The task failed; read error_type and error_message. |
ResultFile
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
id | string | yes | File ID. |
name | string | no | File name. |
type | string | no | File type. |
size | integer | no | File size in bytes. |
download_url | string | no | Temporary download URL, issued for successful results. |
Errors
Errors keep the same envelope shape. Use the numeric code and structured data for program logic instead of parsing the human message.
{
"code": 1402,
"message": "Invalid token",
"data": null
}OpenAPI file
A public OpenAPI JSON file is available for Postman, Apifox, Insomnia, Bruno, code generators, and AI-assisted integration.
Download /developers/pilio-openapi.jsonSDK
Pilio does not maintain official SDKs yet. Use the OpenAPI JSON as the source of truth and generate a thin client that wraps authentication, response envelopes, polling, and downloads.
Tool APIs
GPT Image 2
POST/v1/images/gpt-image-2/generations
Create a GPT Image 2 text-to-image task.
Request example
{
"prompt": "A cinematic product photo of an orange perfume bottle",
"aspect_ratio": "3:2",
"output_count": 2,
"quality": "high"
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
prompt | string | yes | Generation or editing prompt, up to 32000 characters. |
negative_prompt | string | no | Negative prompt, up to 32000 characters. |
aspect_ratio | enum | required for generation; optional for edits | 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 16:9, 9:16, 21:9, or auto. |
output_count | integer | no | Number of output images: 1, 2, or 4. |
resolution | enum | no | 0.5K, 1K, 2K, or 4K. |
quality | enum | no | low, medium, or high. |
preprocess_mode | enum | no | off or auto. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
POST/v1/images/gpt-image-2/edits
Create a GPT Image 2 image editing task with 1-16 reference images.
Request example
{
"prompt": "Turn this reference into a studio product photo",
"image_file_ids": ["123456789", "123456790"],
"aspect_ratio": "auto",
"quality": "medium"
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
image_file_ids | string[] | yes | Reference image file IDs, 1-16 items; supports jpg, jpeg, png, and webp. |
prompt | string | yes | Generation or editing prompt, up to 32000 characters. |
negative_prompt | string | no | Negative prompt, up to 32000 characters. |
aspect_ratio | enum | required for generation; optional for edits | 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 16:9, 9:16, 21:9, or auto. |
output_count | integer | no | Number of output images: 1, 2, or 4. |
resolution | enum | no | 0.5K, 1K, 2K, or 4K. |
quality | enum | no | low, medium, or high. |
preprocess_mode | enum | no | off or auto. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
Image watermark removal
POST/v1/images/remove-watermark
Create an image watermark removal task with automatic detection or manual boxes.
Request example
{
"image_file_id": "123456789",
"mode": "manual",
"boxes": [{ "x1": 10, "y1": 15, "x2": 60, "y2": 70 }]
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
image_file_id | string | yes | File ID of the image to process. |
mode | enum | no | auto detects watermark areas automatically; manual uses explicit boxes. Default: auto. |
boxes | Box[] | yes when mode is manual | Manual watermark regions, 1-5 boxes. Coordinates are percentages of image width and height. |
boxes[].x1 | integer | yes when mode is manual | Top-left X, 0-100. |
boxes[].y1 | integer | yes when mode is manual | Top-left Y, 0-100. |
boxes[].x2 | integer | yes when mode is manual | Bottom-right X, 0-100. |
boxes[].y2 | integer | yes when mode is manual | Bottom-right Y, 0-100. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
Background removal
POST/v1/images/remove-background
Create an image background removal task that returns a transparent-background image.
Request example
{
"image_file_id": "123456789",
"industry_type": "portrait",
"quality_type": "original",
"trim_transparent_background": true
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
image_file_id | string | yes | File ID of the image to cut out; supports jpg, jpeg, png, webp, and heic. |
industry_type | enum | no | portrait, product, general, and compatible aliases. Default: portrait. |
quality_type | enum | no | original, fast, and compatible aliases. Default: original. |
trim_transparent_background | boolean | no | Trim extra transparent canvas around the cutout. Default: false. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
Image upscale
POST/v1/images/upscale
Create an image upscaling task to improve resolution and clarity.
Request example
{
"image_file_id": "123456789",
"method": "ai_super_resolution",
"preset": "hd",
"type": "2X",
"enhance_face": true,
"enhance_quality": true
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
image_file_id | string | yes | File ID of the image to upscale; supports heic, jpg, png, and webp. |
method | enum | no | ai_super_resolution, super_resolution, or enhance. Default: ai_super_resolution. |
preset | enum | no | auto or hd. Default: auto. |
type | string | no | Upscale factor. Default: 2X. |
enhance_face | boolean | no | Enhance face details. |
enhance_quality | boolean | no | Enhance overall image quality. |
enhance_text | boolean | no | Enhance text clarity. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
PDF watermark removal
POST/v1/pdfs/remove-watermark
Create a PDF watermark removal task with structured or AI reconstruction mode.
Request example
{
"pdf_file_id": "123456789",
"mode": "editable"
}Request fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
pdf_file_id | string | yes | File ID of the PDF to process. |
mode | enum | no | editable for structured watermark removal; ai for page-by-page image reconstruction. Default: editable. |
Response data fields
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
task_id | string | yes | Async task ID. |
status | TaskStatus | yes | Usually Processing when the task is created. |
status_url | string | yes | URL for polling task status. |
result_url | string | yes | URL for reading task results. |
created_at | string(date-time) | no | Task creation time. |
Limits and billing
Upload limits
| Field | Type | Required | Notes / allowed values |
|---|---|---|---|
Files per batch | integer | fixed limit | Up to 500 files. |
Single file size | bytes | fixed limit | Up to 2 GB. |
Multipart threshold | bytes | fixed rule | With upload_mode=auto, files larger than 5 MB usually receive upload_urls; simple explicitly asks for one upload_url. |
Upload URL lifetime | duration | fixed rule | upload_url / upload_urls are valid for about 2 hours; call batch-create again after expiration. |
Download URL lifetime | duration | fixed rule | download_url is valid for about 24 hours; query result_url again after expiration. |
- Credits are deducted from your normal Pilio credit balance.
- Image watermark removal costs 1 credits per image.
- Background removal costs 1 credits per image.
- Image upscale costs 3 credits per image.
- PDF watermark removal editable mode costs 2 credits per file.
- PDF watermark removal AI mode costs 1 credits per page.
- GPT Image 2 watermark-free mode costs 2 credits per output image.
- No separate API usage ledger is created; credit records remain the source of truth.
- Web and API tasks share the same in-flight pool:
Pending + Processing <= 20. - The first version only supports asynchronous APIs.
- See the full tool pricing table.