ServiceLabs

Split PDF

Send a PDF. Get back one single-page PDF per page, in page order, each with its own link.

SyncPOST /v1/utilities/split-pdfWaits up to 90 s for the finished job.

AsyncPOST /v1/utilities/split-pdf/jobsAnswers 202 with the job id at once.

What it’s for

  • Scanned batchesOne scan holding many documents becomes one file per page, ready to route or attach.
  • Page-by-page reviewShow, sign or approve a single page without passing the whole document around.
  • Attach one pagePull a page out of a statement to attach it to the transaction or ticket it belongs to.
  • Tools that take one pageEach file carries its pageNumber, so order survives whatever comes next.

How it runs

  1. DownloadStreams the PDF from your http(s):// or s3:// URL with a running size check. Over 150 MB stops early.
  2. CheckRefuses encrypted, empty or unreadable PDFs, and anything over 500 pages.
  3. SplitCopies each page into its own PDF. Pages are copied, not re-rendered, so memory stays low.
  4. Storepage-1.pdf to page-N.pdf, in page order, plus pageCount.

Pages are written one after another. For documents with hundreds of pages, use the async route; the sync route answers 202 with the job id after 90 s anyway.

Input

Send these fields as input in the request body. Anything not listed is refused with 400.

Field Type Required or optional Accepts
url string Required http://, https:// or s3:// URL, 1–4,096 characters. The PDF to split: at most 150 MB and 500 pages.

The request body

Field Required or optional What it is
input Required The fields above.
metadata Optional Your own key–value pairs, returned on the job. At most 50 keys, 4 KB serialised.
callbackUrl Optional Async route only. The finished job is POSTed here, signed. Up to 2,048 characters.

What comes back

Field Value
files[].url A link to the file.
result.pageCount Number of pages produced, equal to files.length.
result.files One entry per page, in page order.
files[].pageNumber The page number, starting at 1.
files[].name page-<N>.pdf, without zero padding. Order by pageNumber.
files[].contentType application/pdf

Example

curl https://api.servicelabs.dev/v1/utilities/split-pdf \
  -H "Authorization: Bearer $DU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "url": "https://example.com/statement.pdf"
    }
  }'
Response · 200 OK
{
  "id": "job_01K7Z3Q4N5P6R7S8T9V0W1X2Y3",
  "object": "job",
  "utility": "split-pdf",
  "mode": "sync",
  "status": "succeeded",
  "createdAt": "2026-09-10T17:30:06.650Z",
  "finishedAt": "2026-09-10T17:30:09.009Z",
  "timings": { "queueMs": 0, "upstreamMs": 2140, "storageMs": 196, "totalMs": 2359 },
  "result": {
    "files": [
      {
        "url": "https://…/page-1.pdf",
        "name": "page-1.pdf",
        "pageNumber": 1,
        "size": 48211,
        "contentType": "application/pdf"
      },
      {
        "url": "https://…/page-2.pdf",
        "name": "page-2.pdf",
        "pageNumber": 2,
        "size": 51377,
        "contentType": "application/pdf"
      },
      {
        "url": "https://…/page-3.pdf",
        "name": "page-3.pdf",
        "pageNumber": 3,
        "size": 39904,
        "contentType": "application/pdf"
      }
    ],
    "pageCount": 3
  },
  "error": null,
  "links": {
    "self": "/v1/jobs/job_01K7Z3Q4N5P6R7S8T9V0W1X2Y3"
  }
}

An example job. File links point at the stored output; download anything you need to keep.

Bad input · 400
{
  "error": {
    "code": "invalid_request",
    "message": "input failed validation for split-pdf",
    "details": [
      {
        "path": "input.url",
        "message": "must be an http://, https:// or s3:// URL"
      }
    ]
  }
}

Input is checked before anything runs. A 400 creates no job and costs nothing.

Limits

Limit Value
Runs up to 900 s (15 min)
Source size 150 MB, checked while streaming
Pages 500
Download timeout 60 s
Password-protected PDFs Refused. Decrypt first.
Empty (0-page) PDFs Refused
Sync wait 90 s, then 202 with the job id
Long-poll Up to 60 s per GET /v1/jobs/{id}?wait=
Rate limit Per key; 600 requests a minute unless set otherwise
Output files Kept for a limited period; download what you need

When it fails

A 400 means nothing ran. Everything else is a failed job with status: "failed", an error code and the utility’s own message.

Situation Status Code Job
url missing, or not http(s):// or s3:// 400 invalid_request No job
The download failed, or the source is over 150 MB 422 upstream_rejected Failed job
Not a valid PDF: Invalid or unsupported PDF: … 422 upstream_rejected Failed job
Password-protected: Password-protected PDFs are not supported 422 upstream_rejected Failed job
More than 500 pages, or none 422 upstream_rejected Failed job
An unexpected failure mid-split 502 upstream_error Failed job

Any call can also get 401 unauthorized, 403 forbidden (the key isn’t allowed this utility) or 429 rate_limited. The full list is in Conventions & errors.

Reference

Also in service

Try Split PDF on your own file.

The console’s playground runs split-pdf against any URL you give it and shows the job it returns.