APIスキャン
APIスキャンは、REST 呼び出しで PDF をリアルなスキャンした文書に変換する機能で、自動処理やアプリ連携に向いています。ジョブを作成し、PDF をアップロードして、ステータスをポーリングするか webhook を待つ——この3ステップで、HTTP リクエストを送れる環境や言語ならどれからでも利用できます。色空間、解像度、回転、ぼかし、ノイズ、明るさ、コントラスト、枠線はすべて指定できます。
呼び出しの流れ
ジョブを作成する
POST /v1/scan-jobs
config と、必要なら webhookUrl を送ると、jobID と署名付きの uploadURL が返ります。
PDF をアップロードする
PUT {uploadURL}
前の手順で返された署名付き S3 アドレスへ、ファイルをそのまま PUT します。トークンは不要です。
スキャンした文書を受け取る
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版 のアカウントが必要です。有効なトークンがない場合は 401、Pro版 のロールがない場合は 403 が返ります。
APIスキャンは Pro版 の機能です
このアカウントはまだ Pro版 ではありません。アップグレードすればここにトークンが表示されます。トークンやロールがない場合、API は 401 / 403 を返します。
試してみる
パラメーターを調整するとリクエストボディもそのまま変わります。そのうえで3つの呼び出しを順に実行してみてください。
スキャンのパラメーター
試し実行は自分のトークンで 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 を送ると、status が 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アカウントが Pro版 ではない404ジョブが存在しない
リクエストボディ
| フィールド | 型 | 既定値 | 説明 |
|---|---|---|---|
| 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。下の2つのアドレスが含まれるかどうかを決めます。
- uploadURL
- created のときだけ返る、有効期限付きの署名付きアップロードアドレス。
- downloadURL
- completed になったときだけ返る、有効期限付きの署名付きダウンロードアドレス。
- inputUploadedAt / completedAt
- 元ファイルのアップロード完了時刻とジョブの完了時刻。差が処理時間になります。
よくある質問
APIスキャンに Pro版 は必要ですか?
必要です。有効なトークンがなければ 401、Pro版 のロールがないアカウントには 403 が返ります。アップグレードしてログインすれば、このページでトークンを取得できます。
ジョブが終わったことはどう分かりますか?
方法は2つあります。GET /v1/scan-jobs/{jobID} をポーリングするか、ジョブ作成時に webhookUrl を渡し、完了時にサービスから1回通知させます。
結果はウェブページでのスキャンと同じですか?
同じです。どちらも同一のスキャン効果の実装を使っており、config の色空間・解像度・回転・ぼかし・ノイズ・明るさ・コントラスト・枠線はウェブページの同名の設定に対応します。同じパラメーターなら同じ出力になり、違うのは処理する場所だけです——ページ側はローカル、API はリモートのサービスです。
アップロードとダウンロードのアドレスを保存して使い回せますか?
おすすめしません。uploadURL と downloadURL はどちらも有効期限付きの署名付きアドレスで、期限が切れたらジョブを取得し直して新しいものを受け取る必要があります。
ジョブの処理にはどのくらいかかりますか?
ページ数と解像度によります。数ページなら通常は数秒で終わり、解像度が高いほど、ページ数が多いほど時間がかかります。inputUploadedAt と completedAt の差で実際の所要時間を測れます。
ジョブが失敗したらどうすればいいですか?
ステータスが failed になります。よくある原因は、有効な PDF ではないファイル、暗号化による制限、アップロードの中断です。ファイルが開けることを確認したうえで、新しいジョブを作成してください。
過去のジョブは確認できますか?
できます。GET /v1/scan-jobs で自分のジョブを一覧でき、jobID・status・createdAfter で絞り込めるので、照合や再ダウンロードに使えます。