Skip to main content

Overview

Proof-of-address (POA) verification emits warnings on poa_verifications[].warnings[] for every quality, authenticity, or matching issue detected during extraction and forensic analysis. Each warning is a Warning object with feature set to "PROOF_OF_ADDRESS". A handful of risks always force Declined; the rest follow a per-risk action (DECLINE / REVIEW / NO_ACTION) configured on your workflow. Every risk below is verified against the live decision pipeline; the exact short and long description strings are reproduced verbatim in the tables.
POA extraction introduces a 5–15 second latency per document. Warnings are written only when the workflow step completes; do not poll faster than every 5 s.

Two production paths

POA warnings are produced on two different paths, and the risk set differs between them:
  • Workflow sessions (the POA step inside a verification session) — the upload endpoint first runs blocking validation with a retry loop (see Retry behavior), then the final stored warnings are computed by check_poa_risks plus the multi-document name check.
  • Standalone API (POST /v3/poa/) — warnings come from check_poa_risks only. There is no retry loop, no verified-ID context, and only one document, so NAME_MISMATCH_ID_VERIFICATION, POA_NAME_MISMATCH_BETWEEN_DOCUMENTS, POA_MAX_ATTEMPTS_EXCEEDED, and FUTURE_ISSUE_DATE are never produced by the standalone API. The pre-extraction validation errors are discarded on this path.
POOR_DOCUMENT_QUALITY is defined in the risk enum and reserved in the action mapping, but no code path in the POA pipeline produces it — it never appears in warnings[] on either path. Do not branch on it.

Auto-decline warnings (always force Declined)

These risks are in AUTO_DECLINE_RISKS; when logged, the POA status is Declined regardless of configuration, and log_type is always error.
RiskCauseRecommended remediation
MISSING_ADDRESS_INFORMATIONNo address could be extracted from the document.Ask the user to resubmit a document that clearly shows their address.
POA_DOCUMENT_EXPIREDThe document is older than the configured maximum age for its type. Defaults: 3 months for UTILITY_BILL and BANK_STATEMENT, 12 months for GOVERNMENT_ISSUED_DOCUMENT and OTHER_POA_DOCUMENT (a month counts as 30 days; -1 disables the check). additional_data carries max_age_months, document_type, document_subtype, and issue_date.Ask the user for a more recent document, or raise age_months for that type.
INVALID_DOCUMENT_TYPEThe document could not be classified into any supported POA type (document_type falls back to UNKNOWN).Ask the user to resubmit; check the file is not corrupted.
UNABLE_TO_VALIDATE_DOCUMENT_AGEThe document-age check itself failed (error while computing the expiration from the issue date).Ask the user for a document with a clearly readable issue date.
FUTURE_ISSUE_DATE is also listed in AUTO_DECLINE_RISKS, but it has a single producer in pre-extraction validation (an issue date more than 7 days in the future) whose errors only feed the workflow retry loop — it surfaces as a blocking upload error there, is never produced by the standalone API, and is not written to warnings[]. See Retry behavior.

Configurable warnings

