Send a document. Get checked JSON back.
The same extraction, confidence scores and missing-information routing as the app, over a simple HTTP API. API access is included on the Team plan and Enterprise.
API keys
Company admins create keys in the app under API & integrations. Keys are shown once; send them as Authorization: Bearer <key> (or an X-API-Key header).
Three calls cover it.
| Endpoint | What it does |
|---|---|
| POST /v1/extract/{pack}/{document_type} | Upload one document as multipart form data (file). Use auto as the document type to detect it. Optional: wait (0–60 seconds) to get the result in the same response, and sync_to. |
| GET /v1/jobs/{id} | The result: status, every field with its value and confidence, validation, what's missing or doubtful with who owns it, and the resolved counterparty. |
| GET /v1/packs | The packs and document types your account can use. |
curl -X POST https://api.lumenglobalsourcing.com/v1/extract/logistics/commercial_invoice \ -H "Authorization: Bearer $LUMEN_API_KEY" \ -F file=@invoice.pdf \ -F wait=30
curl https://api.lumenglobalsourcing.com/v1/jobs/JOB_ID \ -H "Authorization: Bearer $LUMEN_API_KEY"
Logistics document types: commercial_invoice, bill_of_lading, packing_list, arrival_notice, purchase_order. Files can be PDF, JPG or PNG up to 25 MB; clean digital PDFs work best.
What comes back
status is processing, needs_info, ready_for_review, approved, rejected or failed. Extraction never skips review: data is marked approved only after a person approves it in the app.
{
"id": "5f0c2b1e-…",
"pack": "logistics",
"document_type": "commercial_invoice",
"status": "needs_info",
"overall_confidence": 0.86,
"fields": {
"invoice_number": { "value": "INV-2847", "confidence": 0.97 },
"exporter.name": { "value": "Cascade Fabrication Co.", "confidence": 0.95 },
"incoterms": { "value": null, "confidence": 0.0 },
"line_items": [
{ "hs_code": { "value": "8504.40", "confidence": 0.93 }, "…": "…" }
]
},
"validation": { "total_mismatch": false, "blocking_issues": [] },
"missing_or_doubtful": [
{
"field": "incoterms", "label": "Incoterms", "reason": "absent",
"detail": null, "confidence": 0.0,
"owner_role": "supplier", "scope": "external", "urgency": "normal"
}
],
"counterparty": {
"role": "supplier", "email": "billing@cascade.example",
"name": "Cascade Fabrication Co.", "source": "extracted"
},
"sync": null,
"error": null,
"review_url": "https://app.lumenglobalsourcing.com/intelligence/review/5f0c2b1e-…"
}Abbreviated example.
sync_to
Add sync_to=quickbooks when you upload an Accounts Payable document and it's pushed to the connected QuickBooks company as soon as a person approves it. The job's sync object reports awaiting_approval, queued, succeeded or failed.
Signed events
Add endpoints under API & integrations to receive document.sync.succeeded and document.sync.failed. Each request carries Lumen-Signature: t=<unix time>,v1=<hex HMAC-SHA256 of "t.body"> using your endpoint's secret. Failed deliveries are retried with backoff.
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
parts = dict(item.split("=", 1) for item in header.split(","))
timestamp, signature = int(parts["t"]), parts["v1"]
if abs(time.time() - timestamp) > tolerance:
return False
signed = f"{timestamp}.".encode() + body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)When something's wrong
| Status | Meaning |
|---|---|
| 400 | Unsupported file, unknown or ambiguous document type, or an invalid sync_to. |
| 401 | Missing, invalid or revoked API key. |
| 403 | Your plan doesn't include this (API, accounting sync), you've reached a monthly document limit, or the account is suspended. |
| 404 | The pack isn't available on your account, or the job doesn't exist. |