Developers

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.

Authentication

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).

Endpoints

Three calls cover it.

EndpointWhat 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/packsThe 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.

Response

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.

Accounting sync

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.

Webhooks

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)
Errors

When something's wrong

StatusMeaning
400Unsupported file, unknown or ambiguous document type, or an invalid sync_to.
401Missing, invalid or revoked API key.
403Your plan doesn't include this (API, accounting sync), you've reached a monthly document limit, or the account is suspended.
404The pack isn't available on your account, or the job doesn't exist.