# API Reference

# Introduction

Sum&Substance's API allows you to send and receive applicants’ data and documents for verification through simple RESTful APIs. API responds with JSON payload (unless otherwise stated). When data payload should be provided, it expects parameters to be passed in valid JSON (except when stated otherwise) with the Content-Type: application/json header being set.

All incompatible changes made to API will be versioned and won't affect existing endpoints. However, we may add additional fields to JSON response without any notice or API versioning. So it's not a good idea to rely on object mappers in your integration code that will fail on unknown properties.

We have two environments:

  • Test environment test-api.sumsub.com is only needed to implement integration with Sum&Substance. No checks are performed on the test environment.
  • In order to provide you with access to the production environment api.sumsub.com we require that the integration is tested first. We just want to make sure that everything goes right.

# Authentication

All API queries must be made over HTTPS, and plain HTTP will be refused. You must include your X-App headers in all requests.

# App Tokens

This is the most secure method of talking to our API programmatically.

You can generate App Tokens in the dev space in our dashboard for test and production environments.

# Making a request

All requests must contain the following headers:

  • X-App-Token - an App Token that you generate in our dashboard
  • X-App-Access-Sig - signature of the request in the hex format (see below)
  • X-App-Access-Ts - number of seconds since Unix Epoch in UTC

# Signing a request

The value of the X-App-Access-Sig is generated by a sha256 HMAC algorithm using a secret key (provided upon App Token generation) on the bytes obtained by concatenating the following information:

  • A timestamp (value of the X-App-Access-Ts header) taken as a string
  • An HTTP method name in upper-case, e.g. GET or POST
  • URI of the request without a host name, starting with a slash and including all query parameters, e.g. /resources/applicants/123?fields=info
  • Request body, taken exactly as it will be sent. If there is no request body, e.g. for GET requests, don't include it.

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

# Examples

Here are some examples how you can sign a request

# Access tokens for SDKs

When initializing WebSDK or MobileSDK, an access token authentication must be used.

POST /resources/accessTokens

# REQUEST HEADERS
Name Type Value
Accept String application/json
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
ttlInSecs Integer No Lifespan of a token in seconds. Default value is equal to 10 mins.
userId String Yes An external user ID which will be bound to the token.
applicantId String No Applicant ID that should be bound to this token.
# RESPONSE
Name Type Description
token String A newly generated access token for applicant.

An access token for applicant has limited access to the API, e.g. it’s only valid for 1 applicant and can't access other applicants.

# Creating an access token for applicant
# Example response

# Errors

On API errors we return standard HTTP Status Codes. Response body contains a JSON payload with additional information. For example:

# Response body
Name Type Always present Description
description String Yes Human-readable error description.
code Integer Yes HTTP Status code.
correlationId String Yes This id uniquely identifies the error. You can send this id to us, in case the cause of the problem is still unclear.
errorCode Integer No Code of the exact problem (see the Error codes section). For some errors may not be present.
errorName String No String representation of the exact problem (see the Error codes section). It always appears when errorCode presents.

# Error codes

Please, note that not all error responses will contain error code and name. More and more errors will get their codes in the future.

Code Name Description
1000 duplicate-document Duplicate document (image, video) was uploaded. Exact equality is taken into account.
1001 too-many-documents Applicant contains too many documents. Adding new ones is not allowed.
1002 file-too-big Uploaded file is too big (more than 64MB).
1003 empty-file Uploaded file is empty (0 bytes).
1004 corrupted-file File is corrupted or incorrect format (e.g. PDF file is uploaded as JPEG).
1005 unsupported-file-format Unsupported file format (e.g. a TIFF image).

If you still don't understand what the issue is, please, contact us with the correlationId provided.

# Applicants API

# Creating an applicant

An applicant is an entity representing one physical person. It may have several ID documents attached, like an ID card or a passport. Many additional photos of different documents can be attached to the same applicant.

POST /resources/applicants

