Your first scan in five minutes
One endpoint is enough: send a document photo, receive the cleaned, perspective-corrected image. This page walks you through it with cURL, Python and Node, then shows the browser SDK.
First, without an account
If you only want to see the output, open the demo, pick a sample photo and scan it. No signup, no key, and you can compare the result with the original photo.
Step 1: get an API key
- Create an account. Signup includes 50 free credits and needs no card.
- Open the dashboard and go to API keys.
- Create a key and copy it. The key is shown once, treat it like a password.
Step 2: first API call
POST one image as multipart form data to the crop endpoint. With binary=true, which is the default, the response body is the processed image itself, and -o writes it to a file.
curl -X POST "https://www.scankit.io/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:
import requests
with open("document.jpg", "rb") as fh:
response = requests.post(
"https://www.scankit.io/crop",
headers={"X-API-Key": "YOUR_API_KEY"},
files={"file": ("document.jpg", fh, "image/jpeg")},
data={"output_width": 1536, "filter": "white"},
timeout=60,
)
response.raise_for_status()
with open("scan.jpg", "wb") as out:
out.write(response.content)And in Node, without any SDK:
import fs from 'node:fs';
const body = new FormData();
body.append('file', new Blob([fs.readFileSync('document.jpg')]), 'document.jpg');
body.append('output_width', '1536');
body.append('filter', 'white');
const response = await fetch('https://www.scankit.io/crop', {
method: 'POST',
headers: { 'X-API-Key': 'YOUR_API_KEY' },
body,
});
const scan = Buffer.from(await response.arrayBuffer());
fs.writeFileSync('scan.jpg', scan);What you get back is a clean, straight, tightly cropped image of the document, ready for OCR, AI extraction or your archive. Every call costs one credit, and a new account starts with fifty.
Step 3: the parameters you will actually use
| Parameter | Default | What it does |
|---|---|---|
| file or files | required | One image as file, several pages as files. |
| 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. |
| strip_black_border | true | Removes black borders around the detected page. |
| binary | true | true returns the image bytes, false wraps the result in JSON. |
| return_pdf | false | Returns a PDF instead of an image. |
| ocr_lang | eng | Language hint for text extraction. |
| output_width, segment_count | numbers | Anything non numeric is answered with 400 instead of a server error. |
Send several pages in one request with the files parameter, or call the endpoint once per page. Both are supported, the multi page path keeps the pages in one response.
Step 4: capture in the browser
If your own users should take the photo, load the SDK from our CDN and let it own the capture flow. The SDK is served from scankit.io, so there is nothing to build and nothing to publish.
<link rel="stylesheet" href="https://www.scankit.io/sdk/scankit-sdk.css" />
<div id="scan-area"></div>
<script src="https://www.scankit.io/sdk/scankit-sdk.min.js"></script>
<script>
const scanner = new ScanKit({
target: '#scan-area',
apiKey: 'YOUR_API_KEY',
onScanComplete: (result) => {
// result.image is the finished scan as a Blob
uploadToYourBackend(result.image);
},
});
scanner.init();
</script>The scanner calls your onScanComplete handler with the finished scan. A hosted scanner is the alternative when you cannot hold a key in the frontend at all: you create the scanner in the dashboard and send the link to whoever should scan.
Credits, limits and errors
- One credit per scan call (crop, rectify, doc_axis_warp). Fifty free credits on signup.
- A thousand scan requests per hour and key. The request above that limit is refused with 429 and a Retry-After header.
- Authentication works with the X-API-Key header, an Authorization Bearer token, or an api_key query parameter. The header is the recommended one.
Typical error responses, in the order you will meet them:
| Status | Meaning | What to do |
|---|---|---|
| 401 | Missing API Key | Send the X-API-Key header. Check for a trailing space in the key. |
| 402 | Insufficient credits | Top up credits in the dashboard. No credits are consumed by a refused request. |
| 400 | Invalid parameter | output_width and segment_count must be integers. |
| 429 | Rate limit | Wait for the seconds given in Retry-After, then retry. No credits are consumed by a refused request. |
{
"errors": [
{ "title": "Missing API Key" }
]
}