This guide takes an integration from an API key to a decision. You vault the data you already hold about a user, run a playbook with POST /onboardings, and handle the result, whether the playbook does KYC (Know Your Customer), KYB (Know Your Business), identity document verification, or document collection. Security, compliance, and risk and fraud prevention are built into every onboarding. The overview covers customization, and the appendix covers the advanced APIs for less common integrations.

Core concepts

Vault

Every user and business in Footprint has a vault that stores identity, financial, document, and custom data. When a user onboards through a Footprint flow, everything collected is stored in that user's vault. A vault holds structured and unstructured data and keeps a versioned history of every change to every field. Footprint applies base-level validation to structured data, such as identity and PCI fields, and otherwise keeps vaulting flexible.

Each value is addressed by a vault field name, which the API calls a data identifier; id.ssn9, for example, is the user's full SSN. Vault fields carry granular role-based access controls (RBAC) and can be sent to third-party destinations through the Vault Proxy. The full list is in Vault fields.

The "fp_id"

The fp_id, also called the Footprint ID, is the unique identifier of a user in Footprint. It appears in API requests and responses and in the dashboard. A business has an fp_bid instead.

The "external_id"

An external_id is an identifier you assign to a user or business. It maps records in your system to Footprint without storing the fp_id.

Playbook

A playbook defines an onboarding end to end: the information to collect, the verification checks to run, and the rules that turn those checks into a decision. A playbook_key is the playbook's unique, publishable identifier; it appears in API requests and responses and in the dashboard.

Onboarding

An onboarding is one run of a playbook for one user or business. Each time a user or business goes through a playbook, Footprint creates a new onboarding.

Integration overview

A user's journey with Footprint starts with POST /onboardings. It runs one of your playbooks against a user or business and returns the result. How much of the flow runs headlessly depends on how much data you have already collected:

  • Fully headless. If your app already collects everything the playbook needs, vault that data and run the onboarding entirely server-side, with no Footprint UI. The decision comes back synchronously inline or asynchronously through webhooks, depending on your settings.
  • Interactive. If information is still missing, the API returns a continue_onboarding token and link. Hand them to your frontend so the user can finish the remaining steps in one of two ways:
    • Hosted. A web page hosted by Footprint runs the rest of the onboarding. Send the link to the user by email or SMS, or from a button in your app.
    • Embedded. One of the Footprint SDKs for web, iOS, and Android runs the rest of the flow inside your product, launched with the token.

Customization

The interactive flow can be customized to different degrees:

  • Hosted. Uses Footprint's default styling. For element-level styling, use the embedded flow.
  • Embedded. The SDK customizes the look and feel of every element, including fonts, colors, and borders, across over 100 appearance attributes. See Customization.

Identity documents & document collection

Footprint treats document collection and verification as a single component. It covers device handoff (continuing on a mobile device when the flow starts on desktop), automatic capture and liveness, document classification, and selfie capture. The customization options extend to the whole document collection and scanning experience.


The end-to-end integration

These are the most common steps to get Footprint running end to end.

Step 1: Get your secret API key

In the Footprint dashboard, click Create secret key and store the key somewhere safe.

Step 2: Create a playbook

In the Footprint dashboard, create a playbook. It defines what information to collect, which verification checks run, and the rules that turn those checks into a decision. Note its playbook_key for step 4.

Step 3: Create the user and vault their data

Create the user with POST /users (or a business with POST /businesses) and write the data you have already collected:

bash
1curl -X POST https://api.onefootprint.com/users \
2  -u <SECRET_API_KEY>: \
3  -d '{
4    "id.first_name": "Jane",
5    "id.last_name": "Doe",
6    "id.dob": "1990-01-01",
7    "id.ssn9": "123-45-6789",
8    "id.address_line1": "1 Main St",
9    "id.city": "San Francisco",
10    "id.state": "CA",
11    "id.zip": "94105",
12    "id.country": "US"
13  }'
14# -> { "id": "fp_id_K0q6Eh6Rr3WOOfFBLPiHsr" }

The response returns the user's fp_id. Vault fields lists everything you can vault, and Migrating user data covers bringing over data you already hold. If you expect the user to provide most of their information in the interactive flow, vault only what you have, or nothing at all.

Step 4: Run the playbook

Call POST /onboardings with the entity and the playbook key. Set synchronous_timeout_secs (maximum 30) to wait for the decision and receive it inline:

bash
1curl -X POST https://api.onefootprint.com/onboardings \
2  -u <SECRET_API_KEY>: \
3  -d '{
4    "fp_id": "fp_id_K0q6Eh6Rr3WOOfFBLPiHsr",
5    "key": "<PLAYBOOK_KEY>",
6    "synchronous_timeout_secs": 30
7  }'
json
1{
2  "id": "ob_SRFT2a1mN7DAWJ0VPXkiqK",
3  "status": "pass",
4  "requires_manual_review": false,
5  "continue_onboarding": null,
6  "error_message": null
7}

