API-scan
De API-scan maakt met één REST-aanroep van een PDF een realistisch gescande kopie, wat past bij geautomatiseerde processen en app-integraties. Maak de taak aan, upload de PDF en poll de status of wacht op de webhook: drie stappen, vanuit elke omgeving of taal die een HTTP-verzoek kan versturen. Kleurruimte, resolutie, rotatie, vervaging, ruis, helderheid, contrast en rand zijn allemaal in te stellen.
Zo verloopt een aanroep
De taak aanmaken
POST /v1/scan-jobs
Stuur je config en eventueel een webhookUrl; je krijgt een jobID en een vooraf ondertekende uploadURL terug.
De PDF uploaden
PUT {uploadURL}
Doe een PUT van het bestand rechtstreeks naar het vooraf ondertekende S3-adres uit de vorige stap — zonder token.
De gescande kopie ophalen
GET /v1/scan-jobs/{jobID}
Poll de status of wacht op de webhook; zodra de taak completed is, download je hem via downloadURL.
Waar het past
Bulkuitvoer vanuit de backend
Contracten, facturen en rapporten die op de server ontstaan gaan meteen door het scaneffect, zonder dat iemand dezelfde handeling op de webpagina overdoet.
In een bestaand systeem
Voeg aan een CRM, ERP of ticketsysteem een actie «gescande kopie exporteren» toe die de API aanroept.
Automatiseringsketens
CI, n8n, Zapier en dergelijke starten een taak bij een gebeurtenis, en de webhook geeft na afloop het stokje door aan de volgende stap.
Grote wachtrijen met bestanden
Taken zijn asynchroon: eenmaal aangemaakt wordt elke taak op zichzelf verwerkt, en de voortgang blijft opvraagbaar via status en createdAfter.
Talen en omgevingen
De API is gewoon HTTP en JSON, dus elke taal of automatiseringsplatform dat een verzoek kan versturen, kan hem aanroepen.
Codevoorbeelden
Add Look Scanned API Scan to this project, so I can turn a PDF into a
realistic scanned copy from code.
API docs: https://lookscanned.io/en/scan/api
Write one function that:
1. POST https://api.lookscanned.io/v1/scan-jobs
Header: Authorization: Bearer $LOOKSCANNED_API_TOKEN
Body: {"config": {"colorspace": "gray", "resolution": 150, "rotate": 1}}
It returns jobID and a presigned uploadURL.
2. PUT the PDF bytes to uploadURL with Content-Type: application/pdf.
Send no Authorization header — that URL is already signed.
3. Poll GET /v1/scan-jobs/{jobID} until status is "completed" (or "failed"),
then return downloadURL.
Read the token from the LOOKSCANNED_API_TOKEN environment variable. Use the
language and HTTP client this project already uses, and add one test.interface ScanConfig {
rotate?: number // degrees to rotate the document
rotate_var?: number // degrees to rotate the document randomly
colorspace?: 'gray' | 'sRGB' // the colorspace of the output image
blur?: number // the amount of blur to apply to the image
noise?: number // the amount of noise to apply to the image
border?: boolean // whether to add a border to the image
brightness?: number // the brightness of the image. 1 is no change
contrast?: number // the contrast of the image. 1 is no change
resolution?: number // the resolution of the image in DPI
output_format?: 'image/png' | 'image/jpeg' // the format of the output image
}
interface ScanOptions {
config: ScanConfig
webhookUrl?: string // webhook URL to notify when job is completed
}
interface ScanResponse {
jobID: string // UUID of the scan job
userID: string // UUID of the user who created the job
createdAt: number // timestamp of job creation
status: 'pending' | 'processing' | 'completed' | 'failed'
config: ScanConfig
inputUploadedAt?: number // timestamp when input file was uploaded
completedAt?: number // timestamp when job was completed
webhookUrl?: string // webhook URL for notifications
uploadURL?: string // S3 presigned URL for file upload
downloadURL?: string // S3 presigned URL for file download
}
async function apiScan(pdfBlob: Blob, scanOptions: ScanOptions, token: string): Promise<ScanResponse> {
const response = await fetch('https://api.lookscanned.io/v1/scan-jobs', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(scanOptions)
})
const result: ScanResponse = await response.json()
// PUT PDF Blob to upload URL
const uploadURL = result.uploadURL
await fetch(uploadURL, {
method: 'PUT',
headers: {
'Content-Type': 'application/pdf',
'Content-Length': pdfBlob.size.toString()
},
body: pdfBlob
})
// get scan job status
const jobStatusResponse = await fetch(`https://api.lookscanned.io/v1/scan-jobs/${result.jobID}`, {
headers: {
'Authorization': `Bearer ${token}`
}
})
return await jobStatusResponse.json()
}import requests
def api_scan(pdf_file, scan_options, token):
# Create scan job
response = requests.post(
'https://api.lookscanned.io/v1/scan-jobs',
headers={'Authorization': f'Bearer {token}'},
json=scan_options
)
result = response.json()
# Upload PDF to presigned URL
upload_url = result['uploadURL']
requests.put(
upload_url,
headers={
'Content-Type': 'application/pdf',
'Content-Length': str(len(pdf_file))
},
data=pdf_file
)
# Get scan job status
job_status = requests.get(
f'https://api.lookscanned.io/v1/scan-jobs/{result["jobID"]}',
headers={'Authorization': f'Bearer {token}'}
)
return job_status.json()
# Example usage
if __name__ == "__main__":
with open('document.pdf', 'rb') as f:
pdf_content = f.read()
options = {
'config': {
# Optional parameters:
# 'rotate': 0, # degrees to rotate the document
# 'colorspace': 'gray', # gray or sRGB
# 'resolution': 300, # DPI
# 'rotate_var': 0, # random rotation variance in degrees
# 'blur': 0, # amount of blur
# 'noise': 0, # amount of noise
# 'border': False, # whether to add border
# 'brightness': 1, # 1 is no change
# 'contrast': 1, # 1 is no change
# 'output_format': 'image/png' # image/png or image/jpeg
},
'webhookUrl': 'https://example.com/webhook'
}
result = api_scan(pdf_content, options, 'your-api-token')
print(f"Scan job created with ID: {result['jobID']}")# Set your API token and PDF file as environment variables
export LOOKSCANNED_API_TOKEN='your_api_token_here'
# Create a new scan job
curl -X POST 'https://api.lookscanned.io/v1/scan-jobs' \
-H "Authorization: Bearer ${LOOKSCANNED_API_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{
"config": {
"rotate": 0,
"rotate_var": 1,
"colorspace": "gray",
"blur": 0.2,
"noise": 0.1,
"border": true,
"brightness": 1.0,
"contrast": 1.0,
"resolution": 300,
"output_format": "image/jpeg"
},
"webhookUrl": "https://your-domain.com/webhook"
}'
# Response will include uploadURL and jobID
# {
# "jobID": "550e8400-e29b-41d4-a716-446655440000",
# "userID": "446655440000-e29b-41d4-a716-550e8400",
# "createdAt": 1616161616,
# "status": "created",
# "uploadURL": "...",
# "config": { ... }
# }
# Upload PDF file to the presigned URL
curl -X PUT 'PRESIGNED_UPLOAD_URL' \
-H 'Content-Type: application/pdf' \
-H "Content-Length: PDF_FILE_SIZE" \
--data-binary "@path/to/your/file.pdf"
# Check job status
curl 'https://api.lookscanned.io/v1/scan-jobs/JOB_ID' \
-H "Authorization: Bearer ${LOOKSCANNED_API_TOKEN}"
# Response will include status and downloadURL when completed
# {
# "jobID": "550e8400-e29b-41d4-a716-446655440000",
# "status": "completed",
# "downloadURL": "...",
# ...
# }
# Download the PDF
curl -o scanned.pdf 'DOWNLOAD_URL'API Bearer Token
Het token hoort bij je account en kan altijd opnieuw worden gegenereerd. De API-scan vraagt een Pro-account: zonder geldig token antwoordt de API met 401, en zonder de Pro-rol met 403.
De API-scan is een Pro-functie
Dit account heeft nog geen Pro; na de upgrade staat het token hier. Zonder token, of zonder de rol, antwoordt de API met 401 / 403.
Uitproberen
Stel de parameters in, kijk hoe de request body meebeweegt en doe dan de drie aanroepen naar de API.
Scanparameters
Een proefrun roept de API aan met jouw token en vraagt een Pro-account; de parameters en de request body mag je vrij bekijken.
{
"config": {
"rotate": 1,
"rotate_var": 0.5,
"colorspace": "gray",
"blur": 0,
"noise": 0,
"border": false,
"brightness": 1.3,
"contrast": 1.3,
"resolution": 150,
"output_format": "image/jpeg"
}
}Scantaakinformatie
voorbeeld{
"jobID": "3f9c1e64-0000-4000-8000-00000000a71b",
"userID": "8f21c4b0-0000-4000-8000-000000004a17",
"createdAt": 1724409600,
"status": "completed",
"inputUploadedAt": 1724409601,
"completedAt": 1724409602,
"numPages": 6,
"downloadURL": "https://…/output/3f9c.pdf?X-Amz-…"
}API-referentie
| Methode | Pad | Beschrijving |
|---|---|---|
| POST | /v1/scan-jobs | Maakt een scantaak aan. Stuur config en eventueel webhookUrl; je krijgt het taakobject met status created en een vooraf ondertekende uploadURL terug. |
| PUT | {uploadURL}Het vooraf ondertekende S3-adres uit de vorige stap, niet op api.lookscanned.io | Uploadt de bron-PDF met Content-Type: application/pdf en Content-Length. Het adres draagt zijn eigen handtekening, dus voeg geen Authorization-header toe. |
| GET | /v1/scan-jobs/{jobID} | Leest één taak, voor het pollen. Bij created bevat hij uploadURL, bij completed downloadURL. |
| GET | /v1/scan-jobs | Somt je eigen taken op, te filteren op jobID, status of createdAfter. |
401geen geldig token403het account is geen Pro404taak bestaat niet
Request body
| Veld | Type | Standaard | Beschrijving |
|---|---|---|---|
| webhookUrl | string · — | — | Wordt één keer aangeroepen zodra de taak klaar is, dan hoef je niet te pollen. |
| config.colorspace | 'gray' | 'sRGB' · gray | gray | Kleurruimte van de uitvoerafbeelding; gray is een zwart-witte scan. |
| config.resolution | number · 72 | 72 | Resolutie van de uitvoerafbeelding, in dpi. |
| config.rotate | number · — | — | Rotatie van het hele document, in graden. |
| config.rotate_var | number · — | — | Bereik van de willekeurige rotatie per pagina, in graden — het effect van scheef neergelegd papier. |
| config.blur | number · 0 | 0 | Mate van vervaging. |
| config.noise | number · 0 | 0 | Mate van ruis. |
| config.brightness | number · 1 | 1 | Helderheid; 1 laat die ongewijzigd. |
| config.contrast | number · 1 | 1 | Contrast; 1 laat dat ongewijzigd. |
| config.border | boolean · false | false | Of de pagina een scanrand krijgt. |
| config.output_format | 'image/png' | 'image/jpeg' · image/jpeg | image/jpeg | Afbeeldingsformaat waarin de pagina's worden gerenderd. |
Elk veld mag ontbreken. De beginwaarden van «Uitproberen» — resolutie 150, rotatie 1, helderheid en contrast 1,3 — zijn de combinatie die de webapp aanraadt, niet de standaardwaarden van de API.
Velden in het taakobject om op te letten
- status
- created / processing / completed / failed — bepaalt of de twee adressen hieronder aanwezig zijn.
- uploadURL
- Alleen zolang de taak created is. Een vooraf ondertekend uploadadres dat verloopt.
- downloadURL
- Pas als de taak completed is. Een vooraf ondertekend downloadadres dat verloopt.
- inputUploadedAt / completedAt
- Wanneer de upload van de bron klaar was en wanneer de taak klaar was; het verschil is de verwerkingstijd.
Veelgestelde vragen
Is Pro nodig voor de API-scan?
Ja. Zonder geldig token antwoordt de API met 401, en een account zonder de Pro-rol krijgt 403. Na de upgrade en het inloggen staat het token op deze pagina.
Hoe weet ik wanneer een taak klaar is?
Op twee manieren: poll GET /v1/scan-jobs/{jobID}, of geef bij het aanmaken een webhookUrl mee en laat de dienst je één keer terugbellen.
Is het resultaat hetzelfde als scannen op de webpagina?
Ja. Beide gebruiken dezelfde implementatie van het scaneffect, en kleurruimte, resolutie, rotatie, vervaging, ruis, helderheid, contrast en rand in config zijn de gelijknamige opties van de webpagina: dezelfde parameters geven dezelfde uitvoer. Alleen de plaats van verwerking verschilt — lokaal op de pagina, op afstand via de API.
Kan ik de upload- en downloadadressen bewaren en hergebruiken?
Liever niet. uploadURL en downloadURL zijn vooraf ondertekende adressen met een houdbaarheid; na het verlopen moet je de taak opnieuw opvragen om nieuwe te krijgen.
Hoe lang duurt een taak?
Dat hangt af van het aantal pagina's en de resolutie. Een paar pagina's zijn meestal binnen seconden klaar; een hogere resolutie of een langer document duurt langer. Het verschil tussen inputUploadedAt en completedAt is de werkelijke duur.
Wat als een taak mislukt?
De status wordt failed. De gebruikelijke oorzaken zijn een bestand dat geen geldige PDF is, versleutelingsbeperkingen of een afgebroken upload. Controleer of het bestand opengaat en maak een nieuwe taak aan.
Kan ik eerdere taken opzoeken?
Ja. GET /v1/scan-jobs somt je eigen taken op en laat filteren op jobID, status en createdAfter — genoeg om af te stemmen of iets opnieuw te downloaden.