What Are Partner-Managed Resources?
Rather than relying on our aggregation services to bring in your held account and transaction data, you can manage all that yourself — down to the last detail — with partner-managed resources.
This guide will take you through the process of adding one of your held transactions using the Platform API. We’ll also outline best practices and cover common problems you might run into.
The MX Data Architecture
Every resource on the MX platform has to fit into our existing data architecture. For instance, every transaction belongs to an account, every account belongs to a member, and every member belongs to a user. So, before we can deal with the transactions we’re most interested in, we need to deal with users, members, and accounts — in that order.
You’ll also want to think about what your ultimate use case is going to be. Each of these four resources (users, members, accounts, and transactions) have many attributes that you can set, but not all of those attributes will be useful for every case, and some of them depend on other attributes. So, you’ll need to know exactly what information you plan on sending to MX and how it’s going to fit into the product you’re building with the Platform API.
Workflow
Here’s a general workflow for creating your first transaction with held data:
- Create a
user
(which represents your customer). - Create a
member
belonging to that user (which represents the connection between theuser
and your specialinstitution
). - Create an
account
(which represents the account the customer holds with you). - Create a
transaction
(which represents any instance in which money moves into or out of your customer’s account).
Other workflows
Once all those resources exist, workflows are mostly about updating accounts and transactions to reflect the latest information — like increasing an account balance
after a paycheck is deposited, or, for that matter, creating a new transaction
to represent that deposited paycheck.
1. Create a User
The first step is to create a user. A user represents your end user in the MX Platform. Make a POST request to the create user endpoint, as shown below.
We recommend that you include a unique id
of your choice with the request. You may also include metadata
, such as the date the user
was created or the end user’s name. Don’t include any sensitive information here, such as credentials.
In the response, the API gives each new user
an MX-defined guid
(or user_guid
when appearing outside the user
object). Between your id
and the guid
, you can map between your system and ours. You’ll need the user guid
for nearly every request on the MX API, at least when using basic authorization.
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"
}
}'
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 Managed Member
2.1 List the Available Institutions
This endpoint lists the institutions that you are allowed to use for creating managed members. You’ll most likely have only one available institution, but you may have a use case that requires more; this is determined when enabling managed data with MX.
You shouldn’t need to perform this step often since your list of available institutions won’t often change. Feel free to work from a cached list.
Capture the institution_code
that gets returned. You’ll use it in step 2.2.
Endpoint:
GET /managed_institutions
1
2
3
curl -i 'https://int-api.mx.com/managed_institutions' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json'
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
{
"institutions": [
{
"code": "partnerinstitutioncode",
"instructional_text": null,
"medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/default_100x100.png",
"name": "Partner Institution",
"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://PrtnerInstitutionWebsite.com"
},
{
"code": "mxbank",
"instructional_text": null,
"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"
}
],
"pagination": {
"current_page": 1,
"per_page": 30,
"total_entries": 2,
"total_pages": 1
}
}
2.2 Create a Member
Now that we’ve got a user_guid
and your institution_code
, we can create a member
. As with creating a user, MX strongly encourages you to give the member a unique id
so you can match the data on your systems with our systems.
If the request is successful, the response will contain the newly created member
.
See the API reference for more detailed information on each parameter.
Field | Data type | Required? |
---|---|---|
id |
String | No |
institution_code |
String | Yes (This should always be set to your default institution.) |
metadata |
String | No |
name |
String | No |
Endpoint:
POST /users/{user_guid}/managed_members
1
2
3
4
5
6
7
8
9
10
11
curl -i -X POST 'https://int-api.mx.com/users/USR-11141024-90b3-1bce-cac9-c06ced52ab4c/managed_members' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d '{
"member": {
"institution_code": "mxbank",
"id": "partner-1234",
"metadata": "this and that"
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"member": {
"aggregated_at": null,
"connection_status": "CONNECTED",
"guid": "MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e",
"id": "partner-1234",
"institution_code": "aef89293-88d9-42e6-82a2-0a2b14fe7667",
"is_being_aggregated": false,
"is_managed_by_user": false,
"is_oauth": false,
"metadata": "this and that",
"name": null,
"successfully_aggregated_at": null,
"user_guid": "USR-11141024-90b3-1bce-cac9-c06ced52ab4c",
"user_id": "partner-2345"
}
}
3. Create a Managed Account
Now we have a member, so it’s time to create an account.
Remember that a member
represents the overall connection between your institution and the end user. So, if they open a new account with you, you don’t want to create a new member; you want to attach a new account
to the member you just created. In other words, members can have multiple accounts, each one representing an account that user has with you: one for their savings account, another for their checking, another for their mortgage, etc.
See the API reference for more detailed information on each parameter.
Parameters | Required? |
---|---|
account_number |
No |
apr |
No |
apy |
No |
available_balance |
No |
available_credit |
No |
balance |
Yes |
cash_surrender_value |
No |
credit_limit |
No |
currency_code |
No |
day_payment_is_due |
No |
death_benefit |
No |
id |
No |
interest_rate |
No |
is_closed |
No |
is_hidden |
No |
last_payment_at |
No |
last_payment |
No |
loan_amount |
No |
matures_on |
No |
metadata |
No |
minimum_balance |
No |
minimum_payment |
No |
name |
Yes |
nickname |
No |
original_balance |
No |
payment_due_at |
No |
payoff_balance |
No |
routing_number |
No |
started_on |
No |
subtype |
No |
type |
Yes |
Endpoint:
POST /users/{user_guid}/managed_members/{member_guid}/accounts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl -i -X POST 'https://int-api.mx.com/users/USR-11141024-90b3-1bce-cac9-c06ced52ab4c/managed_members/MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e/accounts' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d'{
"account": {
"account_number": "12345",
"balance": "10000",
"id": "partner-account-7890",
"is_closed": false,
"metadata": "some metadata",
"name": "Swiss Bank Acct",
"nickname": "Swiss Account",
"started_on": "1980-03-28",
"subtype": "MONEY_MARKET",
"type": "SAVINGS"
}
}'
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
{
"account": {
"account_number": "12345",
"apr": null,
"apy": null,
"available_balance": 10000.00,
"available_credit": null,
"balance": 10000.00,
"cash_balance": null,
"cash_surrender_value": null,
"created_at": "2021-08-31T18:17:44Z",
"credit_limit": null,
"currency_code": null,
"day_payment_is_due": null,
"death_benefit": null,
"guid": "ACT-1e194555-a690-44ec-b363-282165cf4dab",
"holdings_value": null,
"id": "partner-account-7890",
"institution_code": "mxbank",
"interest_rate": null,
"insured_name": null,
"is_closed": false,
"is_hidden": false,
"last_payment": null,
"last_payment_at": null,
"loan_amount": null,
"matures_on": null,
"member_guid": "MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e",
"metadata": "some metadata",
"minimum_balance": null,
"minimum_payment": null,
"name": "Swiss Bank Acct",
"nickname": null,
"original_balance": null,
"pay_out_amount": null,
"payment_due_at": null,
"payoff_balance": null,
"premium_amount": null,
"routing_number": null,
"started_on": "1980-03-28",
"subtype": "MONEY_MARKEY",
"total_account_value": null,
"type": "SAVINGS",
"updated_at": "2021-08-31T18:17:44Z",
"user_guid": "USR-11141024-90b3-1bce-cac9-c06ced52ab4c"
}
}
4. Create a Managed Transaction
Now that you have a user, member, and account, you can create a transaction.
This example represents a deposit into a savings account.
See the API reference for more detailed information on each parameter.
Field | Data type | Required? |
---|---|---|
amount |
String | Yes |
category |
String | No |
category_guid |
String | No |
check_number_string |
String | No |
currency_code |
String | No |
description |
String | Yes |
id |
String | No |
is_international |
String | No |
latitude |
String | No |
localized_description |
String | No |
localized_memo |
String | No |
longitude |
String | No |
memo |
String | No |
metadata |
String | No |
merchant_category_code |
String | No |
merchant_guid |
String | No |
merchant_location_guid |
String | No |
posted_at |
String | No |
status |
String | Yes |
transacted_at |
String | Yes |
type |
String | Yes |
Endpoint:
POST /users/{user_guid}/managed_members/{managed_member_guid}/accounts/{account_guid}/transactions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl -L -X POST 'https://int-api.mx.com/users/USR-11141024-90b3-1bce-cac9-c06ced52ab4c/managed_members/MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e/accounts/ACT-09c0ee66-51a8-4edf-b977-99534a471134/transactions' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d '{
"transaction": {
"id": "partner-transaction-3QP5X0",
"status": "PENDING",
"type": "CREDIT",
"amount": 400,
"description": "Savings Deposit",
"is_international": false,
"transacted_at": "2021-09-01T12:00:00Z",
"category": "INCOME",
"latitude": 40.429675,
"longitude": -111.891982
}
}'
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
{
"transaction": {
"account_guid": "ACT-1e194555-a690-44ec-b363-282165cf4dab",
"account_id": "1",
"amount": 8.2,
"category": "Gas",
"category_guid": "CAT-b6d63a19-30a7-e852-2703-bdfb4072289e",
"check_number_string": "9543",
"created_at": "2020-06-28T12:00:00Z",
"currency_code": "USD",
"date": "2020-03-02",
"description": "Costcoo Gas",
"guid": "TRN-181ce5d9-d33e-45b9-a9cd-8f8ef9d82d5d",
"id": "T-3QP5X0",
"is_bill_pay": false,
"is_direct_deposit": false,
"is_expense": false,
"is_fee": false,
"is_income": true,
"is_international": false,
"is_overdraft_fee": false,
"is_payroll_advance": false,
"is_recurring": false,
"is_subscription": false,
"latitude": "40.429675",
"localized_description": null,
"localized_memo": null,
"longitude": "-111.891982",
"member_guid": "MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e",
"memo": "POS Purchase",
"merchant_category_code": null,
"merchant_guid": "MCH-bcd4eed1-f341-b7bb-4cbd-e2a854205306",
"merchant_location_guid": null,
"metadata": null,
"original_description": "COSTCO GAS STATION #22299",
"posted_at": null,
"status": null,
"top_level_category": "Car & Auto",
"transacted_at": "2020-06-28T12:00:00Z",
"type": "DEBIT",
"updated_at": "2020-06-28T12:00:00Z",
"user_guid": "USR-11141024-90b3-1bce-cac9-c06ced52ab4c",
"user_id": "U-39XBF7"
}
}
5. Update a Managed Resource
You can now update the account you created so its balance reflects the deposit we just recorded by creating a new transaction. The account balance
was $10,000 before, and you just deposited $400.
Endpoint:
PUT /users/{user_guid}/managed_members/{member_guid}/accounts/{account_guid}
1
2
3
4
5
6
7
8
9
curl -i -X PUT 'https://int-api.mx.com/users/USR-11141024-90b3-1bce-cac9-c06ced52ab4c/managed_members/MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e/accounts/ACT-1e194555-a690-44ec-b363-282165cf4dab' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json' \
-H 'Content-Type: application/json' \
-d '{
"account": {
"balance": 10400.00
}
}'
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
{
"account": {
"account_number": "12345",
"apr": null,
"apy": null,
"available_balance": 10000.00,
"available_credit": null,
"balance": 10400.00,
"cash_balance": null,
"cash_surrender_value": null,
"created_at": "2021-08-31T18:17:44Z",
"credit_limit": null,
"currency_code": null,
"day_payment_is_due": null,
"death_benefit": null,
"guid": "ACT-1e194555-a690-44ec-b363-282165cf4dab",
"holdings_value": null,
"id": "partner-account-7890",
"institution_code": "mxbank",
"interest_rate": null,
"insured_name": null,
"is_closed": false,
"is_hidden": false,
"last_payment": null,
"last_payment_at": null,
"loan_amount": null,
"matures_on": null,
"member_guid": "MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e",
"metadata": "some metadata",
"minimum_balance": null,
"minimum_payment": null,
"name": "Swiss Bank Acct",
"nickname": null,
"original_balance": null,
"pay_out_amount": null,
"payment_due_at": null,
"payoff_balance": null,
"premium_amount": null,
"routing_number": null,
"started_on": "1980-03-28",
"subtype": "MONEY_MARKEY",
"total_account_value": null,
"type": "SAVINGS",
"updated_at": "2021-09-01T18:20:37Z",
"user_guid": "USR-11141024-90b3-1bce-cac9-c06ced52ab4c"
}
}
6. Delete a Managed Resource
Marking an account as closed or temporarily disabling a user might be better than deleting an account or user since you can still restore the data. But sometimes, deletes are necessary.
You won’t get a response body with a delete request. The status will be 204 No Content
if it’s successful.
Endpoint:
DELETE /users/{user_guid}/managed_members/{member_guid}
1
2
3
curl -i -X DELETE 'https://int-api.mx.com/users/USR-11141024-90b3-1bce-cac9-c06ced52ab4c/managed_members/MBR-e6239750-24e8-4833-93a8-d4c2ecf2ec7e' \
-u 'client_id:api_key' \
-H 'Accept: application/vnd.mx.api.v1+json'
Dealing with Pending and Posted Transactions
Because you are in full control of your held data with partner-managed resources, you are also responsible for reconciling pending and posted transactions. There are two different strategies for doing this:
- The ideal case: Keep the same transaction and update it from a status of
PENDING
to a status ofPOSTED
. - The other case: Delete all
PENDING
transactions and create entirely new transactions with a status ofPOSTED
.
The Ideal Case
The best case scenario is to keep the existing Platform transaction and update it from PENDING
to POSTED
. This means the transaction will maintain the same GUID assigned by MX and ID assigned by you. If your systems use different IDs for associated pending/posted transactions, you’re free to update the ID in the Platform API as well.
This also means that if the end user has made any updates while the transaction was PENDING
(like recategorizing it or changing the description), those end-user changes will be maintained.
If a PENDING
transaction never becomes POSTED
on your end, then you should simply delete the PENDING
platform transaction.
The Other Case
This strategy is necessary for partners who are unable to confidently tie pending and posted transactions together on their own systems.
In this scenario, you will need to delete every PENDING
transaction you create on the Platform API. Only POSTED
transactions should persist. It also means that any end-user changes to the pending transaction will be lost when it is deleted. In this scenario you may even consider disallowing end-user updates to PENDING
transactions.
PENDING
transactions should be deleted at the same time as the new POSTED
transaction is created, or as close to it as possible. This is to prevent end users from seeing a both a pending and posted version of the same transaction.