Form Fill
API reference for the form filling endpoints
Form Fill
Fill PDF forms with AI-powered field detection.
Enterprise plans. A request from another plan is refused with
402naming the plan that has it — the same body as every plan-gated feature (documented under the status codes in the OCR reference).
POST /v1/form-fill
Upload a PDF form and field data for AI-powered filling.
Endpoint
POST https://api.deepread.tech/v1/form-fill
Authentication
Include your API key in the X-API-Key header:
X-API-Key: YOUR_API_KEY
Request
Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | multipart/form-data |
Request Body (Multipart)
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | PDF form to fill |
form_fields | string | Yes | JSON object with field names and values |
webhook_url | string | No | URL to receive job completion notifications |
idempotency_key | string | No | Unique key to prevent duplicate submissions |
url_expires_in | integer | No | Signed URL expiration in seconds (default: 604800 = 7 days, min: 3600, max: 604800) |
Example Request
curl -X POST https://api.deepread.tech/v1/form-fill \ -H "X-API-Key: $DEEPREAD_API_KEY" \ -F "file=@application_form.pdf" \ -F 'form_fields={"full_name": "John Doe", "date_of_birth": "1990-01-15", "ssn": "123-45-6789", "address": "123 Main St", "city": "New York", "state": "NY", "zip": "10001"}' \ -F "webhook_url=https://your-app.com/webhooks/form-fill"Response
Success Response (200 OK)
{ "id": "550e8400-e29b-41d4-a716-446655440000", "status": "queued" }
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique job identifier (UUID) |
status | string | Initial job status (queued) |
Status Codes
| Code | Description |
|---|---|
200 | Job created successfully; with an idempotency_key seen before, the job that request created |
400 | Invalid input (bad JSON, unsupported file type, or a PDF over the plan's page cap) |
401 | Invalid or missing API key |
402 | Form fill is not on the plan, or the credits do not cover the job; the body names what is needed |
413 | File over the plan's size cap (15 MB on Free, 50 MB on Standard, 500 MB on Enterprise) or the hard maximum |
429 | Submissions per minute, pages in flight, or the Free monthly allowance exceeded; Retry-After says when to try again |
500 | Internal server error |
503 | The API key could not be checked because our database did not answer; retry after Retry-After (5 s). A bad key is 401 |
GET /v1/form-fill/{job_id}
Retrieve the status and results of a form fill job.
Endpoint
GET https://api.deepread.tech/v1/form-fill/{job_id}
Authentication
X-API-Key: YOUR_API_KEY
Path Parameters
| Parameter | Type | Description |
|---|---|---|
job_id | UUID | The job ID returned from POST /v1/form-fill |
Example Request
curl https://api.deepread.tech/v1/form-fill/550e8400-e29b-41d4-a716-446655440000 \ -H "X-API-Key: $DEEPREAD_API_KEY"Response
Success Response (200 OK)
{ "id": "550e8400-e29b-41d4-a716-446655440000", "status": "completed", "file_name": "application_form.pdf", "created_at": "2024-01-15T10:30:00Z", "completed_at": "2024-01-15T10:30:08Z", "filled_form_url": "https://storage.deepread.tech/filled/abc123.pdf", "fields_detected": 12, "fields_filled": 10, "fields_verified": 10, "fields_hil_flagged": 0, "duration_seconds": 8.5, "report": { ... }, "errors": [] }
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Job identifier |
status | string | queued, processing, completed, or failed |
file_name | string | Original uploaded file name |
created_at | string | ISO 8601 timestamp |
completed_at | string | ISO 8601 timestamp (null if not completed) |
filled_form_url | string | Signed URL to download filled PDF (when completed) |
fields_detected | integer | Number of form fields found |
fields_filled | integer | Number of fields that received values |
fields_verified | integer | Number of fields that passed QA |
fields_hil_flagged | integer | Number of fields flagged for human review |
duration_seconds | number | Processing time |
report | object | Detailed processing report |
errors | array | List of error messages (if any) |
error_message | string | Error description (if status is failed) |
Status Codes
| Code | Description |
|---|---|
200 | Job found |
401 | Invalid or missing API key |
404 | Job not found |
429 | Polling limit for the plan (Free 20 a minute, Standard 60, Enterprise 150); Retry-After says when to try again |
Idempotency
Use the idempotency_key parameter to prevent duplicate form fills:
curl -X POST https://api.deepread.tech/v1/form-fill \ -H "X-API-Key: $DEEPREAD_API_KEY" \ -F "file=@application_form.pdf" \ -F 'form_fields={"full_name": "John Doe"}' \ -F "idempotency_key=user-123-form-456-2024-01-15"If a job with the same idempotency key already exists, the API returns the existing job instead of creating a new one.
Webhooks
When you provide a webhook_url, DeepRead sends a POST request when the job completes:
{ "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "completed", "created_at": "2024-01-15T10:30:00Z", "completed_at": "2024-01-15T10:30:08Z", "result": { "filled_form_url": "https://storage.deepread.tech/filled/abc123.pdf", "fields_detected": 12, "fields_filled": 10, "fields_verified": 10, "fields_hil_flagged": 0, "report": { ... } } }
For failed jobs:
{ "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "failed", "created_at": "2024-01-15T10:30:00Z", "error": "Unable to detect form fields in document", "errors": ["..."] }
Rate Limits
Limits are per plan. Past a limit the request is refused with 429 and a Retry-After header saying when to try again.
| Plan | POST /v1/form-fill per minute | GET /v1/form-fill/{job_id} per minute |
|---|---|---|
| Free | 10 | 20 |
| Standard | 100 | 60 |
| Enterprise | 500 | 150 |
A form-fill job counts its pages towards the account's pages in flight (16 on Free, 200 on Standard, 500 on Enterprise), shared with OCR and PII redaction jobs. No document over 2,000 pages or 500 MB is accepted on any plan (413).
Response headers include:
X-RateLimit-Limit: Maximum requests per periodX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Unix timestamp when limit resets