# Getting Started

To get started with IDnGO:

  1. Log in to the Dashboard.
  2. Set up user access for your company: invite your team and assign roles and permissions.
  3. Create a verification level.
  4. Customize the verification process for your service.
  5. Complete authentication.
  6. Choose the appropriate integration method:

WebSDK → iOS SDK → Android SDK → API integration →

# Authentication

To use the IDnGO SDK and API, you must complete authentication.

# App token

In the «Dev space» section of the Dashboard, generate an appToken and a secretKey. These values are required to obtain an accessToken.

Each environment (Sandbox or Production) requires a separate App token.

Warning:

appToken and secretKey are displayed only once at the time of creation. You will not be able to view or edit them later.

# Authorization headers

All API requests must include the following headers:

  • X-App-Token — the application token generated in the Dashboard;
  • X-App-Access-Sig — the request signature (hexadecimal, lowercase);
  • X-App-Access-Ts — the timestamp (seconds since Unix epoch in UTC).

Header names are case-insensitive and may vary depending on the implementation, both in your requests and in our responses.

# Request signature

The value of X-App-Access-Sig is generated using the HMAC-SHA256 algorithm with the secretKey (created together with the appToken).

The signature input is a string built by concatenating the following elements in order:

  1. Timestamp — the value of the X-App-Access-Ts header;

The timestamp must be within 1 minute of our server time. Make sure the time on your servers is correct.

  1. HTTP method in uppercase (for example, GET or POST);

  2. Request URI without the host name, starting with / and including all query parameters, for example: /resources/applicants/123?fields=info

  3. Request body — if present, use the exact body as sent.

Example of the string for signing:

1607551635POST/resources/accessTokens?userId=cfd20712-24a2-4c7d-9ab0-146f3c142335&levelName=basic-kyc-level&ttlInSecs=600

Apply HMAC-SHA256 using your secretKey to this string, then encode the result in lowercase hexadecimal.

# POST Generate access token

When initializing the SDK, an accessToken is required. Each token is valid for a single applicant and cannot be reused for other applicants. To obtain an accessToken, send the following request:

POST /resources/accessTokens?userId={userId}&levelName={levelName}

Make sure that the authorization headers of the request use the appToken and secretKey pair created in the correct environment (Sandbox or Production):

  • For testing, use the appToken and secretKey pair created in the Sandbox environment;
  • For real checks, use the appToken and secretKey pair created in the Production environment.

Request parameters

Name Type Required Description
userId String Yes External identifier of the applicant linked to the token. Must match the externalUserId of the applicant.
levelName String Yes The name of the verification level, as configured in the «Application Levels» section of the Dashboard.
ttlInSecs Integer No Token validity period in seconds (default: 600).
externalActionId String No External identifier of the applicant action linked to the token.

The userId request parameter should be unique and non-random. It can be the external identifier of the applicant in your system or an email address. Do not generate these identifiers randomly unless you are performing testing.

Warning:

If userId or levelName contains reserved characters (such as «@» or «+»), URL-encode the values to prevent signature mismatches.

Response

Name Type Description
token String The generated access token for the applicant verification.

Example

# Webhooks

IDnGO webhooks allow you to automatically receive notifications about events and changes related to the verification process of your users.

After an applicant verification is completed, we will send you a POST request with a JSON payload to the URL you provided during integration. Usually, the URLs differ for Sandbox and Production environments.

Warning:

  • We do not send any information to an endpoint over HTTP, only HTTPS.
  • Supported TLS protocol versions are 1.2 or higher.
  • The number of webhooks is limited to 20.
  • We do not transmit any personal data via webhooks. You can retrieve all recognized applicant data using this API method.
  • If webhooks are not received, first check your endpoints using SSL Labs or Docker.

Make sure to test your webhook before sending its URL to us. The endpoint should not return an HTTP 500 response and must not require any authorization.

Webhook events can be monitored and analyzed in the «Webhook Logs» tab.

