Flonk
Flonk Docs

Proof of Address

How the Proof of Address (PoA) step works, when to wait for it in real time, and what your end users see.

Last updated: 8/19/2026
5 min read

Proof of Address (PoA)

PoA is an optional verification step that asks the user to upload a document confirming their residential address — a utility bill, bank statement, or a letter from a government authority. The widget extracts the name and address from the document with a vision-language model and reconciles them against the identity document the user already submitted.

This page explains the two settings on the Settings → PoA tab and what your end user experiences for each combination.

Settings overview

SettingWhat it does
Enable PoA verificationAdds the PoA step to the widget flow. When off, the widget skips the step and verification finishes after the identity document.
Wait for PoA result in real timeDecides whether the widget waits for the PoA review before showing the user a final decision, or whether it completes KYC immediately and delivers the PoA outcome later via webhook.

Both toggles are per-environment (Live / Sandbox), so you can experiment in Sandbox without affecting your live flow.

"Wait for PoA result in real time" — explained

This is the toggle that most often surprises integrators, so it is worth walking through carefully.

Toggle ON — synchronous

When the toggle is on, the widget pauses after the user uploads the PoA file and waits for the address review to finish before completing the verification. The end user sees a single processing screen and then the final decision.

  • Typical wait: 40 seconds to 3 minutes for most documents.
  • Worst-case wait: up to ~15 minutes during peak load (rare).
  • End-user experience: one progress card, then the verification result. No second visit to your app required.
  • Webhook timing: verification.completed is fired once, after both the identity document and the PoA have been reviewed. Its payload already contains the final outcome.

Pick this mode when:

  • You want the user to see the verification outcome on screen before they leave your funnel.
  • Your funnel cannot easily resume after the user has navigated away (for example, a one-page sign-up that gates account creation on the result).

Toggle OFF — asynchronous

When the toggle is off, the widget treats PoA as a background task. The KYC session is marked complete as soon as the identity document and face checks finish; the PoA review happens server-side afterwards.

  • End-user experience: the user sees the verification finish immediately after the identity step and can leave your app right away.
  • Webhook timing: you receive the standard verification.completed webhook for the identity / face decision. When the PoA review finishes, the verification record is updated and a follow-up webhook is fired with the PoA status (auto_approved, manual_review, or rejected) and confidence score on the verification object.
  • Server load: absorbed entirely on our side — your user never waits.

Pick this mode when:

  • Your funnel can deal with an asynchronous decision (for example, you send an email when the user is fully verified).
  • You optimise for the lowest perceived completion time.

What the end user sees while waiting

When Wait for PoA result in real time is on, the widget shows a processing card with a circular brand loader, the document name, a calm progress message, and a small "Usually takes about 1–3 minutes" hint. Copy is intentionally non-alarming — we do not show the 15-minute upper bound on screen so that occasional slow runs don't trigger abandonment.

After ~5 minutes the message switches to a softer "A bit busier than usual — your document is in the queue and will be reviewed shortly" without naming a specific time. The session itself stays open up to 15 minutes; if the model has not produced a result by then, the verification will be marked as manual_review and a moderator handles it.

PoA fields on the verification object

After PoA runs (whether sync or async), the verification record exposes the following data:

{
"poaStatus": "auto_approved",
"poaConfidenceScore": 0.91,
"documents": [
{
"type": "poa",
"fileName": "poa_<attemptId>",
"signedUrl": "https://flonk-id.t3.storage.dev/...",
"extractedData": {
"fullName": "KOVALENKO OLEKSANDR",
"address": "Ukraine, region Kyivska, ...",
"city": "Kyiv",
"postalCode": "04080",
"country": "Ukraine",
"documentType": "registration document",
"issueDate": "10.04.2021",
"issuer": "4620",
"poaStatus": "auto_approved",
"poaConfidenceScore": 0.91
}
}
]
}
json

poaStatus values:

StatusMeaning
auto_approvedAddress extracted with high confidence and matches the identity document.
manual_reviewConfidence below the auto-approve threshold; queued for a human moderator.
rejectedCross-validation failed (different name on PoA vs. identity document) or the document was unreadable.
pendingStill being processed (only seen briefly in the async mode).

Webhook reference

  • Sync mode (toggle ON): the regular verification.completed webhook already includes the final PoA fields. No follow-up event is emitted purely for PoA.
  • Async mode (toggle OFF): verification.completed fires after the identity step. When PoA finishes, verification.updated is dispatched with the same payload shape — your handler should look at data.object.poaStatus to react.

See the Webhooks page for signature verification and event-handling boilerplate.

Common questions

Will my user be charged for the wait time? No. PoA does not consume an additional verification credit by itself; it is a sub-step of the regular KYC verification.

Can I switch between sync and async per session? Not currently. The toggle is project-wide per environment. If you need session-level control, contact support.

What file types are accepted? PDF, PNG, JPG, JPEG up to 10 MB. PDFs are rendered on our side; the user does not need to convert them.

What happens if the user's PoA is rejected? The verification record is marked rejected for PoA but the identity verification result is independent — your poaStatus === 'rejected' handler decides whether to allow the user to retry or to fail the whole flow.