Upload and Clean, and unified image conversion

A multipart file that fails the shared stage returns HTTP 400 with upload_rejected before a downstream job is accepted. All tool uploads pass an unbilled, bounded Upload and Clean stage before a processing job is accepted. Format-specific validation remains enforced by the tool. Single-frame PNGs are rebuilt without metadata; other supported files retain their encoding after checks. Encrypted PDFs and damaged PDFs submitted for repair have limited inspection. Cleaning does not certify safety or replace a malware scanner.

  1. POST multipart files to /api/v1/uploads/ using jobs:submit. The response returns ordered owner-bound upload IDs, verified file information, cleaning status and a 24-hour expiry for unsubmitted uploads. Batch acceptance consumes the handles and retires staging copies after verified job copies commit. Do not submit local paths or trust file extensions.
  2. POST JSON {"upload_ids":["…"],"output_format":"png","parameters":{}} to /api/v1/tools/image-converter/quotes/, with Idempotency-Key (1–100 characters), jobs:submit and wallet:read. The server returns a per-image credit table, total and quote token valid for 15 minutes. Existing destination-tool encoding options apply.
  3. POST {"quote_token":"…"} with the same identity to /api/v1/tools/image-converter/jobs/. This atomically creates separate ordinary jobs and reserves each price. Reuse the same token and identity after an uncertain response.
  4. Read /api/v1/tools/image-converter/batches/{batch_id}/ with jobs:read. Download its download_url with results:read: one image returns its file directly; multiple images return an ordered ZIP. Collection is retryable without new conversion charges.

Two conversions per customer and four across the server can run concurrently. Batches share the outstanding-job limit with ordinary jobs and Flows. Each image uses its own existing destination tariff, so the total can exceed an individual tool's single batch price. Failed or cancelled jobs release their holds; completed jobs remain charged. Individual job endpoints provide available partial results, cancellation and Delete Now. Results expire normally; an expired or deleted file prevents a complete ZIP. Image to PDF here produces one PDF per image; the individual tool still combines images into one PDF. Read the OpenAPI schema for current technical limits and explicit fields. Existing individual tool routes remain supported. To remove a prepared upload, DELETE /api/v1/uploads/{upload_id}/ with results:delete; this revokes the handle and schedules physical removal without deleting accepted job copies.

Developer API · v1

Your first PDF API job, step by step.

Create a key, review a quote, then upload your files. Start with the Python client or follow the same workflow over HTTP.

Base URL https://softwarefool.com/api/v1

JSON responses · HTTPS in production · Versioned paths

Review the beta legal documents

Before new submissions, inspections, quotes or flow creation, the account holder must accept the current Terms and acknowledge reading the Privacy notice on the legal review page. Missing decisions return 403 legal_acceptance_required. Show that message to the account holder; do not automatically accept unseen documents. Existing jobs, downloads, deletion, cancellation and account controls remain accessible. Retry uncertain accepted requests with the original Idempotency-Key. New published versions require another review; saving drafts does not.

01 · Start here

Quickstart

  1. 1
    Create a scoped key.

    Sign in, open API access, select only the permissions your application needs, and copy the complete key when it is shown.

  2. 2
    Get a quote.

    Select local PDFs and inspect the cost and available credits. Quoting uploads no file content and reserves no credits.

  3. 3
    Confirm the task.

    Confirmation uploads the selected files and reserves the accepted credits. Save the returned job ID and wait for the result.

  4. 4
    Retrieve the result.

    List the job’s results, download an available file, and delete it early when it is no longer needed.

Merge two or more PDFs with Python

The client keeps your selected file order and separates checking a price from starting work. This example uses Merge PDF.

Select these permissions when creating the API key.

jobs:submit, wallet:read, jobs:read, and results:read. Keep the complete key in an environment variable—never paste it into the program.

1. Install the Python client

Install the Python client ZIP from this site with Python 3.10 or later; it is not published on PyPI.

python -m pip install "https://softwarefool.com/developers/api/python-client.zip"

2. Set the API key for your terminal

Use the command for your operating system. Replace YOUR_API_KEY with the complete key shown when you created it.

Windows PowerShell

$env:SOFTWAREFOOL_API_KEY = "YOUR_API_KEY"

macOS or Linux

export SOFTWAREFOOL_API_KEY="YOUR_API_KEY"

3. Save this as merge_pdfs.py

Put first.pdf and second.pdf beside the program. Set budget to the maximum number of credits you want this task to use.

import os
from softwarefool import Client, Job

client = Client(api_key=os.environ["SOFTWAREFOOL_API_KEY"], base_url="https://softwarefool.com/api/v1")
job = Job(client=client)
job.files(["first.pdf", "second.pdf"])

quote = job.merge()
budget = 5
print(f"Cost: {quote.cost_credits} credits")
print(f"Available: {quote.wallet.available_credits} credits")

if quote.can_afford and quote.cost_credits <= budget:
    run = job.confirm(quote)
    print(f"Job: {run.job_id}")
    result = run.wait()
    saved = result.download_to("./results")
    print(f"Saved: {saved}")
    print(f"Charged: {result.charged_credits} credits")
    print(f"Remaining: {result.available_credits} credits")
else:
    print("Not confirmed: insufficient credits or cost exceeds budget.")
python merge_pdfs.py

job.merge() hashes the files locally and requests a quote valid for 15 minutes. Only job.confirm(quote) sends file content and creates a job. A quote checks the declared sizes and account balance; it does not prove that the PDFs are valid. Structural, page-count, encrypted-file, and interactive-PDF checks run during processing. Failed work releases its reserved credits.

Waiting, retries, and recovery

can_afford is a snapshot, not a reservation. Confirmation rechecks credits and the task cost. The client will not silently accept a changed price. Downloads refuse to overwrite existing files. After confirmation, run.wallet, run.available_credits, and run.reserved_credits show the returned wallet snapshot. Completion refreshes the wallet. These account totals can also reflect other jobs.

Before confirmation, call quote = job.merge() again to request a replacement quote for the same unchanged files, then review it before confirming. This also works after local quote expiry or a definite task_cost_changed or insufficient_credits rejection with no preceding uncertain attempt. An explicit server 409 quote_expired also permits a replacement quote after an earlier uncertain attempt: the server checks for an already accepted job before rejecting expiry. Re-quote using the same Job, key, and unchanged files. The client rejects the old Quote after replacement. File selection is fixed after quoting; a different file set needs a new Job for that new operation.

run.wait() uses a five-minute polling budget by default. Network timeouts are best-effort socket-idle limits, so an already active response can exceed that budget. A WaitTimeout leaves the job running; save run.job_id and resume later with client.get_job(saved_job_id).wait(). A failed or cancelled job raises JobFailed; its completion information records the released credits.

If confirmation loses its response, retry job.confirm(quote) on the same Job and Quote objects. They preserve the original idempotency key and ordered files. Apart from the explicit server expiry rejection described above, uncertainty keeps the original confirmation fixed for retry. Do not start a new job just because delivery is uncertain. Once confirmation returns a job ID, store it for recovery after a restart. The client does not provide persistent recovery of an unacknowledged confirmation across program restarts.

Advanced: existing direct HTTP integration

The existing direct submission route remains supported. This longer example uses requests and confirms the displayed credit amount when it uploads files. It needs jobs:submit, jobs:read, and results:read.

python -m pip install requests

Save the following as merge_pdfs_http.py.

import os
import sys
import time
import uuid
from contextlib import ExitStack
from pathlib import Path
from urllib.parse import urljoin

import requests


API_BASE_URL = "https://softwarefool.com/api/v1"
EXPECTED_CREDITS = 2
OUTPUT_PATH = Path("merged.pdf")
FINAL_STATUSES = {"succeeded", "failed", "cancelled"}


def api_json(response):
    """Read successful JSON or raise the API's readable error."""
    payload = response.json()
    if response.ok:
        return payload

    error = payload.get("error", {})
    code = error.get("code", "api_error")
    message = error.get("message", "The request failed.")
    raise RuntimeError(
        f"SoftwareFool returned {response.status_code} {code}: {message}"
    )


def absolute_url(path):
    return urljoin(f"{API_BASE_URL}/", path)


api_key = os.environ.get("SOFTWAREFOOL_API_KEY", "").strip()
if not api_key:
    raise SystemExit("Set the SOFTWAREFOOL_API_KEY environment variable.")

pdfs = [Path(name) for name in sys.argv[1:]]
if len(pdfs) < 2:
    raise SystemExit("Usage: python merge_pdfs_http.py first.pdf second.pdf [...]")
for pdf in pdfs:
    if not pdf.is_file():
        raise SystemExit(f"File not found: {pdf}")
if OUTPUT_PATH.exists():
    raise SystemExit("Remove or rename the existing merged.pdf first.")

idempotency_key = os.environ.get(
    "SOFTWAREFOOL_IDEMPOTENCY_KEY",
    f"merge-{uuid.uuid4()}",
)
print(f"Idempotency key: {idempotency_key}")

