Responses
The Shufti Pro Verification API will send you two types of responses if a request for verification is made. First is the HTTP response sent against your request, and the second is the callback response. Both HTTP and callback responses will be in JSON format with a header. application/json
The response header also includes a Key Signature. This key is used for validating the source of the response. Be sure to validate the request by generating signature and matching it with the Signature value from the response header.
HTTP Status Codes
Shufti Pro Verification API uses conventional HTTP response codes to indicate the success or failure of an API request. Every response is generated in JSON with a specific HTTP code.
Following is a list of HTTP codes that are generated in responses by Shufti Pro Verification API.
HTTP code | HTTP message | Message |
---|---|---|
200 | OK | success. |
400 | Bad Request | Bad Request: one or more parameter is invalid or missing. |
401 | Unauthorized | Unauthorized: invalid signature key provided in the request. |
402 | Request Failed | Invalid request data: missing required parameters. |
403 | Forbidden | Forbidden: service not allowed. |
404 | Not Found | Resource not found. |
409 | Conflict | Conflicting data: already exists. |
429 | Too Many Requests | Too Many Attempts. |
500 | Server Error | Internal Server Error. |
504 | Gateway Timeout | Server error. |
524 | Timeout from Cloudflare | Unofficial Server Error. |
Response Events
Events are sent in responses that show the status of the request. These events are sent in both HTTP and callback responses.
Event | Description | HTTP Response | Callback Response |
---|---|---|---|
request.pending | Request parameters are valid and verification url is generated in case of on-site verification. | Yes | Yes |
request.invalid | Request parameters provided in request are invalid. | Yes | No |
verification.cancelled | Request is cancelled by the user. This event occurs when end-user disagrees to terms and conditions before starting verifications. | Yes | Yes |
request.timeout | Request has timed out after a specific period of time. The onsite request will Time Out after 60 minutes. | No | Yes |
request.unauthorized | Request is unauthorized. The information provided in authorization header is invalid. | Yes | No |
verification.accepted | Request was valid and accepted after verification. | Yes | Yes |
verification.declined | Request was valid and declined after verification. | Yes | Yes |
verification.status.changed | Request status has been updated. | No | Yes |
request.deleted | Request has been deleted. | Yes | Yes |
request.received | Request has been received. | Yes | Yes |
review.pending | Documents are collected and request is pending for client to review and Accept/Decline. | Yes | Yes |
request.data.changed | The request data is manually updated by the client after the request is finalized. If a callback URL is provided, the updated data will be returned in the callback along with the event. | Yes | Yes |
In case of off-site verification, verification.accepted or verification.declined is returned in event when request is valid after verification. In case of verification.status.changed a callback is sent to notify the client that the verification status has been updated.
- Pending
- Accepted
- Declined
- Review.Pending
- Invalid
- Cancelled
- Timeout
- Unauthorized
- Status.Changed
- Deleted
- Received
- Data.Changed
{
"reference": "17374217",
"event": "request.pending",
"verification_url": "https://app.shuftipro.com/process/verification/RPQ8hwPE3cdHKho2wjK7CVQJCQxNx5Rwmb81k3ediXLSWhQM5QibGBWOSgCVjZJd",
"email": "[email protected]",
"country": "GB"
}
{
"reference": "17374217",
"event": "verification.accepted",
"verification_result": {
"face": {
"face": 1
},
"document": {
"name": 1,
"dob": 1,
"age": 1,
"expiry_date": 1,
"issue_date": 1,
"document_number": 1,
"document": 1,
"gender" : ""
},
"address": {
"name": 1,
"full_address": 1
}
},
"verification_data": {
"face" : {
"duplicate_account_detected" : "0"
},
"document": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"dob": "1978-03-13",
"age": 18,
"issue_date": "2015-10-10",
"expiry_date": "2025-12-31",
"document_number": "1456-0989-5567-0909",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"driving_license",
"passport"
],
"gender" : "M"
},
"address": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"full_address": "3339 Maryland Avenue, Largo, Florida",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"bank_statement"
]
}
},
"info": {
"agent": {
"is_desktop": true,
"is_phone": false,
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
"device_name": "Macintosh",
"browser_name": "",
"platform_name": "OS X - 10_14_0"
},
"geolocation": {
"host": "212.103.50.243",
"ip": "212.103.50.243",
"rdns": "212.103.50.243",
"asn": "9009",
"isp": "M247 Ltd",
"country_name": "Germany",
"country_code": "DE",
"region_name": "Hesse",
"region_code": "HE",
"city": "Frankfurt am Main",
"postal_code": "60326",
"continent_name": "Europe",
"continent_code": "EU",
"latitude": "50.1049",
"longitude": "8.6295",
"metro_code": "",
"timezone": "Europe/Berlin"
}
},
"additional_data": {
"document": {
"proof": {
"height": "183",
"country": "United Kingdom",
"authority": "HMPO",
"last_name": "Doe",
"first_name": "John",
"issue_date": "2018-01-31",
"expiry_date": "2028-01-30",
"nationality": "BRITSH CITIZEN",
"country_code": "GBR",
"document_type": "P",
"place_of_birth": "BRISTOL",
"document_number": "GB1234567",
"personal_number": "12345678910",
"dob": "1978-03-13",
"age": 18,
"gender" : ""
}
}
}
}
{
"reference": "95156124",
"event": "verification.declined",
"verification_result": {
"document": {
"name": 0,
"dob": 1,
"age": 1,
"expiry_date": 1,
"issue_date": 1,
"document_number": 1,
"document": null
},
"address": {
"name": null,
"full_address": null
}
},
"verification_data": {
"document": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"dob": "1978-03-13",
"age": 18,
"issue_date": "2015-10-10",
"expiry_date": "2025-12-31",
"gender" : "M"
"document_number": "1456-0989-5567-0909",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"driving_license",
"passport"
]
},
"address": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"full_address": "3339 Maryland Avenue, Largo, Florida",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"bank_statement"
]
}
},
"info": {
"agent": {
"is_desktop": true,
"is_phone": false,
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
"device_name": "Macintosh",
"browser_name": "",
"platform_name": "OS X - 10_14_0"
},
"geolocation": {
"host": "212.103.50.243",
"ip": "212.103.50.243",
"rdns": "212.103.50.243",
"asn": "9009",
"isp": "M247 Ltd",
"country_name": "Germany",
"country_code": "DE",
"region_name": "Hesse",
"region_code": "HE",
"city": "Frankfurt am Main",
"postal_code": "60326",
"continent_name": "Europe",
"continent_code": "EU",
"latitude": "50.1049",
"longitude": "8.6295",
"metro_code": "",
"timezone": "Europe/Berlin"
}
},
"declined_reason": "Name on the document doesn't match",
"declined_codes":[
"SPDR07",
"SPDR06",
"SPDR23"
],
"additional_data": {
"document": {
"proof": {
"height": "183",
"country": "United Kingdom",
"authority": "HMPO",
"last_name": "Doe",
"first_name": "John",
"issue_date": "2018-01-31",
"expiry_date": "2028-01-30",
"nationality": "BRITSH CITIZEN",
"country_code": "GBR",
"document_type": "P",
"place_of_birth": "BRISTOL",
"document_number": "GB1234567",
"personal_number": "12345678910",
"dob": "1978-03-13",
"age": 18,
"gender" : "M"
}
}
},
"services_declined_codes": {
"document": [
"SPDR13",
"SPDR12"
],
"address": [
"SPDR22",
"SPDR26"
],
"face": [
"SPDR01"
]
}
}
{
"reference": "95156124",
"event": "review.pending",
"verification_result": {
"document": {
"name": 0,
"dob": 1,
"age": 1,
"expiry_date": 1,
"issue_date": 1,
"document_number": 1,
"document": null
},
"address": {
"name": null,
"full_address": null
}
},
"verification_data": {
"document": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"dob": "1978-03-13",
"age": 18,
"issue_date": "2015-10-10",
"expiry_date": "2025-12-31",
"gender" : "M"
"document_number": "1456-0989-5567-0909",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"driving_license",
"passport"
]
},
"address": {
"name": {
"first_name": "John",
"middle_name": "Carter",
"last_name": "Doe"
},
"full_address": "3339 Maryland Avenue, Largo, Florida",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"bank_statement"
]
}
},
"info": {
"agent": {
"is_desktop": true,
"is_phone": false,
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
"device_name": "Macintosh",
"browser_name": "",
"platform_name": "OS X - 10_14_0"
},
"geolocation": {
"host": "212.103.50.243",
"ip": "212.103.50.243",
"rdns": "212.103.50.243",
"asn": "9009",
"isp": "M247 Ltd",
"country_name": "Germany",
"country_code": "DE",
"region_name": "Hesse",
"region_code": "HE",
"city": "Frankfurt am Main",
"postal_code": "60326",
"continent_name": "Europe",
"continent_code": "EU",
"latitude": "50.1049",
"longitude": "8.6295",
"metro_code": "",
"timezone": "Europe/Berlin"
}
},
"declined_reason": "Name on the document doesn't match",
"declined_codes":[
"SPDR07",
"SPDR06",
"SPDR23"
],
"additional_data": {
"document": {
"proof": {
"height": "183",
"country": "United Kingdom",
"authority": "HMPO",
"last_name": "Doe",
"first_name": "John",
"issue_date": "2018-01-31",
"expiry_date": "2028-01-30",
"nationality": "BRITSH CITIZEN",
"country_code": "GBR",
"document_type": "P",
"place_of_birth": "BRISTOL",
"document_number": "GB1234567",
"personal_number": "12345678910",
"dob": "1978-03-13",
"age": 18,
"gender" : "M"
}
}
},
"services_declined_codes": {
"document": [
"SPDR13",
"SPDR12"
],
"address": [
"SPDR22",
"SPDR26"
],
"face": [
"SPDR01"
]
}
}
{
"reference": "17374217",
"event": "request.invalid",
"error": {
"service": "document",
"key": "dob",
"message": "The dob does not match the format Y-m-d."
},
"email": null,
"country": null
}
{
"reference": "17374217",
"event": "verification.cancelled",
"country": "GB",
"proofs": {}
}
{
"reference": "17374217",
"event": "request.timeout",
"country": "GB",
"proofs": {}
}
{
"reference": "",
"event": "request.unauthorized",
"error": {
"service": "",
"key": "",
"message": "Authorization keys are missing/invalid."
},
"email": null,
"country": null
}
{
"reference": "17374217",
"event": "verification.status.changed"
}
{
"reference": "17374217",
"event": "request.deleted"
}
{
"reference": "17374217",
"event": "request.received",
"email": "[email protected]",
"country": "UK"
}
{
"reference": "17374217",
"event": "request.data.changed",
"verification_data": {
"document": {
"name": {
"first_name": "John",
"middle_name": "Doe"
},
"permanent_address": "2601 Amphitheatre Pkwy, ZA, 58023",
"present_address": "1234 Amphitheatre Pkwy, ZA, 58023",
"guardian_name":"John Doe",
"country_of_stay":"Cyprus"
}
}
}
Verification Response
Responses will contain the following parameters:
Parameters | Description |
---|---|
reference | Your unique request reference, which you provided us at the time of request, so that you can identify the response in relation to the request made. |
event | This is the request event which shows status of request. Event is changed in every response. Please consult Events for more information. |
error | Whenever there is an error in your request, this parameter will have the details of that error. |
verification_url | A URL is generated for your customer to verify there documents. It is only generated in case of on-site request. |
verification_result | It is only returned in case of a valid verification. This includes results of each verification. 1 means accepted 0 means declined null means not processed Check verification.accepted and verification.declined responses in Events section for a sample response. |
verification_data | It is only returned in case of a valid verification. This object will include the all the gathered data in a request process. Check verification.accepted and verification.declined responses in Events section for a sample response. |
info | This object will be returned in case of verification.accepted or verification.declined. It contains the following keys: Agent provides information about the device and browser of the end-user. Geolocation provides information about the geographical location of the end-user. For Details on info object go to Info. |
additional_data | This object will be returned in case of verification.accepted or verification.declined. This object contains the additional data extracted by Shufti Pro on the document. For Details on additional_data object go to Additional Data. |
declined_reason | This parameter will have the reason due to which a verification has been declined, and is only returned in this case in the callback URL. |
declined_codes | This array contains status codes of all declined verification reasons. It will return only for verification.declined. |
services_declined_codes | This object contains status codes of declined reasons for each service separately. Each service object will contain an array of status codes for declined reasons specific to that service. It will return only for verification. declined. |
Callback response will be sent on the callback_url provided in the request callback_url parameter.
Frontend Response
The Front End Response Event API facilitates communication between a parent window (client app) and a child window (iFrame). When a child window has completed its task, it can send an event to the parent window, triggering specific actions to be performed by the client app.
To enable parent-child communication, follow these steps:
- Add Listeners: In your client app, add an event listener to the parent window to listen for messages from the child window.
window.addEventListener('message', (e) => {
console.log(e.data);
});
Once you've set up the event listener, your client app will be ready to receive events from the child window.
Request Finalize Event:
This event will be sent to the parent window when the request is finalized.
The event sent from the child window to the parent window has the following structure:
{
"request_id": "unique_id",
"verification_status": "verification.accepted"
}
Always validate the verification_status field before performing any actions to ensure that the event is valid and coming from a trusted source.
- request_id: A unique identifier for the event.
- verification_status: The status of the verification process. This field can hold different values depending on the outcome of the verification.
Upon receiving the event from the child window, the client app can perform specific actions based on the verification_status field. It's important to check the verification_status before taking any action. Depending on the value of verification_status, you can implement different logic or redirect the user as needed.
Ensure that the event listener is set up in the parent window before the child window sends an event.
Status Response
The Shufti Pro Verification API will send a JSON response if a status request is made. Make sure to validate the request by generating signature and matching it with the Signature value from the response header.
Parameters | Description |
---|---|
reference | Your unique request reference, which you provided us at the time of request, so that you can identify the response in relation to the request made. |
event | This is the request event which shows status of request. Event is changed in every response. Please consult Events for more information. |
country | This contains country code sent by the merchant at the time of request. Country code in the format of ISO 3166-1 alpha-2. Please consult Supported Countries for country codes. Type: string Example: DE null if not provided by merchant. |
proofs | This contains all the proofs that were used to verify data. The Proof URLs returned are temporary and valid for 15 minutes only.
|
verification_data | This contains all the data used for verification. This will only be returned in case of verification.accepted or verification.declined. |
verification_result | This is the complete result of the verification. 1 stands for verified, 0 for not verified and null for no verification performed. This will only be returned in case of verification.accepted or verification.declined. |
info | This object will be returned in case of verification.accepted or verification.declined. It contains the following keys: Agent provides information about the device and browser of the end-user. Geolocation provides information about the geographical location of the end-user. For Details on info object go to Info. |
additional_data | This object will be returned in case of verification.accepted or verification.declined. This object contains the additional data extracted by Shufti Pro on the document. For Details on additional_data object go to Additional Data. |
declined_reason | This key will only be returned when event is verification.declined. This will contain the reason why verification was declined. |
declined_codes | This array contains status codes of all declined verification reasons. It will return only for verification.declined. |
services_declined_codes | This object contains status codes of declined reasons for each service separately. Each service object will contain an array of status codes for declined reasons specific to that service. It will return only for verification. declined. |
request.invalid response with HTTP status code 400 means the request is invalid.
//Content-Type: application/json
//Signature: NmI4NmIyNzNmZjM0ZmNl
{
"reference" : "17374217",
"event" : "verification.accepted",
"country" : "GB",
"proofs" : {
"face": {
"proof": "https://ns.shuftipro.com/api/pea/15c1cf23bc0ed5a25613539f5cn3bebc0d566cda"
},
"document": {
"proof": "https://ns.shuftipro.com/api/pea/65c1df23bc0ed5a25613539f5cn3bebc0d566cac"
},
"documenttwo": {
"proof": "https://ns.shuftipro.com/api/pea/65c1cf23bc0fd5a25613539f5cn3bebc0d566cak"
},
"address": {
"proof": "https://ns.shuftipro.com/api/pea/35c1cf23bc0ed5a25613539f5cn3bebc0d5668aa"
},
"consent": {
"proof": "https://ns.shuftipro.com/api/pea/15c1cf23bc0ed5a25613539f5cn3bebc0d565cda"
},
"verification_video" : "https://ns.shuftipro.com/api/pea/63c1cf23bc0ed5a21613539f5cn3bebc0d566cao",
"access_token":"46e02a0a0abd8f449714881f7dd63aaca16ffa30dffc3e5feab78d98c94a434a",
"verification_report": "https://ns.shuftipro.com/api/pea/9ee426402e8633087b183c61ea5ac72acec5a728"
},
"verification_data": {
"document": {
"issue_date": "1990-01-01",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"passport",
"driving_license",
"credit_or_debit_card"
],
"face_match_confidence": 70
},
"document_two": {
"dob": "1990-01-01",
"selected_type": [
"id_card"
],
"supported_types": [
"id_card",
"passport",
"driving_license",
"credit_or_debit_card"
]
},
"address": {
"full_address": "Candyland Avenue",
"selected_type": [
"utility_bill"
],
"supported_types": [
"utility_bill",
"driving_license",
"bank_statement",
"envelope",
"id_card",
"passport",
"rent_agreement",
"employer_letter",
"insurance_agreement",
"tax_bill"
]
},
"consent": {
"text": "My name is John Doe and I authorise this transaction of $100/- Date: July 15, 2020",
"selected_type": [
"handwritten"
],
"supported_types": [
"handwritten",
"printed"
]
},
"background_checks": {
"dob": "1990-01-01",
"name": {
"last_name": "John",
"first_name": "Doe"
}
},
"aml_for_business": {
"business_name": "Company Name",
"business_incorporation_date": "1975-07-01",
"aml_data": {
"filters": [
"sanction",
"warning",
"fitness-probity",
"pep",
"pep-class-1",
"pep-class-2",
"pep-class-3",
"pep-class-4"
],
"hits": [
{
"name": "Company Name",
"entity_type": "organisation",
"score": 24.911245,
"match_types": [
"name_exact"
],
"alternative_names": [
"Company Name"
],
"assets": [
{
"public_url": "http://example.s3.amazonaws.com/834refjadfkjhq4-ahfdkddfa8a.pdf",
"source": "us-securities-exchange-commission-litigation-releases",
"type": "pdf"
}
],
"associates": [],
"fields": {
"Activation Date": [
{
"value": "Jul. 17, 2019",
"source": "united-states-securities-and-exchange-commission-administrative-proceedings-organisation",
"tag": ""
}
],
"Adverse Media Subtypes": [
{
"value": "antitrust, corporate-fraud, corruption, fines, insider-trading, litigation, money-laundering, other-crime, security, tax-evasion",
"source": "company-am",
"tag": ""
}
],
"Date": [
{
"value": "2002-08-03",
"source": "us-securities-exchange-commission-litigation-releases",
"tag": ""
}
],
"Enforcement Agency": [
{
"value": "United States Securities and Exchange Commission",
"source": "united-states-securities-and-exchange-commission-administrative-proceedings-organisation",
"tag": ""
}
],
"Related URL": [
{
"value": "http://www.sec.gov/litigation/link423.shtml",
"source": "us-securities-exchange-commission-litigation-releases",
"tag": "related_url"
},
{
"value": "https://www.sec.gov/litigation/admin/2019/34-72891heq89.pdf",
"source": "united-states-securities-and-exchange-commission-administrative-proceedings-organisation",
"tag": "related_url"
}
],
"Release": [
{
"value": "Release information about company...",
"source": "us-securities-exchange-commission-litigation-releases",
"tag": ""
}
],
"Release Number": [
{
"value": "34-46017",
"source": "us-securities-exchange-commission-litigation-releases",
"tag": ""
}
],
"Related Url": [
{
"value": "http://www.sec.gov/litigation/admin/34-234324.htm",
"source": "us-securities-exchange-commission-litigation-releases",
"tag": "related_url"
}
]
},
"media": [
{
"date": "2019-09-15T00:00:00Z",
"snippet": "The NYPD said 12 men and 75 women were charged with obstructing traffic after blocking cars outside the company's flagship shop on 5th Avenue between 53rd and 54th streets on Satur day",
"title": "Dozens of ICE Protesters Arrested in Midtown - American Renaissance",
"url": "https://www.amren.com/news/2019/23/dozens-of-ice-protesters-arrtedaddsa-in-midtown/"
},
{
"date": "2019-09-15T00:00:00Z",
"snippet": "The NYPD said 12 men and 75 women were charged with obstructing traffic after blocking cars outside the company's flagship shop on 5th Avenue between 53rd and 54th streets on Satur day",
"title": "Dozens of ICE protesters arrested in Midtown",
"url": "https://nypost.com/2019/10/23/dozens-of-ice-asdf-asdfd-in-midtown/"
}
],
"source_notes": {
"company-am": {
"aml_types": [
"adverse-media",
"adverse-media-financial-crime",
"adverse-media-fraud",
"adverse-media-general"
],
"name": "company AM"
},
"united-states-securities-and-exchange-commission-administrative-proceedings-organisation": {
"aml_types": [
"warning"
],
"listing_started_utc": "2019-07-25T00:00:00Z",
"name": "United States Securities and Exchange Commission Administrative Proceedings - organisation",
"url": "https://www.sec.gov/litigation/asddfa.shtml"
},
"us-securities-exchange-commission-litigation-releases": {
"aml_types": [
"warning"
],
"listing_ended_utc": "2016-12-22T00:00:00Z",
"name": "Warnings USA SEC Litigation Releases",
"url": "http://www.sec.gov/litigation/asdfasdf.shtml"
}
},
"sources": [
"company-am",
"united-states-securities-and-exchange-commission-administrative-proceedings-organisation",
"us-securities-exchange-commission-litigation-releases"
],
"types": [
"adverse-media",
"adverse-media-financial-crime",
"adverse-media-fraud",
"adverse-media-general",
"warning"
]
}
]
}
}
},
"verification_result": {
"background_checks": 1,
"consent": {
"consent": 1,
"selected_type": 1
},
"address": {
"partial_address_match_with_id_and_utility_bill": 1,
"full_address": 1,
"address_document_visibility": 1,
"address_document_must_not_be_expired": 1,
"address_document": 1,
"address_document_country": 1,
"selected_type": 1
},
"document": {
"issue_date": 1,
"document_visibility": 1,
"document_must_not_be_expired": 1,
"document": 1,
"document_country": 1,
"selected_type": 1
},
"document_two": {
"dob": 1,
"document_visibility": 1,
"document_must_not_be_expired": 1,
"document": 1,
"document_country": 1,
"selected_type": 1
},
"face": 1
},
"info": {
"agent": {
"is_desktop": true,
"is_phone": false,
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
"device_name": "Macintosh",
"browser_name": "",
"platform_name": "OS X - 10_14_0"
},
"geolocation": {
"host": "212.103.50.243",
"ip": "212.103.50.243",
"rdns": "212.103.50.243",
"asn": "9009",
"isp": "M247 Ltd",
"country_name": "Germany",
"country_code": "DE",
"region_name": "Hesse",
"region_code": "HE",
"city": "Frankfurt am Main",
"postal_code": "60326",
"continent_name": "Europe",
"continent_code": "EU",
"latitude": "50.1049",
"longitude": "8.6295",
"metro_code": "",
"timezone": "Europe/Berlin"
}
},
"additional_data": {
"document": {
"proof": {
"gender": "M",
"height": "183",
"country": "United Kingdom",
"authority": "HMPO",
"last_name": "Doe",
"first_name": "John",
"issue_date": "2018-01-31",
"expiry_date": "2028-01-30",
"nationality": "BRITISH CITIZEN",
"country_code": "GBR",
"document_type": "P",
"place_of_birth": "BRISTOL",
"document_number": "GB1234567",
"personal_number": "12345678910",
"dob": "1978-03-13",
"issue_date": "2015-10-10",
"expiry_date": "2025-12-31",
}
}
}
}
Delete Request Response
The Shufti Pro Verification API will send a JSON response if a delete request is made. Make sure to validate the request by generating signature and matching it with the Signature value from the response header
Parameters | Description |
---|---|
reference | Your unique request reference, which you provided us at the time of request, so that you can identify the response in relation to the request made. |
event | This is the request event which shows status of request. Event is changed in every response. |
Please consult Events for more information.
request.invalid will be returned in case of invalid reference provided or the request is already deleted.
//Content-Type: application/json
//Signature: NmI4NmIyNzNmZjM0ZmNl
{
"reference": "17374217",
"event": "request.deleted"
}
Response Signature
Every HTTP and Callback response will be in application/JSON with a key Signature in the header. It can be used to validate the source of the request. Make a signature using the following procedure:
- Concatenate Secret Key at the end of the raw response string. (i.e. response + secret_key).
- Take SHA256 of concatenated string.
- Match the SHA256 string with Signature value from the header of the response.
In short, make signature as mentioned format and match it with the signature provided in the header in Signature key.
hash('sha256', response . your_secret_key)
The clients who are registered with Shufti Pro after 15th March, 2023. They need to make the signature using the following procedure.
- Take SHA256 of Secret Key string.
- Concatenate hashed Secret Key at the end of the raw response string. (i.e. response + hash('sha256', secret_key)).
- Take SHA256 of concatenated string.
- Match the SHA256 string with Signature value from the header of the response.
hash('sha256', response . hash('sha256', secret_key))
The clients registered with Shufti Pro before 15th March 2023 or have not updated the secret key from the back office. They don't need to take SHA256 of the Secret key.
Here is the sample code to validate the signature:
- Javascript
- PHP
- Python
- Ruby
- Java
- Go
const axios = require('axios');
const base64 = require('base-64');
const crypto = require('crypto');
// Shufti Pro API base URL
const url = 'https://api.shuftipro.com/status';
// Your Shufti Pro account Client ID
const client_id = 'YOUR_CLIENT_ID';
// Your Shufti Pro account Secret Key
const secret_key = 'YOUR_SECRET_KEY';
const request = {
// your request reference
reference: '1234-0987-1234',
};
// calling Shufti Pro request API using axios
const auth = `${client_id}:${secret_key}`;
const b64Val = Buffer.from(auth).toString('base64');
axios.post(url, request, {
headers: {
Authorization: `Basic ${b64Val}`,
'Content-Type': 'application/json',
},
responseType: 'text'
})
.then((response) => {
// get Shufti Pro Signature
const sp_signature = response.headers.signature;
// convert secret key into sha256
const hashed_secret_key = crypto.createHash('sha256').update(secret_key).digest('hex');
// calculating signature for verification
const calculated_signature = crypto.createHash('sha256').update(response.data + hashed_secret_key).digest('hex');
if (sp_signature === calculated_signature) {
console.log(response.data);
} else {
console.log(`Invalid signature: ${response.data}`);
}
})
.catch((error) => {
console.log(error);
});
<?php
// Shufti Pro API base URL
$url = 'https://api.shuftipro.com/status';
// Your Shufti Pro account Client ID
$client_id = 'YOUR_CLIENT_ID';
// Your Shufti Pro account Secret Key
$secret_key = 'YOUR_SECRET_KEY';
$request = array(
// your request reference
"reference" => '1234-0987-1234',
);
// calling Shufti Pro request API using cURL
$auth = $client_id . ':' . $secret_key;
$headers = ['Content-Type: application/json'];
$response = send_curl($url, json_encode($request), $headers, $auth);
//Get Shufti Pro API Response
$response_data = $response['body'];
//Get Shufti Pro Signature
$exploded = explode("\n", $response['headers']);
// Get Signature Key from Hearders
$sp_signature = null;
foreach ($exploded as $key => $value) {
if (strpos($value, 'signature: ') !== false || strpos($value, 'Signature: ') !== false) {
$sp_signature=trim(explode(':', $exploded[$key])[1]);
break;
}
}
// convert secret key into sha256
$hashed_secret_key = hash('sha256', $secret_key);
// calculating signature for verification
$calculated_signature = hash('sha256', $response_data . $hashed_secret_key);
if ($sp_signature === $calculated_signature) {
print_r($response_data);
} else {
echo 'Invalid signature: ' . $response_data;
}
function send_curl($url, $post_data, $headers, $auth){ // remove $auth in case of Access Token
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERPWD, $auth); // remove this in case of Access Token
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // remove this in case of Access Token
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$html_response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($html_response, 0, $header_size);
$body = substr($html_response, $header_size);
curl_close($ch);
return ['headers' => $headers,'body' => $body];
}
# import required libraries
import base64
import requests
import json
import hashlib
import urllib.request
from random import randint
# Shufti Pro api base url
url = 'https://api.shuftipro.com/status'
# Your Shufti Pro account Client ID
client_id = 'YOUR_CLIENT_ID'
# Your Shufti Pro account Secret Key
secret_key = 'YOUR_SECRET_KEY'
request = {
# your request reference
"reference": '1234-0987-1234',
}
# calling Shufti Pro request API using python request
auth = '{}:{}'.format(client_id, secret_key)
b64Val = base64.b64encode(auth.encode()).decode()
response = requests.post(url,
headers={"Authorization": "Basic %s" %
b64Val, "Content-Type": "application/json"},
data=json.dumps(request))
# get Shufti Pro Signature
sp_signature = response.headers.get('Signature')
# convert secret key into sha256
hashed_secret_key = hashlib.sha256(secret_key.encode()).hexdigest()
# calculating signature for verification
calculated_signature = hashlib.sha256('{}{}'.format(
response.content.decode(), hashed_secret_key).encode()).hexdigest()
# Convert json string to json object
json_response = json.loads((response.content))
if sp_signature == calculated_signature:
print(json_response)
else:
print('Invalid signature: {}'.format(response.content))
require 'uri'
require 'net/http'
require 'base64'
require 'json'
require 'digest'
url = URI("https://api.shuftipro.com/status")
# Your Shufti Pro account Client ID
CLIENT_ID = "YOUR-CLIENT-ID"
# Your Shufti Pro account Secret Key
SECRET_KEY = "YOUR-SECRET-KEY"
post_data = {
# your request reference
reference: "1234-0987-1234"
}
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
header_auth = Base64.strict_encode64("#{CLIENT_ID}:#{SECRET_KEY}")
request["Content-Type"] = "application/json"
request["Authorization"] = "Basic #{header_auth}"
request.body = post_data.to_json
response = http.request(request)
response_headers = response.instance_variable_get("@header")
response_data = JSON.parse(response.read_body)
# get Shufti Pro Signature
sp_signature = !(response_headers['signature'].nil?) ? response_headers['signature'].join(',') : ""
# convert secret key into sha256
hashed_secret_key = Digest::SHA256.hexdigest SECRET_KEY
# calculated signature
calculated_signature = Digest::SHA256.hexdigest response.read_body + hashed_secret_key
if sp_signature == calculated_signature
puts response_data
else
puts "Invalid signature"
end
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.shuftipro.com/status";
String CLIENT_ID = "CLIENT_ID";
String SECRET_KEY = "SECRET_KEY";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
// Add request header
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
String basicAuth = "Basic " + Base64.getEncoder().encodeToString((CLIENT_ID + ":" + SECRET_KEY).getBytes(StandardCharsets.UTF_8));
con.setRequestProperty("Authorization", basicAuth);
String payload = "{ \n \"reference\" : \"1234-0987-1234\"\n}";
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(payload);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Payload : " + payload);
if (responseCode == HttpsURLConnection.HTTP_OK) {
// Get Shufti Pro Signature
String spSignature = con.getHeaderField("signature");
// Convert secret key into sha256
String hashedSecretKey = calculateSHA256Hash(SECRET_KEY);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
System.out.println(in.toString());
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// Calculating signature
String calculatedSignature = calculateSHA256Hash(response + hashedSecretKey);
if (spSignature != null && spSignature.equals(calculatedSignature)) {
// Print the response
System.out.println(response);
} else {
System.out.println("Invalid signature");
}
}else{
System.out.println("Response Code : " + responseCode);
}
}
public static String calculateSHA256Hash(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : encodedHash) {
String hex = String.format("%02x", b);
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
}
package main
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
)
type Payload struct {
Reference string `json:"reference"`
}
func main() {
// Create the payload
payload := Payload{
Reference: "",
}
// Marshal the payload to JSON
jsonPayload, err := json.Marshal(payload)
if err != nil {
fmt.Println("Error marshaling payload:", err)
return
}
// Set up Basic Auth header
username := ""
password := ""
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password))
// Create the HTTP client and request
client := &http.Client{}
req, err := http.NewRequest("POST", "https://api.shuftipro.com/status", strings.NewReader(string(jsonPayload)))
if err != nil {
fmt.Println("Error creating request:", err)
return
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", authHeader)
// Send the request and get the response
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
// Read the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return
}
// Convert the response body to string
responseData := string(body)
// Calculate the response hash
responseHash := calculateResponseHash(responseData, password)
// Get the response signature from the header
responseSignature := resp.Header.Get("Signature")
// Check if the response signature matches the calculated hash
signatureMatch := responseSignature == hex.EncodeToString(responseHash[:])
fmt.Println("Response:", responseData)
fmt.Println("Signature Match:", signatureMatch)
}
// calculateResponseHash calculates the SHA256 hash of the response data concatenated with the password hash
func calculateResponseHash(responseData string, password string) [32]byte {
passwordHash := sha256.Sum256([]byte(password))
return sha256.Sum256([]byte(responseData + hex.EncodeToString(passwordHash[:])))
}
Additional Data Parameters
This object will be returned in case of verification.accepted or verification.declined. This object contains the additional data extracted by Shufti Pro. For example height, place_of_birth, nationality, marital_status, weight. The values in the object will be in string format. For keys ('face', 'finger_print', 'signature') comma-separated string will be returned, which will contain coordinates x1, y1, x2, y2 (top-left and bottom-right).
{
"additional_data": {
"document": {
"proof": {
"gender": "M",
"height": "183",
"country": "United Kingdom",
"authority": "HMPO",
"last_name": "Doe",
"first_name": "John",
"issue_date": "2018-01-31",
"expiry_date": "2028-01-30",
"nationality": "BRITSH CITIZEN",
"country_code": "GBR",
"document_type": "P",
"place_of_birth": "BRISTOL",
"document_number": "GB1234567",
"personal_number": "12345678910",
"dob": "1978-03-13",
"age": 18,
"issue_date": "2015-10-10",
"expiry_date": "2025-12-31",
"signature": "335,300,435,400"
}
}
}
}