Introduction
API endpoint
https://api.monzo.com
Examples in this documentation are written using httpie for clarity.
To install
httpieon macOS runbrew install httpie
The Monzo API is designed to be a predictable and intuitive interface for interacting with users’ accounts. We offer both a REST API and webhooks.
Our developers’ community in Slack is the place to get help with our API, discuss ideas, and show off what you build. Hit the button to join:
Authentication
The Monzo API implements OAuth 2.0 to allow users to log in to applications without exposing their credentials. The process involves several steps:
- Acquire an access token, and optionally a refresh token
- Use the access token to make authenticated requests
- If you were issued a refresh token: refresh the access token when it expires
Before you begin, you will need to create a client in the developer tools.
Client confidentiality
Clients are designated either confidential or non-confidential.
- Confidential clients keep their client secret hidden. For example, a server-side app that never exposes its secret to users.
Non-confidential clients cannot keep their client secret hidden. For example, client-side apps that store their client secret on the user’s device, where it could be intercepted.
Non-confidential clients are not issued refresh tokens.
Acquire an access token
Acquiring an access token is a three-step process:
- Redirect the user to Monzo to authorise your app
- Monzo redirects the user back to your app with an authorization code
- Exchange the authorization code for an access token
Redirect the user to Monzo
"https://auth.getmondo.co.uk/?
client_id=$client_id&
redirect_uri=$redirect_uri&
response_type=code&
state=$state_token"
Send the user to Monzo in a web browser, where they will log in and grant access to their account.
URL arguments
| Parameter | Description |
|---|---|
client_idRequired |
Your client ID. |
redirect_uriRequired |
A URI to which users will be redirected after authorising your app. |
response_typeRequired |
Must be set to code. |
state |
An unguessable random string used to protect against cross-site request forgery attacks. |
Monzo redirects back to your app
"https://your.example.com/oauth/callback?
code=$authorization_code&
state=$state_token"
If the user allows access to their account, Monzo redirects them back to your app.
URL arguments
| Parameter | Description |
|---|---|
code |
A temporary authorization code which will be exchanged for an access token in the next step. |
state |
The same string you provided as state when sending the user to Monzo. If this value differs from what you sent, you must abort the authentication process. |
Exchange the authorization code
$ http --form POST "https://api.monzo.com/oauth2/token" \
"grant_type=authorization_code" \
"client_id=$client_id" \
"client_secret=$client_secret" \
"redirect_uri=$redirect_uri" \
"code=$authorization_code"
{
"access_token": "access_token",
"client_id": "client_id",
"expires_in": 21600,
"refresh_token": "refresh_token",
"token_type": "Bearer",
"user_id": "user_id"
}
When you receive an authorization code, exchange it for an access token. The resulting access token is tied to both your client and an individual Monzo user, and is valid for several hours.
Request arguments
| Parameter | Description |
|---|---|
grant_typeRequired |
This must be set to authorization_code |
client_idRequired |
The client ID you received from Monzo. |
client_secretRequired |
The client secret which you received from Monzo. |
redirect_uriRequired |
The URL in your app where users were sent after authorisation. |
codeRequired |
The authorization code you received when the user was redirected back to your app. |
Authenticating requests
$ http "https://api.monzo.com/ping/whoami" \
"Authorization: Bearer $access_token"
{
"authenticated": true,
"client_id": "client_id",
"user_id": "user_id"
}
All requests must be authenticated with an access token supplied in the Authorization header using the Bearer scheme. Your client may only have one active access token at a time, per user. Acquiring a new access token will invalidate any other token you own for that user.
To get information about an access token, you can call the /ping/whoami endpoint.
Refreshing access
$ http --form POST "https://api.monzo.com/oauth2/token" \
"grant_type=refresh_token" \
"client_id=$client_id" \
"client_secret=$client_secret" \
"refresh_token=$refresh_token"
{
"access_token": "access_token_2",
"client_id": "client_id",
"expires_in": 21600,
"refresh_token": "refresh_token_2",
"token_type": "Bearer",
"user_id": "user_id"
}
To limit the window of opportunity for attackers in the event an access token is compromised, access tokens expire after a number of hours. To gain long-lived access to a user’s account, it’s necessary to “refresh” your access when it expires using a refresh token. Only “confidential” clients are issued refresh tokens βΒ “public” clients must ask the user to re-authenticate.
Refreshing an access token will invalidate the previous token, if it is still valid. Refreshing is a one-time operation.
Request arguments
| Parameter | Description |
|---|---|
grant_typeRequired |
Should be refresh_token. |
client_idRequired |
Your client ID. |
client_secretRequired |
Your client secret. |
refresh_tokenRequired |
The refresh token received along with the original access token. |
Pagination
Endpoints which enumerate objects support time-based and cursor-based pagination.
Request arguments
| Parameter | Description |
|---|---|
limitOptional |
Limits the number of results per-page. Maximum: 100. |
sinceOptional |
An RFC 3339-encoded timestamp. eg. 2009-11-10T23:00:00Zβ¦or an object id. eg. tx_00008zhJ3kE6c8kmsGUKgn |
beforeOptional |
An RFC 3339 encoded-timestamp2009-11-10T23:00:00Z |
Expanding objects
Some objects contain the id of another object in their response. To save a round-trip, some of these objects can be expanded inline with the expand[] argument, which is repeatable. Objects that can be expanded are noted in individual endpoint documentation.
Accounts
Accounts represent a store of funds, and have a list of transactions.
List accounts
Returns a list of accounts owned by the currently authorised user.
$ http "https://api.monzo.com/accounts" \
"Authorization: Bearer $access_token"
{
"accounts": [
{
"id": "acc_00009237aqC8c5umZmrRdh",
"description": "Peter Pan's Account",
"created": "2015-11-13T12:17:42Z"
}
]
}
Balance
Retrieve information about an account’s balance.
Read balance
$ http "https://api.monzo.com/balance" \
"Authorization: Bearer $access_token" \
"account_id==$account_id"
{
"balance": 5000,
"currency": "GBP",
"spend_today": 0
}
Returns balance information for a specific account.
Request arguments
| Parameter | Description |
|---|---|
account_idRequired |
The id of the account. |
Response arguments
| Parameter | Description |
|---|---|
balance |
The currently available balance of the account, as a 64bit integer in minor units of the currency, eg. pennies for GBP, or cents for EUR and USD. |
currency |
The ISO 4217 currency code. |
spend_today |
The amount spent from this account today (considered from approx 4am onwards), as a 64bit integer in minor units of the currency. |
Transactions
Transactions are movements of funds into or out of an account. Negative transactions represent debits (ie. spending money) and positive transactions represent credits (ie. receiving money).
Most properties on transactions are self-explanatory. We’ll eventually get around to documenting them all, but in the meantime let’s discuss the most interesting/confusing ones:
Properties
| Property | Description |
|---|---|
amount |
The amount of the transaction in minor units of currency. For example pennies in the case of GBP. A negative amount indicates a debit (most card transactions will have a negative amount) |
decline_reason |
This is only present on declined transactions! Valid values are INSUFFICIENT_FUNDS, CARD_INACTIVE, CARD_BLOCKED or OTHER. |
is_load |
Top-ups to an account are represented as transactions with a positive amount and is_load = true. Other transactions such as refunds, reversals or chargebacks may have a positive amount but is_load = false |
settled |
The timestamp at which the transaction settled. In most cases, this happens 24-48 hours after created. If this field is not present, the transaction is authorised but not yet “complete.” |
category |
The category can be set for each transaction by the user. Over time we learn which merchant goes in which category and auto-assign the category of a transaction. If the user hasn’t set a category, we’ll return the default category of the merchant on this transactions. Top-ups have category mondo. Valid values are general, eating_out, expenses, transport, cash, bills, entertainment, shopping, holidays, groceries. |
merchant |
This contains the merchant_id of the merchant that this transaction was made at. If you pass ?expand[]=merchant in your request URL, it will contain lots of information about the merchant. |
Retrieve transaction
$ http "https://api.monzo.com/transactions/$transaction_id" \
"Authorization: Bearer $access_token" \
# Here we are expanding the merchant \
"expand[]==merchant"
{
"transaction": {
"account_balance": 13013,
"amount": -510,
"created": "2015-08-22T12:20:18Z",
"currency": "GBP",
"description": "THE DE BEAUVOIR DELI C LONDON GBR",
"id": "tx_00008zIcpb1TB4yeIFXMzx",
"merchant": {
"address": {
"address": "98 Southgate Road",
"city": "London",
"country": "GB",
"latitude": 51.54151,
"longitude": -0.08482400000002599,
"postcode": "N1 3JD",
"region": "Greater London"
},
"created": "2015-08-22T12:20:18Z",
"group_id": "grp_00008zIcpbBOaAr7TTP3sv",
"id": "merch_00008zIcpbAKe8shBxXUtl",
"logo": "https://pbs.twimg.com/profile_images/527043602623389696/68_SgUWJ.jpeg",
"emoji": "π",
"name": "The De Beauvoir Deli Co.",
"category": "eating_out"
},
"metadata": {},
"notes": "Salmon sandwich π",
"is_load": false,
"settled": "2015-08-23T12:20:18Z"
}
}
Returns an individual transaction, fetched by its id.
Request arguments
| Parameter | Description |
|---|---|
expand[]Repeated |
Can be merchant. |
List transactions
$ http "https://api.monzo.com/transactions" \
"Authorization: Bearer $access_token" \
"account_id==$account_id"
{
"transactions": [
{
"account_balance": 13013,
"amount": -510,
"created": "2015-08-22T12:20:18Z",
"currency": "GBP",
"description": "THE DE BEAUVOIR DELI C LONDON GBR",
"id": "tx_00008zIcpb1TB4yeIFXMzx",
"merchant": "merch_00008zIcpbAKe8shBxXUtl",
"metadata": {},
"notes": "Salmon sandwich π",
"is_load": false,
"settled": "2015-08-23T12:20:18Z",
"category": "eating_out"
},
{
"account_balance": 12334,
"amount": -679,
"created": "2015-08-23T16:15:03Z",
"currency": "GBP",
"description": "VUE BSL LTD ISLINGTON GBR",
"id": "tx_00008zL2INM3xZ41THuRF3",
"merchant": "merch_00008z6uFVhVBcaZzSQwCX",
"metadata": {},
"notes": "",
"is_load": false,
"settled": "2015-08-24T16:15:03Z",
"category": "eating_out"
},
]
}
Returns a list of transactions on the user’s account.
Request arguments
| Parameter | Description |
|---|---|
account_idRequired |
The account to retrieve transactions from. |
| Pagination Optional |
This endpoint can be paginated. |
Annotate transaction
$ http --form PATCH "https://api.monzo.com/transactions/$transaction_id" \
"Authorization: Bearer $access_token" \
"metadata[$key1]=$value1" \
#Β Set a key's value as empty to delete it
"metadata[$key2]="
{
"transaction": {
"account_balance": 12334,
"amount": -679,
"created": "2015-08-23T16:15:03Z",
"currency": "GBP",
"description": "VUE BSL LTD ISLINGTON GBR",
"id": "tx_00008zL2INM3xZ41THuRF3",
"merchant": "merch_00008z6uFVhVBcaZzSQwCX",
"metadata": {
"foo": "bar"
},
"notes": "",
"is_load": false,
"settled": "2015-08-24T16:15:03Z",
"category": "eating_out"
}
}
You may store your own key-value annotations against a transaction in its metadata.
Request arguments
| Parameter | Description |
|---|---|
metadata[$name]Repeated |
Include each key you would like to modify. To delete a key, set its value to an empty string. |
Feed items
The Monzo app is organised around the feed βΒ a reverse-chronological stream of events. Transactions are one such feed item, and your application can create its own feed items to surface relevant information to the user.
It’s important to keep a few principals in mind when creating feed items:
- Feed items are discrete events that happen at a point in time.
- Because of their prominence within the Monzo app, feed items should contain information of high value.
- While the appearance of feed items can be customised, care should be taken to match the style of the Monzo app so that your feed items feel part of the experience.
Create feed item
$ http --form POST "https://api.monzo.com/feed" \
"Authorization: Bearer $access_token" \
"account_id=$account_id" \
"type=basic" \
"url=https://www.example.com/a_page_to_open_on_tap.html" \
"params[title]=My custom item" \
"params[image_url]=www.example.com/image.png" \
"params[background_color]=#FCF1EE" \
"params[body_color]=#FCF1EE" \
"params[title_color]=#333" \
"params[body]=Some body text to display"
{}
Creates a new feed item on the user’s feed. These can be dismissed.
Request arguments (for all feed item types)
| Parameter | Description |
|---|---|
account_idRequired |
The account to create a feed item for. |
typeRequired |
Type of feed item. Currently only basic is supported. |
paramsRequired |
A map of parameters which vary based on type |
urlOptional |
A URL to open when the feed item is tapped. If no URL is provided, the app will display a fallback view based on the title & body. |
Per-type arguments
Each type of feed item supports customisation with a specific list of params. Currently we only support creation of the basic feed item which requires the parameters below. These should be sent as form parameters as in the example to the right.
Basic
The basic type displays an image, with title text and optional body text.
Note the image supports animated gifs!

