NAV Navbar
Python NodeJS

Overview

Passfort helps companies onboard new applicants and monitor potential risk that existing customers bring to their organization.

For example, take a bank that requires all potential new customers to make an application. As part of the application process, known as onboarding, the bank can use Passfort to run checks on the applicant. If the applicant passes the required checks and is approved to become a customer, the bank can monitor potential risk to their organization by reviewing any new or updated check results that are returned in Passfort.

When you build and host an integration with Passfort, our users have the option to run checks using your product and, if you choose to provide ongoing monitoring, review any new and updated results your product flags.

How a partner integration works

The Passfort Partner API integration has several components that link together to allow a user to run a check with your product. The following diagram shows the flow between components. Components 3, 4, and 5 are built and hosted by you.

Passfort Partner API components

Components

The components of a partner integration are:

  1. Passfort Lifecycle API: The API through which Passfort users request to run a check and see its result. To learn more, see the Passfort Lifecycle API reference.
  2. Passfort product: Our product for onboarding and monitoring. One of our core product features is to allow users to run an onboarding check using the data provider of their choice.
  3. Passfort Partner API: The API through which Passfort requests you run a check and through which you return the result. You’ll build and host this interface. Our documentation is here to help you understand which endpoints to support.
  4. Integration service: Optionally, you can build an intermediary service to handle communication between your product and the Passfort Partner API.
  5. Partner product: Your product runs the check and returns the result.

Request process

The process for a user to request a check and get the result is as follows:

  1. A Passfort user requests a check. This request is passed through the Passfort Lifecycle API to the Passfort product.
  2. The Passfort product passes the request to your Partner product through the Passfort Partner API. The request includes any relevant information you might need to run the check, for example key details about the onboarding applicant. Optionally, you can build a service to handle communication between the Passfort Partner API and your Partner product.
  3. Your Partner product runs the check and uses the Passfort Partner API to return the result to our Passfort product.
  4. Depending on the check type, the Passfort product may perform additional validation on top of the result you return. For example, with a Document verification check, Passfort confirms the data you’ve extract from the document matches the profile data. Profile data is the term Passfort uses to refer to an applicant’s data, for example, the applicant’s name and date of birth.
  5. The Passfort product returns the results to the user through the Passfort Lifecycle API.

How a Passfort customer uses a partner integration

After you’ve published your integration, Passfort customers can ask us to add your check to their account.

To do this, we add the relevant check type and task type to the customer’s product in Passfort. A product in Passfort represents a real-life product that an applicant can apply for. Every product in Passfort is associated with a specific onboarding flow.

The diagram that follows shows the elements of a product.

Elements of a product

Product elements

The elements of a product are as follows:

  1. Smart policy: The smart policy is a flow that determines which due diligence task types an individual or company needs to complete to be onboarded to the product. If individuals and companies can both apply for the product, the product has one smart policy for individuals and another for companies.
  2. Risk model: The risk model is an optional feature for evaluating an applicant’s potential risk to the user’s business. As with smart policies, if individuals and companies can both apply for the product, the product has one risk model for individuals and another for companies. Although risk models don’t directly relate to your check, they can affect how a smart policy behaves.

Note that your check will be for either individuals or companies, so will only be included in one smart policy. If you would like to provide one check for individuals and another for companies, you should create two different integrations, for example partnerurl.com/individual and partnerurl.com/company.

When an individual or company makes a product application, the application follows the smart policy flow. At certain points in the flow, onboarding tasks are added to the application, including the one associated with your check type.

Once the associated task is added to the application, Passfort users have the option to run your check. Alternatively, the check can be set up to run automatically as soon as the task is created so user intervention isn’t required.

Note that one task type can have multiple check types. For example, the Verify identity task can be associated with the Electronic identity check and an ID verification check because both checks provide a way for the user to verify the applicant’s identity.

Passfort users may also have multiple data providers to run the same check type. This is useful, for example, if one check fails, or if the user wants to choose a data provider that specializes in checks for the applicant’s country.

The diagram that follows shows that every task type must have at least one check type and every check type must have at least one data provider. There is no limit to the number of checks that can be associated with a task, and there is no limit to the number of data providers that can be used for one check.

The relationship between task types, check types, and data providers

When a user requests a check with your product, we pass the request to you. When you return the results to us, Passfort users access them through the Passfort Lifecycle API. Our product presents the check result in a clear, consistent way so our customers can easily compare results from different checks.

Get started

To integrate with Passfort, you’ll build the Passfort Partner API. This should be a JSON web service that conforms to the specifications outlined in this document.

Note that an integration should only support one check type. If you would like to provide Passfort users with multiple check types, you should create one integration per check type.

Design your integration

Your design should consider the following:

  1. Which check type you’ll support. The check type determines the kind of information you’ll provide to Passfort users. For example, The Identity check type is used to confirm an individual is who they say they are, and the Company data check type is used to get basic information about a company.
  2. Which check template you’ll use, for example one-time sync or one-time callback. The check template determines how the check behaves, including how long it takes to return the check result and whether you’ll provide ongoing monitoring. Note that each check type supports specific templates, as described in the documentation.
  3. How you’ll map your data to the check result. We ask that you use the structures described in this documentation. Note that when the Passfort product displays the check data to the user, there may be slight differences or certain fields may be hidden.
  4. Which configuration options you’d like to provide Passfort customers. You could, for example, allow customers to specify which countries users can run the check for or require customers to provide authorization credentials. Any configuration options you send to the Configuration endpoint are displayed in Passfort’s portal for customers to see and engage with.

Build your integration

The Passfort Partner API JSON web service you build should meet the technical requirements.

All requests must follow the rules for authentication.

Your service should support endpoints for:

There may be additional endpoints for your check type and template. To learn more, see the documentation for your check type and template.

You can learn more about check input, errors, and charges in the Data Structure section.

Your integration should also support demo checks.

Test your integration

After you’ve implemented a check, sign in to the Passfort portal and register your product as a custom provider. If you’re supporting multiple checks, do this once per check.

Next, run the validation suite to test whether the Passfort product can send requests to your product and receive responses correctly. Note that the validation suite only provides sample data and does not include real check data.

Finally, you should create a sandbox environment so you can test the check with your real check data.

If you make any changes to your check or configuration, you should re-run the validation suite, then repeat your real data tests in your sandbox environment.

Document your integration

Partners are responsible for writing, maintaining, and hosting their own documentation. To ensure the best self-serve experience for customers, we suggest including the following:

Let us know you're ready to launch

Partners are responsible for informing us 14 days before launching so we have time to test and set up any additional components on our end. Please be aware we may need a longer processing time during the Christmas holidays. To inform us or ask any questions, send an email to passfort_partners@moodys.com and include the following information:

Support

If you have any questions, you can always send us an email at passfort_partners@moodys.com.

About this documentation

As the majority of the Passfort Partner API is not called but served by integrations, the endpoints documented here, unless otherwise indicated, are ones that your integration should implement.

Code samples are given in the dark area to the right, and will generally take the form of abbreviated route handlers for the functionality being described. For the Python examples, Flask 1.0 are used as the implementation example, and Express 4 are used for the NodeJS examples.

As described in the Metadata section, the Passfort Partner API is versioned to allow the implementation of integrations to be altered in the future; all information in this document corresponds to Version 1 of the Passfort Partner API Protocol. Versions of the Passfort Partner API won’t be discontinued for as long as existing integrations use them.

Technical Requirements

Your integration must be served over HTTPS; integrations aren’t permitted to be served over unencrypted HTTP connections. Additionally, the connection must be using TLS 1.2 or above. This requirement is enforced to ensure that sensitive information is not transmitted unprotected over the public internet.

Your integration may use plain HTTP for basic testing, but validation will fail if your integration does not use HTTPS.

Authentication

In order to protect the integrity and confidentiality of personal information and to ensure your integration is only utilised by Passfort, all requests are authenticated using the HTTP signatures draft standard, version 12. Several usable implementations of the standard can be found on this tracker of HTTP Signatures implementations maintained by the spec authors.

When implementing an integration, you must generate a 32 byte key secret key to sign and verify all requests and responses your integration handles, unless specifically noted in this document; the key ID to use should be the first 8 characters of the Base64 encoding of this key. The only supported algorithm is hmac-sha256, and the only supported Digest is SHA-256.

You must sign and verify at least the (request-target) (the verb and full path of the initial request) and Date headers. Requests with a body (eg. POST requests) must also include and sign a Digest header. The Date header must be set to the current date. Requests with any of...

... will be rejected.

Metadata

Get Integration Metadata

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/")
def get_integration_metadata():
    return jsonify({
        "protocol_version": 1,
        "provider_name": "My Custom Integration"        
    })
const express = require('express')
const app = express()

app.get('/', (req, res) => {
    res.json({
        protocol_version: 1,
        provider_name: 'My Custom Integration'
    })
})

This endpoint should return JSON in the following format:

{
    "protocol_version": 1,
    "provider_name": "My Custom Integration"
}

This endpoint defines the basic properties of all integrations - which version of the Passfort Partner API Protocol is being used, and the name of the provider this integration connects to (for display and branding purposes within Passfort). Currently, the only API Protocol version is 1. This endpoint is unauthenticated to allow future API versions to use different authentication methods. All integrations regardless of type must serve up this endpoint.

HTTP Request

GET https://my-integration.example.com/

Response fields

Field Type Required? Description
protocol_version number Yes An integer representing the version of the version of the Integration API to use. Currently, this is always 1.
provider_name string Yes The name of the provider this integration connects to. Currently, the name must be at least 6 characters in length, and no greater than 49 characters.

Configuration

A sample configuration for a synchronous identity check.

{
  "check_type": "IDENTITY_CHECK",
  "check_template": {
    "type": "ONE_TIME_SYNCHRONOUS",
    "timeout": 60
  },
  "pricing": {
    "supports_reselling": true,
    "maximum_cost": 200
  },
  "supported_countries": ["GBR", "USA", "CAN"],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "username",
        "label": "Username"
      },
      {
        "type": "password",
        "name": "password",
        "label": "Password"
      }
    ]
  },
  "config": {
    "fields": [
      {
        "type": "boolean",
        "name": "boolean_config",
        "label": "Boolean config field",
        "subtext": "A description of the option",
        "default": false
      },
      {
        "type": "MultiSelect",
        "name": "multiselect_config",
        "label": "Config field with dropdown options",
        "subtext": "A description of the option",
        "options": ["Option 1", "Option 2", "Option 3", "Option 4"],
        "default": null
      }
    ]
  }
}

The configuration endpoint defines several important properties about your integration. Most parts of the configuration are common to all integrations, but the check_type and check_template are specific to each type of integration and will be discussed in their respective sections.

Pricing

The pricing field defines whether you intend to make your integration available to Passfort for reselling, instead of requiring that Passfort customers have a direct commercial relationship with the data provider.

Fields

Field Type Required? Description
supports_reselling boolean Yes Whether your integration supports being configured for reselling.
maximum_cost number No The maximum amount of Passfort credits that can be charged for a single check. Required if supports_reselling is true.

Supported countries

The supported_countries field defines which countries your integration is able to support. The exact interpretation of this field varies depending on the check type, but it typically reflects country of residence for individuals and the country of incorporation for companies. This field is an array of strings, which should be the ISO3 country code for the country. At least one country must be specified.

Supported features

The optional supported_features field allows your integration to declare support for additional features. The absence of this field from your integration's config implies that no additional features are supported.

The list of possible features varies depending on the check type but are often used to surface extra functionality implemented by the provider.

These features are currently recognised as items within the supported_features array:

