The Proof of Address (PoA) solution automates the verification of end-user addresses by capturing and extracting data from documents such as bank statements and utility bills.
The system validates document type and issue date, extracts name and address information, and provides this data via API or Veriff Customer Portal.
It is available via API, web flow, and native SDKs. The flow is set up via Workflows in the Veriff Customer Portal.
Contact your solutions engineer for info and configuration.
Prerequisites
You have an integration set up with Veriff
The Proof of Address check is configured for that integration by your Solutions Engineer
You have configured the decision webhook to get responses from Veriff (see the how-to in webhooks’ Set up webhooks section)
If using the API, you are ready to collect and send Veriff your end-user’s data and document images
Veriff strongly recommends that you create and send us the endUserId or vendorData
Define acceptable document types
To add more flexibility to the solution, you can define which document types are accepted to perform the verification.
You can pass them when creating a session with POST /sessions, using the proofOfAddress.acceptableTypes
array.
→ See the Supported document types article for more info
Flow overview
The flow is a bit different, depending on the method you are using to verify your end-users with Veriff.
Proof of Address Extraction
In this case, data is extracted from the end-user’s document.
Generate a using the API keys and the BaseURL of your PoA integration (see the API Documentation and API Reference[↗] how to find these)
You can use the
proofOfAddress.acceptableTypes
array to define which types of PoA documents the integration accepts
Capture end-user’s PoA document images with Veriff’s SDKs
Send the end-user through the verification flow to capture the image (using the preferred Veriff SDK)
You need the session URL generated in step 1 to use the SDKs (found in response payload as
verification.url
)
Session will be submitted automatically once the end-user takes and submits necessary images of their document
Receive the results from Veriff via decision webhook
1. Create a session using the POST /sessions call
1.1 Include the API URL and mandatory headers
POST {baseURL}/v1/sessions
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
Content-Type: application/json
1.2 Add the following data (minimum payload)
verification
:object
Verification object*. You can send an empty object, or:define the acceptable document types with:
proofOfAddress.acceptableTypes
array, defining them in thename
string(s)
include the following to improve the results:
vendorData
:string
endUserId:
string
include the
person.firstName
andperson.lastName
to do the name match
*Mandatory parameter
Request payload sample
curl -X POST \
--url '/v1/sessions/' \
-H 'Content-Type: application/json' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-d '{
"verification": {
"person": {
"firstName": "John",
"lastName": "Smith",
},
"proofOfAddress": {
"acceptableTypes": [
"name": "UTILITY_BILL",
"name": "TAX_DOCUMENT",
"name": "PHONE_BILL",
]
},
"endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4"
}
}'
→ See the POST /sessions[↗] endpoint documentation for further details about how to start a session
2. Make a POST /sessions/{sessionId}/media request
Send only one image per verification session. Make sure that the value of image.context
parameter of the image is document-front
.
2.1 Include the API URL and mandatory headers
POST {baseURL}/v1/sessions/{sessionId}/media
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json
2.2 Add the following data into the minimum payload
image
:object
*context
:string
* In this case, it must bedocument-front
content
:string
* Base64 encoded image (.jpg, .jpeg, .png, .heif, .heic, .webp and .pdf formats are supported)
*Required parameter
Request payload sample
curl -X POST \
--url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
-H 'Content-Type: application/json' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
-d '{
"image": {
"context": "document-front",
"content": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+.../9fgAEAKcxisFjVfn0AAAAASUVORK5CYII="
}
}'
→ See the POST /sessions/{sessionId}/media[↗] endpoint documentation for further details about how to send media files
3. Update the session status to submitted
using the PATCH /sessions/{sessionId} call
submitted
using the PATCH /sessions/{sessionId} call3.1 Include the API URL and mandatory headers
PATCH {baseURL}/v1/sessions/{sessionId}
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json
3.2 Add the following data (minimum payload)
verification
:object
*status
:string
* Status of the verification session you are patching the session into, alwayssubmitted
*Required parameter
Request payload sample
curl -X PATCH \
--url '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8' \
-H 'Content-Type: application/json' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-H 'X-HMAC-SIGNATURE: dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0' \
-d '{
"verification": {
"status": "submitted"
}
}'
Once done, an event webhook with submitted
status will be sent.
Wait for the session to be approved and decision webhook to send response (see the webhook payload subsection below)
Now you can use the following API calls to query the document info:
GET /sessions/{sessionId}/media[↗] to get a list of media objects and address media with the
sessionId
GET /attempts/{attemptId}/media[↗] to get a list of media objects and address media with the attempt ID
GET /media/{mediaId}[↗] to get a media file with the
mediaId
Find decision and/or session related info
You can get the data from three sources:
Receive the decision webhook
Query the results via GET sessions/{sessionId}/decision
View the session in Veriff Customer Portal
Webhook payload
Below are a sample and an explanation of a decision webhook payload for a minimal Proof of Address Verification.
Depending on your solution, the payload may contain additional parameters. To find more info about it, see the decision webhook documentation.
Sample request
{
"status": "success",
"verification": {
"id": "ab1c2345-678d-4e3b-98a3-a75b00b715kj",
"attemptId": "c6cab5b0-c506-47a6-922d-6ae3b72ca172",
"code": 9001,
"person": {
"gender": null,
"idNumber": null,
"lastName": null,
"addresses": [
{
"fullAddress": "Jaan Koorti 777,
99999 Tallinn, Estonia"
}
],
"firstName": "Jane Doe",
"citizenship": null,
"dateOfBirth": null,
"nationality": null,
"yearOfBirth": null,
"placeOfBirth": null,
"pepSanctionMatch": null
},
"reason": null,
"status": "approved",
"comments": [],
"document": {
"type": null,
"number": null,
"country": null,
"validFrom": "2023-11-25",
"validUntil": null
},
"reasonCode": null,
"vendorData": null,
"endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
"decisionTime": "2024-01-23T10:31:05.293000Z",
"acceptanceTime": "2024-01-23T10:25:40.026Z",
"additionalVerifiedData": {
"proofOfAddress": {
"documentType": "UTILITY_BILL",
"nameMatch": true,
"nameMatcPercentage": 100.00
},
},
}
"technicalData": {
"ip": null
}
Request properties explained
*Required field
status
:string
* Status of the responseverification
:object
* Verification request decision object.null
if decision is not available yetid
:string
* UUID v4 which identifies the verification sessionattemptId
:string
* UUID v4 of the attempt which received a status (as shown inverification.status
field)vendorData
:string | null
* The unique identifier that you created for your end-user.null
if not specifiedendUserId
:string | null
* TheUUID
that you created for your end-user.null
if not specifiedstatus
:string
* Verification status, one ofapproved
,declined
,resubmission_requested
,review
,expired
,abandoned
code
:integer
* Verification session decision code, one of9001
,9102
,9103
,9104
,9121
. For more info, see the verification session decision codesreason
:string | null
Reason why the verification failed, only sent when the verification failedreasonCode
:integer | null
Reason code of the failed verification, only sent when the verification failed. For more info, see the possible codes for a failed verificationdecisionTime
:string
* Timestamp of the decision, represented asUTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset
(ISO 8601)acceptanceTime
:string
* Timestamp of the session generation, represented asUTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset
(ISO 8601)person
:object
* Data about the verified persongender
:string | null
* Person’s gender, represented as M or F, ornull
if not presentidNumber
:string | null
* National identification numberlastName
:string | null
*null
, unless prefilled by the customeraddresses
:array
* Array of person's addressesfullAddress
:string
Address as a single string
firstName
:string | null
* Person's first name as written on the document, if availabledateOfBirth
:string
* Person’s date of birth, represented asYYYY-MM-DD
nationality
:string | null
* Person's nationalityyearOfBirth
:string | null
* Person’s year of birth, represented asYYYY
placeOfBirth
:string | null
* Person's place of birthpepSanctionMatch
:string | null
* Legacy field, may return incorrect result, should be ignoredcitizenship
:string | null
* Deprecated, always returns null
document
:object
* Verified documenttype
:string | null
Document typenumber
:string | null
Document number,[a-zA-Z0-9]
characters onlycountry
:string | null
Document issuing country, represented as ISO 3166alpha-2
codevalidUntil
:string | null
Document is valid until date, represented asYYYY-MM-DD
. Optional, must be configured for your integration by the Solutions EngineervalidFrom
:string | null
* Document is valid from date, represented asYYYY-MM-DD
additionalVerifiedData
:object
* Data which has been optionally verified for sessionproofOfAddress
:object
* Proof of address data. Optional, available only if the name match check has been enabled for the integrationdocumentType
:string
* Indicates the type of the proof of address document.null
if the check could not be completed.nameMatch
:boolean | null
Indicates if the name on the proof of address document matches the name from the initial request data.null
if the check could not be completed. Sent only when the name match check was enabled.nameMatchPercentage
:float| null
Indicates the level of similarity the matched names have, in the range of 0.00-100.00.null
if the check could not be completed. Sent only when the name match check was enabled.
comments
:array
* (Deprecated)
technicalData
:object
* Technical dataip
:string | null
IP of the device from which the verification was made
API call
Below are a sample and an explanation of a API call payload for a minimal Proof of Address Verification.
Depending on your solution, the payload may contain additional parameters. To find more info about it, see the GET sessions/{sessionId}/decision[↗] documentation.
Sample response
{
"status": "success",
"verification": {
"id": "ab1c2345-678d-4e3b-98a3-a75b00b715kj",
"attemptId": "c6cab5b0-c506-47a6-922d-6ae3b72ca172",
"code": 9001,
"person": {
"gender": null,
"idNumber": null,
"lastName": null,
"addresses": [
{
"fullAddress": "Jaan Koorti 777,
99999 Tallinn, Estonia"
}
],
"firstName": "Jane Doe",
"citizenship": null,
"dateOfBirth": null,
"nationality": null,
"yearOfBirth": null,
"placeOfBirth": null,
"pepSanctionMatch": null
},
"reason": null,
"status": "approved",
"comments": [],
"document": {
"type": null,
"number": null,
"country": null,
"validFrom": "2023-11-25",
"validUntil": null
},
"reasonCode": null,
"vendorData": null,
"endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
"decisionTime": "2024-01-23T10:31:05.293000Z",
"acceptanceTime": "2024-01-23T10:25:40.026Z",
"additionalVerifiedData": {
"proofOfAddress": {
"documentType": "UTILITY_BILL",
"nameMatch": true,
"nameMatcPercentage": 100.00
},
},
}
"technicalData": {
"ip": null
}
Response properties explained
status
:string
Status of the responseverification
:object
Verification request decision object.null
if decision is not available yetid
:string
UUID v4 which identifies the verification sessionattemptId
:string
UUID v4 of the attempt which received a status (as shown inverification.status
field)vendorData
:string | null
The unique identifier that you created for your end-user.null
if not specifiedendUserId
:string | null
TheUUID
that you created for your end-user.null
if not specifiedstatus
:string
Verification status, one ofapproved
,declined
,resubmission_requested
,review
,expired
,abandoned
code
:integer
Verification session decision code, one of9001
,9102
,9103
,9104
,9121
. For more info, see the verification session decision codesreason
:string | null
Reason why the verification failed, only sent when the verification failedreasonCode
:integer | null
Reason code of the failed verification, only sent when the verification failed. For more info, see the possible codes for a failed verificationdecisionTime
:string
Timestamp of the decision, represented asUTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset
(ISO 8601)acceptanceTime
:string
Timestamp of the session generation, represented asUTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset
(ISO 8601)person
:object
Data about the verified persongender
:string | null
Person’s gender, represented as M or F, ornull
if not presentidNumber
:string | null
National identification numberlastName
:string | null
null
, unless prefilled by the customeraddresses
:array
Array of person's addressesfullAddress
:string
Address as a single string
firstName
:string | null
Person's first name as written on the document, if availabledateOfBirth
:string
Person’s date of birth, represented asYYYY-MM-DD
nationality
:string | null
Person's nationalityyearOfBirth
:string | null
Person’s year of birth, represented asYYYY
placeOfBirth
:string | null
Person's place of birthpepSanctionMatch
:string | null
Legacy field, may return incorrect result, should be ignoredcitizenship
:string | null
Deprecated, always returns null
document
:object
Verified documenttype
:string | null
Document typenumber
:string | null
Document number,[a-zA-Z0-9]
characters onlycountry
:string | null
Document issuing country, represented as ISO 3166alpha-2
codevalidUntil
:string | null
Document is valid until date, represented asYYYY-MM-DD
. Optional, must be configured for your integration by the Solutions EngineervalidFrom
:string | null
Document is valid from date, represented asYYYY-MM-DD
additionalVerifiedData
:object
Data which has been optionally verified for sessionproofOfAddress
:object
Proof of address data. Optional, available only if the name match check has been enabled for the integrationdocumentType
:string
Indicates the type of the proof of address document.null
if the check could not be completed.nameMatch
:boolean | null
Indicates if the name on the proof of address document matches the name from the initial request data.null
if the check could not be completed. Sent only when the name match check was enabled.nameMatchPercentage
:float| null
Indicates the level of similarity the matched names have, in the range of 0.00-100.00.null
if the check could not be completed. Sent only when the name match check was enabled.
comments
:array
* (Deprecated)
technicalData
:object
* Technical dataip
:string | null
IP of the device from which the verification was made
Veriff Customer Portal
You can find the verification session related info, including the decision, in the Veriff Customer Portal, under the All Verifications tab.
→ See Review verification in Veriff Customer Portal about how to view the session info in the Veriff Customer portal
Proof of Address Capture
This is a separate solution which is used to just capture end-user’s document. No further analysis is done.
Refer to the Proof of Address Capture documentation.
Status and reason codes
For an approved
session, see:
verification.code
about verification session decision code, one of9001
,9102
,9103
,9104
,9121
verification.status
about verification status, one ofapproved
,declined
,resubmission_requested
,review
,expired
,abandoned
If the session was declined
or resubmission_requested
, you can find additional information by checking:
verification.reason
for the reason why the verification failed
verification.reasonCode
for reason code of the failed verification and cross-reference it with Granular reason codes (table)
Most common decline reasons for the Proof of Address solution
|
|
| What does it mean? |
---|---|---|---|
declined | 510 | Presented document type is not supported | The uploaded document type is not on the list of supported document types for the integration. Try altering the list of supported documents. |
declined | 527 | Unable to collect proof of address data | System was unable to collect pieces of document data from the presented document. This can occur when the document itself or its image is of low quality. |
declined | 528 | Proof of address document issue date too old | The presented PoA document is older than 90 days. |
declined | 566 | System processing failure | There was an error when processing the request due to service error, incorrect configuration, etc. Check with your Solutions Engineer or Veriff Customer Support. |
For more info about the codes you are seeing, refer to:
Article Versioning
Date | Description |
---|---|
May 2, 2025 | Documentation published |