When creating the applicant, the request body should contain parameter requiredIdDocs. You can have any combination of docSets in any order (this will be automatically mapped to the corresponding WebSDK steps). The only limitation is that document types must not overlap between different docSets.

When creating an applicant, you don't have to send us prefilled applicant data such as names, dob, addresses, etc. You only need to send us images and get the recognized document data by this method. It's the best way to increase your conversion because rejects of mismatches in names and typos will be excluded.

# REQUEST HEADERS
Name Type Value
Content-Type String application/json
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
#{body} Hash Yes An object representing an applicant (see example).
# REQUEST BODY
Name Type Required Description
externalUserId String No An applicant ID on the client side, should be unique. Required if you intend to initialize WebSDK for the applicant.
sourceKey String No If you want to separate your clients that send applicants, provide this field to distinguish between them.
email String No Applicant email.
lang String No The language in which the applicant should see the result of verification.
metadata Array of strings No Additional information that is not displayed to the end user ( Example: [{"key": "keyFromClient", "value": "valueFromClient"}] ).
requiredIdDocs Hash Yes Description of the required document set.
info Hash No Basic information about the applicant.
# info ATTRIBUTE
Name Type Required Description
firstName String No First name.
lastName String No Last name.
middleName String No Middle name.
legalName String No Legal name.
gender String No Sex of a person.
dob String No Date of birth (format YYYY-mm-dd, e.g. 2001-09-25).
placeOfBirth String No Place of birth.
countryOfBirth String No Country of birth.
stateOfBirth String No State of birth.
country String No Alpha-3 country code (e.g. DEU or RUS) (Wikipedia).
nationality String No Alpha-3 country code (Wikipedia).
phone String No Phone number.
addresses Array No List of addresses.
# addresses ELEMENTS FIELDS
Name Type Required Description
country String No Alpha-3 country code.
postCode String No Postal code.
town String No Town or city name.
street String No Street name.
subStreet String No Additional street information.
state String No State name if applicable.
buildingName String No Building name if applicable.
flatNumber String No Flat or apartment number.
buildingNumber String No Building number.
startDate String No Start date of stay in current building (format YYYY-mm-dd, e.g. 2001-09-25).
endDate String No End date of stay in current building (format YYYY-mm-dd, e.g. 2002-10-26).

An applicant entity with the associated id (refer to the example). Persist the id field after creating the applicant - it will be needed for further requests that you intend to make.

For the IDENTITY step we recommend the following document types: PASSPORT, ID_CARD, RESIDENCE_PERMIT, DRIVERS

# Supported idDocSetType are:
Value Description
IDENTITY A document that identifies an applicant.
IDENTITY2 An additional document that identifies an applicant.
SELFIE Some sort of facial photo of an applicant.
SELFIE2 Some sort of facial video of an applicant (please use this when you ask users to upload a video selfie).
PROOF_OF_RESIDENCE Proof of address, something like a utility bill (e.g. internet or electricity bills).
PAYMENT_METHODS The payment method as credit card, crypto-wallet or other.

Other types can be found in the WebSDK demo.

# Example request
# Example response

# Changing required document set

This method patches the required document set of the applicant. In case you need to add one more step to the check, for example, only the id document and the selfie were requested at first, and after the check has been completed you need to get the proof of address, so you need to add one more step to the current list of required documents. Please note that you should have special permission to make this request (contact the Sum&Substance tech team).

POST /resources/applicants/{applicantId}/requiredIdDocs

# REQUEST HEADERS
Name Type Value
Content-Type String application/json
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
body Hash No A new document set required
# RESPONSE

A new requiredIdDocs will be returned.

# Example request without body for getting current required document set
# Example request with body for changing required document set
# Example response

# Adding an ID document

A method gets a multipart form: ID doc JSON metadata and, optionally, a document photo. If the ID doc with this type already exists, its data will be merged. Existing data will be overwritten if they also present in the new object. However, a new image will be added nonetheless. If document metadata are not known yet, just send type and a country. E.g. "PASSPORT" and "GBR". These two fields are mandatory.

