Embedded Integration for Onboarding Users

A pre-built UI for onboarding users and optionally running KYC / KYB and bank risk checks

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 information is collected and what checks are run- learn more on the Customize User Onboarding Checks page.

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 \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
    "flow_alias": "default-individual"
curl --request POST \
  --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": "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 \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "flow_alias": "default-individual",
     "verified_email": "[email protected]",
     "verified_phone": "+12223334444"
curl --request POST \
  --url https://app.moderntreasury.com/api/user_onboardings \
  -H 'Content-Type: application/json' \
  -d '{
     "flow_alias": "default-business"

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
import { useMTUserOnboarding } from "@modern-treasury/user-onboarding-react";

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

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

return (
    onClick={() => open("dacabe14-4b1b-4219-8226-02b3d247477d")}
    Open MT-Onboarding
<!DOCTYPE html>
<html lang="en">
    <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

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

There are three callbacks.

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.