Proof of Address API
Extract and validate a Proof of Address document — utility bills, bank statements, and government-issued documents — in one call. Returns the issuer, issue/expiry dates, the holder name, the raw and parsed/geocoded address, an Approved/Declined status, and a warnings list explaining every issue found.
Latency. Extraction is LLM-based: typical calls take 5–15 seconds, multi-page PDFs up to ~30 seconds. Configure a client timeout of at least 45 seconds and do not retry before the call completes.
How it works. The document (image or PDF, up to 15 MB; encrypted PDFs require document_password) is classified into a document type and subtype (e.g. UTILITY_BILL / WATER_BILL), and the issuer, dates, holder name, and address are extracted with LLM-based extraction. The address is parsed and geocoded into poa_parsed_address. PDF/EXIF forensics screen for tampering — modification after digital signing, known PDF editors, overlay-text manipulation, suspicious re-exports — surfacing SUSPECTED_DOCUMENT_MANIPULATION or DOCUMENT_METADATA_MISMATCH. Document age is validated against poa_document_age_months, and the language against poa_languages_allowed. If you pass expected_address, expected_country, or expected_first_name/expected_last_name, the extracted values are cross-checked and mismatches are flagged.
Decision logic. status is Approved unless at least one warning resolves to a decline. Hard failures always decline: MISSING_ADDRESS_INFORMATION, POA_DOCUMENT_EXPIRED, INVALID_DOCUMENT_TYPE, UNABLE_TO_VALIDATE_DOCUMENT_AGE, plus UNABLE_TO_EXTRACT_ISSUE_DATE and POA_NAME_NOT_DETECTED (not configurable on this endpoint). Five risk groups are configurable per request via the poa_*_action options (DECLINE or NO_ACTION, all defaulting to DECLINE). POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION and UNPARSABLE_OR_INVALID_ADDRESS are informational on this endpoint and never decline. A document that cannot be processed at all returns 400; a readable but problematic document returns 200 with status: "Declined" — always inspect poa.status and poa.warnings, not just the HTTP code.
Billing. Each 200 response consumes one Proof of Address API credit (standalone APIs have no free tier). When the organization’s balance cannot cover the call, the endpoint returns 403 with the not-enough-credits error before any document processing.
Session persistence (save_api_request, default true). When true, the call is persisted as an API-type session: it appears in the Business Console, the uploaded document is stored, the returned request_id is a real session id you can pass to GET /v3/session/{sessionId}/decision/ (the decision additionally exposes document_file and the document_metadata forensics, which this response omits), and a status.updated webhook is emitted. When false, nothing is stored and request_id is a one-off correlation UUID that cannot be looked up later.
Sandbox. Sandbox API keys skip all processing and billing: after request validation (malformed input still returns 400), the endpoint returns a static Approved mock payload (a fictional “Sandbox Power Co.” electricity bill), no session is persisted, and no credits are consumed.
Authentication. Send your application’s API key in the x-api-key header. Missing or invalid credentials return 403 ({"detail": "You do not have permission to perform this action."}) — this API never returns 401.
Rate limit. Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns 429.
Note: FUTURE_ISSUE_DATE and POOR_DOCUMENT_QUALITY exist in workflow sessions but are never produced by this standalone endpoint — a future-dated document is not auto-declined here.
Authorizations
Body
The Proof of Address document. Allowed extensions: tiff, jpg, jpeg, png, pdf, webp. Maximum upload size: 15 MB (larger files are rejected with 400). Multi-page PDFs are supported (expect higher latency); encrypted PDFs require document_password. Images are automatically compressed before processing.
Password to decrypt document when it is an encrypted PDF. Sending an encrypted PDF without (or with a wrong) password returns 400.
Address to verify against the document. It is geocoded and compared with the extracted address; a mismatch (or an expected address that cannot be geocoded/verified) adds ADDRESS_MISMATCH_WITH_PROVIDED, governed by poa_address_mismatch_action. The geocoded form is echoed back in expected_details_formatted_address / expected_details_parsed_address.
"Av. Monseñor Tavella 1291, Salta, Argentina"
Country to verify against the document (ISO 3166-1 code, e.g. ARG or AR). A mismatch with the document's country adds POA_COUNTRY_MISMATCH_WITH_PROVIDED, governed by poa_address_mismatch_action.
"ARG"
First name to verify against name_on_document (fuzzy match, transliteration-aware). A score below the match threshold adds NAME_MISMATCH_WITH_PROVIDED, governed by poa_address_mismatch_action.
"Sophia"
Last name to verify against name_on_document, combined with expected_first_name for the match score.
"Martinez"
Comma-separated list of accepted document languages as ISO 639-1 codes (e.g. en,es,fr). When omitted or blank, all 51 supported languages are accepted. A document in a language outside the list adds UNSUPPORTED_DOCUMENT_LANGUAGE (governed by poa_unsupported_language_action); an unknown code in the list returns 400 with the full set of supported codes.
"en,es"
Comma-separated key:value pairs setting the maximum document age in months per document type — keys: utility_bill, bank_statement, government_issued_document, other_poa_document; values: 1–120, or -1 for unlimited (no age check). Defaults when omitted: utility_bill:3,bank_statement:3,government_issued_document:12,other_poa_document:12. A document older than its limit declines with POA_DOCUMENT_EXPIRED. Caution: when you provide this field, list every type you accept — omitted types are treated as not accepted (informational POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION) and their age check is skipped.
"utility_bill:3,bank_statement:6"
Accepted but currently not applied — name-mismatch warnings (NAME_MISMATCH_WITH_PROVIDED) follow poa_address_mismatch_action instead. Set poa_address_mismatch_action to control both name and address mismatch behavior.
DECLINE, NO_ACTION What to do on file-integrity problems — in practice only DOCUMENT_METADATA_MISMATCH is produced by this endpoint.
DECLINE, NO_ACTION What to do when document manipulation is suspected (SUSPECTED_DOCUMENT_MANIPULATION) — e.g. the PDF was modified after digital signing, processed by a known PDF editor, shows overlay-text manipulation, or has inconsistent EXIF dates.
DECLINE, NO_ACTION What to do when the document language is outside poa_languages_allowed (UNSUPPORTED_DOCUMENT_LANGUAGE).
DECLINE, NO_ACTION What to do when the extracted details disagree with the expected_* fields: ADDRESS_MISMATCH_WITH_PROVIDED, NAME_MISMATCH_WITH_PROVIDED, and POA_COUNTRY_MISMATCH_WITH_PROVIDED all follow this action.
DECLINE, NO_ACTION What to do when no issuing company/organization can be identified on the document (ISSUER_NOT_IDENTIFIED).
DECLINE, NO_ACTION When true (default), persists the call as an API-type session — visible in the Business Console, retrievable via GET /v3/session/{sessionId}/decision/ using the returned request_id, announced through a status.updated webhook, and with the uploaded document stored. When false, nothing is stored and request_id is a transient UUID for response correlation only.
true
Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.
"user-123"
Optional JSON object stored with the session (when save_api_request=true) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. metadata={"flow":"onboarding"}) — it is parsed into an object.
{ "flow": "onboarding" }Response
Document processed. poa.status is Approved or Declined; every detected issue is itemized in poa.warnings. An expired, mismatched, or suspicious document still returns 200 with status: "Declined" — inspect the body, not just the HTTP code. When save_api_request=true, request_id is the persisted session id.
Persisted session id when save_api_request=true (usable with GET /v3/session/{sessionId}/decision/); otherwise a transient correlation UUID.
Echo of the vendor_data you sent, or null.
Echo of the metadata object you sent, or null.
ISO 8601 timestamp (UTC) of when the response was generated.