Each of these follows an action knob on the workflow’s POA node (DECLINE / REVIEW / NO_ACTION). The warning’s log_type mirrors the configured action: error for Decline, warning for Review, information for No action.
RiskCauseAction knobDefault
NAME_MISMATCH_WITH_PROVIDEDThe name on the document scores below poa_name_match_score_threshold (default 86) against the name supplied at session creation (expected_details).poa_name_or_address_mismatch_actionReview
NAME_MISMATCH_ID_VERIFICATIONThe name on the document scores below the threshold against the verified ID document. additional_data: { poa_name, kyc_name, match_score }. Workflow sessions only.poa_name_or_address_mismatch_actionReview
ADDRESS_MISMATCH_WITH_PROVIDEDThe extracted address differs from the address supplied via API, or either address could not be verified as a residential address.poa_name_or_address_mismatch_actionReview
POA_COUNTRY_MISMATCH_WITH_PROVIDEDThe document’s country does not match the country supplied via API (ISO-3 normalised). additional_data: { expected_country, extracted_country }.poa_name_or_address_mismatch_actionReview
POA_NAME_MISMATCH_BETWEEN_DOCUMENTSTwo or more POA documents in the same session carry different names. additional_data includes both node IDs, both names, and the match score. Workflow sessions only.poa_name_or_address_mismatch_actionReview
DOCUMENT_METADATA_MISMATCHThe file is empty (file_size 0) or its EXIF dates are malformed.poa_document_issues_actionReview
SUSPECTED_DOCUMENT_MANIPULATIONForensics found manipulation evidence — modification after digital signing (is_tampered), overlay-text manipulation (with additional_data.manipulated_regions rectangles), a known PDF editor, inconsistent EXIF dates, or a suspicious re-export. additional_data.detection_method names the check that fired.poa_document_authenticity_actionDecline
UNSUPPORTED_DOCUMENT_LANGUAGEThe document’s language is not in poa_languages_allowed.poa_unsupported_language_actionDecline
POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATIONThe detected document type is not enabled in poa_documents_allowed for the document’s country, or its subtype is explicitly disabled.poa_unsupported_document_type_actionDecline
ISSUER_NOT_IDENTIFIEDThe issuing institution could not be identified from the document.poa_issuer_not_identified_actionReview
UNABLE_TO_EXTRACT_ISSUE_DATENo valid issue date could be located on the document.poa_issue_date_not_detected_actionReview
POA_NAME_NOT_DETECTEDNo name was detected on the document.poa_issue_date_not_detected_action (shared knob)Review
UNPARSABLE_OR_INVALID_ADDRESSAn address was extracted but could not be parsed and geocoded into a valid residential address.poa_unparsable_or_invalid_address_actionReview
POA_MAX_ATTEMPTS_EXCEEDEDThe user exhausted poa_max_retry_attempts (default 2) in the workflow retry loop. additional_data: { attempts }. Workflow sessions only.poa_max_attempts_exceeded_actionDecline
There is one shared action for all name and address mismatches: poa_name_or_address_mismatch_action covers both name risks, both address risks, and the cross-document name check — you cannot configure name and address mismatch behavior separately. On the standalone API the same group follows the poa_address_mismatch_action request option (the poa_name_mismatch_action option is accepted but never read).

Standalone API differences (POST /v3/poa/)

The standalone endpoint builds the same risk-to-action mapping but with request-level options that only accept DECLINE or NO_ACTION (all defaulting to DECLINE):
  • UNABLE_TO_EXTRACT_ISSUE_DATE and POA_NAME_NOT_DETECTED are hard-coded to Decline on this endpoint.
  • POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION and UNPARSABLE_OR_INVALID_ADDRESS are informational here — their actions default to No action and are not configurable per request.
  • FUTURE_ISSUE_DATE, POOR_DOCUMENT_QUALITY, NAME_MISMATCH_ID_VERIFICATION, POA_NAME_MISMATCH_BETWEEN_DOCUMENTS, and POA_MAX_ATTEMPTS_EXCEEDED are never produced — a future-dated document is not auto-declined on this endpoint.
See the POST /v3/poa/ API reference for the request options.

Retry behavior (workflow sessions)

In a verification session, the POA upload step runs blocking validation before the document is accepted. When it finds a blocking error — INVALID_DOCUMENT_TYPE, UNABLE_TO_EXTRACT_ISSUE_DATE, FUTURE_ISSUE_DATE, POA_NAME_NOT_DETECTED, MISSING_ADDRESS_INFORMATION, POA_COUNTRY_MISMATCH_WITH_PROVIDED, POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION, UNSUPPORTED_DOCUMENT_LANGUAGE, or POA_DOCUMENT_EXPIRED — the upload is rejected with 400 and the risk code as the message, and the user can try again with a better document. Once the user has burned poa_max_retry_attempts attempts (default 2, configurable 2–5), the submission is accepted anyway: the stored warnings are recomputed from the saved document, POA_MAX_ATTEMPTS_EXCEEDED is appended, and the status is resolved from the full risk set. This is why FUTURE_ISSUE_DATE can block an upload yet never appears in warnings[].

Configurable settings

