Blue-IQ Capture API
Send a document, get back structured JSON with a confidence score on every field. One flow for every file: submit, then poll or take a webhook. Nothing parses on the request path, so a call never blocks and never trips a gateway timeout.
https://api.parsinglab.blue-iq.ai| Endpoint | What it does |
|---|---|
| POST /resume/parse | Submit one document. Returns a job_id. |
| GET /resume/job/{job_id} | Poll a job until it reaches a terminal status. |
| POST /resume/upload-url | Get a presigned URL for a direct upload. |
| POST /resume/parse-uploaded | Parse a file already uploaded via that URL. |
| POST /resume/batch | Submit up to 200 documents in one request. |
| GET /resume/batch/{batch_id} | Poll a batch. |
| POST /resume/{job_id}/retry | Re-run a parse. |
| POST /resume/{job_id}/feedback | Send corrections back. |
| POST /webhooks | Register a delivery endpoint. |
| GET /webhooks | List your endpoints. |
| DELETE /webhooks/{webhook_id} | Remove one. |
| GET /health | Service and dependency status. |
Quickstart
Three calls: get a key, submit a file, poll until it is done.
# 1. Submit
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/resume/parse" \
-H "X-API-Key: rp_live_your_key" \
-F "file=@resume.pdf"
# -> { "job_id": "01J3K...", "status": "processing",
# "poll_url": "/api/v1/resume/job/01J3K..." }
# 2. Poll until status is terminal
curl "https://api.parsinglab.blue-iq.ai/api/v1/resume/job/01J3K..." \
-H "X-API-Key: rp_live_your_key"Generate a key in the dashboard. It is shown once, so copy it then. Use it only from your server.
Authentication
Every request carries your key in the X-API-Key header. There are no other auth schemes on the parsing endpoints.
X-API-Key: rp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| Code | Meaning |
|---|---|
| MISSING_API_KEY | No X-API-Key header was sent. |
| INVALID_API_KEY | The key is not recognised. |
| REVOKED_API_KEY | The key was revoked in the dashboard. |
| ACCOUNT_DEACTIVATED | The workspace is disabled. |
Parse a document
POST /api/v1/resume/parse with multipart/form-data and one file field. Accepts PDF, DOCX, RTF, PNG, JPG and TIFF up to 10 MB.
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/resume/parse" \
-H "X-API-Key: rp_live_your_key" \
-F "file=@resume.pdf" \
-F "force_textract=false"| Field | Meaning |
|---|---|
| file | The document. Required. |
| force_textract | Skip Tesseract and use AWS Textract for any OCR this file needs. Higher accuracy on hard scans, higher cost. Default false. |
The response is immediate and never contains the parsed record:
{
"job_id": "01J3K5M2N4P6Q8R0S2T4U6V8W0",
"status": "processing",
"poll_url": "/api/v1/resume/job/01J3K5M2N4P6Q8R0S2T4U6V8W0"
}data from the POST response, switch it to polling or a webhook. The old async_only flag is ignored.Poll the job
GET /api/v1/resume/job/{job_id} until status is terminal. A sensible loop polls every 2 seconds and gives up after a couple of minutes.
| Status | Meaning |
|---|---|
| processing | Still working. Poll again. |
| completed | Done. data and confidence are populated. |
| partial | Degraded. Some data recovered; check warnings before trusting it. |
| failed | Could not parse. error explains why. |
job_id is not a permanent handle and an old one returns JOB_NOT_FOUND. Store anything you need to keep on your side as soon as you receive it.The parsed record
A completed job returns the record under data, per-section scores under confidence, and any caveats under warnings.
{
"job_id": "01J3K...",
"status": "completed",
"data": {
"personal_info": { "full_name": "Jane Smith", "email": "jane@example.com",
"phone": "865-541-1111", "credentials": ["RN", "BSN"] },
"experience": [
{ "company": "Fort Sanders Regional Medical Center",
"role": "RN - Med Surg/Tele",
"start_date": "01/2022", "end_date": "Present",
"city": "Knoxville", "state": "TN", "state_id": "42",
"profession": "RN", "profession_id": "1",
"specialties": [
{ "name": "Med Surg/Tele", "specialty_id": "88", "confidence": 1.0 }
],
"description": ["Charge nurse on a 30-bed telemetry unit"] }
],
"education": [{ "institution": "University of Tennessee",
"degree": "BSN", "graduation_year": 2021 }],
"certifications": [{ "name": "BLS", "issued_date": "01/2024" }],
"licenses": [{ "license_type": "RN", "state": "TN", "is_compact": true }]
},
"confidence": { "overall": 0.9, "experience": 1.0, "catalog_mapping": 0.8 },
"partial": false,
"warnings": []
}Reading the scores
Each specialty, profession and location resolves to a platform id with its own confidence. An unresolved id comes back null rather than a guess, so routing on specialty_id === null is a reliable review trigger.
| Field | What it holds |
|---|---|
| data | The record. Every section is present; empty ones are empty, not missing. |
| confidence.overall | 0-1 across the whole record. |
| confidence.catalog_mapping | How much of the record resolved to platform ids. |
| partial | true when the parse degraded. Treat the record as reviewable. |
| warnings | Human-readable caveats, e.g. a duty list that looks short. |
Large files
For anything near the request limit, upload straight to storage and hand back the key. Two calls: ask for a presigned URL, PUT the bytes, then parse it.
# 1. Ask for somewhere to put it
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/resume/upload-url" \
-H "X-API-Key: rp_live_your_key" \
-H "Content-Type: application/json" \
-d '{"filename":"scan.pdf"}'
# 2. PUT the bytes at the returned URL, then:
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/resume/parse-uploaded" \
-H "X-API-Key: rp_live_your_key" \
-H "Content-Type: application/json" \
-d '{"upload_id":"..."}'Batch
POST /api/v1/resume/batch takes up to 200 files, or 60 MB across the whole request, whichever comes first. It returns 202 with a batch_id; poll GET /api/v1/resume/batch/{batch_id} for per-file status.
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/resume/batch" \
-H "X-API-Key: rp_live_your_key" \
-F "files=@one.pdf" -F "files=@two.docx"Webhooks
Register an endpoint and skip polling entirely. Every active endpoint receives every event, and each registration gets its own signing secret.
curl -X POST "https://api.parsinglab.blue-iq.ai/api/v1/webhooks" \
-H "X-API-Key: rp_live_your_key" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-app.example.com/hooks/capture"}'| Event | Fires when |
|---|---|
| parse.completed | A single parse finished successfully. |
| parse.failed | A single parse failed. |
| batch.completed | Every file in a batch reached a terminal status. |
Verifying a delivery
Each request carries three headers. Recompute the signature over the raw body:
| Header | Value |
|---|---|
| X-Signature | sha256=<hex> - HMAC-SHA256 of the raw body, keyed with your endpoint secret. |
| X-Timestamp | Unix timestamp of the delivery. |
| X-Event | The event name from the table above. |
Retry & feedback
POST /api/v1/resume/{job_id}/retry re-runs a parse, for a job that failed on something transient. Repeated retries return RETRY_LIMIT_REACHED.
POST /api/v1/resume/{job_id}/feedback sends corrections back and returns 202. Corrections a reviewer makes are what improve extraction over time, so it is worth wiring up if you have a review step.
Errors
Every error returns the same shape, with a stable machine-readable code. Branch on the code, not the message.
{
"error": {
"code": "UNSUPPORTED_FILE_TYPE",
"detail": "Only PDF, DOCX, RTF, PNG, JPG and TIFF are accepted."
}
}| Code | HTTP | Meaning |
|---|---|---|
| MISSING_API_KEY | 401 | No X-API-Key header on the request. |
| INVALID_API_KEY | 401 | The key is not recognised. |
| REVOKED_API_KEY | 401 | The key was revoked in the dashboard. |
| ACCOUNT_DEACTIVATED | 403 | The workspace is disabled. |
| FILE_TOO_LARGE | 413 | Over the 10 MB per-file limit. |
| UNSUPPORTED_FILE_TYPE | 415 | Not a PDF, DOCX, RTF, PNG, JPG or TIFF. |
| CORRUPTED_FILE | 422 | The bytes did not match the declared type. |
| EMPTY_BATCH | 422 | A batch request with no files. |
| BATCH_TOO_LARGE | 413 | Over 200 files or 60 MB in one batch. |
| JOB_NOT_FOUND | 404 | Unknown job_id, or the result has expired. |
| BATCH_NOT_FOUND | 404 | Unknown batch_id. |
| WEBHOOK_NOT_FOUND | 404 | Unknown webhook_id. |
| RETRY_LIMIT_REACHED | 429 | This job has been retried too many times. |
| EXTRACTION_FAILED | 422 | No text could be read from the file. |
| OCR_FAILED | 422 | OCR could not read the scan. |
| PARSE_FAILED | 500 | The parse stage failed after extraction. |
| VALIDATION_ERROR | 422 | A field on the request did not validate. |
Limits
| Limit | Value |
|---|---|
| File size | 10 MB per document |
| Batch size | 200 files per request |
| Batch payload | 60 MB per request |
| Formats | PDF, DOCX, RTF, PNG, JPG, TIFF |
| Job results | Expire on a TTL - store what you need |
GET /api/v1/health reports service status and dependency health (DynamoDB, S3, the async worker) if you want to monitor it.