Digitalização por API
A digitalização por API transforma um PDF numa cópia digitalizada realista com uma chamada REST, o que serve a fluxos automatizados e integrações em aplicações. Crie o trabalho, envie o PDF e consulte o estado ou espere pelo webhook: três passos, a partir de qualquer ambiente ou linguagem capaz de fazer um pedido HTTP. Espaço de cor, resolução, rotação, desfoque, ruído, brilho, contraste e borda são todos configuráveis.
Como decorre uma chamada
Criar o trabalho
POST /v1/scan-jobs
Envie a sua config e, se quiser, um webhookUrl; recebe um jobID e um uploadURL pré-assinado.
Enviar o PDF
PUT {uploadURL}
Faça PUT do ficheiro diretamente para o endereço S3 pré-assinado do passo anterior — não é preciso token.
Recolher a cópia digitalizada
GET /v1/scan-jobs/{jobID}
Consulte o estado ou espere pelo webhook; assim que o trabalho estiver completed, baixe-a a partir de downloadURL.
Onde se encaixa
Produção em lote no backend
Contratos, faturas e relatórios gerados no servidor passam diretamente pelo efeito de digitalização, sem que ninguém repita o processo à mão na página web.
Dentro de um sistema existente
Acrescente a um CRM, ERP ou sistema de tickets uma ação «exportar cópia digitalizada» que chama a API.
Cadeias de automação
CI, n8n, Zapier e afins iniciam um trabalho a partir de um evento, e no fim o webhook passa a vez ao passo seguinte.
Filas grandes de ficheiros
Os trabalhos são assíncronos: depois de criados, cada um é processado por si, e o progresso fica disponível através de status e createdAfter.
Linguagens e ambientes
A API é HTTP e JSON normais, por isso qualquer linguagem ou plataforma de automação capaz de fazer um pedido consegue chamá-la.
Exemplos de código
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
O token pertence à sua conta e pode ser gerado de novo a qualquer momento. A digitalização por API exige uma conta Pro: sem um token válido a API responde 401 e sem o papel Pro responde 403.
A digitalização por API é uma funcionalidade Pro
Esta conta ainda não tem Pro; depois de mudar, o token aparece aqui. Sem token, ou sem o papel, a API responde 401 / 403.
Experimentar
Ajuste os parâmetros, veja o corpo do pedido mudar com eles e faça as três chamadas à API.
Parâmetros de digitalização
Uma execução de teste chama a API com o seu token e exige uma conta Pro; os parâmetros e o corpo do pedido podem ser consultados à vontade.
{
"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"
}
}Informações do trabalho de digitalização
exemplo{
"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-…"
}Referência da API
| Método | Caminho | Descrição |
|---|---|---|
| POST | /v1/scan-jobs | Cria um trabalho de digitalização. Envie config e, se necessário, webhookUrl; recebe o objeto do trabalho com o estado created e um uploadURL pré-assinado. |
| PUT | {uploadURL}O endereço S3 pré-assinado do passo anterior, que não está em api.lookscanned.io | Envia o PDF de origem com Content-Type: application/pdf e Content-Length. O endereço já traz a própria assinatura, por isso não acrescente o cabeçalho Authorization. |
| GET | /v1/scan-jobs/{jobID} | Lê um único trabalho, para consulta periódica. Em created traz uploadURL; em completed, downloadURL. |
| GET | /v1/scan-jobs | Lista os seus trabalhos, com filtros por jobID, status ou createdAfter. |
401sem token válido403a conta não é Pro404trabalho inexistente
Corpo do pedido
| Campo | Tipo | Predefinição | Descrição |
|---|---|---|---|
| webhookUrl | string · — | — | É chamado uma vez quando o trabalho termina, para não ter de andar a consultar o estado. |
| config.colorspace | 'gray' | 'sRGB' · gray | gray | Espaço de cor da imagem produzida; gray é uma digitalização a preto e branco. |
| config.resolution | number · 72 | 72 | Resolução da imagem produzida, em DPI. |
| config.rotate | number · — | — | Rotação de todo o documento, em graus. |
| config.rotate_var | number · — | — | Amplitude da rotação aleatória de cada página, em graus — o aspeto de uma folha pousada torta. |
| config.blur | number · 0 | 0 | Intensidade do desfoque. |
| config.noise | number · 0 | 0 | Intensidade do ruído. |
| config.brightness | number · 1 | 1 | Brilho; 1 deixa-o inalterado. |
| config.contrast | number · 1 | 1 | Contraste; 1 deixa-o inalterado. |
| config.border | boolean · false | false | Se a página leva uma borda de digitalização. |
| config.output_format | 'image/png' | 'image/jpeg' · image/jpeg | image/jpeg | Formato de imagem em que as páginas são compostas. |
Todos os campos podem ser omitidos. Os valores de partida de «Experimentar» — resolução 150, rotação 1, brilho e contraste 1,3 — são a combinação recomendada pela aplicação web, não as predefinições da API.
Campos do objeto do trabalho a que vale a pena atender
- status
- created / processing / completed / failed — determina se os dois endereços abaixo aparecem.
- uploadURL
- Apenas enquanto está created. Endereço de envio pré-assinado, com prazo de validade.
- downloadURL
- Apenas depois de completed. Endereço de descarregamento pré-assinado, com prazo de validade.
- inputUploadedAt / completedAt
- Quando terminou o envio da origem e quando terminou o trabalho; a diferença é o tempo de processamento.
Perguntas frequentes
A digitalização por API precisa de Pro?
Precisa. Sem um token válido a API responde 401, e uma conta sem o papel Pro recebe 403. Depois de mudar para Pro e iniciar sessão, o token aparece nesta página.
Como sei quando um trabalho termina?
De duas maneiras: consultar GET /v1/scan-jobs/{jobID} periodicamente, ou passar um webhookUrl ao criar o trabalho e deixar que o serviço o contacte uma vez.
O resultado é igual ao da digitalização na página web?
É igual. Ambos usam a mesma implementação do efeito de digitalização, e o espaço de cor, a resolução, a rotação, o desfoque, o ruído, o brilho, o contraste e a borda em config correspondem às opções com o mesmo nome na página web: parâmetros iguais dão resultados iguais. Só muda o sítio onde o trabalho acontece — localmente na página, remotamente através da API.
Posso guardar os endereços de envio e de descarregamento e reutilizá-los?
É melhor não guardar. uploadURL e downloadURL são endereços pré-assinados com prazo; quando expiram é preciso voltar a ler o trabalho para obter novos.
Quanto tempo demora um trabalho?
Depende do número de páginas e da resolução. Poucas páginas costumam ficar prontas em segundos; resoluções mais altas ou documentos mais longos demoram mais. A diferença entre inputUploadedAt e completedAt dá o tempo real.
E se um trabalho falhar?
O estado passa a failed. As causas habituais são um ficheiro que não é um PDF válido, restrições de cifra ou um envio interrompido. Confirme que o ficheiro abre e crie um trabalho novo.
Posso consultar trabalhos anteriores?
Pode. GET /v1/scan-jobs lista os seus trabalhos e aceita filtros por jobID, status e createdAfter, o que chega para conferir contas ou repetir um descarregamento.