IDCanopy Developers
Aletheia

Submitting a case

Four ways to get a case package into Aletheia, plus the outbound webhook

A case package is the documents for one applicant, typically an ID, a bank statement, one or more payslips, sometimes a pension notice. Aletheia accepts case packages four ways. All four converge on the same deterministic engine and produce the same ForensicResult schema; auth and error model (ProblemDetails) are identical across them.

PathDirectionSync?Use when
(a) Stateless POST /analyzeclient to us, pushsyncone-shot integrations, demos
(b) Stateful v1 lifecycleclient to us, pushasync-capableuploads over time, separated audit, async batch
(c) ZIP uploadclient to us, pushasync (submit + poll)one signed bundle per case
(d) Outbound result webhookus to client, push,register a callback URL, we POST the verdict on completion

Recommended default: push to us (paths a, b, c) plus register a callback (path d) for async delivery. You do not need to host your documents on a public URL, Aletheia accepts uploads directly.

An inbound URL-fetch option also exists (you host documents at HTTPS URLs and Aletheia fetches them), see below. It is not recommended for new integrations; it puts document hosting, allowlisting, and availability on you. It is offered only where an existing pipeline already serves documents that way.

1. Stateless POST /analyze

One synchronous request, returns the verdict. The simplest integration path.

Required headers: Authorization: Bearer <token>; X-Tenant-ID (Mode B only, optional); Content-Type: multipart/form-data.

Multipart body:

FieldRequiredDescription
filesyes1-15 files, repeat the field name per file. PDF, JPG, PNG, HEIC, TIFF. Max 20 MB each, 50 MB total.
applicant_idnoCaller-supplied label, echoed in the response
case_metanoJSON string of arbitrary metadata, logged in the audit trail

There is no per-doc-type multipart field. All files go into files=. Document type is inferred from the filename stem; filenames that match nothing get an unrecognized_document_type HIGH finding and the rest of the case still processes.

curl -X POST "$ALETHEIA_BASE_URL/analyze" \
  -H "Authorization: Bearer $TOKEN" \
  -F "files=@applicant_passport.pdf" \
  -F "files=@applicant_statement.pdf" \
  -F "applicant_id=CASE-2026-000123"

Status codes: 401 (no/invalid bearer), 413 (body over 50 MB), 422 (validation), 429 (rate-limited, Retry-After header), 500 (ProblemDetails includes trace_id).

2. Stateful v1 lifecycle

Same upload mechanics, split into steps: create the applicant (POST /v1/applicants, duplicate applicant_id returns 409), upload documents (POST /v1/applicants/{id}/documents), run analysis (POST /v1/applicants/{id}/analyze, returns 409 if no documents were uploaded), fetch findings later (GET /v1/applicants/{id}/findings).

An async batch variant (POST /v1/batch/analyze) triggers when the applicant list reaches the tenant's async-batch threshold (default 50); poll GET /v1/batch/jobs/{job_id}.

3. ZIP upload, submit and poll

Submit one .zip holding the full case package. Aletheia unpacks it, infers document type per entry, and analyzes asynchronously: POST /analyze/zip returns a job_id immediately (202 Accepted); poll GET /analyze/zip/{job_id} until status is done (result carries the full ForensicResult) or failed.

Archive rules: entries must be .pdf/.jpg/.jpeg/.png/.heic/.heif/.tif/.tiff; limits are 15 entries, 20 MB per entry, 50 MB total unpacked, 50 MB zip body. Encrypted, empty, nested-zip, path-traversal, and zip-bomb archives are rejected with 422/413.

If you already run your own OCR and hold a third-party audit trail for it, you can send it alongside the ZIP as a multipart metadata part or as a metadata.json entry inside the archive. It is stored and echoed back under intake_metadata in the poll response; the engine still drives the verdict from Aletheia's own extraction.

4. Outbound result webhook

Aletheia POSTs the verdict to a callback URL you register, use this when you'd rather receive the result than poll for it. Configured per tenant with a callback URL and a shared HMAC secret; signed with X-Forensic-Signature (see Webhooks). Retries: 3 attempts with exponential backoff on any non-2xx response; acknowledge with any 2xx.

5. Inbound URL-fetch, optional

Optional, not recommended for new integrations. In this mode you host documents at HTTPS URLs and Aletheia fetches them server-side, with an SSRF host-allowlist, HMAC request signing, and idempotency. The endpoint is POST /v1/integrations/inbound/webhook; the tenant is derived from the bearer key, and enrolment requires a provisioned inbound webhook secret, signed with the X-Inbound-Signature header, see Webhooks. The document host allowlist is registered per tenant during onboarding.

Which path to use

If you are…Use
just integrating and want the simplest path(1) stateless /analyze
uploading documents incrementally or running async batches(2) stateful v1
handing off one signed bundle per case(3) ZIP upload
an async result consumer that prefers callbacks over polling(4) outbound webhook
an AI agent integratorthe MCP server wraps path 1
a pipeline that already serves documents from HTTPS URLs(5) inbound URL-fetch (optional)

On this page