Skanowanie przez API
Skanowanie przez API zamienia PDF w wiarygodną zeskanowaną kopię jednym wywołaniem REST, co sprawdza się w procesach automatycznych i integracjach z aplikacjami. Utwórz zadanie, prześlij PDF, a potem odpytuj status albo poczekaj na webhook — trzy kroki, z dowolnego środowiska i języka, który potrafi wysłać żądanie HTTP. Przestrzeń barw, rozdzielczość, obrót, rozmycie, szum, jasność, kontrast i obramowanie są w pełni konfigurowalne.
Przebieg wywołania
Utwórz zadanie
POST /v1/scan-jobs
Wyślij swoją config i opcjonalnie webhookUrl; w odpowiedzi otrzymasz jobID i podpisany wcześniej uploadURL.
Prześlij PDF
PUT {uploadURL}
Wykonaj PUT pliku prosto na podpisany wcześniej adres S3 z poprzedniego kroku — token nie jest potrzebny.
Odbierz zeskanowaną kopię
GET /v1/scan-jobs/{jobID}
Odpytuj status albo poczekaj na webhook; gdy zadanie ma status completed, pobierz plik spod downloadURL.
Gdzie się przyda
Zbiorcza produkcja po stronie serwera
Umowy, faktury i raporty tworzone na serwerze od razu przechodzą przez efekt skanowania, bez powtarzania tego samego ręcznie na stronie.
Wewnątrz istniejącego systemu
Dodaj do CRM-a, ERP-a lub systemu zgłoszeń akcję „eksportuj zeskanowaną kopię”, która wywołuje API.
Łańcuchy automatyzacji
CI, n8n, Zapier i podobne uruchamiają zadanie na zdarzenie, a webhook po zakończeniu przekazuje pracę dalej.
Duże kolejki plików
Zadania są asynchroniczne: po utworzeniu każde jest przetwarzane osobno, a postęp można sprawdzać przez status i createdAfter.
Języki i środowiska
API to zwykły HTTP i JSON, więc wywoła je każdy język i każda platforma automatyzacji, która potrafi wysłać żądanie.
Przykłady kodu
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
Token należy do Twojego konta i można go w każdej chwili wygenerować ponownie. Skanowanie przez API wymaga konta Pro: bez ważnego tokena API odpowiada 401, a bez roli Pro — 403.
Skanowanie przez API to funkcja Pro
To konto nie ma jeszcze Pro; po przejściu token pojawi się tutaj. Bez tokena albo bez roli API odpowiada 401 / 403.
Wypróbuj
Ustaw parametry, obserwuj, jak zmienia się treść żądania, a potem wykonaj trzy wywołania do API.
Parametry skanowania
Przebieg próbny wywołuje API Twoim tokenem i wymaga konta Pro; parametry i treść żądania możesz oglądać swobodnie.
{
"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"
}
}Informacje o zadaniu skanowania
przykład{
"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-…"
}Dokumentacja API
| Metoda | Ścieżka | Opis |
|---|---|---|
| POST | /v1/scan-jobs | Tworzy zadanie skanowania. Wyślij config i opcjonalnie webhookUrl; w odpowiedzi otrzymasz obiekt zadania ze statusem created i podpisany wcześniej uploadURL. |
| PUT | {uploadURL}Podpisany wcześniej adres S3 z poprzedniego kroku, który nie znajduje się na api.lookscanned.io | Przesyła źródłowy PDF z nagłówkami Content-Type: application/pdf i Content-Length. Adres ma własny podpis, więc nie dodawaj nagłówka Authorization. |
| GET | /v1/scan-jobs/{jobID} | Odczytuje pojedyncze zadanie, na potrzeby odpytywania. Przy created zawiera uploadURL, przy completed — downloadURL. |
| GET | /v1/scan-jobs | Wypisuje Twoje zadania z filtrami po jobID, status i createdAfter. |
401brak ważnego tokena403konto nie jest Pro404zadanie nie istnieje
Treść żądania
| Pole | Typ | Domyślnie | Opis |
|---|---|---|---|
| webhookUrl | string · — | — | Wywoływany raz po zakończeniu zadania, więc nie trzeba go odpytywać. |
| config.colorspace | 'gray' | 'sRGB' · gray | gray | Przestrzeń barw obrazu wynikowego; gray to czarno-biała zeskanowana kopia. |
| config.resolution | number · 72 | 72 | Rozdzielczość obrazu wynikowego w DPI. |
| config.rotate | number · — | — | Obrót całego dokumentu w stopniach. |
| config.rotate_var | number · — | — | Zakres losowego obrotu każdej strony w stopniach — wrażenie krzywo położonej kartki. |
| config.blur | number · 0 | 0 | Siła rozmycia. |
| config.noise | number · 0 | 0 | Siła szumu. |
| config.brightness | number · 1 | 1 | Jasność; 1 nie zmienia nic. |
| config.contrast | number · 1 | 1 | Kontrast; 1 nie zmienia nic. |
| config.border | boolean · false | false | Czy dodać stronie obramowanie skanu. |
| config.output_format | 'image/png' | 'image/jpeg' · image/jpeg | image/jpeg | Format obrazu, do którego renderowane są strony. |
Każde pole można pominąć. Wartości początkowe w sekcji „Wypróbuj” — rozdzielczość 150, obrót 1, jasność i kontrast 1,3 — to zestaw zalecany przez aplikację webową, a nie wartości domyślne API.
Pola obiektu zadania warte uwagi
- status
- created / processing / completed / failed — decyduje o tym, czy poniższe dwa adresy w ogóle się pojawiają.
- uploadURL
- Tylko dopóki zadanie ma status created. Podpisany wcześniej adres przesyłania, który wygasa.
- downloadURL
- Dopiero po statusie completed. Podpisany wcześniej adres pobierania, który wygasa.
- inputUploadedAt / completedAt
- Kiedy zakończyło się przesyłanie źródła i kiedy zakończyło się zadanie; różnica to czas przetwarzania.
Najczęstsze pytania
Czy skanowanie przez API wymaga Pro?
Tak. Bez ważnego tokena API odpowiada 401, a konto bez roli Pro dostaje 403. Po przejściu na Pro i zalogowaniu token pojawia się na tej stronie.
Skąd wiadomo, że zadanie się skończyło?
Na dwa sposoby: odpytywać GET /v1/scan-jobs/{jobID} albo przekazać webhookUrl przy tworzeniu zadania i pozwolić usłudze zgłosić się raz po zakończeniu.
Czy wynik jest taki sam jak przy skanowaniu na stronie?
Taki sam. Obie drogi korzystają z tej samej implementacji efektu skanowania, a przestrzeń barw, rozdzielczość, obrót, rozmycie, szum, jasność, kontrast i obramowanie w config odpowiadają opcjom o tych samych nazwach na stronie: te same parametry dają ten sam wynik. Różni się tylko miejsce przetwarzania — lokalnie na stronie, zdalnie przez API.
Czy mogę zapisać adresy przesyłania i pobierania i używać ich ponownie?
Lepiej nie. uploadURL i downloadURL to podpisane wcześniej adresy o ograniczonej ważności; po wygaśnięciu trzeba ponownie odczytać zadanie, żeby dostać nowe.
Jak długo trwa zadanie?
Zależy od liczby stron i rozdzielczości. Kilka stron zwykle kończy się w kilka sekund, a wyższa rozdzielczość i dłuższe dokumenty zajmują więcej czasu. Różnica między inputUploadedAt a completedAt to rzeczywisty czas.
Co zrobić, gdy zadanie się nie powiedzie?
Status zmienia się na failed. Najczęstsze przyczyny to plik, który nie jest poprawnym PDF-em, ograniczenia szyfrowania albo przerwane przesyłanie. Sprawdź, czy plik się otwiera, i utwórz nowe zadanie.
Czy mogę sprawdzić wcześniejsze zadania?
Tak. GET /v1/scan-jobs wypisuje Twoje zadania i pozwala filtrować po jobID, status i createdAfter, co wystarcza do uzgodnienia albo ponownego pobrania.