with requests.Session() as session:
    session.headers["Authorization"] = f"Bearer {api_key}"

    # 1. Upload the files. Repeating "files" preserves their order.
    with ExitStack() as stack:
        files = [
            (
                "files",
                (pdf.name, stack.enter_context(pdf.open("rb")), "application/pdf"),
            )
            for pdf in pdfs
        ]
        response = session.post(
            f"{API_BASE_URL}/tools/merge-pdf/jobs/",
            headers={
                "Idempotency-Key": idempotency_key,
                "X-Expected-Credits": str(EXPECTED_CREDITS),
            },
            files=files,
            timeout=(10, 120),
        )

    job = api_json(response)["data"]
    job_url = absolute_url(job["links"]["self"])
    print(f"Accepted job: {job['id']}")

    # 2. Poll the returned job link for up to 15 minutes.
    previous_status = None
    for _ in range(450):
        response = session.get(job_url, timeout=(10, 30))
        job = api_json(response)["data"]
        status = job["status"]
        if status != previous_status:
            print(f"Job status: {status}")
            previous_status = status
        if status in FINAL_STATUSES:
            break
        time.sleep(2)
    else:
        raise TimeoutError(f"Job {job['id']} is still processing.")

    if status != "succeeded":
        raise RuntimeError(f"The merge ended as {status}.")

    # 3. Ask for the result information returned as JSON.
    response = session.get(
        absolute_url(job["links"]["results"]),
        timeout=(10, 30),
    )
    results = api_json(response)["data"]
    result = next(
        (
            item
            for item in results
            if item["filename"] == "merged.pdf"
            and item["status"] == "available"
        ),
        None,
    )
    if result is None or result["links"]["download"] is None:
        raise RuntimeError("The merged PDF is not available.")

    # 4. Download the actual PDF with the same authenticated session.
    with session.get(
        absolute_url(result["links"]["download"]),
        stream=True,
        timeout=(10, 120),
    ) as response:
        if not response.ok:
            api_json(response)
        with OUTPUT_PATH.open("xb") as output:
            for chunk in response.iter_content(1024 * 1024):
                if chunk:
                    output.write(chunk)

print(f"Saved: {OUTPUT_PATH.resolve()}")

EXPECTED_CREDITS is the displayed base charge and only matches this small-file example. Larger inputs can cost more; get a quote for their exact cost. If the API returns task_cost_changed, request and review a current quote before new work.

Run the direct HTTP program

python merge_pdfs_http.py first.pdf second.pdf

# Add more files in the order you want them merged:
python merge_pdfs_http.py first.pdf second.pdf third.pdf

The program prints the idempotency key, job ID, and each new status before saving the result. If submission is interrupted and you do not know whether the server accepted it, set SOFTWAREFOOL_IDEMPOTENCY_KEY to the printed value before rerunning the identical file list.

Check available credits over HTTP
curl "https://softwarefool.com/api/v1/wallet/" \
  --header "Authorization: Bearer YOUR_API_KEY"
{
  "data": {
    "balance_credits": 100,
    "reserved_credits": 1,
    "available_credits": 99,
    "spent_credits": 3
  }
}

Use your own stack

Connect from any language

The API accepts standard HTTP requests. Your application can use Node.js, PHP, Go, Java, C#, or another language that can send HTTPS, JSON, and multipart file uploads. Our server and optional Python client are written in Python; your application does not need to be.

Run these examples on a server you control. Keep bearer keys out of browser JavaScript and publicly distributed apps. For a Merge PDF job, create a key with jobs:submit, wallet:read, jobs:read, and results:read, then set SOFTWAREFOOL_API_KEY as shown in the quickstart.

Node.js

Use Node.js 20+ built-ins to quote ordered PDFs, confirm the cost, wait, and download the result. The command shows the live quote and asks for approval before uploading.

Download Node.js example
node softwarefool-merge.mjs --max-credits 5 first.pdf second.pdf

The 5 is a maximum budget, not a fixed tool price. For local testing, set SOFTWAREFOOL_API_BASE_URL to https://softwarefool.com/api/v1.

Try a read-only request

Save as wallet.mjs and run with node wallet.mjs. The key also needs wallet:read.

const key = process.env.SOFTWAREFOOL_API_KEY;
if (!key) throw new Error("Set SOFTWAREFOOL_API_KEY first.");
const response = await fetch("https://softwarefool.com/api/v1/wallet/", {
  headers: { Authorization: `Bearer ${key}` },
});
console.log(response.status, await response.json());

PHP

Use PHP 8.1+ with its cURL extension to make the same quote, confirmation, job, and result requests. The script shows the live quote and asks for approval before uploading.

Download PHP example
php softwarefool-merge.php 5 ./results first.pdf second.pdf

The 5 is a maximum budget, not a fixed tool price. For local testing, set SOFTWAREFOOL_API_BASE_URL to https://softwarefool.com/api/v1.

Try a read-only request

Save as wallet.php and run with php wallet.php. The key also needs wallet:read.

