Skip to content

Editing a PDF

Two ways to change a PDF:

  • Server-side operations — send options to POST /convert/ and let indox do the work (rotate, merge, watermark, redact, split, encrypt, OCR, …).
  • Save an edited file — you edited the PDF yourself and want indox to store it and deliver it to a destination: POST /save/.

Server-side operations

Add an options object to a normal conversion request. The input must be a PDF and the output format is pdf unless the operation says otherwise. When options is present, target_formats may be omitted — it defaults to pdf.

curl -X POST https://indox.org/api/v1/pdf_handler/convert/json/ \
  -H "Authorization: Bearer $INDOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "s3_key": "…/contract.pdf",
        "target_formats": ["pdf"],
        "options": {
          "pages_delete": "2,4,6-9",
          "watermark_text": "CONFIDENTIAL",
          "watermark_opacity": 0.4,
          "add_page_numbers": true
        }
      }'

The response, polling, and download are exactly the standard conversion flow202, then poll GET /conversion/{id}/.

On the multipart POST /convert/ endpoint, send options as a JSON string in a form field of the same name.

Finding the available options

GET /operations/?input=pdf&output=pdf returns the full option list for the running deployment — every option's name, type, default, description, and, where the value is constrained, its possible_values. Read it rather than hard-coding a list; the set grows.

A representative sample:

Option Type Does
pages_extract / pages_delete string Keep or drop a page range, e.g. 1-3,5.
reorganize_pages string Reorder pages, e.g. 3,1,2.
rotate_angle / rotate_pages number / string Rotate by a multiple of 90°, all pages or a range.
crop_leftcrop_top number Crop insets in points.
additional_urls / additional_s3_keys array Merge further PDFs into this one.
watermark_text (+ size, colour, position, opacity, rotation) mixed Stamp a text watermark; underlay puts it behind the content.
add_page_numbers (+ position, font size, colour, margin) mixed Number the pages.
metadata object Set Title, Author, and friends.
form_fields / form_flatten object / boolean Fill AcroForm fields, optionally making them read-only.
decrypt_password string Password needed to open an encrypted source PDF.
encrypt_user_password / encrypt_owner_password string Protect the output.
change_permissions object Set what the output allows (print, copy, annotate, …).
auto_redact_terms array Black out words or phrases.
remove_annotations boolean Strip comments, highlights, and markup.
compress / ocr / repair / sanitize mixed Shrink, OCR, repair, or strip active content.
split_pages / split_by_size_or_count string / object Split the document; the output is a ZIP.
get_info / verify_pdf / compare boolean / object Inspect a PDF; the output is a JSON report.

Some options change the output type: splitting and image extraction produce a ZIP, and the inspection options produce JSON. The outputs array on the status response tells you what you actually got.

Not every option is available on every deployment — a few rely on an optional PDF service. GET /operations/ only advertises the ones that are wired up.

Saving an edited PDF

POST /save/ accepts a finished PDF and delivers it to your chosen destination. It is synchronous: there is nothing to poll.

curl -X POST https://indox.org/api/v1/pdf_handler/save/ \
  -H "Authorization: Bearer $INDOX_TOKEN" \
  -F "[email protected]" \
  -F "filename=contract-signed.pdf" \
  -F "destination=aws"
{
  "id": "0a2b4c6d-8e01-4f23-9a45-b6c7d8e9f012",
  "status": "completed",
  "destination": "aws",
  "download_url": "/api/v1/pdf_handler/0a2b…/download/",
  "file_url": "https://…"
}

The status code is 201 Created.

Field Type Notes
file file The PDF. Required unless you send file_base64.
file_base64 string The PDF as base64. A data: URI prefix is accepted and stripped.
filename string Name to store it under. Defaults to the uploaded file's name.
destination enum aws (default), google_drive, dropbox, box, onedrive.
  • download_url always works and streams through indox.
  • file_url is the raw link at the destination, so for a cloud destination it points at that provider.
  • Sending neither file nor file_base64 returns 400 file_or_file_base64_required; unparseable base64 returns 400 invalid_base64.
  • A cloud destination you have not connected returns 400 with the code missing_<provider>_token — connect the account first, see Integrations.

Saved PDFs appear in GET /history/ and are subject to the same retention window as conversions.