Omit synchronous_timeout_secs and the call returns immediately with status: "pending" while the run continues in the background; the final decision arrives by webhook (step 6). You generally run a playbook asynchronously only when you have already collected everything it needs. It suits slow steps, such as running an agent, that may not finish within the synchronous timeout.

For a business, put the fp_bid in the fp_id field; there is no separate fp_bid field. The key also accepts a version tag (pb_live_xxx:v3) to run a specific playbook version, though we recommend deploying the version you want from the dashboard rather than pinning it in code.

A KYB playbook that also verifies its beneficial owners can't run here: the owners have to complete their own KYC, which this API can't prompt for. Run those playbooks through an onboarding session instead.

Step 4(a). Optional configuration. The request also takes these optional fields:

Attribute Description
external_id Reference the user or business by your own identifier instead of fp_id. This is the same external_id set when the entity was created. Cannot be provided alongside fp_id.
onboarding_external_id Use to control onboarding idempotency and to associate an onboarding with an event in your application (for example, an account application ID). If an onboarding with this ID already exists on the playbook, its result is reused and returned. If not, a new onboarding is created and the entity re-onboards.
synchronous_timeout_secs Wait up to this many seconds (maximum 30) for the run to finish and return the decision inline. Omit to run asynchronously.
prerequisite_data If your playbook requires additional information from your backend, configure a prerequisite node on the playbook and pass that data here. Only accepted when the playbook has a prerequisite node.

Run a playbook is the full reference for POST /onboardings, including reonboarding patterns, KYB, and passing onboarding data.

Step 5: Handle the decision

Your playbook's rules evaluate the user or business and decide whether to flag it for manual review. Use status and requires_manual_review in the response to decide whether to onboard the user into your product.

Status Meaning
pass / fail / none An action node in your playbook executed and set the user's status. Conventionally, these are the output of rules that you define.
pending Either you ran asynchronously, or the playbook took longer than synchronous_timeout_secs to execute. Certain steps of a playbook, like agents or verification checks, may take longer. The final decision is delivered via webhooks.
incomplete The onboarding could not finish headlessly because more information is needed from the user. Use continue_onboarding to let them finish (see below).
error The run failed due to logic configured on your playbook. See error_message.
requires_manual_review Meaning
False Your playbook's rules have made a decision automatically.
True Your playbook's rules have requested that this user is reviewed manually before onboarding, or the user's previous onboarding status caused the review flag to remain enabled.

