Onboard an individual

How to onboard a user using Pre-Built UIs or the API

TAB-Pre-Built UIs

Onboard a user using Pre-Built UIs

Embedded flows allow you to verify users from within your application. You can securely create Counterparties without touching sensitive information. You will spend less time on development. Alternatively, you can send data via API to have full control over the onboarding experience.

1. Retrieve API Key

Go to your API Keys page. There you will find your Organization ID and API keys. Your default Sandbox or Production keys have the appropriate permissions. Otherwise, create or modify an API key to have manage permissions for Compliance, Counterparties, and External Accounts.

2. Create User Onboarding

Create a User Onboarding. If you would like to use the default flows for KYC and KYB, pass in default-individual or default-business for the flow alias. You can also customize what checks are run- learn more here.

You can also optionally prefill fields in the user onboarding flow using the data parameter. Individuals can still edit the fields. Please pay close attention to the format and names of the attributes, as other data will be ignored.

If you have previously verified the email address or phone number of users, you can optionally pass them. This data will be compared against what the user enters and is a signal for the KYC checks. Phone numbers should include the country code (e.g. +1 for US-based phone numbers) and be formatted without spaces (e.g. +11234567890).

curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
    "flow_alias": "default-individual"
  }'
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
    "flow_alias": "default-individual",
    "data": {
  	  "first_name": "Harry",
   	  "last_name": "Potter",
      "date_of_birth": "1980-07-31",
  	  "phone_number": "+11111111111",
      "email": "[email protected]",
      "address": {
        "line1": "4 Privet Drive",
        "line2": "",
        "locality": "San Francisco",
        "region": "CA",
        "postal_code": "94108",
        "country": "US"
  	  },
      "taxpayer_identifier": "123456789",
      "external_account": {
        "account_details": [
          {
            "account_number": "123456789",
            "account_number_type": "other"
          }
        ],
        "routing_details": [
          {
            "routing_number": "121141822",
            "routing_number_type": "aba"
          }
        ],
        "account_type": "checking"
      }
    }
  }'
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "flow_alias": "default-individual",
     "verified_email": "[email protected]",
     "verified_phone": "+11111111111"
  }'

This API request will return a User Onboarding object.

{
  "id": "dacabe14-4b1b-4219-8226-02b3d247477d",
  "object": "user_onboarding",
  "live_mode": true,
  "metadata": {},
  "flow-alias": "default-individual",
  "status": "processing",
  "counterparty_id": null,
  "external_account_id": null,
  "decision_id": null,
  "created_at": "2022-05-24T02:45:08Z",
  "updated_at": "2022-05-24T02:45:08Z"
}

🚧

Be careful not to share your API key with your frontend, as it is private. Create User Onboarding objects in your backend only.

3. Embed Flow

Integrate Modern Treasury’s user onboarding flow by inserting a code snippet into your application. You can use a React component (see our user-onboarding-react Github repo for detailed instructions), or you can use pure Javascript.