Feature Check Type Description
COMPANY_SEARCH Company Data The integration supports predictive search through the companies known to the provider.

Credentials Fields

The credentials field contains exactly one field, fields, which specify an array of single values needed for your integration to contact the data provider and authorize itself successfully. Customers will provide these as part of configuring your integration. For checks with reselling enabled, these credentials won't be sent.

Per Passfort's general API compatibility policies, we may add new types for configuration fields at any time, although existing types won't be removed.

Fields

These fields are permitted on objects inside the fields array:

Field Type Required? Description
type One of: "string", "password" Yes The type of the credential field. password is functionally identical to string, but is rendered as a password input in the UI.
name string Yes The name of the field which is used when sent to your integration.
label string Yes The name that's displayed for this field in Passfort.

Configuration Fields

Like credentials, the config field contains exactly one field, fields, which specify an array of configurable options for your integration that can be set up on individual provider configurations, and is provided to your integration on every check.

Per Passfort's general API compatibility policies, we may add new types for configuration fields at any time, although existing types won't be removed.

Fields

These fields are permitted on objects inside the fields array:

Field Type Required? Description
type One of: "string", "boolean", "MultiSelect" Yes The type of the configuration field.
name string Yes The name of the field which is used when sent to your integration.
label string Yes The name that's displayed for this field in Passfort.
subtext string No A short description that's displayed under the configuration option in Passfort.
options array[string] No An array of options which may be chosen; used for both display name and value. Only applicable to (and required for) the MultiSelect field type.
default A valid value allowed by the type specified in type Yes The default value for this configuration field. For MultiSelect fields, this value may also be null. Otherwise, it must be a valid value for the field's type; for example, a boolean field may only have a default of either true or false.

Data Structure

Passfort structures data on individual and company entities in a standard format throughout the product. Additionally, many data structure types are common across different checks.

Check input

Checks are given information on a profile through the check_input field on the JSON body of the request, either accepting CompanyData or IndividualData depending on the check type. For full information on the structure of this data, check the input_data field on the 'Run a check' response in our API documentation or consult the schemas for CompanyData and IndividualData in our OpenAPI spec.

Check errors

All checks may return errors in their errors field using the structure specified here.

Error fields

Field Type Required? Description
type One of the supported error types Yes The type of error that's being reported.
sub_type A valid error subtype for the specified type No Provides additional detail for certain types of error.
message string Yes A message displayed in the Passfort portal to show the check error.
data A map of strings to any valid JSON value No Integration-specific structured error information that customers can use to get additional information about the error.

Error types

INVALID_CREDENTIALS

The data provider reported that the credentials used aren't valid.

INVALID_CONFIG

Your integration is not able to run the check because it was sent with invalid configuration values.

MISSING_CHECK_INPUT

Your integration is not able to run the check because the input_data does not contain fields that are required by the data provider.

INVALID_CHECK_INPUT

Your integration is not able to run because the input_data contains values that your integration cannot handle, for example, because the date of birth is not accurate enough, or because the country on the profile is not supported by this data provider.

Subtypes:

Subtype Description
UNSUPPORTED_COUNTRY The data provider doesn't support running checks for the requested country.
MISSING_CONTACT_DETAILS Contact details are missing from the check input.

PROVIDER_CONNECTION

A successful request could not be made to the data provider due to connection issues, such as downtime or a check timeout.

PROVIDER_MESSAGE

The data provider returned an error message when processing this check.

UNSUPPORTED_DEMO_RESULT

This error should be returned when your integration receives a demo_result value which it doesn't support or does not have demo data implemented.

Check charges

Checks may return charges in their charges field using the structure specified here.

Charge fields

Field Type Required? Description
amount integer Yes The amount to charge (in pennies). In the future, it may be possible to specify a different currency unit.
sku string No Stock Keeping Unit (SKU). All charges with the same SKU should cost the same amount. For providers with a fixed cost in each country, the SKU can simply be the 3-letter code for the country in which the check was run. This field can be omitted if there is no sensible value to use.
reference string No The reference should be unique for each check. It should be possible to use the reference to correlate the charges recorded by the provider against the charges recorded in Passfort.

Demo Checks

Integrations should support the ability to provide demo results to customers using Passfort's demo environments for integration work and evaluation. To this end, the Passfort Partner API allows for checks to be run with a specifically requested demo result using the demo_result field in the request payload of most check types.

Guidelines for demo results

Demo result types

To support a wide range of testing scenarios, Passfort uses specific values in the demo_result field to select demo results. The different types of demo result are outlined below.

Demo results for all check types

These demo result values may be requested for any check type.

ANY Required

A demo result that's used as the default if nothing more specific is requested. It should reflect a genuine non-error result for this integration, but it does not need to be a passing result.

ANY_CHARGE Conditional

This demo result will be used to test billing. This is required if your integration supports reselling and the maximum amount your integration can charge for a check is greater than zero.

There are no requirements on what the result of the check must be, but if the check is being resold, at least one non-zero charge must be returned. The usual rules also still apply: the total amount charged must be no greater than the maximum specified in your integration's configuration.

Note that, as this is a demo check, no credits will actually be deducted from the customer.

ERROR_INVALID_CREDENTIALS Required

Your integration must return a result as if a customer with a direct commercial relationship has provided credentials that have been rejected by the data provider.

ERROR_ANY_PROVIDER_MESSAGE Required

Your integration must return a result as if the data provider was successfully reached but encountered a problem fulfilling the request, such a problem with the service, or missing information in the request.

ERROR_CONNECTION_TO_PROVIDER Required

Your integration must return a result as if it attempted to contact the data provider but the connection failed (due to timeouts or outages).

Demo results for Identity Checks

These demo result values are specific to Identity Checks.

NO_MATCHES Required

Your integration must return a result where the data provider could not find any matching records for the submitted profile.

ONE_NAME_ADDRESS_MATCH Required

Your integration must return a result where the data provider could find a match on the full name and address for the submitted profile in a single database.

ONE_NAME_DOB_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name and date of birth for the submitted profile in a single database.

TWO_NAME_ADDRESS_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name and address for the submitted profile in at least two separate databases, if the provider supports this.

ONE_NAME_ADDRESS_ONE_NAME_DOB_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name and address for the submitted profile in a single database, and a match on the full name and date of birth in another separate database, if the provider supports this.

ONE_NAME_ADDRESS_DOB_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name, address, and date of birth for the submitted profile in at least one database.

MORTALITY_MATCH Optional

Your integration must return a result where the data provider could find a match on the submitted profile in at least one mortality register, if the provider supports this.

ONE_NAME_ADDRESS_MORTALITY_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name and date of birth for the submitted profile in a single database, and also a match in at least one mortality register, if the provider supports this.

ONE_NAME_ADDRESS_ONE_NAME_DOB_MORTALITY_MATCH Optional

Your integration must return a result where the data provider could find a match on the full name and address for the submitted profile in a single database, and a match on the full name and date of birth in another separate database, and also a match in at least one mortality register, if the provider supports this.

Demo results for Document Checks

These demo results are specific to Document verification and Document fetch checks unless otherwise specified.

ERROR_UNSUPPORTED_DOCUMENT_TYPE Required

Your integration must return a result as if a document was submitted whose type is not supported by the data provider.

DOCUMENT_IMAGE_CHECK_FAILURE

Your integration must return a result as if a document was submitted which failed one or more image checks. For example, if the document image was too blurry.

DOCUMENT_FORGERY_CHECK_FAILURE

Your integration must return a result as if a document was submitted which failed one or more forgery checks. For example, if the fonts used on the document are incorrect.

DOCUMENT_NAME_FIELD_DIFFERENT

Your integration must return a result where the name extracted from the document differs from the name on the check input.

DOCUMENT_NAME_FIELD_UNREADBALE

Your integration must return a result where no name could be extracted from the document.

DOCUMENT_DOB_FIELD_DIFFERENT

Your integration must return a result where the date of birth extracted from the document differs from the date of birth on the check input.

DOCUMENT_DOB_FIELD_UNREADBALE

Your integration must return a result where no date of birth could be extracted from the document.

DOCUMENT_ALL_PASS Required

Your integration must return a result where the extracted data matches the check input and all image and forgery checks have passed.

ERROR_INVALID_PROVIDER_REFERENCE Conditional

This demo result is required for Document fetch checks. It is not used for Document verification checks.

Your integration must return a result indicating that the document reference passed as part of the check input was invalid.

ERROR_MISSING_CONTACT_DETAILS Conditional

This demo result is optional for Document fetch checks. It is not used for Document verification checks.

Your integration must return an error indicating that the contact details field is missing from the check input.

Demo results for Company Data Checks

These demo results are specific to Company Data checks.

NO_DATA Required

Your integration must return a result as if the company details submitted do not match any on the provider's records.

ALL_DATA Required

Your integration must return a result as if the provider had data for all of their supported fields.

COMPANY_INACTIVE Required

Your integration must return a result as if the company submitted was on record as no longer actively operating.

COMPANY_COUNTRY_OF_INCORPORATION_MISMATCH

Your integration must return a result as if the company submitted was on record with a different country of incorporation from the one submitted in the check input.

COMPANY_NAME_MISMATCH Required

Your integration must return a result as if the company submitted was on record with a different name from the one submitted in the check input.

COMPANY_NUMBER_MISMATCH Required

Your integration must return a result as if the company submitted was on record with a different number from the one submitted in the check input.

COMPANY_RESIGNED_OFFICER

Your integration must return a result with at least one associate with all its officer relationships marked with a FORMER tenure.

