Introduction
Monzo's Open Banking API allows licensed Third Party Providers to access customer's accounts, to provide account information services, or to initiate payments.
If you need support with Monzo's Open Banking API, please create a ticket on the Open Banking Service Desk, or contact [email protected].
Account Information Services API
The Account Information Services API lets authorised Account Information Service Providers access balances, transactions, and more for our customers in the United Kingdom.
Getting Access
To get access to our Open Banking APIs, see the Dynamic Client Registration section below.
Well-Known Endpoints
We've described the paths of our well-known endpoints for the Sandbox and Production environments below.
Endpoints
| Environment | Path |
|---|---|
| Sandbox | https://api.s101.nonprod-ffs.io/open-banking/.well-known/openid-configuration |
| Sandbox (EU) | https://api.s101.nonprod-ffs.io/open-banking/eu/.well-known/openid-configuration |
| Production | https://api.monzo.com/open-banking/.well-known/openid-configuration |
Base URLs
We've included the Base URLs for our Sandbox and Production environments below.
Base URLs
| Environment | Base URL |
|---|---|
| Sandbox | https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/aisp |
| Sandbox (EU) | https://openbanking-s101.eu.monzo.com/open-banking/v3.1/aisp |
| Production | https://openbanking.monzo.com/open-banking/v3.1/aisp |
Dynamic Client Registration
We have implemented the POST /register endpoint in version 3.2 of the Open Banking Dynamic Client Registration specification. You can find the full specification here.
You can find the appropriate URL and supported configuration in our well-known endpoints for each environment.
Authentication
As per the Open Banking specification, we use OAuth 2 and OpenID connect for authentication. We have implemented the redirect flow, with authentication taking place in the customer's Monzo app.
We only support the tls_client_auth authentication method.
Accounts
{
"Data": {
"Account": [
{
"AccountId": "acc_0000AAca1egQMHUQX14Mt7",
"Status": "Enabled",
"StatusUpdateDateTime": "2021-08-23T15:46:29.775Z",
"Currency": "GBP",
"AccountType": "Personal",
"AccountSubType": "CurrentAccount",
"Description": "Personal Account",
"Account": [
{
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345699155454",
"Name": "Camila McSimpburg"
},
{
"SchemeName": "UK.OBIE.IBAN",
"Identification": "GB25MONZ12345699155454",
"Name": "Camila McSimpburg"
}
],
"OpeningDate": "2021-08-23",
"SwitchStatus": "UK.CASS.NotSwitched"
}
]
},
"Links": {
"Self": "https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/aisp/accounts"
},
"Meta": {}
}
We've implemented version 3.1.10 of the Open Banking accounts specification.
Once you have a consent for a customer, you'll be able to see their:
- Personal (individual) accounts
- Joint accounts
- Business accounts
- Flex account
If the account has been closed, it will still be returned in the response, but with an updated Status.
Note that the fields we return as part of the response depend on whether your consent has the ReadAccountsBasic
or ReadAccountsDetail permission. In the former case, we will omit the account scheme data such as account number and sort code or IBAN.
Business Account - Company types
Business account has company type, which is shown in the Description field:
| Company type | Description field |
|---|---|
| Sole srader | Sole Trader |
| Private limited company | Private Limited Company |
Company type affects payment limits, see Payment Initiation Services API - Domestic Payments Limits for details.
Balances
We've implemented version 3.1.10 of the Open Banking balances specification.
When you query this endpoint, you'll see the customer's InterimAvailable balance. This is the same real-time balance
that our customers see in the Monzo app, and it includes pending and settled transactions.
We support an optional query param includePots. When set to true an additional Information balance type will be returned. This balance will be the aggregated account balance made up of the main account balance plus the balance of each pot owned by the account.
Flex
When querying a flex's balance, you'll be returned two balances:
The
InterimAvailablebalance: This is the current amount owed on the flex account. Its the amount the customer would need to pay today to pay off their flex.The
Informationbalance: This is the current flex balance plus all future interest. Its the balance displayed within the Monzo app.
Transactions
{
"Data": {
"Transaction": [
{
"AccountId": "acc_0000AAca1egQMHUQX14Mt7",
"TransactionId": "tx_0000AGpfr2kVwbONyQ4XFR",
"CreditDebitIndicator": "Credit",
"Status": "Booked",
"BookingDateTime": "2022-02-25T10:35:39.636Z",
"TransactionInformation": "Mr. Payroll Services",
"Amount": {
"Amount": "150.0000",
"Currency": "GBP"
},
"ProprietaryBankTransactionCode": {
"Code": "bacs",
"Issuer": "Monzo"
},
"DebtorAccount": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345612345678",
"Name": "Mr Payroll Service"
},
"SupplementaryData": {
"Declined": false,
"RawTransactionDescription": "MR PAYROLL SERVICE"
}
}
]
},
"Links": {
"Self": "https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/aisp/accounts/acc_0000AAca1egQMHUQX14Mt7/transactions?fromBookingDateTime=2022-02-03T00%3A00%3A00"
},
"Meta": {}
}
We've implemented version 3.1.10 of the Open Banking transactions specification.
For consistency with our internal systems and the rest of our API, you will need to provide the start and end times in RFC3339 format.
Your consent needs to have either the ReadTransactionsBasic or ReadTransactionsDetail permissions to access
this endpoint.
When you query this endpoint, you'll receive all of the transactions that the customer made in the date range specified in the request. Like in the Monzo app, we organise transactions in this response based on creation (presentment) time, not the time the transaction settles.
Transaction amounts can change after the transaction is first created, and you can use the Status field to help
identify transactions that are still pending.
You'll only be allowed to fetch transactions that were made in the range defined by TransactionFromDateTime and
TransactionToDateTime in your consent. If you try to access transactions outside this range, it won't work.
Rejected transaction status was added in version 3.1.8 of the Open Banking transactions specification.
This status will begin to be returned from the AIS API on the 25th of September 2022.
By default, we return transactions oldest to newest - we refer to this as ascending order. To return transactions in reverse, or descending, order an additional query parameter can be provided as part of the /transactions request.
Using order=desc will result in the transactions being returned newest to oldest. If you wish to keep transactions ordered oldest to newest then omit the order parameter or set order=asc. All Links will respect the omission or use of the order parameter.
The ProprietaryBankTransactionCode property has two sub-properties: Issuer and Code. Issuer will always be set to Monzo, and the possible values for Code are listed below.
3dsecureaccount_interestbacscard_deliverychapscollections_settlementemergency_cashfaster_paymentsinstalment_loanledger_adjustmentlocked_moneymastercardmonzo_business_account_billingmonzo_flexmonzo_paidoverdraftp2p_paymentpayport_faster_paymentsrbs_chequesepasignup_referralspread_the_costtopupuk_business_potuk_cash_deposits_paypointuk_retail_pot
Parties
We've implemented version 3.1.10. of the Open Banking parties specification
We have implemented the GET /party and GET /accounts/{accountId}/party endpoints for reading details of the consent authoriser and GET /accounts/{accountId}/parties for reading the details of all account holders/owners. These endpoints return the IDs, preferred names, and legal names of account holders/owners.
Your consent needs to have the ReadPartyPSU permission to access the GET /party endpoint and the ReadParty permission to access the GET /account/{accountId}/parties and GET /account/{accountId}/party endpoints.
Pots
Since Pots on Monzo have lots of additional properties that AISPs might find useful, we have implemented a Pots endpoint as an extension to the Open Banking specification.
List Pots
{
"Data": {
"Pot": [
{
"PotId": "pot_00009g4AB7nItyHI3R7CVt",
"AccountId": "acc_00009JrJEKwJrNqKfjwSS",
"Name": "Savings",
"Type": "default",
"CreditDebitIndicator": "Debit",
"Balance": {
"Amount": "5.0000",
"Currency": "GBP"
},
"Style": "cassette",
"Goal": {
"Amount": "1000.0000",
"Currency": "GBP"
},
"Created": "2019-02-21T17:13:39.315Z",
"Updated": "2019-02-21T17:13:39.315Z",
"Status": "Open"
},
{
"PotId": "pot_00009kIt1QKIXu98cu1RM9",
"AccountId": "acc_00009JrJEKwJrNqKfjwSS",
"Name": "Bobs And Bits",
"Type": "flexible_savings",
"CreditDebitIndicator": "Debit",
"Balance": {
"Amount": "1000.0000",
"Currency": "GBP"
},
"Style": "",
"ImageUrl": "...",
"Goal": {
"Amount": "9999.0000",
"Currency": "GBP"
},
"Created": "2019-06-28T11:10:29.478Z",
"Updated": "2019-06-28T11:11:09.173Z",
"Status": "Open"
},
{
"PotId": "pot_00009kIt8JXWB3R9bYUWkD",
"AccountId": "acc_00009JrJEKwJrNqKfjwSS",
"Name": "My Savings Pot",
"Type": "fixed_savings",
"CreditDebitIndicator": "Debit",
"Balance": {
"Amount": "1100.0000",
"Currency": "GBP"
},
"Style": "cassette",
"LockType": "until_date",
"LockedUntil": "2020-07-01T00:00:00Z",
"Created": "2019-06-28T11:11:44.195Z",
"Updated": "2019-06-28T11:11:44.195Z",
"Status": "Open"
}
]
}
}
Endpoints
| Sandbox | https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/aisp/pots |
| Production | https://openbanking.monzo.com/open-banking/v3.1/aisp/pots |
Note that the fields we return as part of the response depend on whether your consent has the ReadAccountsBasic
or ReadAccountsDetailed permission. In the former case, we will omit the Pot name and Image URL from the response.
We'll only return open pots as part of our response. If a customer closes a pot, it won't appear in the response any more.
Field Descriptions
| Field name | Optional | Description | Type |
|---|---|---|---|
| PotId | ❌ | Unique ID representing the pot | string |
| AccountId | ❌ | Unique ID of the account that owns the pot | string |
| Name | ✅ | Pot's name | string |
| Type | ❌ | Type of pot: default, flexible_savings, fixed_savings, instant_access |
string |
| CreditDebitIndicator | ❌ | Indicates whether the pot's balance is positive or negative | OBCreditDebitCode |
| Balance | ❌ | The pot's currency & current balance | OBActiveOrHistoricCurrencyAndAmount |
| Style | ❌ | Internal ID for the cover image of the pot, if a custom image isn't set | string |
| ImageUrl | ✅ | URL to the pot's cover image | string |
| Goal | ✅ | Customer's savings target for their pot | OBActiveOrHistoricCurrencyAndAmount |
| LockType | ✅ | Pot's lock type, if locked will return until_date |
string |
| LockedUntil | ✅ | When the pot will unlock | string |
| Created | ❌ | When the pot was created | string |
| Updated | ❌ | When the pot was last updated | string |
| Closed | ✅ | When the pot was closed | string |
| Status | ❌ | Pot's current status: Open or Closed |
string |
Direct Debits
We've implemented version 3.1.10 of the Open Banking Direct Debits specification.
We have only implemented GET /accounts/{AccountId}/direct-debits endpoint.
Your consent needs to have the ReadDirectDebits permission to access this endpoint.
Scheduled Payments
We've implemented version 3.1.10 of the Open Banking Scheduled Payments specification.
We have only implemented GET /accounts/{AccountId}/scheduled-payments endpoint.
Your consent needs to have either the ReadScheduledPaymentsBasic or ReadScheduledPaymentsDetail permissions to access this endpoint.
Standing Orders
We've implemented version 3.1.10 of the Open Banking Standing Orders specification.
We have only implemented GET /accounts/{AccountId}/standing-orders endpoint.
Your consent needs to have either the ReadStandingOrdersBasic or ReadStandingOrdersDetail permissions to access this endpoint.
Testing in the Sandbox
Our Sandbox environment is a handy playground where you can test your integration before putting it live. We run exactly the same code in our sandbox environment as we do production to make switching between them as easy as possible.
In the sandbox environment, you can automatically have account information consents approved or declined to
help with testing. To do this, you should set some specific fields in the Data/SupplementaryData object:
{
"DesiredStatus": "Authorised",
"UserID": "user_000xxx"
}
Sandbox Users
Heavy User
UserID: user_0000A4C4ZChWNMEvew2U77
AccountID: acc_0000A4C4ZSskDOixqNPfpR
Medium User
UserID: user_0000A4C4nqORb7K9YYW3r0
AccountID: acc_0000A4C4o66FCYJoERQhHN
Light User
UserID: user_0000A4C4wkPFE7x9at8Ujp
AccountID: acc_0000A4C4wz4Ail0f3sONTV
EU (Ireland) User
UserID: user_0000Av3bpksv3AAmdybBCr
AccountID: acc_0000Av3bry7sn2XsI3eZ3C
Additional Help
The Open Banking team at Monzo manage the Account Information Services API. If you require additional assistance, email us at [email protected].
Payment Initiation Services API
The Payment Initiation Services API lets authorised Payment Initiation Service Providers make outbound payments from the accounts of our customers in the United Kingdom. All payments initiated through our Payment Initiation Services API are sent through Faster Payments.
Getting Access
To get access to our Open Banking APIs, see the Dynamic Client Registration section below.
Well-Known Endpoints
We've described the paths of our well-known endpoints for the Sandbox and Production environments below.
| Environment | Path |
|---|---|
| Sandbox | https://api.s101.nonprod-ffs.io/open-banking/.well-known/openid-configuration |
| Production | https://api.monzo.com/open-banking/.well-known/openid-configuration |
Base URLs
We've included the Base URLs for our Sandbox and Production environments below.
Base URLs
| Environment | Base URL |
|---|---|
| Sandbox | https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/pisp |
| Production | https://openbanking.monzo.com/open-banking/v3.1/pisp |
Dynamic Client Registration
We have implemented the POST /register endpoint in version 3.2 of the Open Banking Dynamic Client Registration specification. You can find the full specification here.
You can find the appropriate URL and supported configuration in our well-known endpoints for each environment.
Authentication
As per the Open Banking specification, we use OAuth 2 and OpenID connect for authentication. We have implemented the redirect flow, with authentication taking place in the customer's Monzo app.
We only support the tls_client_auth authentication method.
Once created, you'll need to turn any consent into a payment order within 24 hours. Once the consent is approved, you'll have one hour.
Domestic Payments
We've implemented version 3.1.10 of the Open Banking Domestic Payments specification.
When you request a consent for Domestic Payments, you should provide UK.OBIE.FPS as the LocalInstrument.
We support account identification using UK.OBIE.SortCodeAccountNumber. We don't support identification using
UK.OBIE.IBAN.
You can only make payments in GBP. We don't support other currencies.
Domestic Payments Limits
There are default limits for daily outbound payments:
| Account type | Default limit |
|---|---|
| Personal | £10000 |
| Joint | £10000 |
| Business (sole trader) | £25000 |
| Business (private limited company) | £50000 |
Scheduled Payments
We've implemented version 3.1.10 of the Open Banking Scheduled Payments specification.
For consistency with our internal systems and the rest of our API, you will need to provide times in RFC3339 format.
When you request a consent for Domestic Payments, you should provide UK.OBIE.FPS as the LocalInstrument.
We support account identification using UK.OBIE.SortCodeAccountNumber. We don't support identification using
UK.OBIE.IBAN.
At the moment, we don't support the payment-details endpoint.
You can only make payments in GBP. We don't support other currencies.
Standing Orders
We have implemented version 3.1.10 of the Open Banking Standing Order specification.
For consistency with our internal systems and the rest of our API, you will need to provide times in RFC3339 format.
We support a subset of the standing order frequencies laid out in the specification. These are the same as the frequencies we support in the Monzo app.
| Supported Frequency | Description |
|---|---|
EvryDay |
Every day (including weekends) |
IntrvlWkDay |
We allow the week interval to be 1 (every week), 2 (every 2 weeks) or 4 (every 4 weeks). We ignore the day specified, and instead repeat based on the day of the week of the FirstPaymentDate. |
IntrvlMnthDay |
We allow the month interval to be 1 (every month), 3 (every quarter) or 12 (every year). We ignore the day of month and repeat based on the day of month of the FirstPaymentDate. |
We support account identification using UK.OBIE.SortCodeAccountNumber. We don't support identification using
UK.OBIE.IBAN.
Since we use the FirstPaymentDate to decide when payments will repeat, we don't use the RecurringPaymentDateTime or
RecurringPaymentAmount fields. We'll return an error if you include them.
You can make standing orders with an end date by specifying either a NumberOfPayments or a FinalPaymentDateTime, but
we don't let you include both.
At the moment, we don't support the payment-details endpoint.
You can only make payments in GBP. We don't support other currencies.
International Payments
We've implemented version 3.1.11 of the Open Banking International Payments specification.
International Payment Consent
{
"Data":
{
"Initiation":
{
"CurrencyOfTransfer": "EUR",
"DestinationCountryCode": "GB",
"EndToEndIdentification": "FRESCO.21302.GFX.20",
"InstructionIdentification": "ACME413",
"LocalInstrument": "UK.OBIE.SEPACreditTransfer",
"CreditorAccount":
{
"SchemeName": "UK.OBIE.IBAN",
"Identification": "GB62MONZ12345708578920",
"Name": "Name Surname"
},
"ExchangeRateInformation":
{
"RateType": "Indicative",
"UnitCurrency": "GBP"
},
"InstructedAmount":
{
"Amount": "100.00",
"Currency": "GBP"
},
"RemittanceInformation":
{
"Reference": "FRESCO-101",
"Unstructured": "Internal ops code 5120101"
}
},
"ReadRefundAccount": "Yes"
},
"Risk":
{
"PaymentContextCode": "TransferToThirdParty",
"BeneficiaryAccountType": "Personal"
}
}
Note that we only support indicative exchange rates (ExchangeRateInformation.RateType must be set to Indicative).
International Payment currencies and rails support
The table below outlines the currencies and supported payment rails, along with the required parameters for the Initiation object (- indicates that the parameter is not required).
| CurrencyOfTransfer | LocalInstrumentCode | CreditorAccount.SchemeName | CreditorAccount.Identification | CreditorAccount.SecondaryIdentification | CreditorAgent.SchemeName | CreditorAgent.Identification | Creditor.PostalAddress | Notes |
|---|---|---|---|---|---|---|---|---|
| AUD | - | UK.OBIE.BBAN |
Account Number | - | UK.OBIE.NCC.AU |
BSB Code | - | |
| AUD | - | UK.MONZO.BPAY |
Biller Pay Code | Customer Reference Number | - | - | - | Risk.BeneficiaryAccountType must be Business or BusinessSavingsAccount |
| INR | - | UK.OBIE.BBAN |
Account Number | - | UK.OBIE.NCC.IN |
IFSC Code | - | |
| INR | - | UK.MONZO.UPI |
UPI ID (customername@bank) |
- | - | - | - | |
| EUR | UK.OBIE.SEPACreditTransfer |
UK.OBIE.IBAN |
IBAN | - | - | - | - | |
| EUR | UK.OBIE.SWIFT |
UK.OBIE.IBAN |
IBAN | - | UK.OBIE.BICFI |
BIC | - | |
| RON | - | UK.OBIE.IBAN |
IBAN | - | UK.OBIE.BICFI |
BIC | Required | |
| USD | UK.MONZO.ABA |
UK.OBIE.BBAN |
Account Number | - | UK.OBIE.NCC.US |
ABA Routing Number | Required | |
| USD | UK.MONZO.FEDWIRE |
UK.OBIE.BBAN |
Account Number | - | UK.OBIE.NCC.US |
Fedwire Routing Number | Required | |
| USD | UK.OBIE.SWIFT |
UK.OBIE.BBAN |
Account Number | - | UK.OBIE.BICFI |
BIC | Required |
CreditorAccount.Name is required for all currencies.
Initiation.DestinationCountryCode is required for all currencies.
If Creditor.PostalAddress is required, the following fields must be provided:
TownNamePostCode- Either
AddressLineorBuildingNumber+StreetName
Risk.BeneficiaryAccountType is required and supports the following values:
* Personal
* JointPersonal
* PersonalSavingsAccount
* Business
* BusinessSavingsAccount
For USD payments, the account type (Checking or Savings) is determined based on Risk.BeneficiaryAccountType.
International Payment Order
The consent's CutOffDateTime is set to 30 minutes after creation. A payment must be initiated within this timeframe (otherwise the payment order will be automatically rejected).
{
"Data":
{
"ConsentId": "obpispinternationalpaymentconsent_0000Ar128pFItDBIlaJ9fd",
"Initiation":
{
"CurrencyOfTransfer": "EUR",
"DestinationCountryCode": "GB",
"EndToEndIdentification": "FRESCO.21302.GFX.20",
"InstructionIdentification": "ACME413",
"LocalInstrument": "UK.OBIE.SEPACreditTransfer",
"CreditorAccount":
{
"SchemeName": "UK.OBIE.IBAN",
"Identification": "GB62MONZ12345708578920",
"Name": "Name Surname"
},
"ExchangeRateInformation":
{
"RateType": "Indicative",
"UnitCurrency": "GBP"
},
"InstructedAmount":
{
"Amount": "100.00",
"Currency": "GBP"
},
"RemittanceInformation":
{
"Reference": "FRESCO-101",
"Unstructured": "Internal ops code 5120101"
}
}
},
"Risk":
{
"PaymentContextCode": "TransferToThirdParty",
"BeneficiaryAccountType": "Personal"
}
}
Refund Accounts
{
"Data": {
"Initiation": {
"CreditorAccount": {
"Identification": "12345612345678",
"SchemeName": "UK.OBIE.SortCodeAccountNumber"
},
"ReadRefundAccount": "Yes"
}
}
}
We have enabled reading refund account details as part of domestic and international payment consent resource creation, if requested by the PISP. To read the refund account details set the ReadRefundAccount field to Yes in the consent creation request.
The refund account data will be returned in the payment order creation response. The name on the refund account should pass any confirmation of payee checks.
{
"Data": {
"Initiation": {
"CreditorAccount": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345612345678"
}
},
"ConsentId": "obpispdomesticpaymentconsent_0000AJ93jc7CkiSo8cYCzx",
"DomesticPaymentId": "obdompayment_0000AJ93nDHX1aE8HE66YT",
"CreationDateTime": "2022-05-05T14:47:36.545Z",
"Status": "Pending",
"StatusUpdateDateTime": "2022-05-05T14:47:36.545Z",
"ExpectedExecutionDateTime": "2022-05-05T14:47:36.545Z",
"ExpectedSettlementDateTime": "2022-05-05T14:47:36.545Z",
"Refund": {
"Account": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345612345678",
"Name": "First Last"
}
},
"Debtor": {
"Name": "First Last",
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345612345678"
}
},
"Links": {
"Self": "https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/pisp/obpispdomesticpaymentconsent_0000AJ93jc7CkiSo8cYCzx"
},
"Meta": {}
}
Rejected Payments
When a payment is rejected, we aim to provide TPPs with as much detail as possible. If available, the specific reason for the rejection will be included in the response. TPPs can find the rejection reason within the RejectionReason field in the following locations, depending on the type of payment:
- Single Immediate Payments (SIPs)
Data/Initiation/SupplementaryDataOBDomestic2
- Variable Recurring Payments (VRPs)
Data/Instruction/SupplementaryDataOBDomesticVRPInstruction
| Rejection Reason | Description |
|---|---|
Insufficient funds |
The account does not have enough funds to make the transfer. |
Something went wrong |
We've retired making the payment, but have failed too many times |
FPS not acknowledged |
The beneficiary bank hasn't accepted our FPS message |
Additional security checks were not completed |
The customer either abandoned or cancelled the additional security check flow |
Payment reference contains offensive language |
We don't allow references to contain offensive language |
Payment limits exceeded |
The payment would exceed the customer's limits |
Scheme limits exceeded |
The payment would exceed the scheme's limit |
Other Rejection Scenarios
In some cases, we may not be able to provide specific details about why a payment was rejected. If none of the listed rejection reasons apply, you may encounter the following messages:
Please ask the customer to contact customer support:
For further details on the rejection, the customer will need to get in touch with Monzo's customer support team which they can do via the in-app chat.
Sorry, we're unable to provide additional information on why this payment was rejected:
In certain circumstances, we're unable to share any further information regarding why the payment was rejected.
Testing in the Sandbox
In the sandbox environment, you can automatically have domestic payment requests approved or declined to help with testing. When creating the payment consent, you can add a DesiredStatus field to the Data/Initiation/SupplementaryData object in the consent request. You can set this field to Authorised or Rejected, depending on the behaviour you want.
If you want your payment to come from a specific User and Account then you can also add those values, but you must add both or a random test User and Account is used instead.
We require that the SupplementaryData content is provided in the same order between the consent creation request and the payment request.
{
"DesiredStatus": "Authorised"
}
{
"DesiredStatus": "Rejected",
"UserID": "user_000xxx",
"AccountID": "account_000yyy"
}
Sandbox Users
Heavy User
UserID: user_0000A4C4ZChWNMEvew2U77
AccountID: acc_0000A4C4ZSskDOixqNPfpR
Medium User
UserID: user_0000A4C4nqORb7K9YYW3r0
AccountID: acc_0000A4C4o66FCYJoERQhHN
Light User
UserID: user_0000A4C4wkPFE7x9at8Ujp
AccountID: acc_0000A4C4wz4Ail0f3sONTV
Additional Help
The Open Banking team at Monzo manage the Payment Initiation Services API. If you require additional assistance, email us at [email protected].
Variable Recurring Payments API
The Variable Recurring Payments (VRP) API lets authorised Payment Initiation Service Providers make outbound payments from the accounts of our customers in the United Kingdom. Variable Recurring Payments enable multiple payments to be made under a single long-lived consent without the need for authenticating and approving each payment. Further information on Variable Recurring Payments can be found here.
All payments initiated through our Variable Recurring Payments API are sent through Faster Payments.
We've implemented v3.1.10 of the Open Banking Domestic Variable Recurring Payments specification . All endpoints and models are as outlined in the specifications.
Base URLs
We've included the Base URLs for our Sandbox and Production environments below.
| Environment | Base URL |
|---|---|
| Sandbox | https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/pisp |
| Production | https://openbanking.monzo.com/open-banking/v3.1/pisp |
Domestic Variable Recurring Payments
We've implemented version 3.1.10 of the Open Banking Domestic Variable Recurring Payments specification . All endpoints and models are as outlined in the specifications.
We support account identification using UK.OBIE.SortCodeAccountNumber. We don't support identification using
UK.OBIE.IBAN.
You can only make payments in GBP. We don't support other currencies.
Omitted Endpoints
We have omitted the implementation of GET /domestic-vrps/{DomesticVRPId}/payment-details.
Variable Recurring Payment Consent Creation
We only support creating consents with a PeriodicAlignment of Consent. Additionally, we currently only
allow PeriodType of Day, Week, Month and Year.
Authentication
As per the Open Banking specification, we use OAuth 2 and OpenID connect for authentication. We have implemented the redirect flow, with authentication taking place in the customer's Monzo app.
We only support the tls_client_auth authentication method.
OAuth2 Tokens
We have extended our refresh token expiry for tokens associated with Variable Recurring Payment Consents to account for their long-lived nature. Refresh tokens will have an expiry of 3 years (26,280 hours). Access tokens will continue to expire after 30 hours.
Testing in the Sandbox
In the sandbox environment, you can automatically have Variable Recurring Payment Consent requests approved or
declined to help with testing. When creating the consent, you can add a DesiredStatus field to
the Data/ControlParameters/SupplementaryData object in the consent request. You can set this field to Authorised
or Rejected, depending on the behaviour you want.
{
"DesiredStatus": "Authorised"
}
Sandbox Users
Heavy User
UserID: user_0000A4C4ZChWNMEvew2U77
AccountID: acc_0000A4C4ZSskDOixqNPfpR
Medium User
UserID: user_0000A4C4nqORb7K9YYW3r0
AccountID: acc_0000A4C4o66FCYJoERQhHN
Light User
UserID: user_0000A4C4wkPFE7x9at8Ujp
AccountID: acc_0000A4C4wz4Ail0f3sONTV
Additional Help
The Open Banking team at Monzo manage the Variable Recurring Payment API. If you require additional assistance, email us at [email protected].
Confirmation of Funds API
The Confirmation of Funds API lets authorised Card Based Payment Instrument Issuers check that Monzo customers have enough money for a purchase.
Getting Access
To get access to our Open Banking APIs, see the Dynamic Client Registration section below.
Well-Known Endpoints
We've described the paths of our well-known endpoints for the Sandbox and Production environments below.
| Environment | Path |
|---|---|
| Sandbox | https://api.s101.nonprod-ffs.io/open-banking/.well-known/openid-configuration |
| Production | https://api.monzo.com/open-banking/.well-known/openid-configuration |
Base URLs
We've included the Base URLs for our Sandbox and Production environments below.
Base URLs
| Environment | Base URL |
|---|---|
| Sandbox | https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/cbpii |
| Production | https://openbanking.monzo.com/open-banking/v3.1/cbpii |
Dynamic Client Registration
We have implemented the POST /register endpoint in version 3.2 of the Open Banking Dynamic Client Registration specification. You can find the full specification here.
You can find the appropriate URL and supported configuration in our well-known endpoints for each environment.
Authentication
As per the Open Banking specification, we use OAuth 2 and OpenID connect for authentication. We have implemented the redirect flow, with authentication taking place in the customer's Monzo app.
We only support the tls_client_auth authentication method.
Confirmation of Funds
We have implemented version 3.1.10 of the Open Banking Confirmation of Funds Specification.
We use the redirection flow for approving consents.
You can identify a DebtorAccount using the UK.OBIE.SortCodeAccountNumber scheme. We'll return an error for any
other SchemeName.
Additional Help
The Open Banking team at Monzo manage the Confirmation of Funds API. If you require additional assistance, email us at [email protected].
Open Banking Errors
Our Open Banking APIs return errors in line with the Open Banking specification.
OBErrorResponse1
| Name | Type | Description | Monzo Use |
|---|---|---|---|
| Code | Max40Text | High level textual error code, to help categorise the errors. | Custom error code with a format of <prefix.type> |
| Id | Max40Text | A unique reference for the error instance, for audit purposes, in case of unknown/unclassified errors. | Internal trace identifier |
| Message | Max500Text | Brief Error message, e.g., 'There is something wrong with the request parameters provided' | High level human readable category message |
| Errors | []OBError1 |
Array with one OBError1 element |
OBError1
| Name | Type | Description | Monzo Use |
|---|---|---|---|
| ErrorCode | OBErrorResponseError1Code |
Low level textual error code, e.g., UK.OBIE.Field.Missing | OBIE error code (UK.OBIE.XYZ) or custom error code (UK.MONZO.XYZ) |
| Message | Max500Text | A description of the error that occurred. e.g., 'A mandatory field isn't supplied' or 'RequestedExecutionDateTime must be in future'. OBIE doesn't standardise this field | Human readable message that details the cause of the error |
A full list of OBErrorResponseError1Code can be found here.
Custom Codes
Due to limitations with OBErrorResponseError1Code we've added two additional codes:
| Error Code | Description |
|---|---|
UK.MONZO.Generic |
A generic code used when no specific code is suitable |
UK.MONZO.Forbidden |
Used when a request is authenticated but has insufficient permissions |
Status Codes
The error prefix of OBErrorResponse1.Code will always be paired with a status code as follows:
| Prefix Code | Status Code |
|---|---|
bad_request |
400 |
bad_response |
406 |
forbidden |
403 |
internal_service |
500 |
not_found |
404 |
precondition_failed |
412 |
timeout |
504 |
unauthorized |
401 |
rate_limited |
429 |
Rate Limiting
Monzo's Open Banking API enforces rate limits to maintain platform stability. We apply rate limits both at a platform-wide and TPP level.
TPP Rate Limiting
This limit is shared across all endpoints of our Open Banking APIs and is applied collectively across all client IDs under the same organization ID.
Platform-Wide Rate Limiting
The platform-wide rate limit exists to prevent excessive load on our datastore. This type of rate limiting is not specific to an individual TPP but applies when the datastore is experiencing significantly high load and throttles traffic to reduce it.
If your request is affected by platform-wide rate limiting, it is likely due to temporary high demand on our infrastructure. In this case, retrying the request after a short backoff period should work.
Mapping Errors
Our previous error structure included a code and message. These are now mapped to the new OBErrorResponse1 as follows:
| Previous Feild | New Feild |
|---|---|
code |
OBErrorResponse1.Code |
message |
OBErrorResponse1.OBError1[0].Message |
Previous Error Structure
{
"Code": "bad_request.consent_status",
"Message": "Consent is not authorised"
}
New Error Structure
{
"Code": "bad_request.consent_status",
"Id": "d3628722-749f-4fe9-76f9-f59844ad3714",
"Message": "Invalid consent status",
"Errors": [
{
"ErrorCode": "UK.OBIE.Resource.InvalidConsentStatus",
"Message": "Consent is not authorised"
}
]
}
Using Previous Errors
To revert to the previous error behavior, you can include an additional header X-Open-Banking-Legacy-Errors on each request. If this option does not meet your needs, please contact us at [email protected].
Once we are confident that TPPs have successfully migrated to the new error behavior, we will remove the opt-out functionality.
SCA-RTS (PS21/19)
Overview
In November 2021, the FCA set out new rules for standards on Strong Customer Authentication (SCA) in a change to the Regulatory Technical Standards on Strong Customer Authentication and Secure Communication (SCA-RTS).
We (Monzo) will release these changes as of 2022-08-01. This will not be a breaking change.
Consents created before this date will expire after 90-days, as before. Consents created after this date will be long-lived. Please note, this change is only applicable to AIS consents.
TPPs will still be able to provide an ExpirationDateTime on the consent request at which time the consent will expire. If this is not populated, the permissions will be long-lived.
Contact
If you have any queries about these changes then please contact [email protected].
EU PSD2 API
API Specification
Like our UK Open Banking API, our EU PSD2 Dedicated Interface is also built to the Open Banking spec. This means the structure of requests and responses is for the most part the same, with any differences reflecting product differences between UK and EU regions.
Supported Endpoints
Monzo's EU PSD2 API currently only supports Account Information Services (AIS) and Confirmation of Funds API (CBPII). Payment Initiation Services (PIS) will be available at a later date.
Well-Known Endpoints
The Well-Known Endpoints differ from the UK API, and can be seen below:
Endpoints
| Environment | Path |
|---|---|
| Sandbox | https://api.s101.nonprod-ffs.io/open-banking/eu/.well-known/openid-configuration |
Base URLs
The Base URLs also differ, with sandbox now on openbanking-s101.eu.monzo.com
Base URLs
| Service | Environment | Base URL |
|---|---|---|
| AIS | Sandbox | https://openbanking-s101.eu.monzo.com/open-banking/v3.1/aisp |
| CBPII | Sandbox | https://openbanking-s101.eu.monzo.com/open-banking/v3.1/cbpii |
Dynamic Client Registration
We have implemented the POST /register endpoint in version 3.2 of the Open Banking Dynamic Client Registration specification. You can find the full specification here.
You can find the appropriate URL and supported configuration in our well known endpoint above.
Differing from DCR requests in the UK, TPPs not registered with the Open Banking directory must use a self-signed (or not signed) SSA. This is where the alg claim is set to none
Example DCR Request
Header
{
"alg": "PS256",
"kid": "8ilr3X9lD-oE19ggCRv_ITpSQQc",
"typ": "JWT"
}
Body
{
"application_type": "web",
"aud": "PSDIE-CBI-000000",
"exp": 1742552600,
"grant_types": [
"client_credentials",
"authorization_code",
"refresh_token"
],
"iat": 1742549000,
"id_token_signed_response_alg": "PS256",
"iss": "278BE778-DCAE-4F7C-9713-89C338F7331C",
"jti": "279B865B-554E-48E7-89A4-D2705BC607AF",
"redirect_uris": [
"https://verify-s101.eu.monzo.com/open-banking/callback"
],
"request_object_signing_alg": "PS256",
"response_types": [
"code id_token"
],
"scope": "openid accounts",
"software_id": "278BE778-DCAE-4F7C-9713-89C338F7331C",
"software_statement": "eyJhbGciOiJub25lIiwia2lkIjoiIiwidHlwIjoiSldUIn0.eyJpc3MiOiJNb256byBCYW5rIEx0ZCIsImlhdCI6MTc0MjU0OTAwMCwianRpIjoiIiwic29mdHdhcmVfZW52aXJvbm1lbnQiOiJzYW5kYm94Iiwic29mdHdhcmVfbW9kZSI6IlRlc3QiLCJzb2Z0d2FyZV9pZCI6IjI3OEJFNzc4LURDQUUtNEY3Qy05NzEzLTg5QzMzOEY3MzMxQyIsInNvZnR3YXJlX2NsaWVudF9pZCI6IjI3OEJFNzc4LURDQUUtNEY3Qy05NzEzLTg5QzMzOEY3MzMxQyIsInNvZnR3YXJlX2NsaWVudF9uYW1lIjoiTW9uem8iLCJzb2Z0d2FyZV9jbGllbnRfZGVzY3JpcHRpb24iOiJNYW5hZ2UgeW91ciBtb25leSBpbiBvbmUgcGxhY2UiLCJzb2Z0d2FyZV92ZXJzaW9uIjoiMS4wIiwic29mdHdhcmVfY2xpZW50X3VyaSI6Imh0dHBzOi8vZGV2ZWxvcGVycy5tb256by5jb20iLCJzb2Z0d2FyZV9yZWRpcmVjdF91cmlzIjpbImh0dHBzOi8vdmVyaWZ5LXMxMDEuZXUubW9uem8uY29tL29wZW4tYmFua2luZy9jYWxsYmFjayJdLCJzb2Z0d2FyZV9yb2xlcyI6WyJBSVNQIl0sIm9yZ2FuaXNhdGlvbl9jb21wZXRlbnRfYXV0aG9yaXR5X2NsYWltcyI6eyJhdXRob3JpdHlfaWQiOiJGQ0FHQlIiLCJyZWdpc3RyYXRpb25faWQiOiI3MzA0MjciLCJzdGF0dXMiOiJBY3RpdmUiLCJhdXRob3Jpc2F0aW9ucyI6W3sibWVtYmVyX3N0YXRlIjoiR0IiLCJyb2xlcyI6WyJQSVNQIiwiQUlTUCIsIkFTUFNQIl19LHsibWVtYmVyX3N0YXRlIjoiSUUiLCJyb2xlcyI6WyJQSVNQIiwiQUlTUCIsIkFTUFNQIl19LHsibWVtYmVyX3N0YXRlIjoiTkwiLCJyb2xlcyI6WyJBU1BTUCIsIlBJU1AiLCJBSVNQIl19XX0sInNvZnR3YXJlX2xvZ29fdXJpIjoiaHR0cHM6Ly9wdWJsaWMtaW1hZ2VzLm1vbnpvLmNvbS9sb2dvL2F2YXRhcl9ibHVlLnBuZyIsIm9yZ19zdGF0dXMiOiJBY3RpdmUiLCJvcmdfaWQiOiJQU0RJRS1DQkktMDAwMDAwIiwib3JnX25hbWUiOiJNb256byBCYW5rIExpbWl0ZWQiLCJvcmdfY29udGFjdHMiOlt7Im5hbWUiOiJUZWNobmljYWwiLCJlbWFpbCI6Im9wZW5iYW5raW5nQG1vbnpvLmNvbSIsInBob25lIjoiMDc1NTMxMjM4MDciLCJ0eXBlIjoiVGVjaG5pY2FsIn0seyJuYW1lIjoiQnVzaW5lc3MiLCJlbWFpbCI6Im9wZW5iYW5raW5nQG1vbnpvLmNvbSIsInBob25lIjoiMDc1NTMxMjM4MDciLCJ0eXBlIjoiQnVzaW5lc3MifV0sIm9yZ19qd2tzX2VuZHBvaW50IjoiaHR0cHM6Ly9hcGkuczEwMS5ub25wcm9kLWZmcy5pby9vcGVuLWJhbmtpbmcvZXUvandrcy5qc29uIiwib3JnX2p3a3NfcmV2b2tlZF9lbmRwb2ludCI6IiIsInNvZnR3YXJlX2p3a3NfZW5kcG9pbnQiOiIiLCJzb2Z0d2FyZV9qd2tzX3Jldm9rZWRfZW5kcG9pbnQiOiIiLCJzb2Z0d2FyZV9wb2xpY3lfdXJpIjoiaHR0cHM6Ly9tb256by5jb20vbGVnYWwvdGVybXMtYW5kLWNvbmRpdGlvbnMiLCJzb2Z0d2FyZV90b3NfdXJpIjoiaHR0cHM6Ly9tb256by5jb20vbGVnYWwvdGVybXMtYW5kLWNvbmRpdGlvbnMiLCJzb2Z0d2FyZV9vbl9iZWhhbGZfb2Zfb3JnIjoiIn0.",
"tls_client_auth_subject_dn": "C=GB,O=Monzo Bank Limited,organizationIdentifier=PSDIE-CBI-000000,CN=monzo.com",
"token_endpoint_auth_method": "tls_client_auth"
}
Notes on specific fields:
Header
| Field | Notes |
|---|---|
alg |
Must be "PS256" |
typ |
Must be "jwt" |
Body
| Field | Notes |
|---|---|
software_id |
Must be a valid v4 UUID |
scope |
As only the AIS API is currently supported, must be "openid accounts" |
Header
{
"alg": "none",
"typ": "JWT"
}
Example SSA
Body
{
"iss": "Monzo Bank Ltd",
"iat": 1742549000,
"software_environment": "sandbox",
"software_mode": "Test",
"software_id": "278BE778-DCAE-4F7C-9713-89C338F7331C",
"software_client_id": "278BE778-DCAE-4F7C-9713-89C338F7331C",
"software_client_name": "Monzo",
"software_client_description": "Manage your money in one place",
"software_version": "1.0",
"software_client_uri": "https://developers.monzo.com",
"software_redirect_uris": [
"https://verify-s101.eu.monzo.com/open-banking/callback"
],
"software_roles": [
"AISP"
],
"organisation_competent_authority_claims": {
"authority_id": "FCAGBR",
"registration_id": "730427",
"status": "Active",
"authorisations": [
{
"member_state": "IE",
"roles": [
"PISP",
"AISP",
"ASPSP"
]
}
]
},
"software_logo_uri": "https://public-images.monzo.com/logo/avatar_blue.png",
"org_status": "Active",
"org_id": "PSDIE-CBI-000000",
"org_name": "Monzo Bank Limited",
"org_contacts": [
{
"name": "Technical",
"email": "[email protected]",
"phone": "07553123807",
"type": "Technical"
},
{
"name": "Business",
"email": "[email protected]",
"phone": "07553123807",
"type": "Business"
}
],
"org_jwks_endpoint": "https://api.s101.nonprod-ffs.io/open-banking/eu/jwks.json",
"software_policy_uri": "https://monzo.com/legal/terms-and-conditions",
"software_tos_uri": "https://monzo.com/legal/terms-and-conditions",
}
Notes on specific fields:
Header
| Field | Notes |
|---|---|
alg |
Must be set to "none" for a self signed software statement, otherwise "PS256" |
typ |
Must be "jwt" |
Body
| Field | Notes |
|---|---|
software_id |
Must be a valid v4 UUID |
org_id |
PSD2 Authorization Number, e.g. "PSDIE-CBI-123456" |
As per the example in the DCR request above, this should be included in base64 format, ending in . to signify a self signed SSA.
Authentication
As per the Open Banking specification, we use OAuth 2 and OpenID connect for authentication. We have implemented the redirect flow, with authentication taking place in the customer's Monzo app.
We only support the tls_client_auth authentication method.
As per the Well-Known endpoint above, note the authorization_endpoint for the sandbox is https://verify-s101.eu.monzo.com/open-banking/authorize
Certificates
We expect the use of eIDAS QWAC and QSealC certificates issued by a QTSP. We currently have a manually maintained allow-list of trusted QTSPs. If we don't currently trust the QTSP that issues your certificate, then please get in touch at [email protected].
EU Account Information Services API
It works in the same way as described in the Account Information Services API, with some differences outlined below.
EU Accounts
See the Accounts section.
- In the EU, a customer's pots are returned as accounts.
Example of a Current Account and Pot returned:
{
"Data": {
"Account": [
{
"AccountId": "acc_0000AvDK9NmomdubVdW9jd",
"Status": "Enabled",
"StatusUpdateDateTime": "2025-06-17T07:09:35.3Z",
"Currency": "EUR",
"AccountType": "Personal",
"AccountSubType": "CurrentAccount",
"Description": "Personal Account",
"Account":
[
{
"SchemeName": "UK.OBIE.IBAN",
"Identification": "IE05MONZ00000003102060",
"Name": "Camila McSimpburg"
}
],
"OpeningDate": "2025-06-17",
"SwitchStatus": "UK.CASS.NotSwitched"
},
{
"AccountId": "acc_0000Avmn7n4tTdiAoOXbe5",
"Status": "Enabled",
"StatusUpdateDateTime": "2025-07-04T09:49:08.53Z",
"Currency": "EUR",
"AccountType": "Personal",
"AccountSubType": "Savings",
"Description": "Personal Pot",
"Account":
[
{
"SchemeName": "",
"Identification": "",
"Name": "Holiday"
}
],
"OpeningDate": "2025-07-04",
},
]
},
"Links": {
"Self": "https://openbanking.s101.nonprod-ffs.io/open-banking/v3.1/aisp/accounts"
},
"Meta": {}
}
EU Balances
See Balances section.
includePotsparameter is not supported, as pots are presented as separate accounts in the EU.
EU Pots
EU Confirmation of Funds API
It works in the same way as described in the Confirmation of Funds API, with some differences outlined below.
EU Confirmation of Funds
See Confirmation of Funds section.
- You can identify a
DebtorAccountusing theUK.OBIE.IBANscheme. We will return an error for any otherSchemeName. - In the EU, a customer's pots are considered accounts, so you can identify them in the
DebtorAccountsection.
Edit on GitHub