1. Create a user

Verification with the MX Platform API is a powerful tool to add to your app or other online product, but it does require a number of steps and sometimes complicated processes. This guide will take you through an easy-mode version of what it takes. Along the way, we’ll direct you to other guides or to the API reference to get more in-depth information for particular steps in this flow.

But before we get to all that, you’ll need to create a new user. We’ve already got a detailed guide on creating users and members as well as a technical reference, and really, this step is pretty simple, so there’s not much more to say. Just check out the examples below.

Parameters

Field Data type Required?
email String No
id String No
is_disabled Boolean No
metadata String No

Endpoint:

POST /users

Example request

1
2
3
4
5
6
7
8
9
10
11
12
curl -i -X POST 'https://int-api.mx.com/users' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d '{
      "user": {
        "id": "partner-2345",
        "is_disabled": false,
        "email": "totally.fake.email@notreal.com",
        "metadata": "Yada yada yada"
      }
    }'

Example response

1
2
3
4
5
6
7
8
9
{
  "user": {
    "email": "totally.fake.email@notreal.com",
    "guid": "USR-11141024-90b3-1bce-cac9-c06ced52ab4c",
    "id": "partner-2345",
    "is_disabled": false,
    "metadata": "Yada yada yada"
  }
}

2. Create a member

Creating a member is itself a multi-step process that involves searching for an institution to connect to, finding the type of credentials that the institution requires, and then actually creating the member connected to the correct institution.

2.1 Search for an institution

Now that you have a user to work with, it’s time to create a member. But before we can do that, we need to know what financial institution the member should be connected to. We’ll also need to find out what type of credentials the institution expects to get. These will be our next couple steps.

We’ll need to search for an institution using query parameters on the list institutions endpoint. In this case, we’re looking for MX Bank, which is MX’s institution for testing and development. You’ll get a paginated list of institutions which match the string you send in the name query parameter.

Make a note of the code you find for MX Bank in the example response below; you’ll need this for our next step.

Endpoint:

GET /institutions?name={string}

Example request

1
2
3
curl -i 'https://int-api.mx.com/institutions?name=mx' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json'

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{
  "institutions": [
    {
      "code": "mxbank",
      "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/INS-1572a04c-912b-59bf-5841-332c7dfafaef_100x100.png",
      "name": "MX Bank",
      "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/INS-1572a04c-912b-59bf-5841-332c7dfafaef_50x50.png",
      "supports_account_identification": true,
      "supports_account_statement": false,
      "supports_account_verification": true,
      "supports_oauth": false,
      "supports_transaction_history": true,
      "url": "https://www.mx.com"
    },
    {
      "code": "d8927e54-1aa7-331e-5060-fbee168e628c",
      "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/default_100x100.png",
      "name": "MX Bank of Utah",
      "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/default_50x50.png",
      "supports_account_identification": false,
      "supports_account_statement": false,
      "supports_account_verification": false,
      "supports_oauth": false,
      "supports_transaction_history": false,
      "url": "https://www.mx.com"
    },
    {
      "code": "da3f211e-fd77-8e3b-e921-fee5056480cf",
      "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/INS-93a8780f-fb10-ebfa-cc94-4aede74f6e23_100x100.png",
      "name": "MX Credit Union",
      "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/default_50x50.png",
      "supports_account_identification": false,
      "supports_account_statement": false,
      "supports_account_verification": false,
      "supports_oauth": false,
      "supports_transaction_history": false,
      "url": "https://www.mx.com"
    },
    {
      "code": "2fc6472c-f837-c99d-56fb-a1644702b4cd",
      "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/default_100x100.png",
      "name": "MX Bank of Texas",
      "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/default_50x50.png",
      "supports_account_identification": false,
      "supports_account_statement": false,
      "supports_account_verification": false,
      "supports_oauth": false,
      "supports_transaction_history": false,
      "url": "https://www.mx.com"
    },
    {
      "code": "mx_bank_oauth",
      "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/INS-68e96dd6-eabd-42d3-9f05-416897f0746c_100x100.png",
      "name": "MX Bank (Oauth)",
      "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/INS-68e96dd6-eabd-42d3-9f05-416897f0746c_50x50.png",
      "supports_account_identification": false,
      "supports_account_statement": false,
      "supports_account_verification": false,
      "supports_oauth": false,
      "supports_transaction_history": false,
      "url": "www.mx.com"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 25,
    "total_entries": 5,
    "total_pages": 1
  }
}

2.2 Get the institution-required credentials

Each institution requires different credentials. Some require an email and a password. Some require a username and a password. And some require more exotic credentials. This endpoint will give you what you need in order to move on to the next step, specifically the guid for each credential returned.

Notice too that the request URL includes the institution code you got from the previous step.

Endpoint:

GET /institutions/{institution_code}/credentials

Example request

1
2
3
curl -X GET https://int-api.mx.com/institutions/mxbank/credentials \
  -H 'Accept: application/vnd.mx.api.v1+json' \
  -u 'client_id:api_key'

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "credentials": [
    {
      "display_order": 1,
      "field_name": "LOGIN",
      "field_type": "LOGIN",
      "guid": "CRD-9f61fb4c-912c-bd1e-b175-ccc7f0275cc1",
      "label": "Username"
    },
    {
      "display_order": 2,
      "field_name": "PASSWORD",
      "field_type": "PASSWORD",
      "guid": "CRD-e3d7ea81-aac7-05e9-fbdd-4b493c6e474d",
      "label": "Password"
    }
  ]
}

2.3 Actually create the member

Now that we’ve got a user_guid, an institution_code, and a guid for each credential required by the institution, we can finally create a new member. You’ll also need the end-user-provided values for each necessary credential, in this case a username and a password.

For MX Bank, you should set the username to mxuser and the password to password. When you move on to verifying your new member below, these values will mimic a successful verification with no real MFA, only the special account-selection challenge. For real institutions, these values must be the end user’s correct login information, of course.

Below are the parameters you can include in your request.

Parameters

Parameter Data type Description Required?
background_aggregation_is_disabled Boolean When set to true, background aggregation will be disabled for this member. No
credentials Array The credentials endpoint for the requested institution will give you a list of all the credentials required to create a member for a given institution. Each required credential will need to be included within this array. Yes
id String The unique partner-defined identifier for the member. No
institution_code String The unique code for the institution to which the member will connect. Defined by MX. Yes
metadata String Additional information you can store on this member. No
skip_aggregation Boolean Setting this parameter to true will prevent the member from automatically aggregating when it is created. No

Endpoint:

POST /users/{user_guid}/members

Example request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
curl -i -X POST 'https://int-api.mx.com/users/USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2/members' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d '{
      "member": {
        "credentials": [
          {
            "guid": "CRD-1ec152cd-e628-e81a-e852-d1e7104624da",
            "value": "mxuser"
          },
          {
            "guid": "CRD-1ec152cd-e628-e81a-e852-d1e7104624da",
            "value": "password"
          }
        ],
        "institution_code": "mxbank"
        "skip_aggregation": true
      }
    }'

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "member": {
    "aggregated_at": null,
    "connection_status": "CREATED",
    "guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
    "id": null,
    "institution_code": "mxbank",
    "is_being_aggregated": false,
    "is_managed_by_user": true,
    "metadata": null,
    "name": "MX Bank",
    "successfully_aggregated_at": null,
    "user_guid": "USR-151a102b-90b3-1bc3-48d1-c24cad5a2b13",
    "user_id": "10405939560"
  }
}

3. Verify the member

We now have a user and member to work with, so we can start the verification process. This is essentially identical to the aggregation process covered in this guide and this guide. For that reason, we’ll be skipping some of the details and side cases that you can find in those guides. Here, we’ll just focus on the the happy path for verification.

There are two main differences between aggregation and verification.

  • With verification, you’ll make a POST request to the verify member endpoint rather than the aggregate member endpoint.
  • With verification, you will always have to answer a special account-selection challenge sent by MX. This challenge is identical to an MFA challenge, except that the purpose is for the end user to tell us which account they’d like verified. If you don’t get this special challenge, it means that there are no accounts on that member that are eligible for verification.

Other than these two things, you’re dealing with the same flow as aggregation.

Endpoint:

POST /users/{user_guid}/members/{member_guid}/verify

Example request

1
2
3
4
curl -i -X POST 'https://int-api.mx.com/users/USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2/members/MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0/verify' \
-u 'client_id:api_key' \
  -H 'Accept: application/vnd.mx.api.v1+json' \
  -H 'Content-Type: application/json'

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "member": {
    "aggregated_at": null,
    "connection_status": "CREATED",
    "guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
    "id": null,
    "institution_code": "mxbank",
    "is_being_aggregated": true,
    "is_managed_by_user", true,
    "is_oauth": false,
    "metadata": null,
    "name": "MX Bank",
    "successfully_aggregated_at": null,
    "user_guid": "USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2",
    "user_id": null
  }
}

4. Check the connection status

Several fields on the member give you info about what’s happening with the verification, and we’ve got a special endpoint that returns just the fields you’ll need to deal with for this part of the process: read member connection status. Here’s the simple explanation of what you should be looking for.

Important fields include connection_status, is_being_aggregated, successfully_aggregated_at. These are also used for standard aggregation jobs, which is where they get their names.

A status of CONNECTED means that the member was successfully authenticated and verification has begun. The is_being_aggregated field will tell you whether the verification job has completed; it’ll be true while verification is running and false when complete. Long story short, when you see CONNECTED and false on these two fields at the same time, the verification is done and you can pull account and routing data.

However, you’re not going to get into that state right away. You may run into multi-factor authentication issued by the institution. And as mentioned above, you’ll always have to answer at least one special MFA challenge from MX to select which account to verify. When either of these things happens, you’ll see a status of CHALLENGED, and the response will include the challenges you need to answer.

If you don’t get the special challenge and the member goes to "connection_status": "CONNECTED" and "is_being_aggregated": false, it means that there are no eligible accounts to verify and there’s nothing more to do.

The successfully_aggregated_at field will tell you the exact time that the verification job completed — even the case where there were no eligible accounts on the member. If this time is after your initial request to the verify member endpoint, you should be good to move on to the next steps.

You may need to check this endpoint several times to see these different states and then respond to them.

Endpoint:

GET /users/{user_guid}/members/{member_guid}/status

Example request

1
2
3
curl -i 'https://int-api.mx.com/users/USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2/members/MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0/status' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-u 'client_id:api_key'

Example response before any challenge is issued

1
2
3
4
5
6
7
8
9
10
{
  "member": {
    "aggregated_at": null,
    "connection_status": "CREATED",
    "guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
    "is_authenticated": false,
    "is_being_aggregated": true,
    "successfully_aggregated_at": null
  }
}

Example response with special account-selection challenge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "member": {
    "aggregated_at": "2021-03-02T19:47:02Z",
    "challenges": [
      {
        "field_name": null,
        "guid": "CRD-bc26dc1d-9fe3-41f1-9d67-e84070cf3055",
        "label": "Please select an account:",
        "options": [
          {
            "label": "Checking",
            "value": "act-23445745"
          },
          {
            "label": "Savings",
            "value": "act-352386787"
          }
        ],
        "type": "OPTIONS"
      }
    ],
    "connection_status": "CHALLENGED",
    "guid": "MBR-84ca0882-ad6c-4f10-817f-c8c0de7424fa",
    "is_authenticated": true,
    "is_being_aggregated": true,
    "successfully_aggregated_at": "2021-03-01T22:35:00Z"
  }
}

5. Answer MFA and account-selection challenges

You may or may not run into MFA issued by the institution, so you’ll need to be prepared for the possibility and deal with the various kinds of MFA that might pop up. But the process for answering MFA is identical to answering MX’s account-selection challenge, so we’re showing that in the example here, since you’ll always need to do that and it basically covers both cases.

Keep in mind that you may get challenged multiple times by the institution. For example, they may issue a challenge asking where the end user would like a code sent (phone, email, etc.), then issue another challenge which asks the end user for that code. And then you’ll answer MX’s challenge. So you may need to repeat this step two or three times.

5.1 Answer the challenge

You should have the account-selection challenge from step 4. Now, you’ll use the resume aggregation endpoint to answer the challenge. In your request, include the appropriate credential GUID with the appropriate value chosen by the end user.

The response should come back with a "connection_status": "RESUMED".

Endpoint:

PUT /users/{user_guid}/members/{member_guid}/resume

Example request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "member": {
    "aggregated_at": null,
    "connection_status": "RESUMED",
    "guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
    "id": null,
    "institution_code": "mxbank",
    "is_being_aggregated": true,
    "is_oauth": false,
    "metadata": null,
    "name": "MX Bank",
    "successfully_aggregated_at": null,
    "user_guid": "USR-151a102b-90b3-1bc3-48d1-c24cad5a2b13",
    "user_id": "10405939560"
  }
}

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "member": {
    "aggregated_at": null,
    "connection_status": "RESUMED",
    "guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
    "id": null,
    "institution_code": "mxbank",
    "is_being_aggregated": true,
    "is_oauth": false,
    "metadata": null,
    "name": "MX Bank",
    "successfully_aggregated_at": null,
    "user_guid": "USR-151a102b-90b3-1bc3-48d1-c24cad5a2b13",
    "user_id": "10405939560"
  }
}

5.2 Check the connection status again

This is just a repeat of step 4 above. So check out what we said up there.


6. List the account and routing numbers for the member

Now we can get the data we’ve been after this whole time: the account and routing numbers. The MX Platform API has two endpoints for this: list account numbers by member and list account numbers by account. We’re only going to show the first endpoint here because using the latter requires you to know the account GUID you’re looking for, which requires an extra step — we’re trying to keep things as easy as possible for this guide.

This request is dead simple and returns a list of all the account and routing numbers just gathered for the member.

If MX has both an account number and a routing number for at least one of the member’s accounts, that information will be returned. No information will be returned for accounts that are missing a value for one or both of these fields.

Endpoint:

GET /users/{user_guid}/members/{member_guid}/account_numbers

Example request

1
2
3
curl -i 'https://int-api.mx.com/users/USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2/members/MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0/account_numbers' \
  -H 'Accept: application/vnd.mx.api.v1+json' \
  -u 'client_id:api_key'

Example response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "account_numbers": [
    {
      "account_guid": "ACT-82a93692-f756-534f-9b2e-ad10a0f38462",
      "account_number": "10001",
      "institution_number": null,
      "member_guid": "MBR-3bdc7d6b-efd4-1497-a0af-b23501cf9bd0",
      "routing_number": "68899990000000",
      "transit_number": null,
      "user_guid": "USR-3a17a2b1-acbc-48d1-8098-1b8ae8939ab2"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 25,
    "total_entries": 1,
    "total_pages": 1
  }
}