`COMPANY_FORMER_SHAREHOLDER

Your integration must return a result with at least one associate with a shareholder relationship marked with a FORMER tenure.

COMPANY_OFFICER_WITH_MULTIPLE_ROLES

Your integration must return a result with at least one associate with more than one officer relationship.

COMPANY_SHAREHOLDER_WITH_100_PERCENT_OWNERSHIP

Your integration must return a result with at exactly one associate with a single shareholder relationship owning 100% of the company.

COMPANY_SHAREHOLDER_WITH_SIGNIFICANT_CONTROL

Your integration must return a result with at least one associate who has both a shareholding relationship and one indicating significant control or influence over the company.

COMPANY_INDIVIDUAL_OF_SIGNIFICANT_CONTROL

Your integration must return a result with at least one associate which is an individual with a relationship indicating significant control or influence over the company.

COMPANY_COMPANY_OF_SIGNIFICANT_CONTROL

Your integration must return a result with at least one associate which is a company with a relationship indicating significant control or influence over the company.

COMPANY_ADDRESS_MATCH Conditional

Your integration must return a result as if the company submitted was on record with an address matching the one submitted in the check input. This demo result is required when the Provider Field Checks feature is in use.

COMPANY_ADDRESS_MISMATCH Conditional

Your integration must return a result as if the company submitted was on record with a different address from the one submitted in the check input. This demo result is required when the Provider Field Checks feature is in use.

Using your integration

In order to use your data provider inside Passfort for testing or production use, you must register the integration as a custom provider. A custom provider allows your integration to be used by a single Passfort institution.

Setting up a custom provider

To start setting up your integration, navigate to the Data providers section of the Policy Builder tab in the portal. Then, click the New data provider button in the top-right corner of the page. Choose Individual data provider or Company data provider as appropriate for your integration.

Policy builder data providers

In the New data provider modal, first choose the check type for your custom provider. Custom integrations are found at the bottom of the list.

Check type selection in 'New data provider' modal

Then choose a suitable name for your custom provider.

Provider name entered 'New data provider' modal

Then choose create, after which you will be brought to the Validation screen.

Validation

Your custom provider has not yet been saved; to begin using your custom provider, you must first pass the validation suite for your check type. These tests ensure your integration meets basic technical and security standards required.

Validation screen

Enter the URL for your integration, as well as the secret key you have chosen. See the authentication section for more information on the requirements for your secret key. Once ready, press Run Validation to start the validation process. The validation process may take some time, depending on the check type and configuration of your integration.

Validation results display

Once the validation run has completed, the outcome and information on the tests will be displayed below, including basic information detected about your check, if available. If validation of your integration passed without any failures or errors, you will now be able to click Save to create your custom provider as a usable data provider. You can also view the results of individual tests run during validation.

Error returned by the validation suite

If validation fails or encounters errors, you won't be able to save your custom provider until they're addressed. View the test results for information on why your custom provider has failed validation. In this case, validation failed because a URL was provided for a non-existent domain.

Revalidating your custom provider

Should you want to retest validation for your custom provider at any point, or if you have updated the configuration or settings for your check, you can submit the provider for validation again. This allows you to quickly update your custom provider's configuration without needing to reconfigure your Passfort smart policy.

Update custom integration section on provider config

Press the Update button in the Update custom integration section. You will be brought back to the validation screen.

One-time Sync Identity Check

This section lists all endpoints that must be implemented for a one-time synchronous identity check integration.

One-time synchronous identity checks are identity checks with the following behaviour:

Get Check Configuration (One-time Sync Identity Check)

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "IDENTITY_CHECK",
        "check_template": {
            "type": "ONE_TIME_SYNCHRONOUS",
            "timeout": 60
        },
        "pricing": {
            "supports_reselling": True,
            "maximum_cost": 200
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "username",
                    "label": "Username"
                },
                {
                    "type": "password",
                    "name": "password",
                    "label": "Password"
                }
            ]
        },
        "config": {
            "fields": [
                {
                    "type": "boolean",
                    "name": "require_dob",
                    "label": "Date of birth is required for 1+1 and 2+2 results",
                    "subtext": "The individual's date of birth must be matched in one source for 1+1 and 2+2 results to be achieved",
                    "default": False
                }
            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'IDENTITY_CHECK',
        check_template: {
            type: 'ONE_TIME_SYNCHRONOUS',
            timeout: 60
        },
        pricing: {
            supports_reselling: true,
            maximum_cost: 200
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'username',
                    label: 'Username'
                },
                {
                    type: 'password',
                    name: 'password',
                    label: 'Password'
                }
            ]
        },
        config: {
            fields: [
                {
                    type: 'boolean',
                    name: 'require_dob',
                    label: 'Date of birth is required for 1+1 and 2+2 results',
                    subtext: 'The individuals date of birth must be matched in one source for 1+1 and 2+2 results to be achieveds date of birth must be matched in one source for 1+1 and 2+2 results to be achieved',
                    default: false
                }
            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "IDENTITY_CHECK",
  "check_template": {
    "type": "ONE_TIME_SYNCHRONOUS",
    "timeout": 60
  },
  "pricing": {
    "supports_reselling": true,
    "maximum_cost": 200
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "username",
        "label": "Username"
      },
      {
        "type": "password",
        "name": "password",
        "label": "Password"
      }
    ]
  },
  "config": {
    "fields": [
      {
        "type": "boolean",
        "name": "require_dob",
        "label": "Date of birth is required for 1+1 and 2+2 results",
        "subtext": "The individual's date of birth must be matched in one source for 1+1 and 2+2 results to be achieved",
        "default": false
      }
    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform one-time synchronous identity checks using your integration.

HTTP Request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. Check specific options will be discussed here.

Check type

The check_type field must be set to "IDENTITY_CHECK".

Check template

The check_template fields for this check are:

Field Type Required? Description
type The value "ONE_TIME_SYNCHRONOUS" Yes Which check template to use for this check. For one-time synchronous checks, you must specify "ONE_TIME_SYNCHRONOUS".
timeout number No The number of seconds Passfort should wait without a response before considering identity checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used.

Run One-Time Sync Identity Check

This endpoint exposes your data provider's identity check to Passfort.

HTTP Request

POST https://my-integration.example.com/checks

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ]
  },
  "provider_config": {
    "require_dob": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input An IndividualData object Yes This field contains the profile information for the individual on which the Identity check is run. See the PassFort Data Structure check input section for more information on how profile data is structured within Passfort.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post('/checks')
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)

        return jsonify({
            'check_output': {
                'entity_type': 'INDIVIDUAL',
                'address_history': [],
                'electronic_id_check': {
                    'matches': [
                        ({
                            'count': len(database.matched_records),
                            'database_name': database.name,
                            'database_type': 
                                'CIVIL' if database.is_voting_register else 'CREDIT',
                            'matched_fields': 
                                to_passfort_field_types(database.matched_fields)
                        }) for database in result.matched_databases
                    ]
                }
            },
            'errors': [],
            'warnings': [],
            'provider_data': dict(result)
        })
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })
const express = require("express");
const app = express();

const { createDemoResult } = require("./testing");
const {
  makeProviderRequest,
  RESELLER_CREDS,
  toPassfortFieldTypes,
} = require("./provider");

app.use(express.json());

app.post("/checks", (req, res) => {
  // Handle demo data scenarios
  if (req.body.demo_result !== undefined) {
    return res.json(
      createDemoResult(req.body.demo_result, req.body.check_input)
    );
  }

  // Use provided creds if check is through direct agreement
  const credentials =
    req.body.commercial_relationship === "DIRECT"
      ? res.body.provider_credentials
      : RESELLER_CREDS;

  return makeProviderRequest(
    credentials,
    req.body.provider_config,
    req.body.check_input
  )
    .then((checkResult) => {
      return res.json({
        check_output: {
          entity_type: "INDIVIDUAL",
          address_history: [],
          electronic_id_check: {
            matches: checkResult.matched_databases.map((database) => ({
              count: database.matched_records.length,
              database_name: database.name,
              database_type: database.is_voting_register ? "CIVIL" : "CREDIT",
              matched_fields: toPassfortFieldTypes(database.matched_fields),
            })),
          },
        },
        errors: [],
        warnings: [],
        provider_data: checkResult.data(),
      });
    })
    .catch((err) => {
      if (err.type === "CONNECTION") {
        return res.json({
          errors: [
            {
              type: "PROVIDER_CONNECTION",
              error: "Failed to contact data provider: " + e.message,
            },
          ],
          warnings: [],
        });
      } else {
        return res.json({
          errors: [
            {
              type: "PROVIDER_MESSAGE",
              error: "Provider error: " + e.message,
            },
          ],
          warnings: [],
        });
      }
    });
});

This endpoint should return JSON in the following format:

{
  "check_output": {
    "entity_type": "INDIVIDUAL",
    "address_history": [

    ],
    "electronic_id_check": {
      "matches": [
        {
          "count": 1,
          "database_name": "Credit File from Lender A",
          "database_type": "CREDIT",
          "matched_fields": [
            "FORENAME",
            "SURNAME",
            "ADDRESS",
            "DOB",
            "IDENTITY_NUMBER"
          ]
        },
        {
          "count": 1,
          "database_name": "Electoral Roll",
          "database_type": "CIVIL",
          "matched_fields": [
            "FORENAME",
            "SURNAME",
            "ADDRESS"
          ]
        }
      ]
    }
  },
  "errors": [

  ],
  "warnings": [

  ],
  "provider_data": {
  }
}

Response fields

Field Type Required? Description
check_output Object structured in check_output below If check did not error Indicates the result data for this check. See the check_output section for the full structure of this check. In the absence of a result, Passfort tries to interpret a result from the check_output.
result A supported result type Only when there is no check_output Indicates the result of this check. If this is not empty, this is the result of the check in Passfort. The result field should only be populated when the provider does not give enough information to generate a suitable check_output, or if the user has explicitly requested to use the raw provider result without Passfort's interpretation.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.
charges An array containing one or more Charges No A list of charges incurred while running this check. Charges may only be returned if both of these conditions are met:
  • No errors occur when the check is run.
  • The check is resold by Passfort.
For demo checks, charges may be returned, but they won't be deducted from the institution's credit. If charges are returned, the total amount charged must be no greater than the maximum cost-per-check specified in the integration's configuration.

result

The result types currently supported are:

Result type Description
Pass The check was successful.
Fail The check is not successful.
Error The check returns an error.
1+1 Definition varies based on provider.
2+2 Definition varies based on provider.

check_output

Field Type Required? Description
entity_type The value "INDIVIDUAL" Yes The only supported entity type for Identity Checks is individuals.
address_history An array containing the address history, structured as it is in the Passfort Partner API. No If supported by the provider, should report the known addresses for this individual when matched.
electronic_id_check Object structured in electronic_id_check Yes The resulting matches of an EKYC check.

electronic_id_check

Field Type Required? Description
matches An array containing one or more Identity Check matches Only when result is not present in the Response See the Identity Check matches section below.
provider_url string No A link to an external provider page containing metadata for the associated check.

Identity Check matches

Each object represents zero or more matches in a database returned by the data provider.

Field Type Required? Description
count number Yes A non-negative integer representing the number of matched entries in this database. Databases without matches should be listed with a count of 0.
database_name string Yes The human readable name for the database this match comes from.
database_type A supported database type Yes Describes the categorisation of the database, see the supported types listed below.
matched_fields An array containing zero or more matched fields Yes Describes which fields were matched on in this database. See the list of matched field types supported below.

The database types currently supported are:

Database type Description
CREDIT A credit scoring database or other similar lending activity database.
CIVIL A government or organization maintained database or register of individuals, such as an electoral roll or telephone directory.
MORTALITY A database or register of deceased individuals.

The matched fields currently supported are:

Field Description
FORENAME A match was found for the individual's given name(s).
SURNAME A match was found for the individual's family name.
ADDRESS A match was found for the provided address.
DOB A match was found for the individual's Date of Birth.
IDENTITY_NUMBER A match was found for the individual's government-issued identity number, commonly referred to as a National Identity Number or Social Security Number.
IDENTITY_NUMBER_SUFFIX A match was found for a trailing portion of the individual's government-issued identity number.

One-time Sync Company Data

This section lists all endpoints that must be implemented for a one-time synchronous company data check integration.

One-time synchronous company data checks are company data checks with the following behaviour:

* The check result will be returned directly upon request; the response won't be sent until the check is finished (synchronous)

* The check operates at a point-in-time: there is no ongoing monitoring of the check result (one-time)

Get Check Configuration (One-time Sync Company Data)

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "COMPANY_DATA",
        "check_template": {
            "type": "ONE_TIME_SYNCHRONOUS",
            "timeout": 60
        },
        "pricing": {
            "supports_reselling": True,
            "maximum_cost": 200
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN",
            "NLD"
        ],
        "supported_features": [
            "COMPANY_SEARCH"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "apikey",
                    "label": "API Key"
                }
            ]
        },
        "config": {
            "fields": [

            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'COMPANY_DATA',
        check_template: {
            type: 'ONE_TIME_SYNCHRONOUS',
            timeout: 60
        },
        pricing: {
            supports_reselling: true,
            maximum_cost: 200
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN',
            'NLD'
        ],
        supported_features: [
            'COMPANY_SEARCH'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'apikey',
                    label: 'API Key'
                }
            ]
        },
        config: {
            fields: [

            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "COMPANY_DATA",
  "check_template": {
    "type": "ONE_TIME_SYNCHRONOUS",
    "timeout": 60
  },
  "pricing": {
    "supports_reselling": true,
    "maximum_cost": 200
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN",
    "NLD"
  ],
  "supported_features": [
    "COMPANY_SEARCH"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "apikey",
        "label": "API Key"
      }
    ]
  },
  "config": {
    "fields": [

    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform one-time synchronous Company data checks using your integration.

HTTP Request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. Check specific options will be discussed here.

Check type

The check_type field must be set to "COMPANY_DATA".

Check template

The check_template fields for this check are:

Field Type Always Present? Description
type The value "ONE_TIME_SYNCHRONOUS" Yes Which check template to use for this check. For one-time synchronous checks, you must specify "ONE_TIME_SYNCHRONOUS".
timeout number No The number of seconds Passfort should wait without a response before considering identity checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used.

Run One-Time Sync Company Data Check

This endpoint exposes your data provider's Company data check to PassFort.

HTTP Request

POST https://my-integration.example.com/checks

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "COMPANY",
    "metadata": {
      "name": "Example Co.",
      "number": 123456,
      "country_of_incorporation": "GBR"
    }
  },
  "provider_config": {
  },
  "provider_credentials": {
    "apikey": "foobar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input A CompanyData object Yes This field contains the profile information for the company on which the Company data check is run. See the PassFort Data Structure check input section for more information on how profile data is structured within Passfort.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    extract_passfort_metadata
from integration.errors import ProviderError, ConnectionError

app = Flask(__name__)

@app.post('/checks')
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
      credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)

        return jsonify({
            'check_output': {
                'enitity_type': 'COMPANY', 
                'metadata': extract_passfort_metadata(result),
            },
            'errors': [],
            'warnings': [],
            'provider_data': dict(result)
        })
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })
const express = require("express");
const app = express();

const { createDemoResult } = require("./testing");
const {
  makeProviderRequest,
  RESELLER_CREDS,
  extractPassFortMetadata,
} = require("./provider");

app.use(express.json());

app.post("/checks", (req, res) => {
  // Handle demo data scenarios
  if (req.body.demo_result !== undefined) {
    return res.json(
      createDemoResult(req.body.demo_result, req.body.check_input)
    );
  }

  // Use provided creds if check is through direct agreement
  const credentials =
    req.body.commercial_relationship === "DIRECT"
      ? res.body.provider_credentials
      : RESELLER_CREDS;

  return makeProviderRequest(
    credentials,
    req.body.provider_config,
    req.body.check_input
  )
    .then((checkResult) => {
      return res.json({
        check_output: {
          entity_type: "COMPANY",
          metadata: extractPassFortMetadata(checkResult)
        },
        errors: [],
        warnings: [],
        provider_data: checkResult.data(),
      });
    })
    .catch((err) => {
      if (err.type === "CONNECTION") {
        return res.json({
          errors: [
            {
              type: "PROVIDER_CONNECTION",
              error: "Failed to contact data provider: " + e.message,
            },
          ],
          warnings: [],
        });
      } else {
        return res.json({
          errors: [
            {
              type: "PROVIDER_MESSAGE",
              error: "Provider error: " + e.message,
            },
          ],
          warnings: [],
        });
      }
    });
});

This endpoint should return JSON in the following format:

{
  "provider_data": "Demo result. Did not make request to provider.",
  "warnings": [

  ],
  "errors": [

  ],
  "check_output": {
    "entity_type": "COMPANY",
    "metadata": {
      "trade_description": "Business and domestic software development",
      "tax_ids": [

      ],
      "structured_company_type": {
        "ownership_type": "COMPANY",
        "is_public": false,
        "is_limited": true
      },
      "previous_names": [

      ],
      "number": "0123456",
      "name": "Example Co.",
      "is_active_details": "Active",
      "is_active": true,
      "industry_classifications": [
        {
          "description": "Computer programming, data processing, and other computer related services",
          "code": "737",
          "classification_version": "US SIC",
          "classification_type": "SIC"
        },
        {
          "description": "Computer programming activities",
          "code": "6201",
          "classification_version": "NACE Rev. 2",
          "classification_type": "NACE"
        },
        {
          "description": "Computer Systems Design and Related Services",
          "code": "5415",
          "classification_version": "NAICS 2017",
          "classification_type": "NAICS"
        }
      ],
      "country_of_incorporation": "GBR",
      "contact_information": {
        "url": "www.example.co",
        "email": "info@example.co"
      },
      "company_type": "Private limited companies",
      "addresses": [

      ]
    }
  }
}

Response fields

Field Type Required? Description
check_output Object structured per check_output below If check did not error Indicates the result data for this check. See the check_output section for the full structure of this check.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.
charges An array containing one or more Charges No A list of charges incurred while running this check. Charges may only be returned if both of these conditions are met:
  • No errors occur when the check is run.
  • The check is resold by Passfort.
For demo checks, charges may be returned, but they won't be deducted from the institution's credit. If charges are returned, the total amount charged must be no greater than the maximum cost-per-check specified in the integration's configuration.

check_output

Field Type Required? Description
entity_type The value "COMPANY" Yes The only supported entity type for Company Data Checks is company.
metadata An object containing the registry data, structured as it is in the Passfort Partner API. If a match was found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider
field_checks An array of CompanyFieldCheck objects No This field is used to surface company fields which have been marked as a match or mismatch between the provider's data and the input data sent to your integration. This field is only used if the Provider Field Checks feature is in use.

One-time Callback Document Verification

This section lists all endpoints that must be implemented for a one-time callback document verification integration.

One-time callback checks are checks with the following behaviour:

Get Check Configuration (One-time Callback Document Verification)

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "DOCUMENT_VERIFICATION",
        "check_template": {
            "type": "ONE_TIME_CALLBACK",
            "request_timeout": 15,
            "callback_timeout": 15
        },
        "pricing": {
            "supports_reselling": True,
            "maximum_cost": 200
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "username",
                    "label": "Username"
                },
                {
                    "type": "password",
                    "name": "password",
                    "label": "Password"
                }
            ]
        },
        "config": {
            "fields": [
                {
                    "type": "boolean",
                    "name": "enhanced_verification",
                    "label": "Enable Enhanced Verification",
                    "subtext": "Fall back to a manual process when a document cannot be automatically verified.",
                    "default": False
                }
            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'DOCUMENT_VERIFICATION',
        check_template: {
            type: 'ONE_TIME_CALLBACK',
            request_timeout: 15,
            callback_timeout: 15
        },
        pricing: {
            supports_reselling: true,
            maximum_cost: 200
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'username',
                    label: 'Username'
                },
                {
                    type: 'password',
                    name: 'password',
                    label: 'Password'
                }
            ]
        },
        config: {
            fields: [
                {
                    type: 'boolean',
                    name: 'enhanced_verification',
                    label: 'Enable Enhanced Verification',
                    subtext: 'Fall back to a manual process when a document cannot be automatically verified.',
                    default: false
                }
            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "DOCUMENT_VERIFICATION",
  "check_template": {
    "type": "ONE_TIME_CALLBACK",
    "request_timeout": 15,
    "callback_timeout": 15
  },
  "pricing": {
    "supports_reselling": true,
    "maximum_cost": 200
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "username",
        "label": "Username"
      },
      {
        "type": "password",
        "name": "password",
        "label": "Password"
      }
    ]
  },
  "config": {
    "fields": [
      {
        "type": "boolean",
        "name": "enhanced_verification",
        "label": "Enable Enhanced Verification",
        "subtext": "Fall back to a manual process when a document cannot be automatically verified.",
        "default": false
      }
    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform one-time callback-based document verifications using your integration.

HTTP Request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. Check specific options will be discussed here.

Check type

The check_type field must be set to "DOCUMENT_VERIFICATION".

Check template

The check_template fields for this check are:

Field Type Required? Description
type The value "ONE_TIME_CALLBACK" Yes Which check template to use for this check. For one-time callback checks, you must specify "ONE_TIME_CALLBACK".
request_timeout number No The number of seconds Passfort should wait without a response before considering Document verification checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used. This timeout will also be applied to image downloads.
callback_timeout number No The number of seconds Passfort should wait following a callback without a response before considering Document fetch checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used. This timeout will also be applied to image downloads.

Start One-Time Callback Document Verification

This endpoint is used by Passfort to initiate a Document verification check through your integration.

HTTP Request

POST https://my-integration.example.com/checks

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ],
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "PASSPORT",
        "images": [
          {
            "id": "2a7933f3-c4a2-49f3-883b-946c33d28b26",
            "image_type": "FRONT"
          }
        ]
      }
    ]
  },
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input An IndividualData object Yes This field contains the profile information for the individual on which the Document verification check is run. See the PassFort Data Structure check input section for more information on how profile data is structured within Passfort.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks")
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)

        return jsonify({
            'provider_id': CONST_PROVIDER_UUID,
            'reference': result['reference'],
            'custom_data': {},
            'errors': [],
            'warnings': [],
        })
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })

This endpoint should return JSON in the following format:

{
  "provider_id": "b0b7611e-c024-4ffb-9f9f-928992bec445",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  },
  "provider_data": {
  },
  "errors": [

  ],
  "warnings": [

  ]
}

Response fields

Field Type Required? Description
provider_id UUID Yes Unique identifier for the provider. The reference field should uniquely identify a check when combined with the provider_id
reference string If no errors occurred An opaque string which identifies this check to the provider. No two checks from the same provider should have the same reference.
custom_data object No Use this to store any state required by later requests relating to this check. The intent is for your integration to be completely stateless itself, to make it simpler to deploy and maintain. Note: if present, this *must* be an object, rather than an array or other JSON value. However, the keys and values in this object can be anything you like, although we don't recommend storing large amounts of data here, as it will be passed in on every following request to your integration relating to this check.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response. If an error is returned from this endpoint, no callback will be expected.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.

Ready for Callback

This endpoint is used by Passfort to indicate that it is ready to receive callbacks from your integration.

For demo checks, the callback should be sent synchronously when this request is received, and should generate a reference that won't conflict with live checks.

HTTP Request

POST https://my-integration.example.com/checks/{check_id}/ready

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "external_refs": {
      "generic": "PROVIDER_CHECK_REFERENCE"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ],
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "UNKNOWN"
      }
    ]
  },
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  },
  "provider_id": "16fd3691-40d2-4c74-a808-f4758f435e2d",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input An IndividualData object Yes

This field contains the profile information for the individual on which the Document verification check is run. See the Passfort Data Structure check input section for more information on how profile data is structured within Passfort.

For Document fetch checks, the check input contains a single "placeholder" document with no images attached.

The integration should take this placeholder document and populate it with the result from the provider, including attaching any images that can be downloaded.

Notably, the `id` and `category` fields from the placeholder document should be preserved unchanged, as these indicate how the document should be used within Passfort, for example, as a proof of address.

provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
custom_data A user-defined JSON object No Any custom_data returned by your integration when the check was instructed will be provided here.
provider_id UUID Yes This matches the `provider_id` returned by your integration when the check was instructed, and should also match the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
reference string Yes This matches the `reference` returned by your integration when the check was instructed, and should also match the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
from uuid import UUID
from flask import Flask, jsonify, request, Response
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks/<uuid:id>/ready")
def acknowledge_ready(id: UUID):
    body = request.json

    provider_id = body.get('provider_id')
    reference = body.get('reference')


    # Demo checks should send the callback synchronously
    if demo_result is not None:
      send_callback(provider_id, reference, custom_data)
      return Response(status=200)


    credentials = body.get('credentials')
    config = body.get('config')
    check_input = body.get('check_input')

    # Check if provider result is ready
    check_result = make_provider_request(credentials, config, check_input)
    if check_result['complete']:
      send_callback(provider_id, reference, custom_data)

  return Response(status=200)

Response fields

This response is not required to return any content.

Download images

The document images for verification can be downloaded using the image IDs included in the images array in the request payload.

More details can be found in the download image section.

Callback Request

Once the check is complete, the integration should send a callback request to Passfort, notifying us of this event. More details can be found in the callbacks section.

There are no check-type-specific callback fields for document verification checks.

For demo checks, the callback should be sent within a few seconds of the check being started, and should generate a reference that won't conflict with live checks.

Finish One-Time Callback Document Verification

This endpoint is called shortly after Passfort receives a callback from your integration indicating that a previously instructed check has completed.

In response, your integration should return the result of the check.

HTTP Request

POST https://my-integration.example.com/checks/{check_id}/complete

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "commercial_relationship": "DIRECT",
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  },
  "provider_id": "b0b7611e-c024-4ffb-9f9f-928992bec445",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes This check ID will be the same as the one used to instruct the check.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
provider_id UUID Yes This matches the provider_id returned by your integration when the check was instructed, and also matches the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
reference string Yes This matches the reference returned by your integration when the check was instructed, and also matches the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
custom_data object No Any custom_data returned by your integration when the check was instructed or supplied to the callback endpoint will be merged together and provided here. The merging rules will always prioritise newer data when fields have the same name.
from uuid import UUID
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks/<uuid:id>/complete")
def complete_check(id: UUID):
    body = request.json

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')
    reference = body.get('reference')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = fetch_check_result(credentials, config, reference)

        return jsonify(convert_to_passfort_format(result))
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })

This endpoint should return JSON in the following format:

{
  "check_output": {
    "entity_type": "INDIVIDUAL",
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "PASSPORT",
        "images": [
          {
            "id": "2a7933f3-c4a2-49f3-883b-946c33d28b26",
            "image_type": "FRONT"
          }
        ],
        "extracted_data": {
          "address_history": [

          ],
          "expiry": "2030-01-01",
          "issued": "2020-01-01",
          "issuer": "United Kingdom",
          "issuing_country": "GBR",
          "mrz1": "P<GBRPERSON<<EXAMPLE<<<<<<<<<<<<<<<<<<<<<<<<",
          "mrz2": "9040604586GBR8510264M3001019<<<<<<<<<<<<<<06",
          "number": "904060458",
          "personal_details": {
            "name": {
              "family_name": "Person",
              "given_names": [
                "Example"
              ]
            },
            "dob": "1985-10-26",
            "nationality": "GBR"
          }
        },
        "verification_result": {
          "all_passed": true,
          "image_checks": [
            {
              "category": "Image Quality",
              "type": "Image resolution",
              "result": "PASS"
            },
            {
              "category": "Image Quality",
              "type": "Image sharpness",
              "result": "PASS"
            }
          ],
          "image_checks_passed": true,
          "forgery_checks": [
            {
              "category": "Document Fonts",
              "type": "Title uses correct font",
              "result": "PASS"
            },
            {
              "category": "Checksum",
              "type": "MRZ has a valid checksum",
              "result": "PASS"
            }
          ],
          "forgery_checks_passed": true,
          "document_type_passed": true
        }
      }
    ]
  },
  "errors": [

  ],
  "warnings": [

  ],
  "provider_data": {
  }
}

Response fields

Field Type Required? Description
check_output Object structured per check_output below If check did not error Indicates the result data for this check. See the check_output section for the full structure of this check.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.
charges An array containing one or more Charges No A list of charges incurred while running this check. Charges may only be returned if both of these conditions are met:
  • No errors occur when the check is run.
  • The check is resold by Passfort.
For demo checks, charges may be returned, but they won't be deducted from the institution's credit. If charges are returned, the total amount charged must be no greater than the maximum cost-per-check specified in the integration's configuration.

check_output

Field Type Required? Description
entity_type The value "INDIVIDUAL" Yes The only supported entity type for Document verification checks is individuals.
documents An array containing the documents, structured as it is in the Passfort Partner API. If no errors occurred This should be a copy of the documents array supplied as the check input, but with the extracted_data and verification_result fields populated using the response from the provider.

One-time Callback Document Fetch

This section lists all endpoints that must be implemented for a one-time callback Document fetch integration.

Document fetch integrations are a special variant of Document verification checks where the customer seeks closer integration with additional functionality the provider offers, such as an improved document collection flow for mobile. In this integration, instead of downloading images from Passfort and submitting them to the provider, the customer uploads the images with the provider, and they're downloaded into Passfort through your integration.

Get Check Configuration (One-time Callback Document Fetch)

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "DOCUMENT_FETCH",
        "check_template": {
            "type": "ONE_TIME_CALLBACK",
            "request_timeout": 15,
            "callback_timeout": 15
        },
        "pricing": {
            "supports_reselling": True,
            "maximum_cost": 200
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "username",
                    "label": "Username"
                },
                {
                    "type": "password",
                    "name": "password",
                    "label": "Password"
                }
            ]
        },
        "config": {
            "fields": [
                {
                    "type": "boolean",
                    "name": "enhanced_verification",
                    "label": "Enable Enhanced Verification",
                    "subtext": "Fall back to a manual process when a document cannot be automatically verified.",
                    "default": False
                }
            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'DOCUMENT_FETCH',
        check_template: {
            type: 'ONE_TIME_CALLBACK',
            request_timeout: 15,
            callback_timeout: 15
        },
        pricing: {
            supports_reselling: true,
            maximum_cost: 200
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'username',
                    label: 'Username'
                },
                {
                    type: 'password',
                    name: 'password',
                    label: 'Password'
                }
            ]
        },
        config: {
            fields: [
                {
                    type: 'boolean',
                    name: 'enhanced_verification',
                    label: 'Enable Enhanced Verification',
                    subtext: 'Fall back to a manual process when a document cannot be automatically verified.',
                    default: false
                }
            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "DOCUMENT_FETCH",
  "check_template": {
    "type": "ONE_TIME_CALLBACK",
    "request_timeout": 15,
    "callback_timeout": 15
  },
  "pricing": {
    "supports_reselling": true,
    "maximum_cost": 200
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "username",
        "label": "Username"
      },
      {
        "type": "password",
        "name": "password",
        "label": "Password"
      }
    ]
  },
  "config": {
    "fields": [
      {
        "type": "boolean",
        "name": "enhanced_verification",
        "label": "Enable Enhanced Verification",
        "subtext": "Fall back to a manual process when a document cannot be automatically verified.",
        "default": false
      }
    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform one-time callback-based Document fetch checks using your integration.

HTTP Request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. Check specific options will be discussed here.

Check type

The check_type field must be set to "DOCUMENT_FETCH".

Check template

The check_template fields for this check are:

Field Type Required? Description
type The value "ONE_TIME_CALLBACK" Yes Which check template to use for this check. For one-time callback checks, you must specify "ONE_TIME_CALLBACK".
request_timeout number No The number of seconds Passfort should wait without a response before considering Document fetch checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used. This timeout will also be applied to image downloads.
callback_timeout number No The number of seconds Passfort should wait following a callback without a response before considering Document fetch checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used. This timeout will also be applied to image downloads.

Start One-Time Callback Document Fetch

This endpoint is used by Passfort to initiate a document fetch check through your integration. The important difference with Document verification is the external_refs field on the input data, which contains a generic field specifying the provider-specific token or reference identifying the request made with the provider.

HTTP Request

POST https://my-integration.example.com/checks

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "external_refs": {
      "generic": "PROVIDER_CHECK_REFERENCE"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ],
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "UNKNOWN"
      }
    ]
  },
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input An IndividualData object Yes

This field contains the profile information for the individual on which the Document verification check is run. See the PassFort Data Structure check input section for more information on how profile data is structured within Passfort.

For Document fetch checks, the check input contains a single "placeholder" document with no images attached.

The integration should take this placeholder document and populate it with the result from the provider, including attaching any images that can be downloaded.

Notably, the `id` and `category` fields from the placeholder document should be preserved unchanged, as these indicate how the document should be used within Passfort, for example, as a proof of address.

provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks")
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)

        return jsonify({
            'provider_id': CONST_PROVIDER_UUID,
            'reference': result['reference'],
            'custom_data': {},
            'errors': [],
            'warnings': [],
        })
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })

This endpoint should return JSON in the following format:

{
  "provider_id": "16fd3691-40d2-4c74-a808-f4758f435e2d",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  },
  "provider_data": {
  },
  "errors": [

  ],
  "warnings": [

  ]
}

Response fields

Field Type Required? Description
provider_id UUID Yes Unique identifier for the provider. The reference field should uniquely identify a check when combined with the provider_id
reference string If no errors occurred An opaque string which identifies this check to the provider. No two checks from the same provider should have the same reference. Note that this doesn't need to be the provider reference passed in to the check (and frequently, that may not be suitable as a check reference).
custom_data object No Use this to store any state required by later requests relating to this check. The intent is for your integration to be completely stateless itself, to make it simpler to deploy and maintain. Note: if present, this *must* be an object, rather than an array or other JSON value. However, the keys and values in this object can be anything you like, although we don't recommend storing large amounts of data here, as it will be passed in on every following request to your integration relating to this check.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response. If an error is returned from this endpoint, no callback is expected.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.

Ready for Callback

This endpoint is used by Passfort to indicate that it is ready to receive callbacks from your integration.

For demo checks, the callback should be sent synchronously when this request is received, and should generate a reference that won't conflict with live checks.

HTTP Request

POST https://my-integration.example.com/checks/{check_id}/ready

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "external_refs": {
      "generic": "PROVIDER_CHECK_REFERENCE"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ],
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "UNKNOWN"
      }
    ]
  },
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  },
  "provider_id": "16fd3691-40d2-4c74-a808-f4758f435e2d",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction will contain a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
check_input An IndividualData object Yes

This field contains the profile information for the individual on which the Document verification check is run. See the Passfort Data Structure check input section for more information on how profile data is structured within Passfort.

For Document fetch checks, the check input contains a single "placeholder" document with no images attached.

The integration should take this placeholder document and populate it with the result from the provider, including attaching any images that can be downloaded.

Notably, the `id` and `category` fields from the placeholder document should be preserved unchanged, as these indicate how the document should be used within Passfort, for example, as a proof of address.

provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
custom_data A user-defined JSON object No Any custom_data returned by your integration when the check was instructed will be provided here.
provider_id UUID Yes This matches the `provider_id` returned by your integration when the check was instructed, and should also match the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
reference string Yes This matches the `reference` returned by your integration when the check was instructed, and should also match the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
from uuid import UUID
from flask import Flask, jsonify, request, Response
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks/<uuid:id>/ready")
def acknowledge_ready(id: UUID):
    body = request.json

    provider_id = body.get('provider_id')
    reference = body.get('reference')


    # Demo checks should send the callback synchronously
    if demo_result is not None:
      send_callback(provider_id, reference, custom_data)
      return Response(status=200)


    credentials = body.get('credentials')
    config = body.get('config')
    check_input = body.get('check_input')

    # Check if provider result is ready
    check_result = make_provider_request(credentials, config, check_input)
    if check_result['complete']:
      send_callback(provider_id, reference, custom_data)

  return Response(status=200)

Response fields

This response is not required to return any content.

Callback Request

Once the check is complete, the integration should send a callback request to Passfort, notifying us of this event. More details can be found in the callbacks section.

There are no check-type-specific callback fields for Document fetch checks.

Finish One-Time Callback Document Fetch

This endpoint is called shortly after Passfort receives a callback from your integration indicating that a previously instructed check has completed.

In response, your integration should return the result of the check.

HTTP Request

POST https://my-integration.example.com/checks/{check_id}/complete

A JSON payload following this structure will be sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "commercial_relationship": "DIRECT",
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  },
  "provider_id": "b0b7611e-c024-4ffb-9f9f-928992bec445",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes This check ID will be the same as the one used to instruct the check.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
provider_id UUID Yes This matches the provider_id returned by your integration when the check was instructed, and also matches the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
reference string Yes This matches the reference returned by your integration when the check was instructed, and also matches the field with the same name sent to Passfort as part of the callback indicating that this check had completed.
custom_data object No Any custom_data returned by your integration when the check was instructed or supplied to the callback endpoint will be merged together and provided here. The merging rules will always prioritise newer data when fields have the same name.
from uuid import UUID
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    to_passfort_field_types
from integration.errors import ProviderError, ConnectionError


app = Flask(__name__)


@app.post("/checks/<uuid:id>/complete")
def complete_check(id: UUID):
    body = request.json

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')
    reference = body.get('reference')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = fetch_check_result(credentials, config, reference)

        return jsonify(convert_to_passfort_format(result))
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })

This endpoint should return JSON in the following format:

{
  "check_output": {
    "entity_type": "INDIVIDUAL",
    "documents": [
      {
        "id": "17bb8473-1466-466e-b651-2de39df7c148",
        "category": "PROOF_OF_IDENTITY",
        "document_type": "PASSPORT",
        "images": [
          {
            "provider_reference": "PROVIDER_IMAGE_REF",
            "image_type": "FRONT"
          }
        ],
        "extracted_data": {
          "address_history": [

          ],
          "expiry": "2030-01-01",
          "issued": "2020-01-01",
          "issuer": "United Kingdom",
          "issuing_country": "GBR",
          "mrz1": "P<GBRPERSON<<EXAMPLE<<<<<<<<<<<<<<<<<<<<<<<<",
          "mrz2": "9040604586GBR8510264M3001019<<<<<<<<<<<<<<06",
          "number": "904060458",
          "personal_details": {
            "name": {
              "family_name": "Person",
              "given_names": [
                "Example"
              ]
            },
            "dob": "1985-10-26",
            "nationality": "GBR"
          }
        },
        "verification_result": {
          "all_passed": true,
          "image_checks": [
            {
              "category": "Image Quality",
              "type": "Image resolution",
              "result": "PASS"
            },
            {
              "category": "Image Quality",
              "type": "Image sharpness",
              "result": "PASS"
            }
          ],
          "image_checks_passed": true,
          "forgery_checks": [
            {
              "category": "Document Fonts",
              "type": "Title uses correct font",
              "result": "PASS"
            },
            {
              "category": "Checksum",
              "type": "MRZ has a valid checksum",
              "result": "PASS"
            }
          ],
          "forgery_checks_passed": true,
          "document_type_passed": true
        }
      }
    ]
  },
  "errors": [

  ],
  "warnings": [

  ],
  "provider_data": {
  }
}

Response fields

Field Type Required? Description
check_output Object structured per check_output below If check did not error Indicates the result data for this check. See the check_output section for the full structure of this check.
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.
charges An array containing one or more Charges No A list of charges incurred while running this check. Charges may only be returned if both of these conditions are met:
  • No errors occur when the check is run.
  • The check is resold by Passfort.
For demo checks, charges may be returned, but they won't be deducted from the institution's credit. If charges are returned, the total amount charged must be no greater than the maximum cost-per-check specified in the integration's configuration.

check_output

Field Type Required? Description
entity_type The value "INDIVIDUAL" Yes The only supported entity type for Document verification checks is individuals.
documents An array containing the documents, structured as it is in the Passfort Partner API. If no errors occurred This field should contain as much information on the document as possible from the provider. You must return the provider's document image in the images field, with the provider_reference set to a string identifier used to reference the image to be used in the Download Document Image endpoint.

Download Document File

This endpoint allows Passfort to retrieve images and other files stored with the provider for a given check.

HTTP Request

POST https://my-integration.example.com/download_file

A JSON payload following this structure will be sent to the endpoint:

{
  "check_id": "b383f249-7ffa-4fd4-9465-73728e090d26",
  "file_reference": "12345",
  "download_info": {
    "download_type": "IMAGE",
    "image_type": "FRONT"
  },
  "commercial_relationship": "DIRECT",
  "provider_config": {
    "enhanced_verification": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  },
  "custom_data": {
    "my_field": 42
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
check_id UUID Yes The unique ID for the check corresponding to this request, which can be used to track and identify individual requests without needing to use other information in the request, useful for logging and tracing issues with your integration.
file_reference string Yes The provider reference for the file being requested, as previously specified in the check result's provider_reference field for images or the reference field for other files.
download_info.download_type One of "FILE", "IMAGE" Yes Specifies whether this download is for a file or image, i.e. whether this is from the images or files, for a given document.
download_info.image_type One of "FRONT", "BACK", "FACE" If download_info.download_type is "IMAGE" Specifies which type of document image was indicated for this file.
download_info.file_type One of "LIVE_VIDEO", "VIDEO_FRAME" If download_info.download_type is "FILE" Specifies which type of file was indicated for this file.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the check is for a customer with a direct relationship with your integration's data provider, or if they're using the check through Passfort's pay-as-you-go reselling scheme.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object If commercial_relationship is set to "DIRECT" This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
custom_data object No Any custom_data returned by your integration when the check was instructed or supplied to the callback endpoint will be merged together and provided here. The merging rules will always prioritise newer data when fields have the same name.
from flask import Flask, jsonify, request, Response, send_file
from integration.provider import download_provider_image, reseller_creds


app = Flask(__name__)


@app.post("/download_file")
def run_check():
    body = request.json

    file_ref = body.get('file_reference')

    # Send demo image if requested
    if file_ref == 'DEMO_IMAGE':
        return send_file('static/demo.png', mimetype='image/png')

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if check is through direct agreement
    if commercial_rel == 'DIRECT':
        credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = download_provider_image(credentials, config, file_ref)

        return Response(result.data, mimetype=result.mimetype)

Response

This endpoint should return the raw image data with the appropriate Content-Type.

File names

Wherever possible, your integration should return an appropriate name for the file using a File-Name header. The value of the header is required to be be a a valid UTF-8 string, and should include the file extension. If this is not provided a default filename of "unknown" will be used, with no file extension. If the provider does not provide a file name, it is recommended your integration generate a suitable file name.

Supported image types

The currently supported types for document images on Passfort are:

Supported video types

The currently supported types for live video files on Passfort are:

One-time Sync Company Custom

This section lists all endpoints that must be implemented for a one-time synchronous Company custom check integration.

One-time synchronous Company custom checks are custom checks with the following behavior:

* The check result is returned directly upon request; the response is only sent when the check is finished (synchronous).

* This one-time check operates at a point in time, meaning the check result is returned once and there is no ongoing monitoring.

Get check configuration for one-time sync Company custom

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "COMPANY_CUSTOM",
        "check_template": {
            "type": "ONE_TIME_SYNCHRONOUS",
            "timeout": 60
        },
        "pricing": {
            "supports_reselling": False
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN",
            "NLD"
        ],
        "supported_features": [
            "EXTERNAL_EMBED"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "apikey",
                    "label": "API Key"
                }
            ]
        },
        "config": {
            "fields": [

            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'COMPANY_CUSTOM',
        check_template: {
            type: 'ONE_TIME_SYNCHRONOUS',
            timeout: 60
        },
        pricing: {
            supports_reselling: false
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN',
            'NLD'
        ],
        supported_features: [
            'EXTERNAL_EMBED'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'apikey',
                    label: 'API Key'
                }
            ]
        },
        config: {
            fields: [

            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "COMPANY_CUSTOM",
  "check_template": {
    "type": "ONE_TIME_SYNCHRONOUS",
    "timeout": 60
  },
  "pricing": {
    "supports_reselling": false
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN",
    "NLD"
  ],
  "supported_features": [
    "EXTERNAL_EMBED"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "apikey",
        "label": "API Key"
      }
    ]
  },
  "config": {
    "fields": [

    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform a one-time synchronous custom check using your integration.

HTTP request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. The following options are specific to the Company custom check.

Check type

The check_type field must be set to "COMPANY_CUSTOM".

Check template

The check_template fields for this check are:

Field Type Required? Description
type The value "ONE_TIME_SYNCHRONOUS" Yes Which check template to use for this check. For one-time synchronous checks, you must specify "ONE_TIME_SYNCHRONOUS".
timeout number No The minimum number of seconds Passfort waits without a response before considering identity checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used.

Run a one-time sync Company custom check

This endpoint exposes your data provider's check results to Passfort.

HTTP request

POST https://my-integration.example.com/checks

A JSON payload following this structure is sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "COMPANY",
    "metadata": {
      "name": "Example Co.",
      "number": "123456",
      "country_of_incorporation": "GBR"
    }
  },
  "provider_config": {
  },
  "provider_credentials": {
    "apikey": "foobar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction contains a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship "DIRECT" Yes Specifies whether the check is for a customer with a direct relationship with your integration's data provider or if they're using the check through Passfort's pay-as-you-go reselling scheme. Reselling is not available for Company Custom Check.
check_input A CompanyData object Yes This field contains the profile information for the company on which the Company custom check check is run. See the Passfort Data Structure check input section for more information on how profile data is structured within Passfort.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    extract_passfort_metadata
from integration.errors import ProviderError, ConnectionError

app = Flask(__name__)

@app.post('/checks')
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    config = body.get('provider_config')

    credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)


        return jsonify({
            "result": map_to_passfort_result(result),
            'errors': [],
            'warnings': [],
            'provider_data': dict(result),
            "external_resources": [
                {
                    "type": "EMBED",
                    "url": result.further_details.url,
                    "id": result.id,
                    "label": "Further details"
                }
            ],
        })
    except ConnectionError as e:
        return jsonify({

            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })
const express = require("express");
const app = express();

const { createDemoResult } = require("./testing");
const {
  makeProviderRequest,
  extractPassFortMetadata,
} = require("./provider");

app.use(express.json());

app.post("/checks", (req, res) => {
  // Handle demo data scenarios
  if (req.body.demo_result !== undefined) {
    return res.json(
      createDemoResult(req.body.demo_result, req.body.check_input)
    );
  }

  const credentials = res.body.provider_credentials

  return makeProviderRequest(
    credentials,
    req.body.provider_config,
    req.body.check_input
  )
    .then((checkResult) => {
        result = make_provider_request(credentials, config, check_input)


        return jsonify({
            "result": map_to_passfort_result(result),
            'errors': [],
            'warnings': [],
            'provider_data': result,
            "external_resources": [
                {
                    "type": "EMBED",
                    "url": result.further_details.url,
                    "id": result.id,
                    "label": "Further details"
                }
            ],
        });
    })
    .catch((err) => {
      if (err.type === "CONNECTION") {
        return res.json({
          errors: [
            {
              type: "PROVIDER_CONNECTION",
              error: "Failed to contact data provider: " + e.message,
            },
          ],
          warnings: [],
        });
      } else {
        return res.json({
          errors: [
            {
              type: "PROVIDER_MESSAGE",
              error: "Provider error: " + e.message,
            },
          ],
          warnings: [],
        });
      }
    });
});

check_input

Field Type Required? Description
entity_type The value "COMPANY" Yes The only supported entity type for Company Custom Checks is company.
external_refs Object Yes A provider defined identifier assigned to the profiles or check being run.
customer_refs String Yes A label used by Passfort customers to identify the profile the check is being run against.
metadata An object containing the registry data, structured as it is in the Passfort Partner API. If a match is found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider

check_input.metadata

Field Type Always Present? Description
addresses List No List of addresses associated with the company.
number String No Optional field for company number.
bvd_id UUID No The bvd_id associated with the company.
country_of_incorporation String No The country of incorporation.
state_of_incorporation String No The state of incorporation.

Response fields

Field Type Required? Description
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.

This endpoint should return JSON in the following format:

{
  "provider_data": "Demo result. Did not make request to provider.",
  "warnings": [

  ],
  "errors": [

  ],
  "external_resources": [
    {
      "type": "EMBED",
      "url": "http://host.docker.internal:8080/external_resource",
      "id": "8AA89547-89FC-4EAD-ACEC-FFA36F451337",
      "label": "Example embed"
    }
  ],
  "result": {
    "decision": "PASS",
    "summary": "It's a pass..."
  }
}

check_output

Field Type Required? Description
decision DecisionClass Yes The check will return one of the following decisions: "PASS | FAIL | PARTIAL | WARN | ERROR"
summary A summary of the result in the Passfort Partner API. If a match was found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider
external_resources An object in the Passfort Partner API. No As best as possible, all fields you support should be made to populate all fields supported by the provider
warnings An object containing the registry data, structured as it is in the Passfort Partner API. If a match was found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it is not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.

One-time Sync Individual Custom

This section lists all endpoints that must be implemented for a one-time synchronous Individual custom check integration.

One-time synchronous Individual custom checks are custom checks with the following behavior:

* The check result is returned directly upon request; the response is only sent when the check is finished (synchronous).

* This one-time check operates at a point in time, meaning the check result is returned once and there is no ongoing monitoring.

Get check configuration for one-time sync Individual custom

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/config")
def get_check_configuration():
    return jsonify({
        "check_type": "INDIVIDUAL_CUSTOM",
        "check_template": {
            "type": "ONE_TIME_SYNCHRONOUS",
            "timeout": 60
        },
        "pricing": {
            "supports_reselling": False
        },
        "supported_countries": [
            "GBR",
            "USA",
            "CAN",
            "NLD"
        ],
        "supported_features": [
            "EXTERNAL_EMBED"
        ],
        "credentials": {
            "fields": [
                {
                    "type": "string",
                    "name": "apikey",
                    "label": "API Key"
                }
            ]
        },
        "config": {
            "fields": [

            ]
        }
    })
const express = require('express')
const app = express()

app.get('/config', (req, res) => {
    res.json({
        check_type: 'INDIVIDUAL_CUSTOM',
        check_template: {
            type: 'ONE_TIME_SYNCHRONOUS',
            timeout: 60
        },
        pricing: {
            supports_reselling: false
        },
        supported_countries: [
            'GBR',
            'USA',
            'CAN',
            'NLD'
        ],
        supported_features: [
            'EXTERNAL_EMBED'
        ],
        credentials: {
            fields: [
                {
                    type: 'string',
                    name: 'apikey',
                    label: 'API Key'
                }
            ]
        },
        config: {
            fields: [

            ]
        }
    })
})

This endpoint should return JSON in the following format:

{
  "check_type": "INDIVIDUAL_CUSTOM",
  "check_template": {
    "type": "ONE_TIME_SYNCHRONOUS",
    "timeout": 60
  },
  "pricing": {
    "supports_reselling": false
  },
  "supported_countries": [
    "GBR",
    "USA",
    "CAN",
    "NLD"
  ],
  "supported_features": [
    "EXTERNAL_EMBED"
  ],
  "credentials": {
    "fields": [
      {
        "type": "string",
        "name": "apikey",
        "label": "API Key"
      }
    ]
  },
  "config": {
    "fields": [

    ]
  }
}

This endpoint specifies which configuration is used by Passfort to perform a one-time synchronous custom check using your integration.

HTTP request

GET https://my-integration.example.com/config

Response fields

Most configuration fields are already discussed in the configuration section. The following options are specific to the Individual custom check.

Check type

The check_type field must be set to "INDIVIDUAL_CUSTOM".

Check template

The check_template fields for this check are:

Field Type Required? Description
type The value "ONE_TIME_SYNCHRONOUS" Yes Which check template to use for this check. For one-time synchronous checks, you must specify "ONE_TIME_SYNCHRONOUS".
timeout number No The minimum number of seconds Passfort waits without a response before considering identity checks run through this integration to have timed out. Must be an integer. If not specified or set to null, a timeout of 60 seconds is used.

Run a one-time sync Individual custom check

This endpoint exposes your data provider's check results to Passfort.

HTTP request

POST https://my-integration.example.com/checks

A JSON payload following this structure is sent to the endpoint:

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "check_input": {
    "entity_type": "INDIVIDUAL",
    "personal_details": {
      "name": {
        "family_name": "Person",
        "given_names": [
          "Example"
        ]
      },
      "dob": "1985-10-26",
      "nationality": "GBR"
    },
    "address_history": [
      {
        "address": {
          "type": "STRUCTURED",
          "country": "GBR",
          "locality": "London",
          "postal_code": "E1 1AA",
          "route": "Crown Street",
          "street_number": 42,
          "original_freeform_address": "42 Crown Street, London, E1 1AA"
        },
        "start_date": "1985-10"
      }
    ]
  },
  "provider_config": {
    "require_dob": false
  },
  "provider_credentials": {
    "username": "foo",
    "password": "bar"
  }
}

The payload of the request can contain the following fields:

Field Type Always present? Description
id UUID Yes Every check instruction contains a unique ID which can be used to track and identify individual requests without needing to use other information in the request.
demo_result One of the specified demo result types No If this field is present, the check must be considered a demo check and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship "DIRECT" Yes Specifies whether the check is for a customer with a direct relationship with your integration's data provider or if they're using the check through Passfort's pay-as-you-go reselling scheme. Reselling is not available for Individual Custom Check.
check_input A IndividualData object Yes This field contains the profile information for the individual on which the Individual custom check is run. See the Passfort Data Structure check input section for more information on how profile data is structured within Passfort.
provider_config A user-defined JSON object Yes This field contains the provider config structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    extract_passfort_metadata
from integration.errors import ProviderError, ConnectionError

app = Flask(__name__)

@app.post('/checks')
def run_check():
    body = request.json

    demo_result = body.get('demo_result')
    check_input = body.get('check_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, check_input))

    config = body.get('provider_config')

    credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, check_input)


        return jsonify({
            "result": map_to_passfort_result(result),
            'errors': [],
            'warnings': [],
            'provider_data': dict(result),
            "external_resources": [
                {
                    "type": "EMBED",
                    "url": result.further_details.url,
                    "id": result.id,
                    "label": "Further details"
                }
            ],
        })
    except ConnectionError as e:
        return jsonify({

            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })
const express = require("express");
const app = express();

const { createDemoResult } = require("./testing");
const {
  makeProviderRequest,
  extractPassFortMetadata,
} = require("./provider");

app.use(express.json());

app.post("/checks", (req, res) => {
  // Handle demo data scenarios
  if (req.body.demo_result !== undefined) {
    return res.json(
      createDemoResult(req.body.demo_result, req.body.check_input)
    );
  }

  const credentials = res.body.provider_credentials

  return makeProviderRequest(
    credentials,
    req.body.provider_config,
    req.body.check_input
  )
    .then((checkResult) => {
        result = make_provider_request(credentials, config, check_input)


        return jsonify({
            "result": map_to_passfort_result(result),
            'errors': [],
            'warnings': [],
            'provider_data': result,
            "external_resources": [
                {
                    "type": "EMBED",
                    "url": result.further_details.url,
                    "id": result.id,
                    "label": "Further details"
                }
            ],
        });
    })
    .catch((err) => {
      if (err.type === "CONNECTION") {
        return res.json({
          errors: [
            {
              type: "PROVIDER_CONNECTION",
              error: "Failed to contact data provider: " + e.message,
            },
          ],
          warnings: [],
        });
      } else {
        return res.json({
          errors: [
            {
              type: "PROVIDER_MESSAGE",
              error: "Provider error: " + e.message,
            },
          ],
          warnings: [],
        });
      }
    });
});

check_input

Field Type Required? Description
entity_type The value "INDIVIDUAL" Yes The only supported entity type for Individual Custom Checks is individual.
personal_details Object No A data object containing Personal information about an individual. Refer to Passfort API Documentation for additional details.
contact_details Object No The phone number and email for the individual the check is run against.
documents_metadata Object No Any additional identity numbers that individual has. Note that the individual's national identity number(s) is stored in personal_details.national_identity_number
customer_refs String Yes A label used by Passfort customers to identify the profile the check is being run against.
address_history Object No A list of addresses in which the individual has lived. Each of these can have an approximate start and end date. Refer to Passfort API Documentation for additional details.

Response fields

Field Type Required? Description
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it's not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the check as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.

This endpoint should return JSON in the following format:

{
  "provider_data": "Demo result. Did not make request to provider.",
  "warnings": [

  ],
  "errors": [

  ],
  "external_resources": [
    {
      "type": "EMBED",
      "url": "http://host.docker.internal:8080/external_resource",
      "id": "8AA89547-89FC-4EAD-ACEC-FFA36F451337",
      "label": "Example embed"
    }
  ],
  "result": {
    "decision": "PASS",
    "summary": "It's a pass..."
  }
}

check_output

Field Type Required? Description
decision DecisionClass Yes The check will return one of the following decisions: "PASS | FAIL | PARTIAL | WARN | ERROR"
summary A summary of the result in the Passfort Partner API. If a match was found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider
external_resources An object in the Passfort Partner API. No As best as possible, all fields you support should be made to populate all fields supported by the provider
warnings An object containing the registry data, structured as it is in the Passfort Partner API. If a match is found by the provider As best as possible, all fields you support should be made to populate all fields supported by the provider
errors An array containing one or more Errors No A list of errors that occurred while running this check. If this is provided and it is not empty, the result of this check is considered to be errored by Passfort, regardless of the other contents of this response.

Supported Features

The identifier for this feature is COMPANY_SEARCH.

In order to run a successful company data check, a company must be uniquely identified. Some company data providers allow searching through the candidates in their dataset in order to identify the company to be checked.

This endpoint exposes your data provider's company search functionality to Passfort.

HTTP Request

POST https://my-integration.example.com/search

A JSON payload following this structure will be sent to the endpoint:

{
  "demo_result": "ANY",
  "commercial_relationship": "DIRECT",
  "search_input": {
    "query": "Example Co.",
    "country_of_incorporation": "GBR"
  },
  "provider_config": {
  },
  "provider_credentials": {
    "apikey": "foobar"
  }
}

The payload of the request can contain the following fields

Field Type Always Present? Description
demo_result One of the specified demo result types No If this field is present, the search must be considered a demo search and you should respond with appropriate demo data. See the Demo Checks section for more information.
commercial_relationship One of "DIRECT", "PASSFORT" Yes Specified whether the search is for a customer with a direct relationship with your integration's data provider, or if they're using the search feature through PassFort's pay-as-you-go reselling scheme.
search_input A SearchInput object Yes This field contains the known profile information on the company being searched for.
provider_config A user-defined JSON object Yes This field contains the provider configuration structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option.
provider_credentials A user-defined JSON object No This field contains the credentials structured in the way specified by your integration's configuration endpoint , with the name field corresponding to the key, and the value being the value of the configuration option. This field is only sent if commercial_relationship is set to "DIRECT".
from flask import Flask, jsonify, request
from integration.testing import create_demo_result
from integration.provider import make_provider_request, reseller_creds, \
    convert_to_passfort_candidate
from integration.errors import ProviderError, ConnectionError

app = Flask(__name__)

@app.post('/search')
def run_search():
    body = request.json

    demo_result = body.get('demo_result')
    search_input = body.get('search_input')

    # Handle demo data scenarios
    if demo_result is not None:
        return jsonify(create_demo_result(demo_result, search_input))

    commercial_rel = body.get('commercial_relationship')
    credentials = reseller_creds
    config = body.get('provider_config')

    # Use provided creds if search is through direct agreement
    if commercial_rel == 'DIRECT':
      credentials = body.get('provider_credentials')

    # Make call to provider
    try:
        result = make_provider_request(credentials, config, search_input)

        return jsonify({
            'search_output': sorted(
                [
                  convert_to_passfort_candidate(hit) 
                  for hit 
                  in result.hits
                ],
                key=lambda hit: hit.score
            ),
            'errors': [],
            'warnings': [],
            'provider_data': dict(result)
        })
    except ConnectionError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_CONNECTION',
                'message': f'Failed to contact data provider: {str(e)}'
            }],
            'warnings': []
        })
    except ProviderError as e:
        return jsonify({
            'errors': [{
                'type': 'PROVIDER_MESSAGE',
                'message': f'Provider error: {str(e)}'
            }],
            'warnings': []
        })
const express = require("express");
const app = express();

const { createDemoResult } = require("./testing");
const {
  makeProviderRequest,
  RESELLER_CREDS,
  convertToPassFortCandidate,
} = require("./provider");

app.use(express.json());

app.post("/search", (req, res) => {
  // Handle demo data scenarios
  if (req.body.demo_result !== undefined) {
    return res.json(
      createDemoResult(req.body.demo_result, req.body.search_input)
    );
  }

  // Use provided creds if check is through direct agreement
  const credentials =
    req.body.commercial_relationship === "DIRECT"
      ? res.body.provider_credentials
      : RESELLER_CREDS;

  return makeProviderRequest(
    credentials,
    req.body.provider_config,
    req.body.search_input
  )
    .then((searchResult) => {
      return res.json({
        search_output: searchResult.hits
          .map(hit => convertToPassFortCandidate(hit))
          .sort((a, b) => (a.score > b.score) ? 1 : -1),
        errors: [],
        warnings: [],
        provider_data: checkResult.data(),
      });
    })
    .catch((err) => {
      if (err.type === "CONNECTION") {
        return res.json({
          errors: [
            {
              type: "PROVIDER_CONNECTION",
              error: "Failed to contact data provider: " + e.message,
            },
          ],
          warnings: [],
        });
      } else {
        return res.json({
          errors: [
            {
              type: "PROVIDER_MESSAGE",
              error: "Provider error: " + e.message,
            },
          ],
          warnings: [],
        });
      }
    });
});

This endpoint should return JSON in the following format:

{
  "search_output": [
    {
      "name": "Example Company",
      "number": "123456",
      "country_of_incorporation": "GBR",
      "status": "ACTIVE",
      "provider_reference": {
        "label": "MY-INTEGRATION",
        "reference": "GB-123456"
      }
    },
    {
      "name": "Example Couches",
      "number": "9876531",
      "country_of_incorporation": "GBR",
      "status": "DORMANT",
      "provider_reference": {
        "label": "My-INTEGRATION",
        "reference": "GB-9876531"
      }
    },
    {
      "name": "Example Cars",
      "number": "4851723",
      "country_of_incorporation": "GBR",
      "status": "DISSOLVED",
      "provider_reference": {
        "label": "COMPANY_DATA_REFERENCE_INTEGRATION",
        "reference": "GB-4851723"
      }
    }
  ],
  "errors": [

  ],
  "warnings": [

  ],
  "provider_data": {
  }
}

Response fields

Field Type Required? Description
search_output A list of objects structured per Candidate below If search did not error Indicates the list of candidates for this search. If supported by the provider, they should be sorted by match likelihood with the best match first.
errors An array containing one or more Errors No A list of errors that occurred while running this search. If this is provided and is not empty, Passfort considers the result of this search to be errored, regardless of the other contents of this response.
warnings An array containing one or more warnings No Essentially the same as errors, except the sub_type and data fields aren't present, and providing warnings won't cause Passfort to consider the search as errored.
provider_data Any valid JSON value No This should be the structured JSON data returned by the data provider or a conversion of the data provider's response to allow Passfort to investigate any issues that arise with your integration.
charges An array containing one or more Charges No A list of charges incurred while running this search. Charges may only be returned if both of these conditions are met:
  • No errors occur when the check is run.
  • The check is resold by Passfort.
For demo searches, charges may be returned but they won't be deducted from the institution's credit. If charges are returned, the total amount charged must be no greater than the maximum cost-per-check specified in the integration's configuration.

Candidate

Field Type Required? Description
name string Yes The registered name of the company.
number string Yes The company's number or identifier in some registry.
number_label string No Text to use as a label to explain the number, such as "Company number", "Charity number", "VAT number" etc.
country_of_incorporation string Yes The ISO3 country code for the country where the company is incorporated.
status string No A string describing the current functioning of the company (e.g. "Active" or "Dissolved")
provider_reference A ProviderRef object No An object uniquely identifying this candidate from this provider, structured as it is in the Passfort Partner API
addresses A list of CompanyAddress objects No Addresses of the company, with each CompanyAddress object structured as it is in the Passfort Partner API.
contact A CompanyContactDetails object No Contact details for the company, in an object structured as it is in the Passfort Partner API.
incorporation_date string No Exact date in YYYY-MM-DD format
structure_type A StructuredCompanyType object No An object describing the company type: its members' liability, its ownership structure, and whether it is traded publicly. The object is structured as it is in the Passfort Partner API.
lei string No Global Legal Entity Identifier
tax_ids List of TaxId objects No Tax identifiers, with each TaxId object structured as in the Passfort Partner API.
bvd_id string No Moody's unique company identifier

Provider Field Checks

The identifier for this feature is PROVIDER_FIELD_CHECKS. This feature is compatible with the One-time Sync Company Data check type.

This feature allows an integration to return an array of CompanyFieldCheck objects. The CompanyFieldCheck object describes whether a particular field (i.e. company name or number) has been matched or mismatched according to the integration’s custom logic. Provider field checks should be surfaced using the field_checks attribute of the check_output.

CompanyFieldCheck

Field Type Required? Description
field string Yes The field that the result refers to. One of ["NAME", "NUMBER", "COUNTRY_OF_INCORPORATION", "IS_ACTIVE", "LEI", "ADDRESS"]
result string Yes The result of the comparison. One of ["MATCH", "MISMATCH"]

Embedding or linking an external webpage

Integrations have the option to include a URL within the check result. This URL can then either be displayed as a link or used to embed the resulting webpage within Passfort.

The identifier for this feature is either EXTERNAL_LINK or EXTERNAL_EMBED depending on how you intend to surface the external resource. This feature is compatible with all of our supported check types.

The external_resources object includes: whether the external resource is displayed as a link or an embed, the url, id, and a label describing the resource.

This endpoint returns JSON in the following format:

{
  "provider_data": "Demo result. Did not make request to provider.",
  "warnings": [

  ],
  "errors": [

  ],
  "external_resources": [
    {
      "type": "EMBED",
      "url": "http://host.docker.internal:8080/external_resource",
      "id": "8AA89547-89FC-4EAD-ACEC-FFA36F451337",
      "label": "Example embed"
    }
  ],
  "result": {
    "decision": "PASS",
    "summary": "It's a pass..."
  }
}
Field Type Required? Description
type "EMBED" No The type of external resource that's being reported.
url string No Provides additional detail for certain types of error.
id string Yes The external_resource identifier.
label string No Integration-specific structured error information that customers can use to get additional information about the error.

Authentication

Passfort makes a request to your application via a signed url, which contains arguments as query parameters:

https://your-url.com/?version=&valid_until=&auditee_id=&signature=

The list of query parameter arguments is shown below, and is delivered in this order:

Field Type Required? Description
custom_data string No Any other parameters the integration wishes to have provided.
version string Yes Versioning information for the signed URL.
valid_until string Yes The epoch time the URL is considered valid until. Requests after this time will be deemed unauthentic by your integration.
auditee_id string Yes UUID identifying the user or API key viewing the check.
signature string Yes A base64url encoding of the SHA-256 HMAC of the entire URL, excluding the signature parameter.

The signature contains a HMAC of the entire URL excluding &signature=, and can be verified using a shared secret between Passfort and your backend systems.

The entire base URL (https://you-url.com/) is returned by your integration as part of the result. It’s worth noting this URL should be considered permanent, meaning the content it serves should not change over time.

Requests to Passfort

Although the majority of the integrations API consists of endpoints to be served by an integration and called by Passfort. There are several endpoints provided by Passfort to allow an integration to do its job. These endpoints are documented in this section.

Callbacks

If your integration follows one of the callback-based check templates, such as ONE_TIME_SYNC_CALLBACK you will need to make requests to Passfort's "callback" endpoint to notify us of certain events, such as when a check is complete.

HTTP Request

POST https://api.passfort.com/integrations/v1/callbacks

A JSON payload following this structure should be sent to the endpoint:

{
  "provider_id": "b0b7611e-c024-4ffb-9f9f-928992bec445",
  "reference": "12345",
  "custom_data": {
    "my_field": 42
  }
}

Depending on the nature of the callback, additional fields may also be expected. It will be documented in the check-specific documentation, if any additional fields are expected.

Regardless of the check type, the payload of the request should contain the following fields:

Field Type Required? Description
provider_id UUID Yes This should match the provider ID returned by your integration when the check was started.
reference string Yes This should match the reference returned by your integration when the check was started.
custom_data object No An object containing custom data to be sent to your integration in follow-up requests relating to this check. If we are already storing custom data for this check, the new data will be merged in, overwriting any fields with the same name.
requests.post(url, json={
    "provider_id": "b0b7611e-c024-4ffb-9f9f-928992bec445",
    "reference": "12345",
    "custom_data": {
        "my_field": 42
    }
}, auth=outbound_auth())
await outbound_auth().fetch(url, {
    method:'POST',
    headers: {
        'Content-Type': 'application/json'
    }
    body: JSON.stringify({
        provider_id: 'b0b7611e-c024-4ffb-9f9f-928992bec445',
        reference: '12345',
        custom_data: {
            my_field: 42
        }
    })
})

If this endpoint returns a non-2xx status code, the callback should be retried several times (with an exponential backoff) to ensure that events aren't lost. If the callback is being triggered by the provider, it is expected that the integration will simply forward the failure code to the provider, at which point it is the provider's job to retry appropriately.

This endpoint will return JSON in the following format:

{
  "callback_id": "243c4758-28a2-476f-868d-7ce239f9574b"
}

Response fields

There will never be any check-type-specific fields returned from this endpoint.

Field Type Always present? Description
callback_id UUID Yes This field has no specific purpose, but if you need to contact our support for an issue relating to callbacks, we may ask for this field so that we can cross-reference your requests with our own logs.

Download image

If your integration implements a Document verification check, you will need to download images from our system to pass to the provider.

This endpoint returns the raw image data for a given image ID. Your integration will be granted temporary access to an image whenever a check using that image is instructed.

HTTP Request

GET https://api.passfort.com/integrations/v1/images/{image_id}

res = requests.get(url, auth=outbound_auth())
res.raise_for_status()
image_bytes = res.content
const res = await outbound_auth().fetch(url);
if (!res.ok) throw new Error(`Failed to fetch image: ${res.statusText}`);
const imageBytes = res.body

This endpoint will return the raw image data.