AsyncReducto with progress tracking and error handling.
Sample Dataset
We’ll use the Northwind Invoices dataset from Hugging Face, which contains 831 PDF invoices. Each invoice includes customer information, line items, and totals.
Create API Key
1
Open Studio
Go to studio.reducto.ai and sign in. From the home page, click API Keys in the left sidebar.

2
View API Keys
The API Keys page shows your existing keys. Click + Create new API key in the top right corner.

3
Configure Key
In the modal, enter a name for your key and set an expiration policy (or select “Never” for no expiration). Click Create.

4
Copy Your Key
Copy your new API key and store it securely. You won’t be able to see it again after closing this dialog.
Set the key as an environment variable:

Download the Dataset
First, download the Northwind invoices dataset using the Hugging Face libraries:Process the Batch
Document processing is network-bound, not CPU-bound. While your code waits for one API response, it could be uploading and processing other documents. Python usesAsyncReducto with asyncio, while JavaScript uses Promise.all() with the p-limit package for concurrency control.
Extract Structured Data
To extract specific fields like invoice numbers, totals, and line items, use the Extract API with a schema:Cost Optimization with Job Chaining
Parse once, extract multiple times. When you need different extractions from the same documents, reuse the parse job ID to avoid re-parsing:Handling Failures
Add retry logic with exponential backoff to handle transient network errors:Monitoring Job Status
When using webhooks or async jobs, you can poll for job status:For production workloads, prefer webhooks over polling. Webhooks are more efficient and don’t require keeping connections open.
Why Concurrency Control?
The semaphore (asyncio.Semaphore in Python, p-limit in JavaScript) limits how many requests run simultaneously. Without it, submitting 831 files would create 831 concurrent connections, overwhelming both your system and the API. The concurrency limiter acts as a queue, letting only max_concurrency requests proceed at once.
| File Size | Recommended Concurrency |
|---|---|
| Small (< 5 pages) | 50-100 |
| Medium (5-50 pages) | 20-50 |
| Large (50+ pages) | 10-20 |
Fire-and-Forget with Webhooks
For very large batches where you don’t want to wait for results, use webhooks. Submit all jobs immediately and receive results as they complete via HTTP callbacks.client.job.get(job_id).
Sync Alternative (Python)
If you can’t use async in Python, use threading with the synchronousReducto client.
This section is Python-specific. The JavaScript SDK is async by default—all methods return Promises and work naturally with
async/await and Promise.all(). No threading is needed in JavaScript.