Integrations
Mono banking connector eligibility
Eligibility, classification, and reconciliation guidance for the Mono banking connector.
We only convert Mono banking events into invoices when they look like real business activity. Personal transfers (family, gifts, loans, pocket money) are ignored and logged for review.
Connector flow (auth + reauth)
- Create a widget link:
POST /si/mono/widget-linkwithcustomer,redirectUrl, and optionalmeta.refandinstitution. - Complete Mono Connect in the widget and capture the
code. - Exchange code:
POST /si/mono/exchangeto store the account ID. - For reauthorization, call
POST /si/mono/widget-linkwithaccountandscope: "reauth". meta.refmust be at least 10 characters; Taxpoynt will generate one if omitted.
Webhook and reconciliation
- Mono posts events to
/si/mono/webhookwithx-mono-signatureandx-mono-timestamp. transaction.updatedandtransaction.settledevents trigger reconciliation against invoices.- Reconciliation validates reference, amount, currency, and eligibility rules.
Draft invoices (review required)
- Eligible bank transactions are ingested as invoices with status
DRAFT. - Drafts must be reviewed and confirmed before validation/signing (
POST /si/invoices/:id/validate,POST /si/invoices/:id/sign). - Payment evidence is not an invoice until confirmed.
What is considered
- Credits (and debits used as refunds) that look like business income/expense: business keywords in narration/description/tags (invoice, payment, contract, subscription, settlement).
- Above the business floor amount (default: NGN 1,000) or explicitly allowlisted.
- Reference matches your invoice/reference pattern (optional regex:
MONO_REFERENCE_REGEX). - Currency matches the invoice currency.
What is rejected
- Narration/tags that match personal keywords (family, gift, personal, allowance, loan, charity, etc.).
- Below floor and no counterparty info.
- Reference or currency mismatch.
- Explicit denylist hits.
Allow/deny lists
- Set allowlist/denylist rules per organization or per account via
POST /si/mono/allow-deny. - Denylist takes precedence over allowlist.
Consent, revocation, retention
- Consent is explicit via the widget link + code exchange; only linked accounts can sync.
- Revoke consent with
POST /si/mono/accounts/:id/unlink(addpurge=trueto delete stored Mono invoices for that account). - Retention control: set
MONO_DATA_RETENTION_DAYSto auto-purge Mono-derived invoices older than N days.
Sync and cursor management
- Pull transactions for a linked account with
POST /si/mono/sync(supports cursor + pageSize). - Sync all stored accounts in an environment with
POST /si/mono/sync-stored. - Get the last cursor with
GET /si/mono/cursor?accountId=.... - Sync responses include
skippedcounts for ineligible transactions.
Monitoring
- Webhook status:
GET /si/mono/webhook-status. - Recent eligibility previews (with reasons):
GET /si/mono/events.
Config knobs
MONO_BASE_URL,MONO_SECRET_KEY,MONO_APP_ID.MONO_WEBHOOK_SECRETandMONO_VERIFY_SIGNATURE(default true).MONO_WIDGET_BASE_URL(optional override).MONO_BUSINESS_FLOOR(default 1000, in NGN) -- below this we require a business signal or allowlist.MONO_REFERENCE_REGEX-- optional pattern to accept references (e.g.,^INV-\d+$).MONO_DATA_RETENTION_DAYS-- optional retention window for Mono-derived invoices.
Behavior on mismatch
- We do not create/validate an invoice.
- Event goes to DLQ with a reason (personal_or_low_confidence, reference_mismatch, currency_mismatch).
- A monitoring event
invoice_failedis emitted with environment + traceId so ops can review.
Mono account API endpoints
Use the upstream Mono API to retrieve account details once you have exchanged the auth code for an account ID.
Account details
Last updated September 16th, 2025
Method GET
URL https://api.withmono.com/v2/accounts/{id}
Version v1.0
This resource represents the account details with the financial institution.
Data statuses and definitions
AVAILABLE: Both balance and transactions were returned.PARTIAL: Either balance or transactions were returned, but not both.UNAVAILABLE: Balance and transactions were not returned due to issues from the bank or the user has no data available.FAILED: Balance and transactions were not returned due to an issue from Mono's system only (e.g. internal service errors, timeouts, etc.).
This endpoint consistently includes a retrieved_data array in the meta object for all statuses so you can see what was actually fetched.
Real-time data
Real-time account balance is returned when x-real-time (or x-realtime) is set to true in your headers.
Currency
- NGN (kobo)
- GHC (pesewa)
- KSH (cents)
- ZAR (cents)
BVN (Nigeria only)
Only the last 4 digits of the BVN are returned on this API. To get the full BVN, call the Identity API.
Data status
If meta.data_status is still in the processing stage, wait before calling Statement, Transaction, Income, or Identity endpoints. Some banks are faster than others, so it may be available instantly after authorization or take a few seconds or minutes.
Path parameters
id(string, required): Account ID returned from token exchange.
Headers
mono-sec-key(string, required): Your app's secret key.x-realtime(boolean, optional): Set totrueto initiate a real-time data request.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts/{id}",
headers: {
accept: "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Request was successfully completed",
"timestamp": "2024-04-12T06:31:02.289Z",
"data": {
"account": {
"id": "64779d900000000000b3de23aeb8",
"name": "Samuel Olamide Nomo",
"currency": "NGN",
"type": "Digital Savings Account",
"account_number": "1234567890",
"balance": 333064,
"bvn": "0065",
"institution": {
"name": "GTBank",
"bank_code": "058",
"type": "PERSONAL_BANKING"
}
},
"customer": {
"id": "682dd53a74682beb490a0ed4"
},
"meta": {
"data_status": "AVAILABLE",
"auth_method": "internet_banking",
"data_request_id": "ALP2JGV0I4KH",
"session_id": "bOSKXZ6btpUHue5xUIlj",
"retrieved_data": [
"identity",
"balance",
"transactions"
]
}
}
}
404
View full snippet(click to expand)
{
"status": "failed",
"message": "This account does not exist.",
"data": null
}
Account identity
Last updated June 20th, 2025
Method GET
URL https://api.withmono.com/v2/accounts/{id}/identity
Version v1.0
This resource provides a mini customer identity information.
Path parameters
id(string, required): Account ID returned from token exchange.
Headers
mono-sec-key(string, required): Your app's secret key.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts/{id}/identity",
headers: {
accept: "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Request was successfully completed",
"timestamp": "2024-05-22T06:38:27.799Z",
"data": {
"full_name": "SAMUEL OLAMIDE NOMO",
"bvn": "22000000012",
"phone": "08012345678",
"gender": "Male",
"dob": "1997-08-07",
"address_line1": "Ikeja",
"state_of_origin": "Ogun State",
"lga_of_origin": "Abeokuta South",
"marital_status": "Single",
"verified": true,
"created_at": "2024-05-16T17:05:07.357Z",
"updated_at": "2024-05-16T17:05:07.357Z"
}
}
404
View full snippet(click to expand)
{
"status": "failed",
"message": "This account does not exist.",
"data": null
}
Account balance
Last updated Feb 20th, 2025
Method GET
URL https://api.withmono.com/v2/accounts/{id}/balance
Version v1.0
This resource provides the account balance of the user.
Path parameters
id(string, required): Account ID returned from token exchange.
Headers
mono-sec-key(string, required): Your app's secret key.x-realtime(boolean, optional): Set totrueto initiate a real-time data request (x-real-timealso supported).
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts/{id}/balance",
headers: {
accept: "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Request was successfully completed",
"timestamp": "2024-05-22T06:44:42.884Z",
"data": {
"id": "61e54d400000007510073257",
"name": "SAMUEL OLAMIDE NOMO",
"account_number": "01000005899",
"balance": 35232,
"currency": "NGN"
}
}
404
View full snippet(click to expand)
{
"status": "failed",
"message": "This account does not exist.",
"data": null
}
Account income
Last updated October 17th, 2025
Method GET
URL https://api.withmono.com/v2/accounts/{id}/income
Version v1.0
This resource returns income information to the account.
Path parameters
id(string, required): Account ID returned from token exchange.
Query parameters
period(string, optional): Number of months to consider (e.g.,6for the last 6 months). If omitted, the lifetime transactions are considered.
Headers
mono-sec-key(string, required): Your app's secret key.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts/{id}/income",
headers: {
accept: "application/json",
"Content-Type": "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "The income of ${account.name} is currently being processed, and the data will be sent to you through your webhook",
"timestamp": "2024-05-21T10:38:02.376Z",
"data": null
}
401
View full snippet(click to expand)
{
"status": "failed",
"message": "subscription plan does not cover endpoint",
"timestamp": "2024-06-06T10:54:45.786Z",
"data": null
}
Webhook response
View full snippet(click to expand)
{
"event": "mono.events.account_income",
"data": {
"account": "682dd53b74682beb490a0ed6",
"app": "62da7b4b342c3aab5dd2a2c4",
"business": "60cc8fa5ba177218c5c6a11d",
"account_name": "JOHN DOE",
"account_number": "2000000041",
"income_summary": {
"total_income": 0,
"employer": ""
},
"income_streams": [
{
"income_type": "WAGES",
"frequency": "VARIABLE",
"monthly_average": 10300,
"average_income_amount": 3166,
"currency": "",
"stability": 0.32,
"first_income_date": "2025-05-03",
"last_income_date": "2025-05-03",
"last_income_amount": 1700,
"last_income_description": "cip cr transfer from jane doe",
"periods_with_income": 1,
"number_of_incomes": 3,
"number_of_months": 1
},
{
"income_type": "WAGES",
"frequency": "MONTHLY",
"monthly_average": 3000,
"average_income_amount": 3000,
"currency": "",
"stability": 1,
"first_income_date": "2025-03-27",
"last_income_date": "2025-04-22",
"last_income_amount": 3000,
"last_income_description": "cip cr subscriptions",
"periods_with_income": 2,
"number_of_incomes": 2,
"number_of_months": 2
}
],
"income_source_type": "BANK",
"first_transaction_date": "2024-09-30",
"last_transaction_date": "2025-05-03",
"period": "7 months",
"number_of_income_streams": 2,
"total_income": 11300,
"annual_income": 11300,
"monthly_income": 6130,
"aggregated_monthly_average": 2133,
"aggregated_monthly_average_regular": 1350,
"aggregated_monthly_average_irregular": 10300,
"total_regular_income_amount": 3000,
"total_irregular_income_amount": 10300
}
}
Income records
Last updated June 20th, 2025
Method GET
URL https://api.withmono.com/v2/accounts/{id}/income-records
Version v1.0
This resource returns all the records of income linked to a particular account.
Path parameters
id(string, required): Account ID returned from token exchange or webhook.
Query parameters
page(string, optional): Page number (defaults to1if omitted).
Headers
mono-sec-key(string, required): Your app's live secret key.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts/{id}/income-records",
headers: {
accept: "application/json",
"mono-sec-key": "sk_live_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Data retrieved successfully",
"timestamp": "2025-05-27T13:52:05.804Z",
"data": [
{
"income": {
"account": "682dd53b74682beb490a0ed6",
"account_name": "JOHN DOE",
"account_number": "2000000041",
"income_summary": {
"total_income": 0,
"employer": ""
},
"income_streams": [
{
"income_type": "WAGES",
"frequency": "VARIABLE",
"monthly_average": 11300,
"average_income_amount": 3766,
"currency": "",
"stability": 0.32,
"first_income_date": "2025-05-03",
"last_income_date": "2025-05-03",
"last_income_amount": 3500,
"last_income_description": "cip cr transfer from jane doe",
"periods_with_income": 1,
"number_of_incomes": 3,
"number_of_months": 1
},
{
"income_type": "WAGES",
"frequency": "MONTHLY",
"monthly_average": 5000,
"average_income_amount": 5000,
"currency": "",
"stability": 1,
"first_income_date": "2025-03-27",
"last_income_date": "2025-04-22",
"last_income_amount": 500000,
"last_income_description": "cip cr subscriptions",
"periods_with_income": 2,
"number_of_incomes": 2,
"number_of_months": 2
}
],
"income_source_type": "BANK",
"first_transaction_date": "2024-09-30",
"last_transaction_date": "2025-05-03",
"period": "7 months",
"number_of_income_streams": 2,
"total_income": 16300,
"annual_income": 16300,
"monthly_income": 8150,
"aggregated_monthly_average": 5433,
"aggregated_monthly_average_regular": 2500,
"aggregated_monthly_average_irregular": 11300,
"total_regular_income_amount": 5000,
"total_irregular_income_amount": 11300
},
"app": "67c9aeea65e5644ece474b2d",
"created_at": "2025-05-23T09:48:43.276Z",
"updated_at": "2025-05-23T09:48:43.784Z"
},
{
"income": {
"account": "682dd53b74682beb490a0ed6",
"account_name": "JOHN DOE",
"account_number": "2000000041",
"income_summary": {
"total_income": 0,
"employer": ""
},
"income_streams": [
{
"income_type": "WAGES",
"frequency": "VARIABLE",
"monthly_average": 11300,
"average_income_amount": 3766,
"currency": "",
"stability": 0.32,
"first_income_date": "2025-05-03",
"last_income_date": "2025-05-03",
"last_income_amount": 3500,
"last_income_description": "cip cr transfer from jane doe",
"periods_with_income": 1,
"number_of_incomes": 3,
"number_of_months": 1
},
{
"income_type": "WAGES",
"frequency": "MONTHLY",
"monthly_average": 5000,
"average_income_amount": 5000,
"currency": "",
"stability": 1,
"first_income_date": "2025-03-27",
"last_income_date": "2025-04-22",
"last_income_amount": 500000,
"last_income_description": "cip cr subscriptions",
"periods_with_income": 2,
"number_of_incomes": 2,
"number_of_months": 2
}
],
"income_source_type": "BANK",
"first_transaction_date": "2024-09-30",
"last_transaction_date": "2025-05-03",
"period": "7 months",
"number_of_income_streams": 2,
"total_income": 16300,
"annual_income": 16300,
"monthly_income": 8150,
"aggregated_monthly_average": 5433,
"aggregated_monthly_average_regular": 2500,
"aggregated_monthly_average_irregular": 11300,
"total_regular_income_amount": 5000,
"total_irregular_income_amount": 11300
},
"app": "67c9aeea65e5644ece474b2d",
"created_at": "2025-05-23T09:48:43.276Z",
"updated_at": "2025-05-23T09:48:43.519Z"
}
],
"meta": {
"total": 2,
"pages": 1,
"previous": null,
"next": null
}
}
401
View full snippet(click to expand)
{
"error": "failed",
"error_description": "invalid request"
}
Get customer accounts
Last updated June 20th, 2025
Method GET
URL https://api.withmono.com/v2/accounts
Version v1.0
This resource provides all accounts linked to your business.
Headers
mono-sec-key(string, required): Your app's secret key.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "GET",
url: "https://api.withmono.com/v2/accounts",
headers: {
accept: "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Data retrieved successfully",
"timestamp": "2024-04-12T09:55:07.980Z",
"data": [
{
"id": "61e54d10073257",
"name": "SAMUEL, OLAMIDE NOMO",
"account_number": "1100000899",
"currency": "NGN",
"balance": 35232,
"auth_method": "mobile_banking",
"status": "AVAILABLE",
"bvn": "2200000019",
"type": "SAVINGS ACCOUNT",
"institution": {
"id": "5f2d088287702",
"name": "GTBank",
"bank_code": "058",
"type": "PERSONAL_BANKING"
},
"customer": {
"id": "61e54d41007325b",
"name": "SAMUEL, OLAMIDE NOMO"
}
},
{
"id": "61e5fe0ee39f7a",
"name": "OLAMIDE SAMUEL",
"account_number": "780000069",
"currency": "NGN",
"balance": 365222,
"auth_method": "internet_banking",
"status": "AVAILABLE",
"bvn": "22000000022",
"type": "WALLET_ACCOUNT",
"institution": {
"id": "5f2d088828770d",
"name": "Barter",
"bank_code": null,
"type": "PERSONAL_BANKING"
},
"customer": {
"id": "61e5fa9c9dc6a0150ee2c5a1",
"name": "OLAMIDE SAMUEL"
}
},
{
"id": "61e6d880105d1",
"name": "NOMO OLAMIDE",
"account_number": "23000000034",
"currency": "NGN",
"balance": 3655,
"auth_method": "internet_banking",
"status": "AVAILABLE",
"bvn": "N/A",
"type": "WALLET_ACCOUNT",
"institution": {
"id": "5f2d088828770d",
"name": "Barter",
"bank_code": null,
"type": "PERSONAL_BANKING"
},
"customer": {
"id": "61e69cf0b79e5323d3c335e7",
"name": "NOMO OLAMIDE"
}
}
],
"meta": {
"total": 1571,
"pages": 158,
"previous": null,
"next": "https://api.withmono.com/v2/accounts/?page=2"
}
}
Taxpoynt API wrapper (dashboard-friendly)
Method GET
URL /si/mono/accounts
Query parameters
page(string, optional): Page number when listing all Mono accounts. Usemeta.nextfor pagination.linkedOnly(boolean, optional): Whentrue, return only accounts linked to the org + environment in Taxpoynt.env(string, optional): Environment label used withlinkedOnly=true(sandboxorproduction).envId(string, optional): Environment ID used withlinkedOnly=true(preferred if available).
Notes
- If
linkedOnly=true, pagination is not needed;meta.nextwill benull. - When
linkedOnlyis omitted/false, pagination follows Mono’s upstream response (meta.next).
Response (shape)
View full snippet(click to expand)
{
"status": "successful",
"message": "Linked Mono accounts",
"timestamp": "2024-07-15T12:00:00.000Z",
"data": [
{
"id": "61e54d10073257",
"name": "SAMUEL, OLAMIDE NOMO",
"account_number": "1100000899",
"currency": "NGN",
"balance": 35232,
"type": "SAVINGS ACCOUNT",
"institution": { "name": "GTBank", "bank_code": "058", "type": "PERSONAL_BANKING" }
}
],
"meta": { "total": 1, "pages": 1, "previous": null, "next": null }
}
Unlink
Last updated Feb 20th, 2025
Method POST
URL https://api.withmono.com/v2/accounts/{id}/unlink
Version v1.0
This enables you to provide your customers with the option to unlink their financial account(s).
Path parameters
id(string, required): Account ID returned from token exchange.
Headers
mono-sec-key(string, required): Your app's secret key.
Request
View full snippet(click to expand)
const axios = require("axios");
const options = {
method: "POST",
url: "https://api.withmono.com/v2/accounts/{id}/unlink",
headers: {
accept: "application/json",
"mono-sec-key": "sk_test_your_secret_key",
},
};
axios
.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
Response
200
View full snippet(click to expand)
{
"status": "successful",
"message": "Request was successfully completed",
"timestamp": "2024-03-15T15:20:27.732Z"
}
404
View full snippet(click to expand)
{
"status": "failed",
"message": "This account does not exist.",
"data": null
}
Quick copy for the Mono connect UI / tooltip
"We only invoice business-related credits (invoice/payment/contract, above NGN 1,000). Personal or family/gift/loan transfers are ignored. Keep references consistent (e.g., INV-123) for matching."