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.

Base URLhttps://api.parsinglab.blue-iq.ai
EndpointWhat it does
POST /resume/parseSubmit one document. Returns a job_id.
GET /resume/job/{job_id}Poll a job until it reaches a terminal status.
POST /resume/upload-urlGet a presigned URL for a direct upload.
POST /resume/parse-uploadedParse a file already uploaded via that URL.
POST /resume/batchSubmit up to 200 documents in one request.
GET /resume/batch/{batch_id}Poll a batch.
POST /resume/{job_id}/retryRe-run a parse.
POST /resume/{job_id}/feedbackSend corrections back.
POST /webhooksRegister a delivery endpoint.
GET /webhooksList your endpoints.
DELETE /webhooks/{webhook_id}Remove one.
GET /healthService and dependency status.
01

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.

02

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
CodeMeaning
MISSING_API_KEYNo X-API-Key header was sent.
INVALID_API_KEYThe key is not recognised.
REVOKED_API_KEYThe key was revoked in the dashboard.
ACCOUNT_DEACTIVATEDThe workspace is disabled.
03

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"
FieldMeaning
fileThe document. Required.
force_textractSkip 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"
}
Every parse is asynchronous. This endpoint used to return the record inline for digital PDFs and DOCX. It no longer does, for any file type. If your integration reads data from the POST response, switch it to polling or a webhook. The old async_only flag is ignored.
04

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.

StatusMeaning
processingStill working. Poll again.
completedDone. data and confidence are populated.
partialDegraded. Some data recovered; check warnings before trusting it.
failedCould not parse. error explains why.
Results expire. The jobs table carries a TTL, so a 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.
05

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.

FieldWhat it holds
dataThe record. Every section is present; empty ones are empty, not missing.
confidence.overall0-1 across the whole record.
confidence.catalog_mappingHow much of the record resolved to platform ids.
partialtrue when the parse degraded. Treat the record as reviewable.
warningsHuman-readable caveats, e.g. a duty list that looks short.
06

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":"..."}'
07

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"
08

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"}'
EventFires when
parse.completedA single parse finished successfully.
parse.failedA single parse failed.
batch.completedEvery file in a batch reached a terminal status.

Verifying a delivery

Each request carries three headers. Recompute the signature over the raw body:

HeaderValue
X-Signaturesha256=<hex> - HMAC-SHA256 of the raw body, keyed with your endpoint secret.
X-TimestampUnix timestamp of the delivery.
X-EventThe event name from the table above.
A 401 is never retried. If your endpoint rejects a delivery as unauthorised we treat that as a deliberate refusal and drop it. Return 2xx once you have verified the signature; use 5xx if you want the delivery retried.
09

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.

10

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."
  }
}
CodeHTTPMeaning
MISSING_API_KEY401No X-API-Key header on the request.
INVALID_API_KEY401The key is not recognised.
REVOKED_API_KEY401The key was revoked in the dashboard.
ACCOUNT_DEACTIVATED403The workspace is disabled.
FILE_TOO_LARGE413Over the 10 MB per-file limit.
UNSUPPORTED_FILE_TYPE415Not a PDF, DOCX, RTF, PNG, JPG or TIFF.
CORRUPTED_FILE422The bytes did not match the declared type.
EMPTY_BATCH422A batch request with no files.
BATCH_TOO_LARGE413Over 200 files or 60 MB in one batch.
JOB_NOT_FOUND404Unknown job_id, or the result has expired.
BATCH_NOT_FOUND404Unknown batch_id.
WEBHOOK_NOT_FOUND404Unknown webhook_id.
RETRY_LIMIT_REACHED429This job has been retried too many times.
EXTRACTION_FAILED422No text could be read from the file.
OCR_FAILED422OCR could not read the scan.
PARSE_FAILED500The parse stage failed after extraction.
VALIDATION_ERROR422A field on the request did not validate.
11

Limits


LimitValue
File size10 MB per document
Batch size200 files per request
Batch payload60 MB per request
FormatsPDF, DOCX, RTF, PNG, JPG, TIFF
Job resultsExpire 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.