סריקה דרך API
סריקה דרך API הופכת קובץ PDF לעותק סרוק אמין בקריאת REST אחת, מה שמתאים לתהליכים אוטומטיים ולשילוב באפליקציות. יוצרים משימה, מעלים את ה‑PDF ואז מתשאלים את הסטטוס או ממתינים ל‑webhook: שלושה שלבים, מכל סביבה או שפה שיודעת לשלוח בקשת HTTP. מרחב הצבע, הרזולוציה, הסיבוב, הטשטוש, הרעש, הבהירות, הניגודיות והגבול ניתנים כולם לכוונון.
איך מתנהלת קריאה
יצירת המשימה
POST /v1/scan-jobs
שולחים את ה‑config ואם רוצים גם webhookUrl; בתשובה מתקבלים jobID וכתובת uploadURL חתומה מראש.
העלאת ה‑PDF
PUT {uploadURL}
שולחים את הקובץ ב‑PUT ישירות לכתובת ה‑S3 החתומה מראש מהשלב הקודם — בלי אסימון.
איסוף העותק הסרוק
GET /v1/scan-jobs/{jobID}
מתשאלים את הסטטוס או ממתינים ל‑webhook; ברגע שהמשימה במצב completed מורידים אותה מ‑downloadURL.
למה זה מתאים
הפקה מרובה בצד השרת
חוזים, חשבוניות ודוחות שנוצרים בשרת עוברים ישר דרך אפקט הסריקה, בלי שאיש יחזור על אותה פעולה ידנית בדף האינטרנט.
בתוך מערכת קיימת
מוסיפים ל‑CRM, ל‑ERP או למערכת פניות פעולה של «ייצוא עותק סרוק» ונותנים לה לקרוא ל‑API.
שרשראות אוטומציה
CI, n8n, Zapier ודומיהן מתחילות משימה לפי אירוע, וה‑webhook מעביר את הטיפול לשלב הבא בסיום.
תורים גדולים של קבצים
המשימות אסינכרוניות: אחרי היצירה כל אחת מעובדת בנפרד, וההתקדמות זמינה דרך status ו‑createdAfter.
שפות וסביבות
ה‑API הוא HTTP ו‑JSON רגילים, ולכן כל שפה או פלטפורמת אוטומציה שיודעת לשלוח בקשה יכולה לקרוא לו.
דוגמאות קוד
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
האסימון שייך לחשבון שלך וניתן להפיק אותו מחדש בכל עת. סריקה דרך API מחייבת חשבון Pro: בלי אסימון תקף ה‑API משיב 401, ובלי תפקיד Pro הוא משיב 403.
סריקה דרך API היא יכולת של Pro
החשבון הזה עדיין לא Pro; אחרי השדרוג האסימון מופיע כאן. בלי אסימון, או בלי התפקיד, ה‑API משיב 401 / 403.
התנסות
קבעו את הפרמטרים, ראו את גוף הבקשה משתנה בהתאם, ואז הריצו את שלוש הקריאות מול ה‑API.
פרמטרים של הסריקה
הרצת ניסיון קוראת ל‑API עם האסימון שלך ומחייבת חשבון Pro; את הפרמטרים ואת גוף הבקשה אפשר לעיין בהם בחופשיות.
{
"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"
}
}מידע על משימת הסריקה
דוגמה{
"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
| שיטה | נתיב | תיאור |
|---|---|---|
| POST | /v1/scan-jobs | יוצר משימת סריקה. שולחים config ולפי הצורך גם webhookUrl; בתשובה מתקבל אובייקט המשימה בסטטוס created וכתובת uploadURL חתומה מראש. |
| PUT | {uploadURL}כתובת ה‑S3 החתומה מראש מהשלב הקודם, שאינה נמצאת ב‑api.lookscanned.io | מעלה את קובץ ה‑PDF המקורי עם Content-Type: application/pdf ו‑Content-Length. הכתובת נושאת חתימה משלה, ולכן אין להוסיף כותרת Authorization. |
| GET | /v1/scan-jobs/{jobID} | קורא משימה אחת, לצורך תשאול. בסטטוס created הוא כולל uploadURL, ובסטטוס completed הוא כולל downloadURL. |
| GET | /v1/scan-jobs | מציג את המשימות שלך, עם סינון לפי jobID, status או createdAfter. |
401אין אסימון תקף403החשבון אינו Pro404המשימה אינה קיימת
גוף הבקשה
| שדה | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
| webhookUrl | string · — | — | נקרא פעם אחת כשהמשימה מסתיימת, כך שאין צורך לתשאל אותה. |
| config.colorspace | 'gray' | 'sRGB' · gray | gray | מרחב הצבע של תמונת הפלט; gray הוא עותק סרוק בשחור‑לבן. |
| config.resolution | number · 72 | 72 | רזולוציית תמונת הפלט, ב‑DPI. |
| config.rotate | number · — | — | סיבוב המסמך כולו, במעלות. |
| config.rotate_var | number · — | — | טווח הסיבוב האקראי לכל עמוד, במעלות — המראה של דף שהונח עקום. |
| config.blur | number · 0 | 0 | עוצמת הטשטוש. |
| config.noise | number · 0 | 0 | עוצמת הרעש. |
| config.brightness | number · 1 | 1 | בהירות; הערך 1 משאיר אותה כמות שהיא. |
| config.contrast | number · 1 | 1 | ניגודיות; הערך 1 משאיר אותה כמות שהיא. |
| config.border | boolean · false | false | האם להוסיף לעמוד גבול של סריקה. |
| config.output_format | 'image/png' | 'image/jpeg' · image/jpeg | image/jpeg | פורמט התמונה שאליו העמודים מעובדים. |
אפשר להשמיט כל שדה. הערכים שמהם מתחיל החלק «התנסות» — רזולוציה 150, סיבוב 1, בהירות וניגודיות 1.3 — הם השילוב שיישום האינטרנט ממליץ עליו, ולא ברירות המחדל של ה‑API.
שדות שכדאי לשים לב אליהם באובייקט המשימה
- status
- created / processing / completed / failed — קובע אם שתי הכתובות שלהלן מופיעות.
- uploadURL
- רק כל עוד המשימה במצב created. כתובת העלאה חתומה מראש שתוקפה פג.
- downloadURL
- רק לאחר שהמשימה במצב completed. כתובת הורדה חתומה מראש שתוקפה פג.
- inputUploadedAt / completedAt
- מתי הסתיימה העלאת המקור ומתי הסתיימה המשימה; ההפרש הוא זמן העיבוד.
שאלות נפוצות
האם סריקה דרך API מחייבת Pro?
כן. בלי אסימון תקף ה‑API משיב 401, וחשבון בלי תפקיד Pro מקבל 403. אחרי שדרוג והתחברות האסימון מופיע בדף הזה.
איך אדע שמשימה הסתיימה?
בשתי דרכים: לתשאל את GET /v1/scan-jobs/{jobID}, או להעביר webhookUrl בעת יצירת המשימה ולתת לשירות לפנות אליך פעם אחת.
האם התוצאה זהה לסריקה בדף האינטרנט?
זהה. שני הצדדים משתמשים באותו מימוש של אפקט הסריקה, ומרחב הצבע, הרזולוציה, הסיבוב, הטשטוש, הרעש, הבהירות, הניגודיות והגבול ב‑config הם אותן אפשרויות בדף האינטרנט תחת אותם שמות: אותם פרמטרים נותנים אותה תוצאה. ההבדל היחיד הוא מקום העיבוד — מקומית בדף, ומרחוק דרך ה‑API.
אפשר לשמור את כתובות ההעלאה וההורדה ולהשתמש בהן שוב?
עדיף שלא. uploadURL ו‑downloadURL הן כתובות חתומות מראש בעלות תוקף מוגבל; משפג התוקף צריך לקרוא את המשימה שוב כדי לקבל חדשות.
כמה זמן לוקחת משימה?
תלוי במספר העמודים וברזולוציה. מסמך של כמה עמודים מסתיים בדרך כלל תוך שניות; רזולוציה גבוהה יותר ומסמכים ארוכים יותר לוקחים זמן רב יותר. ההפרש בין inputUploadedAt ל‑completedAt נותן את הזמן בפועל.
מה עושים כשמשימה נכשלת?
הסטטוס משתנה ל‑failed. הסיבות הרגילות הן קובץ שאינו PDF תקין, הגבלות הצפנה או העלאה שנקטעה. ודא שהקובץ נפתח וצור משימה חדשה.
אפשר לצפות במשימות קודמות?
כן. GET /v1/scan-jobs מציג את המשימות שלך ותומך בסינון לפי jobID, status ו‑createdAfter, וזה מספיק להתאמה או להורדה חוזרת.