The workflow’s POA node exposes these knobs (matching VerificationSettings fields):
SettingControlsDefault
poa_name_or_address_mismatch_actionNAME_MISMATCH_WITH_PROVIDED, NAME_MISMATCH_ID_VERIFICATION, ADDRESS_MISMATCH_WITH_PROVIDED, POA_COUNTRY_MISMATCH_WITH_PROVIDED, POA_NAME_MISMATCH_BETWEEN_DOCUMENTSReview
poa_document_issues_actionDOCUMENT_METADATA_MISMATCHReview
poa_document_authenticity_actionSUSPECTED_DOCUMENT_MANIPULATIONDecline
poa_unsupported_language_actionUNSUPPORTED_DOCUMENT_LANGUAGEDecline
poa_unsupported_document_type_actionPOA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATIONDecline
poa_issuer_not_identified_actionISSUER_NOT_IDENTIFIEDReview
poa_issue_date_not_detected_actionUNABLE_TO_EXTRACT_ISSUE_DATE, POA_NAME_NOT_DETECTEDReview
poa_unparsable_or_invalid_address_actionUNPARSABLE_OR_INVALID_ADDRESSReview
poa_max_attempts_exceeded_actionPOA_MAX_ATTEMPTS_EXCEEDEDDecline
poa_documents_allowedPer-country accepted document types, each with enabled and age_months (-1 = unlimited); per-subtype overrides via document_subtypes_config.Utility bill and bank statement: 3 months; government-issued and other: 12 months
poa_languages_allowedAccepted document languages.All supported languages
poa_name_match_score_thresholdMinimum name-match score (0–100) before the NAME_MISMATCH* risks fire.86
poa_max_retry_attemptsUpload attempts before the retry loop gives up (2–5).2

Name matching logic

POA name matching tolerates common variations:
  • Middle names and initials are matched leniently (presence/absence is allowed).
  • Candidate names — every name detected on the document (name_on_document plus additional_names) is scored, and the best-scoring candidate is kept.
  • Match threshold — the default poa_name_match_score_threshold is 86; a score below it fires the relevant NAME_MISMATCH* warning.
The numeric scores are exposed on the report as name_match_score_expected_details and name_match_score_id_verification (0–100). Score values are useful for fine-grained review even when no warning has been raised.

Examples

Overlay manipulation (Decline by default)

{
  "warnings": [
    {
      "feature": "PROOF_OF_ADDRESS",
      "risk": "SUSPECTED_DOCUMENT_MANIPULATION",
      "additional_data": {
        "reason": "Overlay-text manipulation detected: same base font embedded with multiple subset prefixes on 1 page(s).",
        "detection_method": "overlay_text_manipulation",
        "signals": ["duplicate_font_subset", "glyph_fragmentation"],
        "duplicate_font_subsets": [{ "page": 1, "base_font": "Helvetica" }],
        "fragmented_fonts": [],
        "manipulated_regions": [
          { "page": 1, "x": 102.4, "y": 318.1, "width": 187.0, "height": 18.0, "page_width": 595, "page_height": 842 }
        ]
      },
      "log_type": "error",
      "short_description": "Suspected document manipulation",
      "long_description": "The system detected signs of potential document manipulation or editing.",
      "node_id": "feature_poa_1"
    }
  ]
}

Expired document + missing address (auto-decline)

{
  "warnings": [
    {
      "feature": "PROOF_OF_ADDRESS",
      "risk": "POA_DOCUMENT_EXPIRED",
      "additional_data": {
        "max_age_months": 3,
        "document_subtype": "ELECTRICITY_BILL",
        "document_type": "UTILITY_BILL",
        "issue_date": "2025-11-02"
      },
      "log_type": "error",
      "short_description": "Document expired",
      "long_description": "The submitted document is older than 90 days from its issue date, which exceeds the acceptable time period for validity.",
      "node_id": "feature_poa_1"
    },
    {
      "feature": "PROOF_OF_ADDRESS",
      "risk": "MISSING_ADDRESS_INFORMATION",
      "additional_data": null,
      "log_type": "error",
      "short_description": "Missing address information",
      "long_description": "The document does not contain complete or clear address information that can be extracted.",
      "node_id": "feature_poa_1"
    }
  ]
}

Name mismatch (Review by default)

{
  "warnings": [
    {
      "feature": "PROOF_OF_ADDRESS",
      "risk": "NAME_MISMATCH_ID_VERIFICATION",
      "additional_data": {
        "poa_name": "JOHN B SMYTH",
        "kyc_name": "John A. Smith",
        "match_score": 60
      },
      "log_type": "warning",
      "short_description": "Name mismatch with ID verification",
      "long_description": "The full name on the document does not match the name from the user's verified identity documents.",
      "node_id": "feature_poa_1"
    }
  ]
}

Warning types