Public API

Jobs

Create, inspect, list, cancel, and delete conversion jobs.

Task graph

A v1 job has three tasks: an import task (import/upload or import/url), a convert task, and an export/url task. Each task names the one before it in input, and you choose the task names. Add an optional tag (up to 255 characters) to match jobs with your own records.

{
	"tasks": {
		"import-1": { "operation": "import/upload" },
		"convert-1": {
			"operation": "convert",
			"input": "import-1",
			"input_format": "png",
			"output_format": "webp",
			"options": {}
		},
		"export-1": { "operation": "export/url", "input": "convert-1" }
	},
	"tag": "invoice-42"
}

POST /jobs returns 201 with the job. A pair of formats the platform does not convert is refused up front with unsupported_conversion; GET /operations (no key needed) lists every supported pair with an estimated cost. options is passed through to the target format's conversion options.

The job object

{
	"id": "11111111-1111-4111-8111-111111111111",
	"status": "finished",
	"mode": "single",
	"tag": "invoice-42",
	"testMode": false,
	"test_mode": false,
	"credits_estimated": 1,
	"credits_used": 1,
	"tasks": [
		{
			"name": "import-1",
			"operation": "import/upload",
			"status": "finished",
			"credits": 0
		},
		{
			"name": "convert-1",
			"operation": "convert",
			"status": "finished",
			"credits": 1
		},
		{
			"name": "export-1",
			"operation": "export/url",
			"status": "finished",
			"credits": 0,
			"result": {
				"url": "https://…",
				"urlExpiresAt": "2026-10-11T12:00:00.000Z"
			}
		}
	],
	"createdAt": "2026-10-10T12:00:00.000Z",
	"created_at": "2026-10-10T12:00:00.000Z",
	"expires_at": "2026-10-11T12:00:00.000Z",
	"api_key_id": "22222222-2222-4222-8222-222222222222"
}
  • testMode and test_mode carry the same value (the camelCase field is kept for compatibility, as is createdAt).
  • A failed job has status: "error" and an error object with code, message and sometimes details.
  • credits_estimated and credits_used are described in Credits.

Statuses

StatusMeaning
waitingCreated; the file has not arrived yet (or an import/url fetch is still running).
queuedAccepted; waiting for a free conversion slot.
processingBeing converted.
finishedDone. The export/url task has result.url.
errorFailed. See error. Nothing is charged.
cancelledCancelled by you.
expiredThe result was kept for 24 hours and has been removed. There is no download link.

Tasks use the same status values. Results are kept for 24 hours; expires_at tells you exactly when. After it the job reports expired.

Read and wait

GET /jobs/{id} returns the job. Add ?wait=<seconds> (0–25) to hold the request until the job's status changes or the time is up; it returns the current job either way, so call it in a loop until the status is terminal (finished, error, cancelled, expired). A value above 25, below 0 or non-numeric is a 400 validation_failed.

Any key of your organization with the same mode can read a job. Another organization's job, or a job made with the other key mode, is a 404.

List jobs

GET /jobs returns your organization's jobs, newest first.

GET /jobs?status=finished&tag=invoice-42&page=1&per_page=20&include=tasks
ParameterMeaning
page1-based page number (default 1).
per_pageJobs per page, 1–100 (default 20).
statusOne of the statuses above.
tagExact tag match.
api_key_idOnly jobs created by this key.
include=tasksAdd each job's tasks; omitted by default to keep the list small.
{
	"data": [
		{
			"id": "11111111-1111-4111-8111-111111111111",
			"status": "finished",
			"mode": "single",
			"tag": "invoice-42",
			"testMode": false,
			"test_mode": false,
			"credits_estimated": 1,
			"credits_used": 1,
			"createdAt": "2026-10-10T12:00:00.000Z",
			"created_at": "2026-10-10T12:00:00.000Z",
			"expires_at": "2026-10-11T12:00:00.000Z",
			"api_key_id": "22222222-2222-4222-8222-222222222222"
		}
	],
	"page": 1,
	"per_page": 20,
	"total": 1
}

Cancel and delete

POST /jobs/{id}/cancel cancels a job that is waiting or queued, releases its credits, and returns the cancelled job. A job.cancelled webhook is sent.

A job that a worker is already converting cannot be cancelled yet: it answers 409 with error.details.reason set to processing_cannot_be_cancelled. Let it finish (or fail). A job that is already finished, error, cancelled or expired answers 409 with reason: "already_terminal" and the job's current status.

DELETE /jobs/{id} removes the job and its stored files and returns 204. A job that has not started converting is cancelled first. A job that is being converted answers 409 with reason: "processing_cannot_be_deleted"; delete it after it finishes. Deleting twice is harmless.

On this page