<?php
$key = getenv("SOFTWAREFOOL_API_KEY");
if (!$key) { throw new RuntimeException("Set SOFTWAREFOOL_API_KEY first."); }
$curl = curl_init("https://softwarefool.com/api/v1/wallet/");
curl_setopt_array($curl, [
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key],
    CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($curl);
if ($body === false) { throw new RuntimeException(curl_error($curl)); }
echo curl_getinfo($curl, CURLINFO_RESPONSE_CODE) . " " . $body . PHP_EOL;
curl_close($curl);

For any other language, follow the four HTTP steps and the OpenAPI contract. The route, request fields, scopes, credit quote, and result links are the same for every language; tool-specific options still vary.

One workflow for every tool

From quote to download

Use the tool's slug in the first two paths. The Python client performs these calls for you; use the HTTP routes when you need another language or an existing integration.

  1. 1
    Quote the taskPOST /api/v1/tools/{slug}/quotes/

    Send ordered file sizes, SHA-256 hashes, and that tool's options as JSON. The response gives an exact credit cost and a token. No file content or credits move yet.

  2. 2
    Confirm and uploadPOST /api/v1/tools/{slug}/quotes/confirm/

    Send the token and the unchanged files as multipart data. Use the same Idempotency-Key. This creates a job and reserves the quoted credits.

  3. 3
    Check the jobGET /api/v1/jobs/{job_id}/

    Poll until the status is succeeded, failed, or cancelled. Failed or cancelled work releases the reservation.

  4. 4
    Download the resultGET /api/v1/jobs/{job_id}/results/

    Follow the returned download link for an available result. Results are private and have their own expiry time.

Keep one key for one task.

Send the same Idempotency-Key with the quote and confirmation. If the confirmation response is lost, repeat that confirmation with the same token, key, options, and ordered files. A new key could create another job.

For a complete HTTP program, open the direct HTTP example. The Merge PDF reference also shows the quote manifest and a cURL confirmation request. The cURL snippets use Bash line continuations; Windows users can run the Python example above. Existing direct submission routes remain supported and use X-Expected-Credits instead of a quote token.

Choose an operation

Find a tool

All twenty-six PDF tools and converters use the same job, credit, and result workflow. Choose a tool below for its input and option details. The current price is in the price table; the quote gives the exact cost for your files.

Change tools in the Python client

For the newer tools, select a slug and pass its options before requesting a quote. This example rotates every page clockwise by 90°.

job = client.pdf_tool_job("rotate-pdf").file("source.pdf")
job.options({"ranges": [], "degrees": 90})
quote = job.quote()
if quote.can_afford and quote.cost_credits <= budget:
    result = job.confirm(quote).wait()
    result.download_to("./results")

Use the same client and budget variables from the Python quickstart. The OpenAPI JSON lists every request field and response schema.

02 · Access

Authentication

The external API accepts bearer keys only. A website login session does not authenticate an /api/v1/ request.

Before creating or using API keys, set up an authenticator app under Account settings → Two-factor authentication (2FA) and save your recovery codes. Creating a key requires a recent authenticator or recovery-code check. API requests continue using the bearer key alone; do not send authenticator codes with API requests.

Existing keys return the generic 401 authentication response until the account has an active authenticator. Completing setup restores otherwise valid keys. Revoke all active API keys before turning off two-factor authentication. Ordinary website-only accounts can continue using tools without setting it up.

Authorization: Bearer YOUR_API_KEY
Store the key like a password.

The complete value is displayed once. Create a replacement if it is lost, revoke a key immediately if it may be exposed, and never place it in browser-side code or a public repository.

Scopes

ScopeAllows
jobs:readView jobs
jobs:submitSubmit jobs
jobs:cancelCancel jobs
results:readDownload results
results:deleteDelete results
wallet:readView wallet

Scopes and expiry are fixed when a key is created. Create a new key when different access is needed.

03 · Contract

Conventions

Versioning

All documented external endpoints begin with /api/v1/. Include the trailing slash shown in each path.

Ownership

Wallets, jobs, and results are limited to the account that owns the key. A missing or unowned object returns the same 404 shape.

Dates and IDs

IDs are UUID strings. Timestamps use ISO 8601 with a timezone. A timestamp can be null before that event occurs.

Response envelopes

Successful JSON responses place records in data and supporting information in meta when needed.

Idempotency

Every quote and submission requires an Idempotency-Key of 1–160 characters. Keys are account-wide: use one key for a logical task's quote and confirmation. If confirmation delivery is uncertain, retry the same token and identical ordered files with the same key. An already accepted job is returned with 200, even if its quote has since expired or the advertised price has changed. Reusing a key for different accepted work returns 409 idempotency_conflict. The existing direct submission route instead confirms the expected credit header.

Job states

queuedrunningsucceeded

A job can instead finish as failed or cancelled. Credits are reserved while work is active, used after success, and released after failure or cancellation.

Job responses include failure: for a failed job, an object with customer-safe message and next_step strings; otherwise null. Known failures explain the issue and a suggested remedy. Unknown failures use general recovery guidance. Internal codes and exception details remain private. The Python client exposes this guidance as JobFailed.failure_message and JobFailed.next_step, also available on its completion.

04 · Capacity

Rate and job limits

A separate source-address ceiling allows 600 API requests per UTC minute, shared with browser API traffic from that address and checked before authentication. More than 20 unmatched 404 requests per UTC minute can pause access. Successive scanning bursts after an earlier pause ends incur 600, 3600 and 86400 seconds respectively. Requests during a pause do not extend it; strike history resets after 86400 seconds without a new burst. These refusals return 429 rate_limit_exceeded with Retry-After. Protection-state exhaustion or unavailability returns 503 capacity_unavailable; wait before retrying.

Request limits are shared by every API key belonging to one account. They use separate fixed windows for reads, writes, and submissions.

Repeated failed or cancelled processing can temporarily pause submissions to protect shared capacity. A 429 response includes Retry-After; wait before retrying. Failed and cancelled jobs release their reserved credits. Upload authentication is checked before files enter shared upload capacity.

Read120

requests per 60 seconds

Write30

requests per 60 seconds

Submit10

requests per 60 seconds

Successful responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. A 429 response also includes Retry-After.

Requesting a quote uses the write limit. Confirming a quote and direct job submission use the submit limit. Wallet, job, and result reads use the read limit.

Submission and upload-confirmation throttles are shared across your API keys and website usage. Aggregate server capacity and available private storage are also checked. A temporary 503 capacity_unavailable refusal includes Retry-After; retry the same unchanged request identity after waiting.

Any endpoint can return 503 capacity_unavailable during service maintenance or an outage. Wait for Retry-After. If a submission response was interrupted, check the job status or retry with the same idempotency key; the job may already have been accepted.

An account may have up to 20 queued or running jobs and up to 2 running jobs at once. These limits are shared by website and API work.

05 · Tool

Merge PDF

There is no account-tier file-count quota. An independent 1024-file multipart safety limit protects request parsing. There is no fixed page-count limit. Merged output may be up to 128 MiB. Complex PDFs can still exceed processing limits; failed jobs do not consume credits.

Get a quote

POST/api/v1/tools/merge-pdf/quotes/

Required scopes: both jobs:submit and wallet:read. Send Content-Type: application/json and an Idempotency-Key. The files array contains each local file's byte size and lowercase SHA-256 digest, in merge order. parameters must be the empty object {}; no extra fields are accepted. The JSON body must be 262144 bytes or smaller.

{
  "files": [
    {"bytes": 1200, "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
    {"bytes": 2400, "sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}
  ],
  "parameters": {}
}

The sizes and hashes above illustrate the format; compute the values from your actual files. The Python client does this for you. A quote sends no file content, creates no job, and places no credit hold.

200 returns data.token, tool (merge-pdf), cost_credits, can_afford, expires_at, file_count, total_bytes, and wallet. The wallet contains balance_credits, reserved_credits, available_credits, and spent_credits. The quote lasts 15 minutes; affordability is checked again at confirmation.

Confirm the quote

POST/api/v1/tools/merge-pdf/quotes/confirm/

Required scopes: both jobs:submit and wallet:read. Send multipart/form-data containing quote_token (the returned token, at most 524288 characters) and repeated files fields in the quoted order. Use the same Idempotency-Key as the quote. No X-Expected-Credits header is needed for this route.

curl --request POST "https://softwarefool.com/api/v1/tools/merge-pdf/quotes/confirm/" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Idempotency-Key: SAME_KEY_AS_QUOTE" \
  --form "quote_token=TOKEN_FROM_QUOTE" \
  --form "[email protected];type=application/pdf" \
  --form "[email protected];type=application/pdf"

A new confirmation returns 201 with the job record in data, meta.created: true, and meta.wallet containing current credit totals after reservation. An identical accepted retry returns 200 and meta.created: false. Location identifies the job endpoint.

A changed file/order, an expired unconfirmed quote, or a changed task cost is rejected before a new job is created. Get a fresh quote and review it before confirming new work. File structure, the page limit, and encrypted or interactive PDFs are checked during processing; a quote is not a guarantee of successful processing. Failed or cancelled work releases its reservation.

Existing direct submission

POST /api/v1/tools/merge-pdf/jobs/

Required scope: jobs:submit. This route remains supported for existing integrations. Submit at least 2 PDF files using repeated files fields and confirm the cost with X-Expected-Credits. The independent multipart file limit above still applies; the multipart order becomes the page order in the output.

20 MiB per file 100 MiB total No fixed page-count limit 2 credits currently

Malformed, password-protected, encrypted, or interactive PDFs are rejected safely. If processing fails, reserved credits are released.

Request

curl --request POST "https://softwarefool.com/api/v1/tools/merge-pdf/jobs/" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Idempotency-Key: merge-2026-09-04-001" \
  --header "X-Expected-Credits: 2" \
  --form "[email protected];type=application/pdf" \
  --form "[email protected];type=application/pdf"

Direct submission response

HTTP/1.1 201 Created
Location: /api/v1/jobs/0d57d720-5be4-4bd8-a3db-b3e10d8df5a1/

{
  "data": {
    "id": "0d57d720-5be4-4bd8-a3db-b3e10d8df5a1",
    "tool": {"slug": "merge-pdf", "name": "Merge PDF"},
    "status": "queued",
    "status_label": "Queued",
    "failure": null,
    "accepted_credits": 2,
    "credit_state": "reserved",
    "submitted_via": "api",
    "submitted_at": "2026-09-04T22:14:06.184Z",
    "started_at": null,
    "completed_at": null,
    "cancellation_requested": false,
    "links": {
      "self": "/api/v1/jobs/0d57d720-5be4-4bd8-a3db-b3e10d8df5a1/",
      "results": "/api/v1/jobs/0d57d720-5be4-4bd8-a3db-b3e10d8df5a1/results/",
      "cancel": "/api/v1/jobs/0d57d720-5be4-4bd8-a3db-b3e10d8df5a1/cancel/"
    }
  },
  "meta": {"created": true}
}

A new job returns 201. An identical idempotent retry returns 200 with meta.created set to false.

06 · Tool

Split PDF

Upload one PDF and receive one private ZIP. Choose pages for a separate PDF for every page, or ranges to create one PDF per chosen inclusive range. Ranges such as 1-3,5,8-10 may leave gaps but must be ascending and cannot overlap. The source file may be up to 100 MiB and 500 pages. The current tariff appears in the price table below.

Get a quote

POST/api/v1/tools/split-pdf/quotes/

Required scopes: jobs:submit and wallet:read. Send a JSON manifest with the source file's byte size and lowercase SHA-256 hash, selected mode and ranges, and an Idempotency-Key. The manifest must be at most 131072 bytes. A quote uploads no PDF bytes, creates no job, and reserves no credits.

{
  "files": [{"bytes": 1200, "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}],
  "parameters": {"mode": "ranges", "ranges": [[1, 3], [5, 5], [8, 10]]}
}

For one PDF per page, use "parameters": {"mode": "pages", "ranges": []}. The returned quote echoes the canonical parameters and has the same cost, wallet, expiration, and affordability fields as a Merge PDF quote, with tool: split-pdf. Actual PDF structure and source page count are checked by the worker after confirmation.

Confirm the quote

POST/api/v1/tools/split-pdf/quotes/confirm/

Required scopes: jobs:submit and wallet:read. Send the returned quote_token (at most 262144 characters) and the unchanged source PDF as one multipart files part. Use the same Idempotency-Key. The token binds the mode and ranges; no separate fields or expected-credit header are needed here. An identical accepted retry returns the original job.

curl --request POST "https://softwarefool.com/api/v1/tools/split-pdf/quotes/confirm/" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Idempotency-Key: SAME_KEY_AS_QUOTE" \
  --form "quote_token=TOKEN_FROM_QUOTE" \
  --form "[email protected];type=application/pdf"

Direct submission

POST/api/v1/tools/split-pdf/jobs/

Required scope: jobs:submit. Send one files part, mode (pages or ranges), and a ranges text field only in range mode. Supply Idempotency-Key and X-Expected-Credits headers. For a new accepted job, the response is 201; an identical retry returns 200. A successful job has one ZIP in its results list. Processing failure or cancellation releases reserved credits.

curl --request POST "https://softwarefool.com/api/v1/tools/split-pdf/jobs/" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Idempotency-Key: split-001" \
  --header "X-Expected-Credits: 3" \
  --form "[email protected];type=application/pdf" \
  --form "mode=ranges" \
  --form "ranges=1-3,5,8-10"

The Python client offers client.split_job().file("source.pdf").every_page() or .ranges("1-3,5,8-10"). Call job.split() to review its quote, then job.confirm(quote).

Tool

Extract Pages

Choose inclusive, ascending, nonoverlapping source page ranges such as 1-3,5,8-10. Gaps are allowed. The selected pages become one PDF in their original order. This differs from Split PDF, which makes separate files in a ZIP. One source PDF may be up to 100 MiB and 500 pages.

Use POST /api/v1/tools/extract-pdf/quotes/ with Idempotency-Key and both jobs:submit and wallet:read scopes. Send one file size and SHA-256 hash with "parameters": {"ranges": [[1,3],[5,5],[8,10]]}. The quote returns its cost, wallet snapshot, expiry and token without uploading content or reserving credits.

Confirm at POST /api/v1/tools/extract-pdf/quotes/confirm/ with the same key, quote_token, and one multipart files PDF part. For direct submission, use POST /api/v1/tools/extract-pdf/jobs/ with one files part and a ranges=1-3,5,8-10 form field, plus Idempotency-Key and X-Expected-Credits headers. A new accepted job returns 201; an identical retry returns 200.

Tool

Remove Pages

Choose pages to discard using inclusive, ascending, nonoverlapping ranges. The remaining pages become one PDF in original order. At least one page must remain. One source PDF may be up to 100 MiB and 500 pages.

Quote at POST /api/v1/tools/remove-pdf/quotes/ with one file size/SHA-256 manifest, "parameters": {"ranges": [[2,2],[4,6]]}, the same key and scopes as Extract Pages. Confirm at POST /api/v1/tools/remove-pdf/quotes/confirm/ with quote_token and the unchanged PDF. Direct submissions go to POST /api/v1/tools/remove-pdf/jobs/ with one multipart files part, ranges=2,4-6, and the idempotency and expected-credit headers.

Tool

Organize PDF

Reorder pages, omit pages, and rotate retained pages from one PDF. The result is one new PDF. The source may be up to 100 MiB and 500 pages. Use 1-based source page numbers.

Quote at POST /api/v1/tools/organize-pdf/quotes/ with one file manifest and parameters such as {"order":[1,3,2],"rotations":[[2,90],[3,180]]}. An empty order means keep every page in its existing order; an omitted page is removed. Rotations use source page numbers and clockwise degrees 90, 180, or 270. Confirm at POST /api/v1/tools/organize-pdf/quotes/confirm/ with the quote token and unchanged PDF.

Direct submissions go to POST /api/v1/tools/organize-pdf/jobs/ with one multipart files part. Optional order=1-3,6,5,4 and rotations=2:right,4:left,5:flip form fields express the same choices. Supply Idempotency-Key and X-Expected-Credits.

Tool

Scan to PDF

Upload JPEG, PNG, or WebP photos and scans in page order. They become one PDF. The website supports adding images from a file picker, drag and drop, or a phone camera in several passes. Per-task technical limits are 20 MiB per image, 100 MiB combined, 100 images/pages, and 12000000 pixels per image. These limits are the same for free and purchased credits.

Quote at POST /api/v1/tools/scan-to-pdf/quotes/ with ordered size/SHA-256 entries and "parameters": {} for photo compression, or {"mode":"lossless"} for document/line-art pixels. Photo encoding uses JPEG and may resize large images; lossless uses PNG at decoded dimensions and can produce larger files. Both apply orientation, remove source metadata and flatten transparency to white. Confirm at POST /api/v1/tools/scan-to-pdf/quotes/confirm/ using the same key, quote_token, and repeated multipart files parts in quoted order. Direct submissions use POST /api/v1/tools/scan-to-pdf/jobs/ with the same ordered files parts plus Idempotency-Key and X-Expected-Credits; optional multipart parameters is a JSON object. The SDK supports scan_job().mode("lossless").

A current quote is authoritative. Input contents and page validity are checked during processing; a failed or cancelled job releases its reserved credits. Results use the same private job, download, expiry, and Delete Now endpoints described below.

Tool

Compress PDF

Optimize one PDF up to 100 MiB and 500 pages. lossless keeps image quality; balanced may recompress images. A file that cannot be made smaller produces no result and releases its reserved credits.

Quote at POST /api/v1/tools/compress-pdf/quotes/ with one size/SHA-256 entry and "parameters": {"mode": "lossless"} or "mode": "balanced". Confirm at POST /api/v1/tools/compress-pdf/quotes/confirm/ using the quote token and unchanged PDF. Direct submission at POST /api/v1/tools/compress-pdf/jobs/ requires one multipart files part, a mode field, Idempotency-Key, and X-Expected-Credits.

Tool

Repair PDF

Attempt to recover the structure of one damaged PDF up to 100 MiB and 500 pages. Recovery is best effort. The result is a new PDF with interactive content and document-level metadata removed; embedded content may retain metadata. Unrecoverable, encrypted, or signed inputs fail and release reserved credits.

Quote at POST /api/v1/tools/repair-pdf/quotes/ with one size/SHA-256 entry and "parameters": {}. Confirm at POST /api/v1/tools/repair-pdf/quotes/confirm/ with the quote token and unchanged PDF. Direct submission at POST /api/v1/tools/repair-pdf/jobs/ requires one multipart files part, Idempotency-Key, and X-Expected-Credits.

Tool

OCR PDF

Make printed English, French, Spanish or German text in scanned content searchable. Select language as eng, fra, spa, deu, eng+fra, eng+spa or eng+deu. Other languages are unsupported; proofread blurred, skewed or low-contrast scans. Handwriting is not supported. This includes scans on pages with visible digital text. Visible digital text is preserved; existing OCR text may be regenerated. Embedded attachments are excluded from the result; your original upload is unchanged. Pure digital-text PDFs fail without a charge. Submit one PDF up to 10 MiB and 50 pages. The OCR working image is downsampled to at most 4 million pixels; embedded images above 16 million pixels are rejected. Password-protected, signed, and interactive PDFs are unsupported.

Quote at POST /api/v1/tools/ocr-pdf/quotes/ with one size/SHA-256 entry and "parameters": {} for English, or {"language":"fra"} for French. Optional direct multipart parameters uses the same JSON object. The SDK supports ocr_job().language("fra"). Confirm at POST /api/v1/tools/ocr-pdf/quotes/confirm/ with the quote token and unchanged PDF. Direct submission at POST /api/v1/tools/ocr-pdf/jobs/ requires one multipart files part, Idempotency-Key, and X-Expected-Credits. A failed or cancelled task releases reserved credits.

Tools

Edit, protect, and review

These tools use the same quote and confirmation workflow. Put the shown JSON under parameters in your quote manifest; include each input file's size and lowercase SHA-256 hash under files. The Python client can build and confirm each job without you assembling the HTTP fields.

Rotate PDF

rotate-pdf

Turn selected PDF pages clockwise without flattening them.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "degrees": 90
}

Python client: job = client.pdf_tool_job("rotate-pdf").file("source.pdf").options({"ranges": [], "degrees": 90}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/rotate-pdf/quotes/ · POST /api/v1/tools/rotate-pdf/quotes/confirm/ · POST /api/v1/tools/rotate-pdf/jobs/

Crop PDF

crop-pdf

Trim visible margins manually or detect them separately on each selected page with mode=auto and optional padding in PDF points (default 6). Hidden content stays in the file; this is not redaction.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "left": 5,
  "right": 5,
  "top": 5,
  "bottom": 5
}
HTTP routes

POST /api/v1/tools/crop-pdf/quotes/ · POST /api/v1/tools/crop-pdf/quotes/confirm/ · POST /api/v1/tools/crop-pdf/jobs/

Add Page Numbers

page-numbers-pdf

Add styled numbers or Page X of Y labels while preserving ordinary forms, links, and comments.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "start": 1,
  "position": "bottom-center",
  "style": "decimal",
  "format": "page-x-of-y"
}
HTTP routes

POST /api/v1/tools/page-numbers-pdf/quotes/ · POST /api/v1/tools/page-numbers-pdf/quotes/confirm/ · POST /api/v1/tools/page-numbers-pdf/jobs/

Add Watermark

watermark-pdf

Stamp selected PDF pages with text or a PNG/JPEG/SVG image, once or as a repeated pattern.

One PDF + optional image 20 MiB per PDF 100 pages per PDF

Quote options (the parameters value):

{
  "kind": "text",
  "text": "Draft",
  "position": "center",
  "opacity": 25,
  "rotation": 0,
  "layer": "over",
  "pages": []
}

For an image watermark, describe the image second in the quote manifest and upload it as the second files part when confirming.

HTTP routes

POST /api/v1/tools/watermark-pdf/quotes/ · POST /api/v1/tools/watermark-pdf/quotes/confirm/ · POST /api/v1/tools/watermark-pdf/jobs/

Redact PDF

redact-pdf

Remove selected visual areas by rebuilding the PDF pages as images.

One PDF 10 MiB per PDF 20 pages per PDF

Quote options (the parameters value):

{
  "rectangles": [
    [
      1,
      100,
      100,
      300,
      80
    ]
  ]
}
HTTP routes

POST /api/v1/tools/redact-pdf/quotes/ · POST /api/v1/tools/redact-pdf/quotes/confirm/ · POST /api/v1/tools/redact-pdf/jobs/

Unlock PDF

unlock-pdf

Remove a PDF opening password using a password you know.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{}

Send the known password in the pdf_password multipart field when confirming. Leave it out of the quote JSON.

HTTP routes

POST /api/v1/tools/unlock-pdf/quotes/ · POST /api/v1/tools/unlock-pdf/quotes/confirm/ · POST /api/v1/tools/unlock-pdf/jobs/

Protect PDF

protect-pdf

Create an AES-256 password-protected copy of a PDF.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{}

Send the new password in the pdf_password multipart field when confirming. Leave it out of the quote JSON.

Python client: job = client.pdf_tool_job("protect-pdf").file("source.pdf").password(os.environ["PDF_OUTPUT_PASSWORD"]), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/protect-pdf/quotes/ · POST /api/v1/tools/protect-pdf/quotes/confirm/ · POST /api/v1/tools/protect-pdf/jobs/

Edit PDF

edit-pdf

Add text, rectangles, or highlights over existing PDF pages.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "operations": [
    {
      "type": "text",
      "page": 1,
      "x": 0.1,
      "y": 0.1,
      "width": 0.3,
      "height": 0.08,
      "color": "#000000",
      "text": "Approved",
      "font_size": 12
    }
  ]
}
HTTP routes

POST /api/v1/tools/edit-pdf/quotes/ · POST /api/v1/tools/edit-pdf/quotes/confirm/ · POST /api/v1/tools/edit-pdf/jobs/

PDF Forms

forms-pdf

Add fillable text boxes or checkboxes to a static PDF.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "fields": [
    {
      "type": "text",
      "name": "customer_name",
      "page": 1,
      "x": 0.1,
      "y": 0.1,
      "width": 0.4,
      "height": 0.06,
      "label": "Name"
    }
  ]
}
HTTP routes

POST /api/v1/tools/forms-pdf/quotes/ · POST /api/v1/tools/forms-pdf/quotes/confirm/ · POST /api/v1/tools/forms-pdf/jobs/

Sign PDF

sign-pdf

Place a visible typed signature on one PDF page without identity verification.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{
  "name": "Jane Doe",
  "page": 1,
  "placement": "bottom_right",
  "date": true
}
HTTP routes

POST /api/v1/tools/sign-pdf/quotes/ · POST /api/v1/tools/sign-pdf/quotes/confirm/ · POST /api/v1/tools/sign-pdf/jobs/

Flatten PDF

flatten-pdf

Turn supported visible form fields and annotation appearances into static content, removing links and interactive controls.

Returns flattened.pdf. Existing selectable text and vector quality are preserved. Supported visible appearances become static content; links and interactive controls are removed. Form fields must have saved, valid appearances. Popup comment text and discussion threads are not included. Encrypted, digitally signed, active-content, XFA, and multimedia PDFs are unsupported. Missing or unsupported appearances fail with an explanation and release reserved credits. Keep the original for later form editing or comments.

One PDF 100 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{}

Python client: job = client.pdf_tool_job("flatten-pdf").file("source.pdf"), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/flatten-pdf/quotes/ · POST /api/v1/tools/flatten-pdf/quotes/confirm/ · POST /api/v1/tools/flatten-pdf/jobs/

PDF to DOCX

pdf-to-docx

Default text mode exports selectable PDF text and detected ruled tables into editable Word paragraphs and tables. Layout is approximate; graphics and font styling are omitted and scans need OCR first. For appearance, use ranges, mode image and dpi 72/150/300: rendered pages retain visible graphics but are not individually editable or searchable. Mixed pages fit the first page geometry with narrow white margins. Completed image-mode jobs offer a private first-page preview.

One PDF 20 MiB per PDF 100 pages per PDF

Quote options (the parameters value):

{
  "ranges": []
}

Python client: job = client.pdf_tool_job("pdf-to-docx").file("source.pdf").options({"ranges": []}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/pdf-to-docx/quotes/ · POST /api/v1/tools/pdf-to-docx/quotes/confirm/ · POST /api/v1/tools/pdf-to-docx/jobs/

PDF to XLSX

pdf-to-xlsx

Extract ruled or borderless PDF tables into one worksheet per detected table. Explicit ruled-cell merges are retained; multiline cells wrap. Borderless geometry is inferred and needs review. Cells stay literal text, including numbers and dates; completed jobs offer a private bounded first-table preview. Scans need OCR first.

One PDF 20 MiB per PDF 100 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "table_mode": "lines"
}

Python client: job = client.pdf_tool_job("pdf-to-xlsx").file("source.pdf").options({"ranges": [], "table_mode": "lines"}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/pdf-to-xlsx/quotes/ · POST /api/v1/tools/pdf-to-xlsx/quotes/confirm/ · POST /api/v1/tools/pdf-to-xlsx/jobs/

PDF to PPTX

pdf-to-pptx

Choose appearance-preserving image slides or editable text slides with approximate positioning. Text mode omits graphics and needs OCR first for scans. DPI applies only to image mode.

One PDF 20 MiB per PDF 100 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "mode": "image",
  "dpi": 150
}

Python client: job = client.pdf_tool_job("pdf-to-pptx").file("source.pdf").options({"ranges": [], "mode": "text"}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/pdf-to-pptx/quotes/ · POST /api/v1/tools/pdf-to-pptx/quotes/confirm/ · POST /api/v1/tools/pdf-to-pptx/jobs/

PDF to JPG

pdf-to-jpg

Export PDF pages as JPG images. A single page returns an image; multiple pages return a ZIP in source order. The source-page limit applies to the whole PDF; rendering and output limits apply to selected pages. Choose fewer pages or lower DPI if needed. Current limits are in the OpenAPI schema.

One PDF 90 MiB per PDF 5000 pages per PDF

Quote options (the parameters value):

{
  "ranges": [
    [
      1,
      3
    ],
    [
      5,
      5
    ]
  ],
  "dpi": 150
}

Python client: job = client.pdf_tool_job("pdf-to-jpg").file("source.pdf").options({"ranges": [], "dpi": 150}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/pdf-to-jpg/quotes/ · POST /api/v1/tools/pdf-to-jpg/quotes/confirm/ · POST /api/v1/tools/pdf-to-jpg/jobs/

PDF to PNG

pdf-to-png

Export PDF pages as lossless PNG images. A single page returns an image; multiple pages return a ZIP in source order. Outputs have a white background. The source-page limit applies to the whole PDF; rendering and output limits apply to selected pages. Choose fewer pages or lower DPI if needed. Current limits are in the OpenAPI schema.

One PDF 90 MiB per PDF 5000 pages per PDF

Quote options (the parameters value):

{
  "ranges": [],
  "dpi": 150
}

Python client: job = client.pdf_tool_job("pdf-to-png").file("source.pdf").options({"ranges": [[2, 2]], "dpi": 300}), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/pdf-to-png/quotes/ · POST /api/v1/tools/pdf-to-png/quotes/confirm/ · POST /api/v1/tools/pdf-to-png/jobs/

Compare PDF

compare-pdf

Create a compact summary-first PDF report with content-aligned pages, text and visual differences, optional unchanged-page details and flatten preparation.

Defaults to {} for plain PDFs. Set "parameters": {"flatten": true} to flatten both PDFs in temporary copies before comparison, or use .flatten_before_processing() in Python. This is optional, off by default, and included in the Compare PDF quote. Flatten limitations apply; originals are not modified. false is accepted and omitted from canonical quote parameters.

Two PDFs 20 MiB per PDF 500 pages per PDF

Quote options (the parameters value):

{}

Python client: job = client.pdf_tool_job("compare-pdf").files(["old.pdf", "new.pdf"]), then call job.quote() and job.confirm(quote).

HTTP routes

POST /api/v1/tools/compare-pdf/quotes/ · POST /api/v1/tools/compare-pdf/quotes/confirm/ · POST /api/v1/tools/compare-pdf/jobs/

Direct submission fields and detailed limits

Direct submission at /api/v1/tools/{slug}/jobs/ requires Idempotency-Key, X-Expected-Credits, and the multipart fields below. Unlike quote confirmation, it submits the files immediately. A new accepted job returns 201; an identical retry returns 200.

Tool slugInput limitDirect multipart options
edit-pdf100 MiB / 500 pagesparameters JSON with ordered operations of text, rectangle, or highlight overlays.
watermark-pdf20 MiB PDF, optional 5 MiB image / 100 pageskind, text, position, opacity, rotation, layer, optional pages, repeat, repeat_spacing, and repeat_scale. Upload PDF first, PNG/JPEG/SVG image second.
page-numbers-pdf100 MiB / 500 pagesOptional ranges; start, position, style. Optional format, template, font, font_size, min_font_size, color, bold, italic, underline, auto_fit, margin_x, margin_y, skip_first, parity, mirror, numbering, total, restart.
rotate-pdf100 MiB / 500 pagesOptional ranges; degrees = 90, 180, or 270 clockwise.
crop-pdf100 MiB / 500 pagesManual: ranges and four whole-percentage margins (left, right, top, bottom). Auto-trim: {"ranges":[],"mode":"auto","padding":6}; padding is 0–72 PDF points, default 6. Empty ranges means all pages.
forms-pdf100 MiB / 500 pagesparameters JSON with fields describing text or checkbox widgets.
unlock-pdf100 MiB / 500 pagespdf_password on direct submission and confirmation; quote parameters are {}.
protect-pdf100 MiB / 500 pagespdf_password on direct submission and confirmation; quote parameters are {}.
sign-pdf100 MiB / 500 pagesparameters JSON with name, page, placement, and date.
flatten-pdf100 MiB / 500 pagesOne files part; optional parameters must be {}. Quote parameters are {}.
redact-pdf10 MiB / 20 pagesrectangles lines of page,left%,top%,width%,height%.
compare-pdfTwo PDFs, 20 MiB / 500 pages eachTwo ordered files parts; optional parameters accepts boolean flatten and include_unchanged_pages, both defaulting to false.

The OpenAPI document supplies the current server-owned limits and full parameter schemas. For rotate, crop, and page numbers, quoted ranges are ascending inclusive pairs such as [[1,3],[5,5]]; [] means every page. Watermark quotes use {"kind":"text","text":"Draft","position":"center","opacity":25,"rotation":0,"layer":"over","pages":[]}; image watermarks use kind=image, empty text, and a second PNG/JPEG/SVG file. Watermark repeat defaults to false (single placement). Set repeat=true to tile the page; repeat_spacing is 0–144 PDF points (default 36), and repeat_scale is 25–200% (default 100). Position is ignored for repeat; opacity, rotation, layer, and page selection still apply. Edge tiles may be clipped. SVGs must be self-contained static vector artwork with dimensions or a viewBox; scripts, animations, XML DTDs/entities, embedded images, and external resources are unsupported. SVG is rendered into a transparent image within the existing byte/pixel limits before placement. Repeat options are bound to the quote and cannot change during confirmation. Redaction quotes use integer thousandths of the visible page in {"rectangles":[[1,100,100,300,80]]}. Document editing uses page-relative fractions from 0 to 1; review the OpenAPI schema before constructing an operation.

Choose the right change for sensitive content.

Crop hides content while leaving it in the PDF. Redact removes the selected regions by rebuilding image-only pages, which loses selectable text, links, and forms. Sign adds a visible typed mark without identity verification or a certificate.

Behavior and limitations

Edit PDF adds overlays and does not erase existing text. PDF Forms adds fields to static documents. Sign PDF does not invite signers or provide an audit trail. Unlock PDF needs a password you know. Protect PDF uses AES-256 encryption, but PDF viewer permissions do not provide strong access control.

Page numbering preserves ordinary AcroForm fields, comments, and HTTP/HTTPS, mail, or internal links. Unlock encrypted inputs first; signatures, scripts, attachments, XFA forms and active document actions are unsupported. Number styles are decimal, decimal-leading, roman, roman-lower, letters, letters-lower, and ordinal. Label formats are number, page-number, x-of-y, page-x-of-y, dash, brackets, and custom. For example, format=page-x-of-y prints “Page 1 of 10”. A custom template can be Page {page} of {total}. Custom templates use printable ASCII and {page}, {total}, {index}, {pages}; {page} is required. Roman output stays within 1–3999; letters and ordinals start at 1. Decimal starts may be 0–999999. Fonts are helvetica, times, or courier, with 4–72 point sizes and a minimum fitting size no greater than the chosen size. Margins use 0–144 points (72 points = 1 inch). Font colour is #RRGGBB. Boolean options use true/false, including multipart values. Defaults: bare decimal numbers, Helvetica 10pt, 6pt minimum, black, regular, no underline, 24pt margins, auto-fit, all pages, no skipped first page, no mirroring or restart. numbering=selected counts stamped pages consecutively; document offsets physical page positions. total=document counts all document pages; selected counts stamped pages, or the current range with restart. parity is all/odd/even by physical page. skip_first hides physical page 1. mirror swaps left/right alignment on even physical pages. restart resets each selected range and requires selected numbering. Options are bound to the quote and cannot be changed during confirmation. Labels that cannot fit at the minimum font size fail without charging.

Compare PDF aligns pages by normalized text and visual fingerprints, allowing added, removed and moved pages, and returns comparison.pdf. The report starts with a summary and includes changed-page details only by default. Set "include_unchanged_pages": true in parameters for an exhaustive report; false is omitted from canonical quote parameters. Both comparison options must be JSON booleans. It accepts plain PDFs by default; opt-in flatten preparation supports suitable forms, links, and annotation appearances. No automatic flattening occurs. Changed comparison options require a new quote and submission identity. Failed or cancelled jobs release their reserved credits.

Pricing

Current PDF tool prices

One credit is US$0.001. For size-priced tools, the base price covers the first size step shown below; each additional started step adds the listed charge. Flat-price tools have no size surcharge. Every task costs at least one credit, and its live quote is the exact price to review before confirmation.

ToolBase creditsAdditional input charge
Merge PDF2+1 credit per additional started 50 MiB
Split PDF3+1 credit per additional started 50 MiB
Extract Pages1+1 credit per additional started 50 MiB
Remove Pages1+1 credit per additional started 50 MiB
Organize PDF2+1 credit per additional started 50 MiB
Scan to PDF5+2 credits per additional started 50 MiB
Compress PDF5+2 credits per additional started 50 MiB
Repair PDF4+1 credit per additional started 50 MiB
Flatten PDF3+1 credit per additional started 100 MiB
OCR PDF20None (flat price)
Edit PDF5+1 credit per additional started 50 MiB
Add Watermark3None (flat price)
Add Page Numbers2+1 credit per additional started 50 MiB
Rotate PDF1+1 credit per additional started 50 MiB
Crop PDF2+1 credit per additional started 50 MiB
PDF Forms4+1 credit per additional started 50 MiB
Unlock PDF2+1 credit per additional started 50 MiB
Protect PDF3+1 credit per additional started 50 MiB
Sign PDF2+1 credit per additional started 50 MiB
Redact PDF8None (flat price)
Compare PDF6None (flat price)
PDF to JPG3+1 credit per additional started 50 MiB
PDF to PNG3+1 credit per additional started 50 MiB
PDF to DOCX5+1 credit per additional started 20 MiB
PDF to XLSX5+1 credit per additional started 20 MiB
PDF to PPTX5+1 credit per additional started 20 MiB

07 · Jobs

Jobs

GET/api/v1/jobs/

Scope: jobs:read. Lists owned website and API jobs newest first. Pass ?page=2 for another page; each page currently contains 20 jobs.

GET/api/v1/jobs/{job_id}/

Scope: jobs:read. Returns the current customer-safe job record and links for the next available actions.

POST/api/v1/jobs/{job_id}/cancel/

Scope: jobs:cancel. Cancels queued work immediately or requests cancellation of running work. The response’s meta.changed is false when no new change was needed.

Polling example

curl "https://softwarefool.com/api/v1/jobs/JOB_ID/" \
  --header "Authorization: Bearer YOUR_API_KEY"

Poll at a measured interval and apply backoff. Stop when the status becomes succeeded, failed, or cancelled.

08 · Output

Results

GET/api/v1/jobs/{job_id}/results/

Scope: results:read. Returns result metadata and its available, unavailable, expired, or deleted state.

GET/api/v1/jobs/{job_id}/results/{result_id}/download/

Scope: results:read. Downloads an available private file as an attachment.

DELETE/api/v1/jobs/{job_id}/results/{result_id}/

Scope: results:delete. Permanently deletes the owned result. This action is one-way and safe to repeat.

Per-file image validation errors identify the one-based input position (for example, Image 2). Replace that file and request a new quote; rejected uploads create no job or credit hold.

Use each result’s returned expires_at value rather than assuming a fixed retention period. Results remain available until expiry or explicit deletion. Interrupted downloads can be retried while the result is available. Original uploads are removed after the first result download starts. Save a copy locally. A download link is null when the file is not available. Failed-job files are held for up to 24 hours while you can opt in through the website failure page to help development investigate the issue; consent is off by default.

08 · Failures

Errors

JSON errors always contain a stable machine-readable code and a safe message.

{
  "error": {
    "code": "insufficient_scope",
    "message": "This API key does not have the required permission."
  }
}
HTTPCommon codesMeaning
400invalid_request, invalid_page, invalid_file_count, invalid_pdf_file, file_too_large, request_too_large, invalid_expected_credits, invalid_manifest, invalid_quoteCorrect the request before retrying. Quotes require ordered sizes, hashes, and tool-specific parameters; confirmations require a valid quote token.
401invalid_api_keyThe bearer key is missing, invalid, expired, or revoked.
403insufficient_scope, verified_account_requiredThe key lacks permission or the account is not eligible.
404not_found, result_not_foundThe owned record or available file could not be found.
409insufficient_credits, idempotency_conflict, task_cost_changed, job_limit_reached, result_in_use, quote_mismatch, quote_expiredThe request conflicts with current account or job state. Changed files or an expired unconfirmed quote require a new quote. Review a changed cost explicitly before confirming.
413request_too_largeThe quote manifest exceeds 262144 bytes or the upload request exceeds its hard body ceiling.
415unsupported_media_typeUse application/json for a quote and multipart/form-data for confirmation or direct submission.
429rate_limit_exceededWait for Retry-After before retrying.
503tool_unavailable, storage_unavailable, capacity_unavailableWait for Retry-After when present, then retry unchanged work with the same idempotency key. Capacity refusals create no new job or credit hold.

Unexpected methods return 405 method_not_allowed and an Allow header.

Machine readable

OpenAPI contract

Use the versioned OpenAPI 3.1 document to inspect request and response schemas or generate a client. The human guide remains the source for workflow and operational guidance.

View OpenAPI JSON

Flows: saved sequences and progress

Build a sequence in Flows, save it, and use its UUID through the bearer API. Each run keeps its accepted version and prices. Flow IDs identify reusable definitions; run IDs identify individual executions. Quotes reserve no credits.

  1. GET /api/v1/flows/ and /api/v1/flows/tools/ with jobs:read to discover owned/published flows and reviewed tool defaults and limits. Saved flows return twenty per page with meta; use ?page=2 for subsequent pages.
  2. POST /api/v1/flows/ with jobs:submit and JSON {"name":"My flow","definition":{"input_count":2,"steps":[{"tool":"flatten-pdf","parameters":{}},{"tool":"compare-pdf","parameters":{}}]}} to save a private flow. POST the same shape to /api/v1/flows/{flow_id}/ to create a version of your own flow. GET that URL reads an accessible flow.
  3. POST /api/v1/flows/{flow_id}/quotes/ with jobs:submit, an Idempotency-Key, and JSON {"files":[{"bytes":1234,"sha256":"…"},{"bytes":2345,"sha256":"…"}]}. Real hashes must be 64 lowercase hexadecimal characters. Keep the order. Review estimated_credits, maximum_credits and the per-job allocation. Quotes expire after 15 minutes.
  4. POST /api/v1/flows/{flow_id}/runs/ with jobs:submit, the same request identity, and multipart files, quote_id, confirmed_credits equal to the quoted maximum, and acknowledge_risks=true. Approval must come from your customer before submission. Accepted runs return 201; identical retries return 200 and the same run. After an uncertain response, retry that exact quote, files and identity rather than creating another run.
  5. GET /api/v1/flows/runs/{run_id}/ with jobs:read for overall status, charged/reserved credits, and individual step jobs. Fetch results through each job's existing results links with results:read; normal private download, expiry and deletion rules apply.
  6. POST the run's cancel/ endpoint with jobs:cancel to stop remaining work. POST resume/ with jobs:submit, a fresh Idempotency-Key, and JSON {"confirmed_credits":6,"acknowledge_risks":true}, replacing 6 with that run's original approved maximum. Reuse that resume key after an uncertain response; it cannot schedule another retry after a later failure.

Flows accept one or two PDFs and up to the server's reviewed step limit, returned by the tools endpoint (initially ten steps/twenty jobs). Reviewed PDF edits include Add Page Numbers, Rotate PDF and automatic Crop PDF; use the tools endpoint for their defaults and limits. Compare joins exactly two PDFs; converters must be last. Only reviewed tools are accepted; flows cannot specify executors, arbitrary dependencies, URLs, or storage paths. Saved private flows are limited to 100 per account. Flow tasks share the existing 20-outstanding/two-running customer limits and four global execution slots. Browser/API work shares the same wallet, dependencies, admission controls and accounting. Each step keeps its normal credit tariff.

Intermediate results required by an active or paused flow have no download or delete links. Direct download and deletion return 409 result_in_use until the flow finishes or is cancelled.

Costs and failure risks: Flatten → Compare preserves the current total Compare price: one credit for each flattening job and the remainder for comparison. Successful jobs remain charged even if a later step fails. Failed/cancelled holds release; unstarted jobs cost nothing. General flows use existing tariffs and an approved maximum because intermediate sizes can change. Holds are placed when each job queues, so insufficient available credits pause later work. Tool limits, unsafe-content checks, and quality limitations still apply.

Completed outputs remain private and downloadable even after a later failure. A resume creates new jobs only for failed work and reuses available successful outputs without charging for completed jobs again. Deleting or expiring required files can prevent chaining or resume; missing files require a fresh upload and quote. No internal measurements, executor details, storage keys, credentials, or confidential pricing evidence appear in flow responses. See the OpenAPI document for exact safe fields, limits, statuses and errors.

Image converters

Image to PDF combines pages; JPG, PNG, WebP, AVIF, TIFF, BMP, GIF, and ICO return one file or an ordered ZIP. Empty parameters: {} uses defaults. JPG, WebP, AVIF and Compress Image accept integer quality from 1 to 100. Compress Image also accepts format: webp (default), png, or preserve. Preserve keeps JPEG, PNG, WebP or AVIF; other types become PNG. Outputs can be larger; completed jobs show actual input/output sizes and a private preview. WebP and Compress Image accept boolean lossless; quality does not control lossless pixel fidelity. JPG accepts background of white or black. GIF accepts colors of 16, 32, 64, 128 or 256 and dither of none or floyd-steinberg. Options are bound to the quote and cannot change on confirmation. Supported formats, pixel/byte limits and output behavior are listed in each OpenAPI operation. Animated/multipage inputs use their first frame or primary image; metadata is removed. Keep originals when converting to lossy formats or replacing transparency.

Use client.image_job("image-to-png").files([...]).quote() in the Python client, then explicitly confirm the quoted credits. The local MCP connector supports the same destinations.

Image to PDF

Convert ordered images to PDF. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-pdf/quotes/

POST/api/v1/tools/image-to-pdf/quotes/confirm/

POST/api/v1/tools/image-to-pdf/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to JPG

Convert ordered images to JPG. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-jpg/quotes/

POST/api/v1/tools/image-to-jpg/quotes/confirm/

POST/api/v1/tools/image-to-jpg/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to PNG

Convert ordered images to PNG. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-png/quotes/

POST/api/v1/tools/image-to-png/quotes/confirm/

POST/api/v1/tools/image-to-png/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to WEBP

Convert ordered images to WEBP. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 40000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-webp/quotes/

POST/api/v1/tools/image-to-webp/quotes/confirm/

POST/api/v1/tools/image-to-webp/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to AVIF

Convert ordered images to AVIF. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 25000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-avif/quotes/

POST/api/v1/tools/image-to-avif/quotes/confirm/

POST/api/v1/tools/image-to-avif/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to TIFF

Convert ordered images to TIFF. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-tiff/quotes/

POST/api/v1/tools/image-to-tiff/quotes/confirm/

POST/api/v1/tools/image-to-tiff/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to BMP

Convert ordered images to BMP. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-bmp/quotes/

POST/api/v1/tools/image-to-bmp/quotes/confirm/

POST/api/v1/tools/image-to-bmp/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to GIF

Convert ordered images to GIF. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-gif/quotes/

POST/api/v1/tools/image-to-gif/quotes/confirm/

POST/api/v1/tools/image-to-gif/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Image to ICO

Convert ordered images to ICO. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 64000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/image-to-ico/quotes/

POST/api/v1/tools/image-to-ico/quotes/confirm/

POST/api/v1/tools/image-to-ico/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Compress Image

Compression accepts at most 16000000 pixels/image. Compress ordered images with quality, lossless and format choices. Default is lossy WebP quality 80. Choose PNG or preserve supported JPEG/PNG/WebP/AVIF input format; other preserved inputs become PNG. Dimensions and transparency are preserved where the output supports alpha; source metadata is removed and orientation applied. Already compressed inputs can produce larger outputs. Animated/multipage files use the first/primary image. One input returns one encoded image, several return an ordered ZIP. Convert ordered images to WEBP. Supported inputs: JPG/JPEG, PNG, WebP, AVIF, GIF, TIFF, BMP, ICO, HEIC/HEIF, JPEG 2000, PSD, PPM/PGM/PBM, TGA, PCX, and self-contained vector SVG. At most 16000000 decoded pixels/image, 1000000000 pixels/batch and 512 MiB output; SVG at most 1 MiB. Animated/multipage inputs use the first/primary image; PSD uses its merged preview. SVG is rasterized at intrinsic dimensions and rejects scripts, external resources, and embedded raster elements. Source metadata is removed; orientation is applied; high-bit-depth pixels become 8-bit. JPG/WebP/AVIF are lossy; GIF is still 256-color. JPG/BMP/GIF/PDF replace transparency with white. ICO fits into 256x256 without enlarging; PDF combines one page per image at 96 pixels/inch; other batches return ordered ZIPs. Pricing uses total input bytes and current published tariff; failures release holds.

POST/api/v1/tools/compress-image/quotes/

POST/api/v1/tools/compress-image/quotes/confirm/

POST/api/v1/tools/compress-image/jobs/

Quotes and confirmation require jobs:submit and wallet:read; direct jobs require jobs:submit. Use Idempotency-Key for all three. Direct jobs additionally require X-Expected-Credits. Quotes use JSON sizes/SHA-256 and reserve nothing. Confirmation uses multipart quote_token and ordered files; direct jobs use multipart files and JSON-encoded empty parameters. Repeat the unchanged key/token/files after uncertain outcomes. Success captures holds; final failure/cancellation releases them. Existing shared job, rate, owner/result access, expiry and deletion rules apply.

Document converters

Convert DOCX, DOC, ODT, RTF, UTF-8 TXT, Markdown and static self-contained HTML to PDF, DOCX, DOC, ODT, RTF, TXT, Markdown or HTML. Submit exactly one document per conversion. Markdown with images also returns a ZIP; HTML embeds images. No password-protected files, macros, embedded objects, active HTML or external image resources.

Limits: 1 files, 50 MiB per file, 90 MiB combined, 512 MiB expanded per package, 10000 package entries, 16 MiB text/XML parts, 16000000 pixels per embedded image, 512 MiB output. Multipart and token bounds come from OpenAPI.

First POST ordered files and JSON parameters to inspect/. text_mode is auto, txt or md. Auto uses a Markdown filename hint only after validating UTF-8 text; TXT and Markdown are inherently ambiguous. Inspection returns safe detected formats, grouped expected/possible changes, a blocked flag for already-target files, and an opaque customer-bound review token. Review uploads are deleted and no credits are reserved.

POST a JSON manifest of ordered bytes/sha256, parameters with acknowledge_risks: true, and review_token to quotes/ with Idempotency-Key. Both jobs:submit and wallet:read scopes are required for quotes and confirmation. Inspection and direct submission require jobs:submit.

After reviewing the warnings and exact cost, POST the same ordered files, quote_token and acknowledge_risks=true to quotes/confirm/ with the same key. Review/quote tokens expire after 15 minutes. Files, order, target and interpretation are bound to the review; changes require a fresh review. An accepted idempotent retry remains valid after token expiry. Direct jobs/ also requires review_token, acknowledged JSON options and X-Expected-Credits. Failed/cancelled jobs release credits.

Validation errors include invalid_document, invalid_review, review_expired, review_mismatch, already_target, invalid_parameters and risk_acknowledgement_required, in addition to the shared job/quote/authentication errors. Already-target files are rejected before charging. Internal engine diagnostics are never returned.

Document to DOC

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-doc/inspect/
  • POST/api/v1/tools/document-to-doc/quotes/
  • POST/api/v1/tools/document-to-doc/quotes/confirm/
  • POST/api/v1/tools/document-to-doc/jobs/

Document to DOCX

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-docx/inspect/
  • POST/api/v1/tools/document-to-docx/quotes/
  • POST/api/v1/tools/document-to-docx/quotes/confirm/
  • POST/api/v1/tools/document-to-docx/jobs/

Document to HTML

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-html/inspect/
  • POST/api/v1/tools/document-to-html/quotes/
  • POST/api/v1/tools/document-to-html/quotes/confirm/
  • POST/api/v1/tools/document-to-html/jobs/

Document to Markdown

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-md/inspect/
  • POST/api/v1/tools/document-to-md/quotes/
  • POST/api/v1/tools/document-to-md/quotes/confirm/
  • POST/api/v1/tools/document-to-md/jobs/

Document to ODT

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-odt/inspect/
  • POST/api/v1/tools/document-to-odt/quotes/
  • POST/api/v1/tools/document-to-odt/quotes/confirm/
  • POST/api/v1/tools/document-to-odt/jobs/

Document to PDF

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-pdf/inspect/
  • POST/api/v1/tools/document-to-pdf/quotes/
  • POST/api/v1/tools/document-to-pdf/quotes/confirm/
  • POST/api/v1/tools/document-to-pdf/jobs/

Document to RTF

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-rtf/inspect/
  • POST/api/v1/tools/document-to-rtf/quotes/
  • POST/api/v1/tools/document-to-rtf/quotes/confirm/
  • POST/api/v1/tools/document-to-rtf/jobs/

Document to TXT

5 credits per document, plus 1 credit per additional started size tier; the exact current cost is returned by the quote.

  • POST/api/v1/tools/document-to-txt/inspect/
  • POST/api/v1/tools/document-to-txt/quotes/
  • POST/api/v1/tools/document-to-txt/quotes/confirm/
  • POST/api/v1/tools/document-to-txt/jobs/

Presentation converters

Convert PPTX, PPT/PPS/POT, ODP, PPSX, POTX and OTP to PPTX, PPT, ODP or PDF. Legacy PPT/PPS/POT are detected as ppt. Export Keynote or online slides to PPTX first. Fonts, layout, animations, transitions, notes and hidden-slide state can change; PDF is static. PPT output uses rendered slide pictures to retain visible crops and subtitle colors; its text and shapes are not individually editable or searchable. Choose PPTX or ODP for editing. Protection, macros, objects, audio/video and external resources are unsupported. Keep originals and check results.

POST ordered files and JSON parameters {} to /api/v1/tools/presentation-to-<output>/inspect/ (jobs:submit). Inspection returns ordered detected formats, warnings and an account-bound token without reserving credits. POST files manifest, review_token and parameters {"acknowledge_risks":true} to quotes/ (jobs:submit and wallet:read), then explicitly confirm with the same files, quote_token and acknowledge_risks=true at quotes/confirm/. Use one Idempotency-Key for quote/confirmation and unchanged retries. Direct jobs/ accepts files, review_token, JSON parameters with acknowledge_risks true and X-Expected-Credits. Reviews/quotes expire after 15 minutes; accepted retries survive expiry. Same-format inputs block charging.

The updated warnings require a new inspection for older unaccepted reviews/quotes. Identical retries of already accepted jobs retain their original job and accounting identity.

Five credits per presentation plus one per additional started 20 MiB of aggregate input. Submit exactly one presentation; it returns one converted file. Shared customer/concurrency limits apply; failed/cancelled jobs release holds. Current limits: 1 files, 50 MiB/file, 90 MiB combined, 1000 slides, 100000 shapes/structural elements, 512 MiB expanded package, 10000 entries, 16 MiB XML parts, 16000000 pixels/embedded image and 512 MiB output.

See OpenAPI for all safe fields, scopes, headers and errors: invalid_presentation, invalid_file_count, invalid_parameters, invalid_manifest, invalid_review, invalid_quote, already_target and risk_acknowledgement_required (400); authentication/scope (401/403), method (405), review/quote expiry or mismatch, price/wallet/idempotency/job conflicts (409), upload size (413), media type (415), rate limit (429), tool/capacity/storage unavailable (503, capacity Retry-After). Inspect/quote return 200; acceptance 201, replay 200 with Location. Rate-limit headers follow shared behavior.

job = client.presentation_job("presentation-to-odp").files(["slides.pptx"])
quote = job.quote()
print(job.review, quote.cost_credits)
run = job.confirm(quote, acknowledge_risks=True)

Spreadsheet data converters

Spreadsheet to XLSX, XLS, ODS, CSV, TSV, PDF and HTML accepts XLSX, XLS, XLSB, ODS and UTF-8 CSV/TSV. These are data snapshots: stored formula results become values without recalculation. Formatting, charts, images, merged cells and workbook logic are removed. All data sheets, including hidden sheets, become visible unless selected with sheets: an ascending array of one-based positions such as [1,3]. Inspection returns a bounded sheet catalogue (labels shortened to 24 characters) and a literal first-sheet sample of up to three rows/four columns, with values shortened to 64 characters. These transient previews are incomplete. CSV/TSV accept encoding of utf-8 or utf-8-sig; CSV also accepts delimiter of comma or semicolon. Set the same options in inspection and quoting; changing them requires another review. Recalculate and save the original first; missing stored results may be blank. Unlisted formats, including XLSM and Apple Numbers, are not accepted.

For each /api/v1/tools/spreadsheet-to-<output>/ route, POST ordered files and JSON-string parameters to inspect/. Use text_mode auto, csv or tsv for delimited text. CSV recognizes comma/semicolon and TSV tabs; text remains literal, including leading zeroes. Inspection returns ordered formats, grouped warnings and an account-bound review token; it stores no job and reserves no credits.

POST JSON {"files":[{"bytes":123,"sha256":"…"}],"parameters":{"text_mode":"auto","acknowledge_risks":true},"review_token":"…"} with Idempotency-Key to quotes/. Show the exact cost and warnings. After approval, POST the identical ordered files, quote_token and multipart acknowledge_risks=true to quotes/confirm/, retaining the same key. Inspect needs jobs:submit; quotes/confirmation also need wallet:read. Direct jobs/ submission needs files, review_token, JSON parameters with consent, Idempotency-Key and X-Expected-Credits. Bearer authentication is mandatory; browser sessions cannot substitute.

Reviews/quotes expire after 15 minutes. Accepted retries remain idempotent after expiry. Changed input order/options, missing consent, expired review or changed prices fail before new acceptance. Retrying an uncertain confirmation must use the original files/key/token; do not automatically create a replacement job. Jobs/history/results/cancellation use the existing account-scoped APIs and credits. Failure/cancellation releases the reservation; success captures it once.

Submit exactly one workbook per conversion. CSV/TSV returns one file per sheet, bundled into one ZIP when there are multiple sheets. Current limits are derived below and in OpenAPI: 1 files, 50 MiB/file, 90 MiB combined, 2000000 rectangular cells per workbook including blank gaps, 256 sheets, 1048576 rows and 16384 columns per sheet. Expanded archive 512 MiB/10000 entries; XML/text part 16 MiB; text cell 32,767 characters; output 512 MiB. XLS additionally requires at most 65,536 rows/256 columns per sheet (legacy_dimensions before charging). The existing customer/global concurrency and processing ceilings apply.

CSV/TSV produce one numbered file per sheet; multiple sheets return an ordered ZIP. Formula-like text is prefixed with an apostrophe for safer opening; numeric negative values remain numeric. XLSX/ODS/XLS keep separate data sheets; HTML contains escaped static tables and PDF uses a generated print layout. Dates/times use standard formats, sheet names may be normalized, and wide PDF snapshots continue across pages at normal scale with repeated coordinate headings. Very long cells are refused rather than clipped; failed jobs release held credits. Check sensitive numeric precision and keep originals. The legacy XLS reader can round times to milliseconds; use XLSX/ODS source and output for finer timestamps. Same-output inputs are blocked before charging. Password protection, macros, external data connections and chart-only sheets are rejected.

Responses and errors follow the OpenAPI contract: invalid_spreadsheet, invalid_file_count, legacy_dimensions, invalid_parameters, invalid_manifest, invalid_review, invalid_quote, already_target and risk_acknowledgement_required (400); generic authentication/scope errors (401/403); method_not_allowed (405); review/quote mismatch or expiry, task_cost_changed, insufficient_credits, idempotency_conflict and job_limit_reached (409); request_too_large (413), unsupported_media_type (415), rate_limited (429), tool_unavailable/capacity_unavailable/storage_unavailable (503). Inspect/quote return 200, first acceptance 201 and idempotent replay 200. Accepted responses include Location; rate-limit headers and capacity Retry-After follow shared behavior. Internal pricing/resource evidence is never exposed.

job = client.spreadsheet_job("spreadsheet-to-csv").files(["book.xlsx"])
quote = job.quote()
# Show quote.cost_credits and job.review; obtain approval.
run = job.confirm(quote, acknowledge_risks=True)

Image editing

Prepare a separate edit plan for each changed image. Omit unchanged images. Request a fixed quote without reserving credits, review it, then explicitly confirm using the same key and original files. An optional logo follows all edited images as the last multipart file. Each file manifest includes its original byte count and SHA-256 plus orientation-corrected pixel width and height; the server checks these against actual uploads before reserving credits.

{"files": [{"bytes": 12345, "sha256": "<64 lowercase hex characters>", "width": 1200, "height": 800}], "parameters": {"items": [{"operations": [{"op": "rotate", "angle": 90}]}], "format": "png"}}

Rectangle coordinates are left, top, right, bottom in 0–10000 fractions of the current image. Right/bottom are exclusive; pixels touched at the boundaries are included. Preview differences are possible; review downloaded results. Redaction requires PNG and permanently replaces pixels, without including source images or metadata.

image-editor combines up to eight ordered operations per image using the same individual editing tools. Each operation acts on the current result; export encodes each final image once. Editing quotes include separate_jobs_credits and batch_savings_credits: the comparison uses the same per-image plans as separate jobs for that same tool at its current price, with the logo repeated when needed. Savings can be zero. The editor retains workload and file-size price floors without billing their overlap. Review its exact price before confirming.

Resize Image

Resize ordered images with aspect-ratio and enlargement controls. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/resize-image/quotes/
POST /api/v1/tools/resize-image/quotes/confirm/
POST /api/v1/tools/resize-image/jobs/

Crop Image

Crop each image with a visual selection or exact proportions. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/crop-image/quotes/
POST /api/v1/tools/crop-image/quotes/confirm/
POST /api/v1/tools/crop-image/jobs/

Rotate & Flip Image

Rotate, straighten or flip images individually or as a batch. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/rotate-image/quotes/
POST /api/v1/tools/rotate-image/quotes/confirm/
POST /api/v1/tools/rotate-image/jobs/

Watermark Image

Add a text or image watermark with position, size and opacity controls. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/watermark-image/quotes/
POST /api/v1/tools/watermark-image/quotes/confirm/
POST /api/v1/tools/watermark-image/jobs/

Adjust Image

Adjust image brightness, contrast, saturation and sharpness. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/adjust-image/quotes/
POST /api/v1/tools/adjust-image/quotes/confirm/
POST /api/v1/tools/adjust-image/jobs/

Redact Image

Permanently replace selected image regions with solid opaque pixels. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/redact-image/quotes/
POST /api/v1/tools/redact-image/quotes/confirm/
POST /api/v1/tools/redact-image/jobs/

Image Editor

Edit images one by one with rotation, crop, resize, watermark, adjustments and solid redaction, then process one quoted batch. JPG, PNG, WebP, AVIF, GIF and BMP inputs; first animation frame only. Up to 16000000 pixels and 16383 per side at each step, 256000000 combined peak pixels. Quote manifests require orientation-corrected width and height, revalidated against actual files before any hold. Prepare edits without spending, review a fixed quote, then explicitly confirm. Unchanged images are omitted from the job. PNG is lossless; JPG/WebP lossy; JPG fills transparency white. Redaction replaces RGBA pixels with opaque fills and requires PNG. Source metadata is removed. A single edited image returns an image; multiple edited images return an ordered ZIP. Optional logo is the last file with logo_index equal to items length. Failed/cancelled jobs release holds. Browser previews are approximate; inspect outputs.

POST /api/v1/tools/image-editor/quotes/
POST /api/v1/tools/image-editor/quotes/confirm/
POST /api/v1/tools/image-editor/jobs/

Quote and confirmation require jobs:submit and wallet:read; direct submission requires jobs:submit and X-Expected-Credits. Use bearer authentication and Idempotency-Key. See each Parameters schema in OpenAPI for fields, defaults and current technical limits. Existing private job status, download, cancellation and Delete Now routes apply.