To initiate the flow, supply the ID (from the User Onboarding object created in the last step (dacabe14-4b1b-4219-8226-02b3d247477d).

You can also optionally supply custom callback methods that fire on specific events.

import { MTUserOnboarding } from "@modern-treasury/user-onboarding-react";

const options = {
  userOnboardingId: "dacabe14-4b1b-4219-8226-02b3d247477d",
  onSuccess: () => {
    console.log("MT User Onboarding is a Success!");
  },
  onCancel: () => {
    console.log("MT User Onboarding has been Canceled!");
  },
  onError: () => {
    console.log("MT User Onboarding has an Error!");
  },
  style: {
    backgroundColor: "green",
    boarder: "none",
    color: "white",
    width: "200px",
    height: "75px",
    children: "Open User Onboarding",
    className: "MT-Onboarding",
    padding: "15px 32px",
    textAlign: "center",
    textDecoration: "none",
    display: "inline-block",
    fontSize: "16px",
  },
};

function App() {
  return (
    <div className="App">
      <MTUserOnboarding {...options}>
        Open User Onboarding
      </MTUserOnboarding>
    </div>
  );
}
import { useMTUserOnboarding } from "@modern-treasury/user-onboarding-react";

// Pass in optional options as shown below
const options = {
 ...
}

const [ready, error, open] = useMTUserOnboarding(options);

return (
  <button
    onClick={() => open("dacabe14-4b1b-4219-8226-02b3d247477d")}
    disabled={!ready}
  >
    Open MT-Onboarding
  </button>
);
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdn.moderntreasury.com/compliance/v1/mt-onboarding.js"></script>
    <script type="application/ecmascript">
      function openIframe() {
        const onSuccess = function (event) {
          // handle success event (e.g. move user to the next step of your flow following KYC)
        };
        
        const onError = function (event) {
          // handle error event (e.g. open the iframe again)
        };
        
        const onCancel = function (event) {
          // handle cancel event (e.g. email the user later to try and reactivate them)
          // note: this event will not be triggered if the user closes their browser.
        };
        
        const userOnboardingId = document.getElementById('userOnboardingId').value;

        window.onboardingInstance = MTOnboarding.open({
          userOnboardingId: userOnboardingId, // required
          onSuccess: onSuccess, // optional
          onError: onError, // optional
          onClose: onCancel, // optional
        });
      }
    </script>
  </head>

  <body>
    <label for="userOnboardingId">User Onboarding ID:</label>
    <input type="text" value="dacabe14-4b1b-4219-8226-02b3d247477d" name="userOnboardingId" id="userOnboardingId">
    <br/>
    <button onclick="openIframe()">
      Open
	  </button>
  </body>
</html>

There are three callbacks.

CallbackDescription
onSuccessRuns if the user completes the onboarding flow, regardless of the eventual outcome of the verification.
onCancelRuns if the user closes the iframe before the user completes the onboarding flow.
onErrorRuns if there is an error in the onboarding flow.

For each event, a message will be sent. For error events, this message will look like { event: "error", error: "REASON_FOR_ERROR" }. Below are potential reasons for an error.

Error MessageReason
user_onboarding_expiredThe userOnboardingId has expired (it is valid for 24 hours).
user_onboarding_api_key_invalidThe API key used for creating the user onboarding was deactivated.
user_onboarding_completedUser onboarding already completed.
user_onboarding_not_foundUser onboarding with given ID was not found.
internal_server_errorAn unexpected error occurred.

When the user successfully completes the onboarding flow, checks will be kicked off automatically.

❗️

Authenticating the user before sending them to Modern Treasury Compliance, and limiting the number of submission attempts, help prevent fraudsters from abusing your verification flow.

4. Monitor User Onboarding

Based on the compliance score, a User Onboarding will be automatically approved, automatically denied, or have a Case opened for manual review.

If a User Onboarding is approved, a Counterparty and External Account will be created. If a User Onboarding is denied, a Counterparty will not be created. The id of the Counterparty and External Accounts will be included in the webhooks and User Onboarding object.

Webhooks are used to provide status updates on User Onboardings.

{
  "event": "approved",
    "data": {
      "id": "dacabe14-4b1b-4219-8226-02b3d247477d",
      "object": "user_onboarding",
      "live_mode": true,
      "metadata": {},
      "party_type": "individual",
      "status": "approved",
      "counterparty_id": "72d63b95-910f-41ae-a13c-5a9465c891a1",
      "external_account_id": "4c95964e-c9d4-4102-9183-2c8ae39e2c1d",
      "decision_id": "08d9b87d-67a2-4234-a6d0-e8fec11ebb4f",
      "created_at": "2022-05-16T05:14:02Z",
      "updated_at": "2022-05-16T05:14:02Z"
    }
}

Additional information about the User Onboarding can be found in the related Decision object. You can alternatively monitor this object for status on User Onboardings.

Check out this guide to learn more about testing Customer Onboarding in the Sandbox.

TAB-API

Onboard a user using the API

With the API integration, you have full control over the user onboarding experience. Implement your own frontend to collect the data and send Modern Treasury the data for verification. Alternatively, you can embed a pre-built flow to quickly add this capability to your application.

1. Retrieve your API Key

Go to your API Keys page. There you will find your Organization ID and API keys. Your default Sandbox or Production keys have the appropriate permissions. Otherwise, create or modify an API key to have manage permissions for Compliance, Counterparties, and External Accounts.

2. Create a User Onboarding

Create a User Onboarding. Provide information via the data field and set the status field to processing.

For KYC, the flow alias should be default-individual. For KYB, the flow alias should be default-business. You can also customize what checks are run- learn more on the Customize User Onboarding Checks page.

Optionally, you can provide:

  • Verified email and verified phone: You can enter an email address or phone number that you have verified previously with the user. Phone numbers should include the country code (e.g. +1 for US-based phone numbers) and be formatted without spaces (e.g. +11234567890). This data will be compared against what the user enters and is a signal for the KYC checks.
  • Session key: If you integrate the Device and Behavior SDK, pass in a session key for matching data collected from the SDK with this customer onboarding.
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "status":"processing",
     "flow_alias": "default-individual",
     "data": {
        "first_name": "Harry",
        "last_name": "Potter",
        "date_of_birth": "1980-07-31",
        "phone_number": "+11111111111",
        "email": "[email protected]",
        "address": {
          "line1": "4 Privet Drive",
          "line2": "",
          "locality": "San Francisco",
          "region": "CA",
          "postal_code": "94108",
          "country": "US"
        },
        "taxpayer_identifier": "123456789",
        "external_account": {
          "account_details": [
            {
              "account_number": "123456789",
              "account_number_type": "other"
            }
          ],
          "routing_details": [
            {
              "routing_number": "121141822",
              "routing_number_type": "aba"
            }
          ],
           "account_type": "checking"
        }
     }
  }'
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "status":"processing",
     "flow_alias": "default-individual",
     "verified_email": "[email protected]",
     "verified_phone": "+11111111111",
     "data": {
        "first_name": "Harry",
        "last_name": "Potter",
        "date_of_birth": "1990-01-02",
        "phone_number": "+11111111111",
        "email": "[email protected]",
        "address": {
          "line1": "Hogsmeade Ave",
          "line2": "",
          "locality": "San Francisco",
          "region": "CA",
          "postal_code": "94108",
          "country": "USA"
        },
        "taxpayer_identifier": "123456789",
        "external_account": {
          "account_details": [
            {
              "account_number": "1111111111",
              "account_number_type": "other"
            }
          ],
          "routing_details": [
            {
              "routing_number": "021000021",
              "routing_number_type": "aba"
            }
          ],
           "account_type": "checking"
        }
     }
  }'
