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)

  1. Create a widget link: POST /si/mono/widget-link with customer, redirectUrl, and optional meta.ref and institution.
  2. Complete Mono Connect in the widget and capture the code.
  3. Exchange code: POST /si/mono/exchange to store the account ID.
  4. For reauthorization, call POST /si/mono/widget-link with account and scope: "reauth".
  5. meta.ref must be at least 10 characters; Taxpoynt will generate one if omitted.

Webhook and reconciliation

  • Mono posts events to /si/mono/webhook with x-mono-signature and x-mono-timestamp.
  • transaction.updated and transaction.settled events 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 is explicit via the widget link + code exchange; only linked accounts can sync.
  • Revoke consent with POST /si/mono/accounts/:id/unlink (add purge=true to delete stored Mono invoices for that account).
  • Retention control: set MONO_DATA_RETENTION_DAYS to 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 skipped counts 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_SECRET and MONO_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_failed is 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 to true to 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 to true to initiate a real-time data request (x-real-time also 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., 6 for 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 to 1 if 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. Use meta.next for pagination.
  • linkedOnly (boolean, optional): When true, return only accounts linked to the org + environment in Taxpoynt.
  • env (string, optional): Environment label used with linkedOnly=true (sandbox or production).
  • envId (string, optional): Environment ID used with linkedOnly=true (preferred if available).

Notes

  • If linkedOnly=true, pagination is not needed; meta.next will be null.
  • When linkedOnly is 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 }
}

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."