POST /resources/applicants/{applicantId}/info/idDoc

# REQUEST HEADERS
Name Type Value
Content-Type String multipart/form-data
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
# FORM DATA
Name Type Required Description
metadata Hash Yes An object representing an ID document
content Binary No A photo of a document
# REQUEST metadata BODY PART FIELDS
Name Type Required Description
idDocType String Yes See supported document types here
idDocSubType String No FRONT_SIDE, BACK_SIDE or null
country String Yes 3-letter country code (Wikipedia)
firstName String No First name
middleName String No Middle name
lastName String No Last name
issuedDate String No Issued date (format YYYY-mm-dd, e.g. 2001-09-25)
validUntil String No Valid until date (format YYYY-mm-dd, e.g. 2001-09-26)
number String No Document number
dob String No Date of birth
placeOfBirth String No Place of birth
# RESPONSE

JSON representing added document information.

If you need to know the imageId of the photo, you can find this information in the response header X-Image-Id

# Example request
# Example response

In cases when only the data of the document needs to upload:

# Example response

# Supported document types

Value Description
ID_CARD An ID card
PASSPORT A passport
DRIVERS A driving license
BANK_CARD A bank card, like Visa or Maestro
UTILITY_BILL A utility bill
BANK_STATEMENT A bank statement
SELFIE A selfie with a document (in this case no additional metadata should be sent)
VIDEO_SELFIE A selfie video (can be used in webSDK or mobileSDK)
PROFILE_IMAGE A profile image, i.e. userpic (in this case no additional metadata should be sent)
ID_DOC_PHOTO Photo from an ID doc (like a photo from a passport) (No additional metadata should be sent)
AGREEMENT Agreement of some sort, e.g. for processing personal info
CONTRACT Some sort of contract
RESIDENCE_PERMIT Residence permit or registration document in the foreign city/country
EMPLOYMENT_CERTIFICATE A document from an employer, e.g. proof that a user works there
DRIVERS_TRANSLATION Translation of the driving license required in the target country
INVESTOR_DOC A document from an investor, e.g. documents which disclose assets of the investor
VEHICLE_REGISTRATION_CERTIFICATE Certificate of vehicle registration
INCOME_SOURCE A proof of income
PAYMENT_METHOD Entity confirming payment (like bank card, crypto wallet, etc)
OTHER Should be used only when nothing else applies

# Getting applicant data

During the verification we also extract data from the applicant's id docs. To get the full structured view of an applicant you should perform the following request.

GET /resources/applicants/{applicantId}

or

GET /resources/applicants/-;externalUserId={externalUserId}

You may want to use the second request when you don't know an applicant id yet. E.g. when WebSDK created an applicant for you and we called your webhook endpoint.

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant id
externalUserId String Yes User id in your system
# RESPONSE

The existence of each field depends on the documents submitted for verification and the regulations of verification.