Request arguments
| Parameter | Description |
|---|---|
titleRequired |
The title to display. |
image_urlRequired |
URL of the image to display. This will be displayed as an icon in the feed, and on the expanded page if no url has been provided. |
bodyOptional |
The body text of the feed item. |
background_colorOptional |
Hex value for the background colour of the feed item. Defaults to to standard app colours (ie. white background). |
title_colorOptional |
Hex value for the colour of the title text. Defaults to standard app colours. |
body_colorOptional |
Hex value for the colour of the body text. Defaults to standard app colours. |
Webhooks
Webhooks allow your application to receive real-time, push notification of events in an account.
Registering a webhook
$ http --form POST "https://api.monzo.com/webhooks" \
"Authorization: Bearer $access_token" \
"account_id=$account_id" \
"url=$url"
{
"webhook": {
"account_id": "account_id",
"id": "webhook_id",
"url": "http://example.com"
}
}
Each time a matching event occurs, we will make a POST call to the URL you provide. If the call fails, we will retry up to a maximum of 5 attempts, with exponential backoff.
Request arguments
| Parameter | Description |
|---|---|
account_idRequired |
The account to receive notifications for. |
urlRequired |
The URL we will send notifications to. |
List webhooks
$ http "https://api.monzo.com/webhooks" \
"Authorization: Bearer $access_token" \
"account_id==$account_id"
{
"webhooks": [
{
"account_id": "acc_000091yf79yMwNaZHhHGzp",
"id": "webhook_000091yhhOmrXQaVZ1Irsv",
"url": "http://example.com/callback"
},
{
"account_id": "acc_000091yf79yMwNaZHhHGzp",
"id": "webhook_000091yhhzvJSxLYGAceC9",
"url": "http://example2.com/anothercallback"
}
]
}
List the webhooks your application has registered on an account.
Request arguments
| Parameter | Description |
|---|---|
account_idRequired |
The account to list registered webhooks for. |
Deleting a webhook
$ http DELETE "https://api.monzo.com/webhooks/$webhook_id" \
"Authorization: Bearer $access_token"
{}
When you delete a webhook, we will no longer send notifications to it.
Transaction created
{
"type": "transaction.created",
"data": {
"account_id": "acc_00008gju41AHyfLUzBUk8A",
"amount": -350,
"created": "2015-09-04T14:28:40Z",
"currency": "GBP",
"description": "Ozone Coffee Roasters",
"id": "tx_00008zjky19HyFLAzlUk7t",
"category": "eating_out",
"is_load": false,
"settled": true,
"merchant": {
"address": {
"address": "98 Southgate Road",
"city": "London",
"country": "GB",
"latitude": 51.54151,
"longitude": -0.08482400000002599,
"postcode": "N1 3JD",
"region": "Greater London"
},
"created": "2015-08-22T12:20:18Z",
"group_id": "grp_00008zIcpbBOaAr7TTP3sv",
"id": "merch_00008zIcpbAKe8shBxXUtl",
"logo": "https://pbs.twimg.com/profile_images/527043602623389696/68_SgUWJ.jpeg",
"emoji": "π",
"name": "The De Beauvoir Deli Co.",
"category": "eating_out"
}
}
}
Each time a new transaction is created in a user’s account, we will immediately send information about it in a transaction.created event.
Attachments
Images (eg. receipts) can be attached to transactions by uploading these via the attachment API. Once an attachment is registered against a transaction, the image will be shown in the transaction detail screen within the Monzo app.
There are two options for attaching images to transactions - either Monzo can host the image, or remote images can be displayed.
If Monzo is hosting the attachment the upload process consists of three steps:
- Obtain a temporary authorised URL to upload the attachment to.
- Upload the file to this URL.
- Register the attachment against a
transaction.
If you are hosting the attachment, you can simply register the attachment with the transaction:
- Register the attachment against a
transaction.
Upload attachment
The first step when uploading an attachment is to obtain a temporary URL to which the file can be uploaded. The response will include a file_url which will be the URL of the resulting file, and an upload_url to which the file should be uploaded to.
$ http --form POST "https://api.monzo.com/attachment/upload" \
"Authorization: Bearer $access_token" \
"file_name=foo.png" \
"file_type=image/png"
{
"file_url":"https://s3-eu-west-1.amazonaws.com/mondo-image-uploads/user_00009237hliZellUicKuG1/LcCu4ogv1xW28OCcvOTL-foo.png",
"upload_url":"https://mondo-image-uploads.s3.amazonaws.com/user_00009237hliZellUicKuG1/LcCu4ogv1xW28OCcvOTL-foo.png?AWSAccessKeyId=AKIAIR3IFH6UCTCXB5PQ\u0026Expires=1447353431\u0026Signature=k2QeDCCQQHaZeynzYKckejqXRGU%!D(MISSING)"
}
Request arguments
| Parameter | Description |
|---|---|
file_nameRequired |
The name of the file to be uploaded |
file_typeRequired |
The content type of the file |
Response arguments
| Parameter | Description |
|---|---|
file_url |
The URL of the file once it has been uploaded |
upload_url |
The URL to POST the file to when uploading |
Register attachment
Once you have obtained a URL for an attachment, either by uploading to the upload_url obtained from the upload endpoint above or by hosting a remote image, this URL can then be registered against a transaction. Once an attachment is registered against a transaction this will be displayed on the detail page of a transaction within the Monzo app.
$ http --form POST "https://api.monzo.com/attachment/register" \
"Authorization: Bearer $access_token" \
"external_id=tx_00008zIcpb1TB4yeIFXMzx" \
"file_type=image/png" \
"file_url=https://s3-eu-west-1.amazonaws.com/mondo-image-uploads/user_00009237hliZellUicKuG1/LcCu4ogv1xW28OCcvOTL-foo.png"
{
"attachment": {
"id": "attach_00009238aOAIvVqfb9LrZh",
"user_id": "user_00009238aMBIIrS5Rdncq9",
"external_id": "tx_00008zIcpb1TB4yeIFXMzx",
"file_url": "https://s3-eu-west-1.amazonaws.com/mondo-image-uploads/user_00009237hliZellUicKuG1/LcCu4ogv1xW28OCcvOTL-foo.png",
"file_type": "image/png",
"created": "2015-11-12T18:37:02Z"
}
}
Request arguments
| Parameter | Description |
|---|---|
external_idRequired |
The id of the transaction to associate the attachment with. |
file_urlRequired |
The URL of the uploaded attachment. |
file_typeRequired |
The content type of the attachment. |
Response arguments
| Parameter | Description |
|---|---|
id |
The ID of the attachment. This can be used to deregister at a later date. |
user_id |
The id of the user who owns this attachment. |
external_id |
The id of the transaction to which the attachment is attached. |
file_url |
The URL at which the attachment is available. |
file_type |
The file type of the attachment. |
created |
The timestamp in UTC when the attachment was created. |
Deregister attachment
To remove an attachment, simply deregister this using its id
$ http --form POST "https://api.monzo.com/attachment/deregister" \
"Authorization: Bearer $access_token" \
"id=attach_00009238aOAIvVqfb9LrZh"
{}
Request arguments
| Parameter | Description |
|---|---|
idRequired |
The id of the attachment to deregister. |
Errors
The Monzo API uses conventional HTTP response codes to indicate errors, and includes more detailed information on the exact nature of an error in the HTTP response.
HTTP response codes
| Response code | Meaning |
|---|---|
200OK |
All is well. |
400Bad Request |
Your request has missing arguments or is malformed. |
401Unauthorized |
Your request is not authenticated. |
403Forbidden |
Your request is authenticated but has insufficient permissions. |
405Method Not Allowed |
You are using an incorrect HTTP verb. Double check whether it should be POST/GET/DELETE/etc. |
404Page Not Found |
The endpoint requested does not exist. |
406Not Acceptable |
Your application does not accept the content format returned according to the Accept headers sent in the request. |
429Too Many Requests |
Your application is exceeding its rate limit. Back off, buddy. :p |
500Internal Server Error |
Something is wrong on our end. Whoopsie. |
504Gateway Timeout |
Something has timed out on our end. Whoopsie. |
Authentication errors
Errors pertaining to authentication are standard errors but also contain extra information to follow the OAuth specification. Specifically, they contain the error key with the following values:
error argument values
| Value | Meaning |
|---|---|
invalid_token |
The supplied access token is invalid or has expired. |
Edit on GitHub