POST /scan/crop
Send one document photo, get back a clean, straight, tightly cropped scan. This is the endpoint behind the quickstart and the one almost every integration uses first.
Request contract
| Field | Required | What it does |
|---|---|---|
| file | yes (single page) | One image as multipart form data. JPEG and PNG are the tested formats. |
| files | yes (multi page) | Repeat the field once per page to get one multi-page result. |
The endpoint is POST https://api.scankit.io/scan/crop and takes multipart/form-data. Send either file or files, never both.
- Authentication: X-API-Key header (recommended), Authorization: Bearer YOUR_API_KEY or the api_key query parameter.
- Images only. A PDF upload is answered with 502 and a decode error; PDF is an output format here, not an input.
- One credit per page. Two pages in one request cost two credits.
Parameters
| Parameter | Default | What it does |
|---|---|---|
| output_width | 1536 | Width of the returned image in pixels. |
| filter | white | white cleans the background, flat keeps the texture, original changes nothing. |
| version | 2 | Processing pipeline. 2 is the current one. |
| binary | true | true returns the image bytes, false wraps the result in JSON. |
| strip_black_border | true | Removes black borders around the detected page. |
| return_pdf | false | Returns one PDF instead of an image. |
| return_meta | false | Adds the detection metadata to the JSON response (with binary=false) and makes the pipeline report the detection result on the image path, where it comes back as the X-ScanKit-Detected header. |
| return_warp_geometry | false | Returns the geometry of the detected page instead of an image. |
| segment_count | 12 | Number of grid segments used by the v2 pipeline. Must be an integer. |
| ocr_lang | eng | Language hint for the text layer of the PDF output. |
{
"error": "return_warp_geometry cannot be combined with return_pdf (geometry mode returns no image)"
}When no document is found
A missed detection is not an error. The request answers 200 and returns the image you sent, unchanged, so a client that only looks at the status code cannot tell a scan from a miss. Ask for the detection flag and check it.
| Signal | Where it appears | Values |
|---|---|---|
| document_detected | JSON response (binary=false, plus return_meta=true or return_warp_geometry=true) | true: a document was detected and warped. false: no usable document was modelled and the image is the unchanged input. null: the pipeline answered without a detection result. |
| X-ScanKit-Detected | Response header on the image path (send return_meta=true) | true or false. Absent when the pipeline reported no detection result. |
{
"success": true,
"document_detected": false,
"image_base64": "<the unchanged input image>"
}When the flag is false, the usual handling is to show the photo back to the user with a manual crop screen, or to ask for a better photo: whole page in frame, even light, no hard shadow across the edge. ScanKit does not invent a crop for a document it did not find.
Examples
First call, image in and image out:
curl -X POST "https://api.scankit.io/scan/crop" \
-H "X-API-Key: YOUR_API_KEY" \
-F "file=@document.jpg" \
-F "output_width=1536" \
-F "filter=white" \
-o scan.jpgThe same call in Python, asking for a PDF:
import requests
with open("document.jpg", "rb") as fh:
response = requests.post(
"https://api.scankit.io/scan/crop",
headers={"X-API-Key": "YOUR_API_KEY"},
files={"file": ("document.jpg", fh, "image/jpeg")},
data={"return_pdf": "true"},
timeout=60,
)
response.raise_for_status()
with open("scan.pdf", "wb") as out:
out.write(response.content)Two pages in one request, one PDF back:
curl -X POST "https://api.scankit.io/scan/crop" \
-H "X-API-Key: YOUR_API_KEY" \
-F "files=@page-1.jpg" \
-F "files=@page-2.jpg" \
-F "return_pdf=true" \
-o scan.pdfErrors
| Status | Meaning | What to do |
|---|---|---|
| 400 | Invalid parameter or no file | output_width and segment_count must be integers, and the request needs file or files. |
| 401 | Missing API Key | Send the X-API-Key header. Check for a trailing space in the key. |
| 401 | Invalid API Key | The key was sent but belongs to no active account. |
| 402 | Insufficient credits | Top up credits in the dashboard. |
| 429 | Rate limit | Wait for the seconds given in Retry-After, then retry. |
| 502 | The image could not be processed | An unsupported or corrupt upload, or a detection that fails inside the pipeline. A missed detection does not have to error: see "When no document is found". |
{ "errors": [ { "title": "Invalid API Key" } ] }A refused request costs nothing: only a call that produced a result consumes credits. That is why a failed batch can be retried without paying twice.