Scanare prin API
Scanarea prin API transformă un PDF într-o copie cu aspect de scanare printr-un apel REST, potrivit pentru automatizări și integrarea în aplicații. Creează o sarcină, încarcă PDF-ul, apoi verifică periodic starea sau așteaptă notificarea webhook. Sunt trei pași, din orice mediu sau limbaj care poate trimite cereri HTTP. Poți regla spațiul de culoare, rezoluția, rotația, estomparea, zgomotul, luminozitatea, contrastul și chenarele.
Cum funcționează un apel
Creează sarcina
POST /v1/scan-jobs
Trimite configurația și, opțional, un webhookUrl. Primești un jobID și un uploadURL presemnat.
Încarcă PDF-ul
PUT {uploadURL}
Trimite fișierul prin PUT direct la adresa S3 presemnată din pasul anterior. Nu este nevoie de token.
Descarcă copia scanată
GET /v1/scan-jobs/{jobID}
Verifică periodic starea sau așteaptă notificarea webhook. Când sarcina este finalizată, descarcă rezultatul de la downloadURL.
La ce îl poți folosi
Procesare în lot pe server
Aplică efectul de scanare direct contractelor, facturilor și rapoartelor generate pe server, fără să repeți manual operația pe site.
Integrare într-un sistem existent
Adaugă o acțiune de export al unei copii scanate într-un CRM, ERP sau sistem de tichete și conecteaz-o la API.
Fluxuri automatizate
CI, n8n, Zapier și alte instrumente pot porni o sarcină la un anumit eveniment. Notificarea webhook declanșează pasul următor la finalizare.
Cozi mari de fișiere
Sarcinile sunt asincrone: le creezi și fiecare este procesată separat. Poți urmări progresul folosind status și createdAfter.
Limbaje și medii
API-ul folosește HTTP și JSON, deci îl poți apela din orice limbaj sau platformă de automatizare care poate trimite o cerere.
Exemple de cod
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
Tokenul aparține contului tău și îl poți regenera oricând. Scanarea prin API necesită un cont Pro: fără un token valid, API-ul răspunde cu 401, iar fără rolul Pro, cu 403.
Scanarea prin API este o funcție Pro
Acest cont nu are încă Pro. Treci la Pro pentru a vedea tokenul aici. Fără token sau fără rolul necesar, API-ul răspunde cu 401 / 403.
Încearcă API-ul
Reglează parametrii și urmărește cum se actualizează corpul cererii, apoi execută cele trei apeluri API.
Parametri de scanare
Testul apelează API-ul cu tokenul tău și necesită un cont Pro. Poți consulta gratuit parametrii și corpul cererii.
{
"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"
}
}Detaliile sarcinii de scanare
exemplu{
"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-…"
}Referință API
| Metodă | Cale | Descriere |
|---|---|---|
| POST | /v1/scan-jobs | Creează o sarcină de scanare. Trimite config și, opțional, webhookUrl. Primești obiectul sarcinii cu starea created și un uploadURL presemnat. |
| PUT | {uploadURL}Adresa S3 presemnată din pasul anterior, nu o adresă de pe api.lookscanned.io | Încarcă PDF-ul sursă cu Content-Type: application/pdf și Content-Length. Adresa include propria semnătură, deci nu adăuga un antet Authorization. |
| GET | /v1/scan-jobs/{jobID} | Citește o sarcină pentru a-i verifica starea. Cât timp starea este created, obiectul include uploadURL; când este completed, include downloadURL. |
| GET | /v1/scan-jobs | Listează propriile sarcini, filtrate după jobID, status sau createdAfter. |
401token lipsă sau nevalid403contul nu are Pro404sarcina nu există
Corpul cererii
| Câmp | Tip | Valoare implicită | Descriere |
|---|---|---|---|
| webhookUrl | string · — | — | Apelat o singură dată la finalizarea sarcinii, ca să nu fie nevoie să verifici periodic starea. |
| config.colorspace | 'gray' | 'sRGB' · gray | gray | Spațiul de culoare al imaginii rezultate; gray produce o scanare în tonuri de gri. |
| config.resolution | number · 72 | 72 | Rezoluția imaginii rezultate, în DPI. |
| config.rotate | number · — | — | Rotația întregului document, în grade. |
| config.rotate_var | number · — | — | Intervalul rotației aleatorii pentru fiecare pagină, în grade, pentru a imita hârtia așezată ușor strâmb. |
| config.blur | number · 0 | 0 | Intensitatea estompării. |
| config.noise | number · 0 | 0 | Intensitatea zgomotului. |
| config.brightness | number · 1 | 1 | Luminozitate; valoarea 1 o păstrează neschimbată. |
| config.contrast | number · 1 | 1 | Contrast; valoarea 1 îl păstrează neschimbat. |
| config.border | boolean · false | false | Adaugă sau nu un chenar de scanare paginii. |
| config.output_format | 'image/png' | 'image/jpeg' · image/jpeg | image/jpeg | Formatul de imagine în care sunt redate paginile. |
Toate câmpurile sunt opționale. Valorile inițiale din „Încearcă API-ul” (rezoluție 150, rotație 1, luminozitate și contrast 1.3) sunt cele recomandate de aplicația web, nu valorile implicite ale API-ului.
Câmpuri de urmărit în obiectul sarcinii
- status
- created / processing / completed / failed — determină dacă sunt prezente cele două adrese de mai jos.
- uploadURL
- Doar în starea created. O adresă presemnată de încărcare, cu termen de valabilitate.
- downloadURL
- Doar în starea completed. O adresă presemnată de descărcare, cu termen de valabilitate.
- inputUploadedAt / completedAt
- Momentul încheierii încărcării și momentul finalizării sarcinii; diferența reprezintă timpul de procesare.
Întrebări frecvente
Am nevoie de Pro pentru scanarea prin API?
Da. Fără un token valid, API-ul răspunde cu 401, iar pentru un cont fără rolul Pro, cu 403. Treci la Pro și autentifică-te pentru a vedea tokenul pe această pagină.
Cum aflu când s-a terminat o sarcină?
Ai două opțiuni: verifici periodic GET /v1/scan-jobs/{jobID} sau trimiți un webhookUrl la crearea sarcinii, iar serviciul îl apelează o singură dată la finalizare.
Rezultatul este același ca la scanarea pe site?
Da. Ambele folosesc aceeași implementare a efectului de scanare. Spațiul de culoare, rezoluția, rotația, estomparea, zgomotul, luminozitatea, contrastul și chenarul din config corespund opțiunilor de pe site, sub alte nume. Aceiași parametri dau același rezultat. Diferă doar locul procesării: local pe site, pe server prin API.
Pot păstra adresele de încărcare și descărcare pentru a le refolosi?
Nu este recomandat. uploadURL și downloadURL sunt adrese presemnate care expiră. După expirare, citește din nou sarcina pentru a obține adrese noi.
Cât durează o sarcină?
Depinde de numărul de pagini și de rezoluție. Câteva pagini sunt de obicei gata în câteva secunde; rezoluțiile mai mari și documentele mai lungi necesită mai mult timp. Diferența dintre inputUploadedAt și completedAt este timpul efectiv de procesare.
Ce se întâmplă dacă o sarcină eșuează?
Starea devine failed. Cauzele obișnuite sunt un fișier PDF nevalid, restricții de criptare sau o încărcare întreruptă. Verifică dacă fișierul se deschide, apoi creează o sarcină nouă.
Pot consulta sarcinile anterioare?
Da. GET /v1/scan-jobs listează propriile sarcini și permite filtrarea după jobID, status și createdAfter, pentru verificarea evidențelor sau o nouă descărcare.