It's basically an applicant that you've created (or we've created for you, e.g. via WebSDK) with augmented information in cases where a verification has been completed. The info.idDocs field contains information extracted from applicants’ documents. As the described endpoint is actually quite generic (e.g. may return several applicants by external id, but we omit such details in this document), it returns a list of items. However, if you provide an applicant id that exists, only 1 item will be returned.

If an applicant ID does not exist, the endpoint won't return 404, instead it will return an empty list.

# Example request
# Example response

Here you can find examples of recognition results for all supported document types.

# Changing applicant data

If you want to change an applicant's data you can issue a PATCH request instead of creating a new applicant, which is highly discouraged. This method patches the fields in the info key of the applicant. Please note that you should have special permissions to make this request (contact the Sum&Substance tech team).

PATCH /resources/applicants/{applicantId}/info

# REQUEST HEADERS
Name Type Value
Content-Type String application/json
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS

The body must contain only those fields that you intend to change. Null fields will be ignored. If you want to unset some fields, provide these in the unsetFields query parameter. Check the info attribute above for the list of supported fields.

Name Type Required Description
#{body} Hash No Field in the info attribute that should be changed
applicantId String Yes Applicant ID
unsetFields String No Comma-separated list of fields to unset
# RESPONSE

A patched info entity. As this endpoint could be quite damaging if misused, please check that it returns expected results on the test environment — it's a client's responsibility to treat their applicants well 😃

Changing applicant data will cause the applicant to be switched back to the pending state.

# Example request
# Example response

# Getting verification results

When we are talking about verification results we typically mean two labels:

Value Description
GREEN Everything is fine
RED Some violations found

Once verification is finished, we will send you a POST request with JSON payload to the URL provided to us while integrating. Oftentimes, there are different URLs for staging and production environments. We may send several types of webhooks, but the one of interest here is the applicantReviewed webhook. This type of webhook is expected to arrive on average after 3-5 minutes, but can take up to 24 hours, in theory.

If for some reason you missed the webhooks, don't worry: we make a note of everything that was attempted to be sent, and can resend failed webhooks at any point in time. If webhook request fails we attempt to resend it four times: after 5 minutes, 1 hour, 5 and 18 hours until request succeeds.

Check createdAt field of webhook payload to make sure that you're getting relevant applicant status.

We recommend that you wait for the webhook no more than a day, and then send a request to our server for information about the status of the applicant.

Also you can monitor webhook statuses and resend them manually on the API Health page of dashboard on test and production.

Please note that the rejectLabels are only needed to analyze your statistics. They are generalized, so you should not use them to generate comments for your end user.

Webhook contains a reviewResult field that contains extra information, please see example. An important field is reviewAnswer, which contains a final highly trusted answer. Additionally, in cases of the RED answer, the rejectLabels field contains one or more of the following machine-readable constants:

Value Default reviewRejectType Description
FORGERY FINAL Forgery attempt has been made
DOCUMENT_TEMPLATE FINAL Documents supplied are templates, downloaded from internet
LOW_QUALITY RETRY Documents have low-quality that does not allow definitive conclusions to be made
SPAM FINAL An applicant has been created by mistake or is just a spam user (irrelevant images were supplied)
NOT_DOCUMENT RETRY Documents supplied are not relevant for the verification procedure
SELFIE_MISMATCH FINAL A user photo (profile image) does not match a photo on the provided documents
ID_INVALID RETRY A document that identifies a person (like a passport or an ID card) is not valid
FOREIGNER FINAL When a client does not accept applicants from a different country or e.g. without a residence permit
DUPLICATE FINAL This applicant was already created for this client, and duplicates are not allowed by the regulations
BAD_AVATAR RETRY When avatar does not meet the client's requirements
WRONG_USER_REGION FINAL When applicants from certain regions/countries are not allowed to be registered
INCOMPLETE_DOCUMENT RETRY Some information is missing from the document, or it's partially visible
BLACKLIST FINAL User is blacklisted
UNSATISFACTORY_PHOTOS RETRY There were problems with the photos, like poor quality or masked information
DOCUMENT_PAGE_MISSING RETRY Some pages of a document are missing (if applicable)
DOCUMENT_DAMAGED RETRY Document is damaged
REGULATIONS_VIOLATIONS FINAL Regulations violations
INCONSISTENT_PROFILE FINAL Like woman's name with male's documents
PROBLEMATIC_APPLICANT_DATA RETRY Applicant data does not match the data in the documents
ADDITIONAL_DOCUMENT_REQUIRED RETRY Additional documents required to pass the check
AGE_REQUIREMENT_MISMATCH FINAL Age requirement is not met (e.g. cannot rent a car to a person below 25yo)
EXPERIENCE_REQUIREMENT_MISMATCH FINAL Not enough experience (e.g. driving experience is not enough)
CRIMINAL FINAL The user is involved in illegal actions
WRONG_ADDRESS RETRY The address from the documents doesn't match the address that the user entered
GRAPHIC_EDITOR RETRY The document has been edited by a graphical editor
DOCUMENT_DEPRIVED RETRY The user has been deprived of the document
COMPROMISED_PERSONS FINAL The user does not correspond to Compromised Person Politics
PEP FINAL The user belongs to the PEP category
ADVERSE_MEDIA FINAL The user was found in the adverse media
FRAUDULENT_PATTERNS FINAL The user was found in criminal reports
SANCTIONS FINAL The user was found on sanction lists
NOT_ALL_CHECKS_COMPLETED RETRY All checks were not completed
FRONT_SIDE_MISSING RETRY Front side of the document is missing
BACK_SIDE_MISSING RETRY Back side of the document is missing
SCREENSHOTS RETRY The user uploaded screenshots
BLACK_AND_WHITE RETRY The user uploaded black and white photos of documents
INCOMPATIBLE_LANGUAGE RETRY The user should upload translation of his document
EXPIRATION_DATE RETRY The user uploaded expired document
UNFILLED_ID RETRY The user uploaded the document without signatures and stamps
BAD_SELFIE RETRY The user uploaded a bad selfie
BAD_VIDEO_SELFIE RETRY The user uploaded a bad video selfie
BAD_FACE_MATCHING RETRY Face check between document and selfie failed
BAD_PROOF_OF_IDENTITY RETRY The user uploaded a bad ID document
BAD_PROOF_OF_ADDRESS RETRY The user uploaded a bad proof of address
BAD_PROOF_OF_PAYMENT RETRY The user uploaded a bad proof of payment
SELFIE_WITH_PAPER RETRY The user should upload a special selfie (e.g. selfie with paper and date on it)
OTHER RETRY Some unclassified reason

Finally, the reviewRejectType field tells about the rejection type (if the RED answer is given). The following values are possible:

Value Description
FINAL Final reject, e.g. when a person is a fraudster, or a client does not want to accept such kinds of clients in his/her system
RETRY A reject that can be fixed, e.g. by uploading an image of better quality
EXTERNAL When everything is fine with the submitted documents, but there are some external reasons to reject, like the avatar on the client's site does not meet the requirements
# Example webhook payload with 'RED' answer
# Example webhook payload with 'GREEN' answer

# Applicant life-cycle

  • When creating an applicant, its status becomes init.
  • After uploading all required documents the status becomes pending.

Automatic status change (to pending) only works if a list of required documents is specified and all necessary documents are uploaded.

  • In some cases (discussed in advance), there is a special mode, when a client must manually signal to us when an applicant is ready to be reviewed.
  • After the verification process is completed, the status of the applicant will change to completed.

# Getting applicant status (SDK)

It is recommended that you use this method if you are using a WebSDK.

GET /resources/applicants/{applicantId}/status

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
# RESPONSE
Name Type Optional Value
createDate Date No Date of creation of the applicant.
reviewDate Date No Date of check ended.
startDate Date No Date of check started.
moderationComment String Yes A human-readable comment that can be shown to the end user.
clientComment String Yes A human-readable comment that should not be shown to the end user.

The reviewStatus can be one of the following:

Value Description
init Initial registration has started. A client is still in the process of filling out the applicant profile. Not all required documents are currently uploaded.
pending An applicant is ready to be processed.
queued The checks have been started for the applicant.
completed The check has been completed.
onHold Requires investigation - applicant waits for a final decision.
# Example request
# Example response

# Getting applicant status (API)

It is recommended that you use this method if you not only need an applicant’s status, but also information about documents.

GET /resources/applicants/{applicantId}/requiredIdDocsStatus

# REQUEST HEADERS
Name Type Value
Accept String application/json; charset=UTF-8
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
# RESPONSE

A breakdown for each step. Each step contains an array of images' IDs (could be several, e.g. if two sides were uploaded). You can get images with those IDs by issuing a request described here.

# Example request:
# Example response:

# Requesting an applicant re-check

You can programmatically ask us to re-check an applicant in cases where you or your user believe that our system made a mistake, or you want to request some additional checks agreed with us in advance. To do so you should explicitly move an applicant to the pending state by performing the following request.

POST /resources/applicants/{applicantId}/status/pending?reason=#{reason}

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
reason String No Status change reason

Provide a reason if available. It will help us understand why you want to recheck an applicant. If agreed in advance the reason you will be sending, we can automate the process and e.g. perform some additional checks and notify you about the results by the usual webhook means. If you want to automate complaints to your support, just send a user message along and we will consider it on a case-by-case basis.

# RESPONSE

In case of HTTP response 200, you may ignore the response body.

# Example request
# Example response

# Requesting an applicant check with different flow

If you plan to use this endpoint, please inform the Sum&Substance team, because this requires certain settings on our side.

You can programmatically request applicant check with flow that somehow differs from your usual checks.

POST /resources/applicants/{applicantId}/status/pending?reasonCode={reason}

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
reasonCode String Yes Code of the new flow

Provide a reasonCode to us so we could set up different flows on our side.

# RESPONSE

In case of HTTP response 200, you may ignore the response body.

# Example request
# Example response

# Getting document images

Since a user may re-upload images several times and, for example, also change a passport photo to an ID card, it might be tricky for you to understand which ones actually made the applicant pass or fail.

If you are interested in receiving images that were part of the final verification, you should use this method. Please note that you should have special permissions to make this request (contact the Sum&Substance tech team).

GET /resources/inspections/{inspectionId}/resources/{imageId}

# REQUEST ARGUMENTS
Name Type Required Description
inspectionId String Yes Inspection ID (it's a part of an applicant)
imageId String Yes Image ID (see above)
# RESPONSE

Binary content representing a document. The Content-Type response header more precisely describes the response mime-type.

# Example request:

# Adding an applicant to blacklist

If for some reason you need to add an applicant to the blacklist, you can use this endpoint. It is necessary to add the reason for adding the applicant to the blacklist.

POST /resources/applicants/{applicantId}/blacklist

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
note String Yes Reason or note for the applicant added to the blacklist (URL encoded)
# RESPONSE

The answer will contain the applicant added to the blacklist.

# Example request
# Example response

# Sharing applicants between partner services

Sharing Flow

Sometimes our clients partner with each other and want to simplify and speed up verification for their users when they have passed KYC once via Sum&Substance.

Assume a user A passed KYC in service X, and is now registering at the partner service Y. If X agrees to share information about A with Y, it can be done as follows:

  • X generates a share token and passes it to Y
  • Y calls our API with the share token and receives an applicant for user A (with all its data and documents) on their account

# Generating a share token

POST /resources/accessTokens/-/shareToken?applicantId={applicantId}&forClientId={clientId}

# Example of getting a share token (done by X)
# Example response
# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description Default
applicantId String Yes Applicant ID on service X
forClientId String Yes Client ID of service Y (ask them for this information)
ttlInSecs Integer No Time to live in seconds 1200
# RESPONSE

Share token in the token field of the returned JSON (see example).

# Importing an applicant

# Example of importing an applicant (done by Y)
# Example response

POST /resources/applicants/-/import?shareToken={shareToken}

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description Default
shareToken String Yes Share token generated by X
trustReview Boolean No If you trust your partner's check result, then you should use true. If it is false, then the applicant will be rechecked. false
# RESPONSE

Applicant entity in service Y. Note a new applicant ID returned in the response. Bind it in your system as needed.

Please note that share tokens will be invalidated once used.

# Resetting an applicant

In very rare cases, it is required to change the status of the applicant to init. For example, if a user has contacted support with a request to re-pass verification. Or if the applicant has been rejected with FINAL reviewRejectType and needs to be allowed to re-upload the documents.

If you plan to use this endpoint, please inform the Sum&Substance team, as we may be able to suggest another flow for your case.

POST /resources/applicants/{applicantId}/reset

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
applicantId String Yes Applicant ID
# Example request
# Example response

# Changing top-level info

This method patches top-level applicant info like email, externalUserId, sourceKey, type for specified applicantId. The body must contain only those fields that you intend to change. Null fields will be ignored.

PATCH /resources/applicants/

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST BODY
Name Type Required Description
id String Yes Applicant ID
externalUserId String No New External ID for an applicant
email String No New email
sourceKey String No New sourceKey
type String No New type (individual/company)
# Example request
# Example response

# Import applicants

This method is intended for data import. For example, in case if you already got a lot of applicants and want to recheck or maintain data consistency.

If you plan to use this endpoint, please inform the Sum&Substance team, as we may be able to suggest another flow for your case.

POST /resources/applicants/-/ingestCompleted

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
#{body} Hash Yes An object representing an applicant (see example).

Please note that the request body structure may be unique depending on the case, please inform the Sum&Substance team before using this method.

# Example request
# Example response

# Webhooks

The test server does not automatically check the applicants. If you need to change the status of the applicant or get webhook on the test server, you can do it by yourself.

We can send webhooks not only via HTTP request, but also as notifications in Slack, Telegram or via email.

# Webhooks types

The types of webhooks we send depend on the settings.

Value Description
applicantReviewed When verification is completed. Contains the verification result. More information about this type of webhook can be found here.
applicantPending When a user uploaded all the required documents and the applicant's status changed to pending.
applicantCreated When an applicant is created.
applicantOnHold Processing of the applicant is paused for an agreed reason.
applicantPrechecked When primary data processing is completed.
# Example applicantReviewed webhook payload you can find here. Example applicantCreated webhook payload:
# Example applicantPending webhook payload:
# Example applicantOnHold webhook payload:
# Example applicantPrechecked webhook payload:

# Testing on the test environment

On a test environment you can try receiving results via applicantReviewed webhooks by triggering the following endpoint (provide either GREEN or RED to simulate a positive or negative answer, correspondingly):

POST /resources/applicants/{applicantId}/status/testCompleted

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
Accept String application/json; charset=UTF-8
Content-Type String application/json
# REQUEST ARGUMENTS
Name Type Required Description
#{body} Hash Yes Please see example
applicantId String Yes Applicant ID
# REQUEST BODY
Name Type Required Description
reviewAnswer String Yes Provide GREEN or RED to simulate answer you need
rejectLabels String Yes Reasons for rejections
reviewRejectType String No Choose EXTERNAL, FINAL or RETRY to simulate other types of rejections
# RESPONSE

In the case of HTTP response 200, you may ignore the response body.

# Example request to change the applicant status to GREEN
# Example request to change the applicant status to RED
# Example response

# Verifying webhook sender

It's better to not rely on our IP addresses for whitelisting them as webhook sender because they're changing from time to time.

In order to make sure that a webhook is sent by us, we have the possibility to sign it with the HMAC Sha1Hex algorithm. If you want to utilize this feature, we need to agree on a secret key that will be used for signing the HTTP webhook body. To compute digest correctly, you need to convert the HTTP webhook body into bytes and then perform calculations. The header x-payload-digest will be added to the webhook. In order to verify that a webhook is sent by us, you compute the same digest using the HTTP body and a secret key and compare it to the digest value that we've sent to you.

In order to check that you compute the digest the same way we do, you can call the following endpoint.

POST /resources/inspectionCallbacks/testDigest?secretKey={secretKey}

# REQUEST HEADERS
Name Type Value
X-App-Token String App Token that you generate in our dashboard
X-App-Access-Sig String Signature of the request in the hex format
X-App-Access-Ts String Number of seconds since Unix Epoch in UTC
# REQUEST ARGUMENTS
Name Type Required Description
#{body} Hash Yes Any payload
secretKey String Yes A secret key that might be used for signing
# RESPONSE
Value Description
digest Result of the calculation

Please test your webhook before sending its URL to us. At a minimum, it should not give a 500 HTTP response or require any sort of authorization.

# Example request to get digest
# Example response
# Example request to client's endpoint
# Example of computing digest on JS
Last Updated: 5/14/2020, 3:15:58 PM