In the Sandbox environment, API integration does not perform automatic verification. You need to set verification parameters using this request. After that, verification results can be received via the applicantReviewed webhook.

If a webhook is not delivered for any reason, all delivery attempts are logged, and webhooks can be resent at any time. If a webhook fails to deliver, we retry four times: after 5 minutes, 1 hour, 5 hours, and 18 hours, until the request succeeds.

It is recommended to wait no longer than 24 hours for a webhook. If it has not arrived, send a request to the server to retrieve the applicant’s current status.

Check the createdAtMs field in the webhook payload to ensure you are receiving the most recent applicant status.

# Webhook types

You can configure webhook types, track their statuses, and resend them manually in the «Webhook manager» section.

Value Description
applicantCreated The applicant has been created.
applicantPending The user has uploaded all required documents, and the applicant is pending review.
applicantReviewed The applicant verification is complete. Contains the verification result.
applicantOnHold The applicant is awaiting a final decision from a compliance officer (manual review started).
applicantReset The applicant has been reset: the applicant’s status changed to init, and all documents marked inactive. New images/data are expected to be uploaded.
applicantPersonalInfoChanged The provided user information has been changed.
applicantDeleted The applicant has been permanently deleted.
applicantLevelChanged The verification level has been changed.
applicantActionPending The applicant actions are pending review.
applicantActionReviewed The applicant actions review has been completed.
applicantActionOnHold The applicant action is awaiting a final decision from a compliance officer.

Webhook payload fields

Name Type Required Description
applicantId String Yes Unique identifier of the applicant in our system.
inspectionId String Yes Unique identifier of the inspection.
correlationId String Yes Unique identifier of the event on our side.
levelName String No The name of the verification level, as configured in the «Application Levels» section of the Dashboard.
externalUserId String No External applicant identifier — the unique identifier of the user in your system.
type String Yes Type of webhook event.
sandboxMode Boolean Yes Indicates whether the webhook was sent from the Sandbox environment (true/false).
reviewStatus String Yes Current applicant status. See the status reference for details.
createdAtMs Date Yes The date and time the webhook was created in UTC (YYYY-MM-dd hh:mm:ss.fff).
applicantType String No Applicant type, for example: individual/company.
reviewResult Object No Additional details about the verification result.
applicantMemberOf Array of objects No List of company profiles where the current applicant is a beneficiary.
applicantActionId String No Unique identifier of the applicant action.
externalApplicantActionId String No External unique identifier of the action in your system.
clientId String Yes Unique identifier of your company in our system.

# Rejection reasons

The verification result webhook contains the rejectLabels field, which specifies one or more tags describing the reason for rejection.
These tags are intended only for analyzing check results and provide a general description of the issue. They should not be used to generate messages displayed to users.