curl --request POST \
  -u ORGANIZATION_ID:API_KEY \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "status":"processing",
     "flow_alias": "default-individual",
     "session_key": "5195ac52-afb7-4425-bd8b-8234263f2139",
     "data": {
        "first_name": "Harry",
        "last_name": "Potter",
        "date_of_birth": "1990-01-02",
        "phone_number": "+11111111111",
        "email": "[email protected]",
        "address": {
          "line1": "Hogsmeade Ave",
          "line2": "",
          "locality": "San Francisco",
          "region": "CA",
          "postal_code": "94108",
          "country": "USA"
        },
        "taxpayer_identifier": "123456789",
        "external_account": {
          "account_details": [
            {
              "account_number": "1111111111",
              "account_number_type": "other"
            }
          ],
          "routing_details": [
            {
              "routing_number": "021000021",
              "routing_number_type": "aba"
            }
          ],
           "account_type": "checking"
        }
     }
  }'

This API request will return a User Onboarding object.

{
    "id": "dacabe14-4b1b-4219-8226-02b3d247477d",
    "object": "user_onboarding",
    "live_mode": true,
    "metadata": {},
    "party_type": "individual",
    "status": "processing",
    "counterparty_id": null,
    "external_account_id": null,
    "compliance_rule_metadata": null,
    "decision_id": null,
    "created_at": "2023-03-20T22:02:03Z",
    "updated_at": "2023-03-20T22:02:03Z"
}

The checks will be kicked off automatically.

3. Monitor User Onboarding

Based on the compliance score, a User Onboarding will be automatically approved, automatically denied, or have a Case opened for manual review.

If a User Onboarding is approved, a Counterparty and External Account will be created. If a User Onboarding is denied, a Counterparty will not be created. The id of the Counterparty and External Accounts will be included in the webhooks and User Onboarding object.

Webhooks are used to provide status updates on User Onboardings.

{
  "event": "approved",
    "data": {
      "id": "dacabe14-4b1b-4219-8226-02b3d247477d",
      "object": "user_onboarding",
      "live_mode": true,
      "metadata": {},
      "party_type": "individual",
      "status": "approved",
      "counterparty_id": "72d63b95-910f-41ae-a13c-5a9465c891a1",
      "external_account_id": "4c95964e-c9d4-4102-9183-2c8ae39e2c1d",
      "decision_id": "08d9b87d-67a2-4234-a6d0-e8fec11ebb4f",
      "created_at": "2022-05-16T05:14:02Z",
      "updated_at": "2022-05-16T05:14:02Z"
    }
}

Additional information about the User Onboarding can be found in the related Decision object. You can alternatively monitor this object for status on User Onboardings.

Check out this guide to learn more about testing Customer Onboarding in the Sandbox.