If Footprint still needs information from the user (for example, your playbook collects a field you didn't vault, or requires an identity document), the status is incomplete and the response carries a continue_onboarding object:

json
1{
2  "id": "ob_SRFT2a1mN7DAWJ0VPXkiqK",
3  "status": "incomplete",
4  "requires_manual_review": false,
5  "error_message": null,
6  "continue_onboarding": {
7    "token": "obtok_UxM6Vbvk2Rcy1gzcSuXgk3sj3L9I0pAnNH",
8    "link": "https://verify.onefootprint.com/?type=user#obtok_UxM6Vbvk2Rcy1gzcSuXgk3sj3L9I0pAnNH",
9    "expires_at": "2025-05-08T12:00-07:00"
10  }
11}

The token resumes this exact onboarding: the user picks up where the headless run stopped, and the completed run keeps the same id. Treat the token as a secret and use it before expires_at (12 hours). Hand it to your frontend and let the user finish the remaining steps with either launch option below.

Step 5(a). Finish via hosted. Extract the link and deliver it to the user by email or SMS, or from a button in your app.

Step 5(b). Finish via embedded. Extract the token and launch Footprint with one of the SDKs. Install the SDK first: web (JS/TS/React/Vue/Angular) with npm install @onefootprint/footprint-js; iOS with Swift Package Manager or Cocoa Pods; Android as in the installation instructions. Then launch with the token:

1import "@onefootprint/footprint-js/dist/footprint-js.css";
2import { onboarding } from "@onefootprint/footprint-js";
3
4const App = () => {
5  const launch = () => {
6    onboarding.initialize({
7      // replace with `continue_onboarding.token` from the api response
8      onboardingSessionToken: "obtok_UxM6Vbvk2Rcy1gzcSuXgk3sj3L9I0pAnNH",
9      onComplete: (validationToken) => {
10        console.log("completed", validationToken);
11      },
12    });
13  };
14
15  return <button onClick={launch}>Verify Identity</button>;
16};

When the user finishes the remaining steps, the SDK calls onComplete with a validation_token. Validate that token to get the state of the onboarding immediately (step 5c). The final decision also arrives by webhook (step 6), and you can fetch it at any time with GET /users/{fp_id}/onboardings/{id} using the onboarding id from step 4.

Step 5c: Process the validation_token

This step applies only to the embedded SDK. If you use the hosted page, skip to step 6.

At the end of the flow, the SDK's onComplete handler passes a validation_token to your code. Send it to your backend and validate it with POST /onboarding/session/validate. This is the recommended way to get the state of the onboarding immediately after the user finishes the flow.

bash
1curl -X POST https://api.onefootprint.com/onboarding/session/validate \
2   -u <SECRET_API_KEY>: \
3   -d '{"validation_token": "<VALIDATION_TOKEN>"}'

The response looks like:

json
1{
2  "user": {
3    "fp_id": "fp_id_GSxJr68GAf5jUT3pdL9ndjf7TLkA3GCX",
4    "onboarding_id": "ob_SRFT2a1mN7DAWJ0VPXkiqK",
5    "playbook_key": "pb_test_VMooXd04EUlnu3AvMYKjMW",
6    "requires_manual_review": false,
7    "status": "pass"
8  },
9  ...
10}

Step 6: Listen to webhooks

Footprint delivers every onboarding's decision by webhook when it reaches a terminal status. For asynchronous runs, and for synchronous runs that returned pending, webhooks are how you receive the final result.

Step 6(a). Subscribe a webhook endpoint. Register your webhook endpoints in the Footprint dashboard. Footprint then pushes event data to them in real time as events happen. The Svix guide to consuming webhooks covers the receiving side.

We recommend verifying that every webhook request comes from Footprint; the Svix guide to verifying webhook signatures shows how.

Step 6(b). Recommended events. For the core integration, subscribe to these three event types.

  • Onboarding completed.footprint.onboarding.completed fires when an onboarding reaches a terminal status. A synchronous POST /onboardings call usually returns a terminal pass, fail, or none decision inline; this event delivers the final decision when you run an onboarding asynchronously or when identity verification vendors take longer to verify a user.
  • Manual review. A member of your team may change a user's status during manual review in the Footprint dashboard, which fires footprint.user.manual_review. When you receive it, call GET /users/{fp_id} for the user's new manual status.
  • Watchlist checks. If your playbook has continuous monitoring enabled, Footprint regularly checks whether any of your users appear on AML watchlists and sends the results as footprint.watchlist_check.completed.

Appendix

Advanced integration options

Everything below is optional and suits less common uses of Footprint. Some of these APIs are gated; contact Footprint if one you need is not enabled on your account.

Use the API to fetching onboardings, PII, decisions, risk signals, documents, and more

In more advanced integrations, you may want to process detailed verification data and results from Footprint instead of only viewing them in the dashboard, for example to embed results in your application. A seller marketplace might pass risk signals to the seller who verifies a buyer for large transactions.

The onboarding object. Each time a user or business onboards onto a playbook, Footprint generates an onboarding with a unique ID, often referenced as onboarding_id. Use it to fetch the risk signals, decisions, documents, and collected data of that specific onboarding. An onboarding ID also lets you track the user as they update their data over time.

You receive onboarding IDs in two main places:

  1. The id field of the POST /onboardings response.
  2. The webhook sent when an onboarding is completed.

List a user's or business's onboardings with GET /users/{fp_id}/onboardings and GET /businesses/{fp_bid}/onboardings.

Fetch risk signals, collected data, and documents by onboarding ID. With an onboarding_id, call GET /users/{fpid}/onboardings/{onboardingid}/risk_signals and GET /users/{fpid}/documents?onboardingid=ob_xyz.. to fetch that onboarding's risk signals and captured documents.

Fetch decisions. For a user or business, fetch every decision, including manual review decisions made with a human in the loop, with the list all decisions API. The response looks like:

json
1{
2  "data": [
3    {
4      "kind": "playbook_run",
5      "playbook_key": "pb_test_xxxxx",
6      "status": "fail",
7      "timestamp": "2022-01-04T12:00-07:00"
8    },
9    {
10      "kind": "manual",
11      "status": "pass",
12      "timestamp": "2022-01-04T12:00-07:00"
13    }
14  ],
15  "meta": {
16    "next_page": 2
17  }
18}

Decrypt PII and documents from the vault at a specific onboarding. Vault access is governed by granular access controls. Use the decrypt API to read plaintext user or business data:

bash
1curl -X POST https://api.onefootprint.com/users/{fp_id}/vault/decrypt \
2  -u <API_KEY>: \
3  -d '{
4    "fields": [
5      "id.ssn9",
6      "id.last_name",
7      "document.passport.front.image",
8      "document.passport.dob"
9    ],
10    "reason": "compliance",
11    "at_onboarding_id": "ob_id_xyz..."
12  }'

Set at_onboarding_id to decrypt the user's data as it was at the time of that onboarding.

Linking users to businesses via API

If you run KYB playbooks without verifying beneficial owners together with the business, you can still link users to their businesses, and businesses to their users, so the connection shows in the API and in the Footprint dashboard. After onboarding both the business and the users, call the link a business owner API.