Rejection Tag
(rejectLabels value)
Rejection Type
reviewRejectType
Description
FORGERY FINAL Fraud attempt detected.
SPAM FINAL Too many images were uploaded (photo spam).
BAD_PROOF_OF_IDENTITY RETRY Identity document is invalid, unsuitable, missing, or of poor quality.
SELFIE_MISMATCH FINAL The selfie does not match the photo in the submitted documents.
ID_INVALID RETRY Identity document is invalid.
DUPLICATE FINAL The applicant already has a verified profile; duplicates are not allowed.
BAD_AVATAR RETRY Avatar does not meet requirements.
WRONG_USER_REGION FINAL Applicants from this region/country are not accepted.
INCOMPLETE_DOCUMENT RETRY Document is only partially visible; required data is missing.
BLACKLIST FINAL The applicant has been blacklisted by IDnGO.
BLOCKLIST FINAL The applicant has been blacklisted by the client.
UNSATISFACTORY_PHOTOS RETRY Traces of editing in a graphic editor are visible on the image.
DOCUMENT_PAGE_MISSING RETRY Required document pages are missing.
DOCUMENT_DAMAGED RETRY The document is damaged.
REGULATIONS_VIOLATIONS FINAL The applicant does not meet regulatory requirements.
INCONSISTENT_PROFILE FINAL Data or documents of different people detected in one applicant.
ADDITIONAL_DOCUMENT_REQUIRED RETRY Additional documents are required.
AGE_REQUIREMENT_MISMATCH FINAL Applicant does not meet age requirements.
EXPERIENCE_REQUIREMENT_MISMATCH FINAL Applicant does not meet experience requirements (for example, driving experience).
CRIMINAL FINAL Applicant involved in illegal activities.
WRONG_ADDRESS RETRY The address in the documents does not match the address provided by the user.
GRAPHIC_EDITOR RETRY Document or photo edited in a graphic editor.
DOCUMENT_DEPRIVED RETRY The document was confiscated.
FRAUDULENT_PATTERNS FINAL Fraudulent behavior detected.
NOT_ALL_CHECKS_COMPLETED RETRY Not all required checks have been completed.
FRONT_SIDE_MISSING RETRY The front side of the document is missing.
BACK_SIDE_MISSING RETRY The back side of the document is missing.
SCREENSHOTS RETRY Screenshots uploaded instead of photos.
BLACK_AND_WHITE RETRY Black-and-white document images uploaded.
INCOMPATIBLE_LANGUAGE RETRY Translation of the document is required.
EXPIRATION_DATE RETRY Document has expired.
BAD_SELFIE RETRY Poor-quality selfie uploaded.
BAD_FACE_MATCHING RETRY The face in the selfie cannot be matched with the document photo.
BAD_PROOF_OF_ADDRESS RETRY Proof of address (PoA) document is of poor quality.
FRAUDULENT_LIVENESS FINAL Attempt to bypass the liveness check detected.
OTHER RETRY Other reason.
PROBLEMATIC_APPLICANT_DATA RETRY The provided information does not match the information obtained from the document.
OK RETRY Custom rejection tag.

Example

# Example of a webhook payload for applicantReviewed:

# Example of a webhook payload for applicantCreated:

{
    "applicantId": "5c9e177b0a975a6eeccf5960",
    // inspection ID that contains a result
    "inspectionId": "5c9e177b0a975a6eeccf5961",
    // an ID to debug in case of unexpected errors (should be provided to IDnGO)
    "correlationId": "req-63f92830-4d68-4eee-98d5-875d53a12258",
    "levelName": "basic-kyc-level",
    "externalUserId": "12672",
    // type of webhook (see the corresponding section)
    "type": "applicantCreated",
    "sandboxMode": "false",
    "reviewStatus": "init",
    "createdAtMs": "2020-02-21 13:23:19.001",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantPending:

{
    "applicantId": "5c7791f80a975a1df426b9e9",
    "inspectionId": "5c7791f80a975a1df426b9ea",
    "applicantType" : "individual",
    "correlationId": "req-4af54c06-6a50-4cb9-a7dc-b94b2f5b07eb",
    "levelName": "liveness-level",
    "externalUserId": "12672",
    "type": "applicantPending",
    "sandboxMode": "false",
    "reviewStatus": "pending",
    "createdAtMs": "2020-02-21 13:23:19.001",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantOnHold:

{
    "inspectionId": "5d10ca4e0a975a1c4cc30bbb",
    "applicantType" : "individual",
    "correlationId": "req-a98abc30-a5d9-4e1d-bab4-2f1af64bd5a5",
    "levelName": "poa-level",
    "externalUserId": "12672",
    "reviewStatus": "onHold",
    "applicantId": "5d10ca4e0a975a1c4cc30bba",
    "type": "applicantOnHold",
    "sandboxMode": "true",
    "createdAtMs": "2020-02-21 13:23:19.001",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantPersonalInfoChanged:

{
    "applicantId" : "5ede51230a975a19a19ba5c1",
    "inspectionId" : "5ede51230a975a19a19ba5c2",
    "applicantType" : "individual",
    "correlationId" : "req-60103dee-79f1-43f4-bdcc-eb2554556afa",
    "levelName": "id+liveness",
    "externalUserId" : "12672",
    "type" : "applicantPersonalInfoChanged",
    "sandboxMode": "false",
    "reviewResult" : {
        "reviewAnswer" : "GREEN"
    },
    "reviewStatus" : "completed",
    "createdAtMs" : "2020-06-08 19:39:29.001",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantDeleted:

{
    "applicantId": "5f194e74040c3f316bda271c",
    "inspectionId": "5f194e74040c3f316bda271d",
    "applicantType": "individual",
    "correlationId": "req-d34c974c-5935-41b8-a0a9-cedd2407eada",
    "levelName": "phone-level",
    "externalUserId": "12672",
    "type": "applicantDeleted",
    "sandboxMode": "false",
    "reviewStatus": "init",
    "createdAtMs": "2020-07-23 11:18:33.001",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantLevelChanged:

{
    "applicantId": "5f194e74040c3f316bda271c",
    "inspectionId": "5f194e74040c3f316bda271d",
    "applicantType": "individual",
    "correlationId": "req-d34c974c-5935-41b8-a0a9-cedd2407eadd",
    "levelName": "basic-kyc-level",
    "externalUserId": "12672",
    "type": "applicantLevelChanged",
    "sandboxMode": "false",
    "reviewStatus": "init",
    "createdAtMs": "2020-07-23 11:19:33.002",
    "clientId": "idngoClient"
}

# Example of a webhook payload for applicantReset:

{
    "applicantId": "5f194e74040c3f316bda271c",
    "inspectionId": "5f194e74040c3f316bda271d",
    "applicantType": "individual",
    "correlationId": "req-57fed49a-07b8-4413-bdaa-a1be903769e9",
    "levelName": "basic-kyc-level",
    "externalUserId": "12672",
    "type": "applicantReset",
    "sandboxMode": "false",
    "reviewResult": {
        "reviewAnswer": "GREEN"
    },
    "reviewStatus": "init",
    "createdAtMs": "2021-03-01 11:34:51.001",
    "clientId": "idngoClient"
}

# Webhook sender verification

It is not recommended to rely on our IP addresses when creating a whitelist of webhook senders, as they may change from time to time.

To ensure that a webhook is sent by us, you can use HMAC-based signing. To enable this feature, set a secret key for each webhook and select an HMAC algorithm in the «Dev space».

When signing is enabled, we add an additional HTTP header X-Payload-Digest-Alg, which specifies the algorithm used:

  • HMAC_SHA1_HEX — deprecated
  • HMAC_SHA256_HEX — used by default when creating a new webhook
  • HMAC_SHA512_HEX

Webhook sender verification instructions:

  1. Retrieve the webhook header value x-payload-digest and the payload exactly as it is, without any modifications or conversion to JSON.
  2. Get the HTTP webhook body in bytes.
  3. Compute the digest using the original payload in bytes and the HMAC algorithm specified in the x-payload-digest-alg header.
  4. Compare the x-payload-digest header value with the digest you calculated.

Webhook sender verification: POST /resources/inspectionCallbacks/testDigest?secretKey={secretKey}

# Example request to your endpoint:

curl -X POST \
    'https://callbackurl.com/kyc' \
    -H 'Content-Type: application/json' \
    -d '{
    "applicantId": "5cb56e8e0a975a35f333cb83",
    "inspectionId": "5cb56e8e0a975a35f333cb84",
    "correlationId": "req-ec508a2a-fa33-4dd2-b93d-fcade2967e03",
    "externalUserId": "12672",
    "type": "applicantReviewed",
    "reviewResult": {
        "reviewAnswer": "GREEN"
    },
    "reviewStatus": "completed",
    "createdAtMs": "2020-02-21 13:23:19.111",
    "clientId": "idngoClient"
}'

# Example of calculating the digest value: