> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MDX On Demand v5

MDX On Demand v5 is a proprietary specification for the RESTful exchange of data between financial institutions and MX.

Data providers implement the MDX On Demand API for the purpose of allowing MX to synchronize account and transaction data with the MX Platform.

MDX On Demand supports XML encoding of the request and response bodies. JSON encoding is not supported at this time.

An MDX On Demand session will start with a request to the sessions endpoint to authenticate the user. Additional endpoints are used to request account and transaction information once the user is authenticated.

## Base URL

All endpoints in the MDX On Demand API have the following base URL:

`https://{partner_base_url}/{institution_id}`

The `partner_base_url` varies with each implementation and is provided to MX by you, the partner. The base URL may contain a port if needed.

The `institution_id` identifies the financial institution for which the request is made. The `institution_id` is provided to MX by you. In many integrations — especially those for an online banking provider — the client is a financial institution. In these cases it is recommended to use the same value for the `client_id` and the `institution_id` to avoid confusion; however, different values can be used if needed.

## HTTPS

All API requests must be made over HTTPS. Calls made to your implementation of the API over plain HTTP should fail. 256-bit SSL or greater is preferred.

## Versioning

The MDX version will change as the specification is updated. On Demand requests will specify the version expected in the response. Data providers may wish to support multiple MDX versions as they upgrade from one version to another.

Requests that don't specify a version should return the latest representation of resources. Unsupported endpoints should simply return `HTTP 404 NOT FOUND`.

## Accept Header

All requests will have an `Accept` header that specifies the encoding and the version being requested.

`Accept: application/vnd.moneydesktop.mdx.v5+xml`

## Content-Type Header

`POST` and `PUT` requests will include  a `Content-Type` header to specify the encoding and the version of the request body. Your responses should include the same header.

`Content-Type: application/vnd.moneydesktop.mdx.v5+xml`

## Job Type Header

An `MDX-Job-Type` header is provided with each request. The header identifies whether the request is being initiated by a user login or a background aggregation request to update the user's data. The provided value will be either `foreground` or `background`.

`MDX-Job-Type: foreground`

`MDX-Job-Type: background`

## Sessions

When synchronizing accounts and transactions with MDX On Demand, a session key must first be obtained. MX will open a session with a request to the sessions endpoint.

When the session is established, the partner will return a session key to MX. MX will provide this session key in an `MDX-Session-Key` header in all subsequent requests during that session, as shown in the example.

If a request is made with an invalid session key, you should return a `401 (Unauthorized)` error.

**Example Session Request**

```
$ curl -H "MDX-Session-Key: [SESSION_KEY]" https://dataprovider_base_url/:institution_id/accounts
```

## Authentication

Every MDX On Demand request will include `MDX-HMAC` and `Content-MD5` headers. If the HMAC signature or MD5 content do not match, you should return a `412 (precondition failed)` error.

The HMAC key will be provided during your integration with MX and will be a 32- to 64-byte string. The length depends on the algorithm used. The key will be provided in base64 format since the key may contain non-printable characters. Supported algorithms are SHA1, SHA224, SHA256, SHA384, and SHA512.

### MD5 Authentication

The `Content-MD5` header is calculated by MD5 authenticating the body of each request. For `GET` requests without a body, you will use an empty string when computing the `Content-MD5` value.

### HMAC Signature

The `MDX-HMAC` header is composed using a string that is signed via [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code). It is a canonical composition of the request's headers, the HTTP verb, and the REST resource.

The `MDX-Session-Key` value will be an empty string in requests to the sessions endpoint.

The `REST Resource of the Request` value will be the final portion of the URL. It will be one of these values:

* `/sessions`
* `/accounts`
* `/transactions`
* `/user`
* `/member`
* `/account_owner`
* `/account_number`

**Signature Pattern**

```
HTTP VERB + "\n" + Content-MD5 Header + "\n" + Content-Type Header + "\n" + UNIX Epoch Date Time + "\n" + Accept Header + "\n" + MDX-Session-Key + "\n" + REST Resource of Request
```

**HMAC Example**

Given the information above, let's take a look at what a `POST` request to `/sessions` would look like.

```
POST /sessions "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n  <session>\n    <userkey><![CDATA[the-userkey]]></userkey>\n  </session>\n</mdx>\n"
Content-Type: application/vnd.moneydesktop.mdx.v5+xml
Date: 1382975431
Accept: application/vnd.moneydesktop.mdx.v5+xml
MDX-Session-Key:
```

### MD5 Hash

The MD5 hash would be computed using the body of the example above.

```
require 'digest/md5'
digest = Digest::MD5.hexdigest("<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n  <session>\n    <userkey><![CDATA[the-userkey]]></userkey>\n  </session>\n</mdx>\n")
puts digest
=> "e9a179f879165fd64bdeaa57032d342f"
```

### HMAC Signature

Now that we have our MD5 hash, we can take a look at our headers to compose our HMAC signature.

```
POST /sessions "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n  <session>\n    <userkey><![CDATA[the-userkey]]></userkey>\n    </session>\n</mdx>\n"
Content-MD5: e9a179f879165fd64bdeaa57032d342f
Content-Type: application/vnd.moneydesktop.mdx.v5+xml
Date: 1382975431
Accept: application/vnd.moneydesktop.mdx.v5+xml
MDX-Session-Key:
```

### Canonical String

The canonical string to be signed can now be composed.

```
"POST\ne9a179f879165fd64bdeaa57032d342f\napplication/vnd.moneydesktop.mdx.v5+xml\n1382975431\napplication/vnd.moneydesktop.mdx.v5+xml\n\n/sessions"
```

### Generated Signature

If your HMAC key (salt) was `QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo3ODkwMTI=`, the resulting signed signature would be generated as shown below.

The resulting signature is `e47928dcd29e494116961ad12884c8fd7aae07f2`. This signature will be provided in the `MDX-HMAC` header of our request.

```
require 'base64'
require 'openssl'

salt = 'QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo3ODkwMTI='
digest = ::OpenSSL::Digest.new('sha1')
hmac_signature = "POST\ne9a179f879165fd64bdeaa57032d342f\napplication/vnd.moneydesktop.mdx.v5+xml\n1382975431\napplication/vnd.moneydesktop.mdx.v5+xml\n\n/sessions"
hmac = ::OpenSSL::HMAC.hexdigest(digest, ::Base64.decode64(salt), hmac_signature)
puts hmac

# => "e47928dcd29e494116961ad12884c8fd7aae07f2"
```

### Session Request

We are now ready to compose our `POST` request to the `/sessions` endpoint.

```
POST /sessions "<?xml version=\"1.0\"?>\n<mdx version=\"5.0\">\n  <session>\n    <userkey><![CDATA[the-userkey]]></userkey>\n  </session>\n</mdx>\n"
Content-MD5: e9a179f879165fd64bdeaa57032d342f
Content-Type: application/vnd.moneydesktop.mdx.v5+xml
Date: 1382975431
Accept: application/vnd.moneydesktop.mdx.v5+xml
MDX-Session-Key:
MDX-HMAC: e47928dcd29e494116961ad12884c8fd7aae07f2
```

### HMAC Notes

The HMAC signature is generated in the MX system with lower-case letters in the hexadecimal representation. Some code libraries return the signature with upper-case letters. A ToLower or downcase applied to the signature may be required on your end before comparing it to the one provided in the request header. A case-insensitve comparison may also be used.

The base64 HMAC key in this example decodes to a 32-byte string. This is the ideal size for the SHA1 algorithm, although most libraries such as OpenSSL will accept other key lengths. SHA1 outputs a 40-character HMAC result. The length of the HMAC key and of the resulting signatures will vary if other algorithms are used.

### IP Filtering

MDX On Demand requests will initiate from one of MX's data centers. For failover and load balancing purposes, these requests can initiate from any data center. If you intend to use IP whitelisting, the IP address ranges of all of MX's data centers must be included.

You should return a `403 (Forbidden)` error for an MDX On Demand request that fails IP validation.

| CIDR              | Range                                              |
| :---------------- | :------------------------------------------------- |
| 64.77.254.32/27   | 30 addresses from 64.77.254.33 to 64.77.254.62     |
| 68.142.151.128/26 | 62 addresses from 68.142.151.129 to 68.142.151.190 |
| 146.75.94.131/32  | 1 address 146.75.94.131                            |
| 97.75.178.32/27   | 30 addresses from 97.75.178.33 to 97.75.178.62     |
| 192.41.25.128/26  | 62 addresses from 192.41.25.129 to 192.41.25.190   |
| 192.41.58.128/26  | 62 addresses from 192.41.58.129 to 192.41.58.190   |

### Additional Authentication

In addition to request signing and IP filtering, you may choose to implement any or all of the following: HTTP basic authentication, mutual authentication, and/or CA certification authentication. Any additional authentication must be set up with MX during your initial integration.

## Errors

The MDX On Demand API uses conventional HTTP response codes to indicate success or failure of an API request. In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that resulted from the provided information (for example, a required parameter was missing), and codes in the 5xx range indicate an error with your servers.

**HTTP Status Code Summary**

* 200 OK: Everything worked as expected.
* 400 Bad Request: Malformed request body or missing a required parameter.
* 401 Unauthorized: No valid session key or credentials provided.
* 403 Forbidden: The IP address isn't whitelisted.
* 404 Not Found: The requested item doesn't exist.
* 406 Not Acceptable: The request didn't specify a valid version.
* 412 Precondition Failed: The HMAC was invalid or missing.
* 422 Unprocessable Entity: The credentials couldn't be decrypted.
* 429 Too Many Requests: The partner's MDX service is at capacity.
* 500 Internal Server Error: Something went wrong on the data provider's end.
* 502 Bad Gateway: Something went wrong on the data provider's end.
* 503 Service Unavailable: The service is down for maintenance.
* 504 Gateway Timeout: The request couldn't be completed in the time allotted.

### Additional Error Codes

You should use the error codes and messages documented here when applicable. These error codes and messages are intended to supplement the HTTP status code and offer additional detail. A message should always be returned. The code is optional. You can return your own code or leave the field blank, but the `<code>` and `<message>` elements should always be present in the error response body.

The format for sending an error is shown in the example.

| Code | Message             | Description                                       |
| ---- | ------------------- | ------------------------------------------------- |
| 4010 | Invalid Credentials | The user key or login and password were invalid.  |
| 4011 | Locked              | The login was valid, but the account was locked.  |
| 4012 | Invalid Session Key | The provided session key was invalid.             |
| 4013 | MFA Failed          | The MFA login information provided was incorrect. |

```xml theme={null}
<mdx version="5.0">
  <error>
    <code>4010</code>
    <message>Error message.</message>
  </error>
</mdx>
```

## Response Format

The MDX On Demand specification is XML-based. Responses are required to be UTF-8 encoded and XML tags must be lowercase. Reserved XML characters must be properly escaped. The XML response must not contain Unicode Byte Order Mark characters (for example, `0xfeff`).

## Compression

Gzip compression is supported when `Content-Encoding` is set to `gzip`.

## Data Sanitization

You are required to avoid sending identifiable account information such as complete account and/or credit card numbers for account IDs and names.
