# Audits and changelog
Source: https://docs.centipidbilling.com/analytics/audits-and-changelog
Use the audit trail to see who changed which record and when, filter events by actor or action, and read the changelog for product updates sent to operators.
## Review operational history
Audit records and the changelog answer different questions:
* **Audits:** who/what changed data in this workspace or performed a recorded action.
* **What's new / Changelog:** product updates published to operators.
## Audits
The audit list/detail pages can show actor, action/event, affected model/record, time, old/new values, and request/context metadata where captured. Access is permission-gated.
Open **Insights → Audit trail**. The page header shows three counts: all events recorded, events today, and events in the last 7 days. Four cards below it show **All events**, **Today**, **Updates** and **Deletions**. These counts refresh about every 30 seconds.
### Filter the audit trail
You can narrow the list with five filters:
| Filter | What it matches |
| - | - |
| Event | One of 5 types: Created, Updated, Deleted, Restored or Action |
| Model | The kind of record changed, such as a subscriber or payment |
| Operator | The staff member who made the change |
| From / To | A date range |
| Search | Text in the URL, IP address, user-agent or model name |
The list loads 50 rows at a time. Scroll down to load the next 50. Click a row to open its detail page with the old and new values.
Use audits to investigate:
* subscriber status/profile changes;
* settings updates;
* login/denied activity where recorded;
* payment/invoice/expense changes;
* staff/role actions;
* destructive or bulk operations.
An absent audit row does not prove an event never happened. Not every external provider/router action produces the same application audit. Correlate with domain records, provider references, router logs, and timestamps.
## Changelog
The sidebar can show an unread indicator for a newly published entry. Open **What's new** to read operator-facing releases. Opening the page clears the dot. It comes back only when a newer entry is published. Your browser remembers what you have read for 1 year.
Each entry carries one of 5 labels: **New feature**, **Bug fix**, **Improvement**, **Announcement** or **Release**. Entries are listed newest first, 50 at a time. Each one has a share link to the same entry on the public Centipid changelog.
Changelog text explains product changes. It is not a transaction/audit record and does not override current UI behavior.
## Investigation workflow
1. Record exact time/timezone, user, ISP, and affected record ID.
2. Open the record's own activity/history.
3. Search audits around the time.
4. Compare old/new values and actor/context.
5. Correlate with provider/router/message status where relevant.
6. Preserve evidence before corrective action.
7. Avoid placing secrets or unnecessary personal data in investigation notes.
# Dashboard and analytics
Source: https://docs.centipidbilling.com/analytics/dashboard-and-analytics
Read the Overview dashboard for router health and today's payments and signups, then filter Analytics by period and router for revenue, sessions and traffic.
## Use metrics as a path to records
The dashboard provides current pulse/triage. **Analytics** provides period- and router-filtered analysis. Financial amounts can be hidden and remain permission-gated.
## Dashboard
Open **Overview** at the top of the sidebar. Depending on data and permission, the overview can show:
* router health and online/offline counts;
* new subscribers and payments today;
* revenue/payment-method summary;
* live feed of payments and signups;
* prioritized “what's next” actions;
* upcoming renewals/expiries;
* busiest routers and live sessions;
* deferred subscriber-health and expiry trends.
### What each section holds
| Section | What it shows |
| - | - |
| Stat cards | **Revenue today**, **Active subscriptions**, **Online now** and, on Centipid's SMS gateway, **SMS credits** |
| Revenue today | Change against the same time yesterday, split by **Mobile money** and **Vouchers**, and by **PPPoE** and **Hotspot** |
| Today | Up to 10 of the latest events since midnight |
| What's next? | Up to 6 actions that need attention |
| Renewals due | Up to 12 subscribers due in the next 48 hours |
| Where the traffic is | The 5 busiest routers over the last hour |
| Subscriber health | **At risk** (no session in 30+ days), **Churned**, **Expiring in 7d**, and expiries per day for the last 14 days |
Staff without money access see **New today** in place of **Revenue today**.
Dashboard polling refreshes current feed/pulse data every 60 seconds. A new payment also updates the feed and revenue at once. Heavy sections load separately. Wait for their skeletons to resolve before treating a zero/blank as a business result.
## Analytics filters
Open **Insights → Analytics**. Choose the current period, optional MikroTik/NAS, and service filter where available.
* **Period:** Daily, Weekly, Monthly, Yearly, Last Year or Custom. Monthly is the default. Periods follow the calendar: Weekly starts on Monday and Monthly on the 1st. A custom range can cover up to 366 days and cannot end after today.
* **Router:** All routers or one router.
* **Service:** All, Hotspot or PPPoE. Payment trend can be filtered by Hotspot or PPPoE.
Export uses the active period/router context.
## Analytics sections
A row of 8 cards sits at the top: Active subscribers, Revenue, ARPU (average revenue per user), Sessions, Data transferred, Online now, Payments and Overdue.
* **Revenue & billing:** payment trend, payments versus expenses/net, top customers, Hotspot/PPPoE revenue mix, payment-method split, accounts receivable/overdue.
* **Subscribers:** active/new, lifecycle (active/paused/expired), stage/type, expiring series.
* **Network:** sessions/peak/duration, traffic upload/download, usage by plan and session behavior.
* **MikroTik:** revenue, subscribers, sessions, and traffic by router when viewing all routers.
Top packages and top customers show 6 rows. Click **View top 50** for more. Usage by plan lists 8 plans and Top talkers lists 10. Expiring soon counts the next 7, 14 and 30 days.
Most figures are cached for 1 to 5 minutes. Online now and active sessions refresh every 60 seconds.
## Interpretation cautions
* Period and timezone boundaries can change totals.
* Pending/manual/offline payments may differ from provider settlement.
* Active sessions are accounting records and can contain stale/reconnect state.
* Revenue per router depends on record association, not physical cash location.
* A deferred chart's absence is a loading/error state, not zero.
* Compare underlying payments, expenses, subscribers, or sessions before acting on an anomaly.
## Export
Download only the required period and router scope. Click **Export CSV**. Only staff with money access see it. The analytics CSV includes its filter context: the period, the router and the time it was made. It then lists a summary, payment methods, daily revenue and daily data usage. With all routers selected, it adds one row per router. The service filter is not applied to the export.
Protect it as customer/financial data and reconcile totals against the visible filtered page.
# Search, imports, and exports
Source: https://docs.centipidbilling.com/analytics/search-and-exports
Find subscribers, payments, routers, vouchers and more with global search (Cmd/Ctrl+K), then import and export page data without leaking customer details.
## Find the record before changing it
Global search can group results from active sessions, subscribers, leads, tickets, packages, routers, payments, invoices, expenses, vouchers, SMS, equipment, IP bindings, and campaigns. It also offers context actions for the page being viewed.
Press **⌘K** on a Mac or **Ctrl+K** on Windows, or click the search bar at the top. Results appear as you type, with no minimum length. Each of the 14 groups shows up to 5 matches. The group for the page you are on is listed first. Use ↑ and ↓ to move, Enter to open, and Esc to close. Before you type, the box lists up to 5 recent searches.
## Search well
Prefer stable identifiers:
* subscriber username/account number/phone/email;
* MAC or framed IP for network incidents;
* receipt/reference/invoice number for money;
* router identity;
* ticket ID/subject;
* voucher code;
* equipment serial number.
Verify the ISP and the record before using a result action. Short/common names can return several valid matches.
## Page-specific import/export
Subscribers, payments, leads, tickets, vouchers, analytics, and other workspaces expose purpose-built export or import/export pages. Use them instead of reconstructing data from screenshots.
| Page | Export formats | Notes |
| - | - | - |
| Subscribers | CSV or Excel (XLSX) | Excel is limited to 50,000 rows. CSV has no limit. |
| Payments | CSV | Scopes: all, today, 7 days, 30 days, custom, unreconciled or pending |
| Leads, Tickets | CSV or Excel | |
| Vouchers | CSV or Excel, plus PDF to print | The PDF holds 1,000 vouchers by default and up to 5,000 |
| Analytics | CSV | Needs money access |
Most exports download straight away. The voucher PDF is prepared in the background. You get a notice when it is ready, and its link works once, for 30 minutes.
### Export procedure
1. Apply scope filters.
2. Choose only needed columns.
3. Review expected count/date range.
4. Export once.
5. Reconcile a sample and totals.
6. Store with controlled access and remove temporary copies.
### Import procedure
Subscribers are imported from **Import & export** on the Subscribers page. You can upload a file or pull PPPoE secrets live from a MikroTik router. A file can be CSV, XLSX or XLS, up to 10 MB and 50,000 rows. The upload runs in 3 steps: Upload, Map fields and Review.
1. Download the current template where offered.
2. Preserve headers and required formats.
3. Normalize identifiers as text.
4. Preview/parse before writing.
5. Test a small representative batch.
6. Keep the result summary and avoid blind re-upload.
The template has 11 columns: name, first\_name, last\_name, email, phone, account\_number, type, package, nas, password and comment. A row matches an existing subscriber by username, then account number, then phone. You choose what happens to a match:
* **Skip duplicates** (default): leave the existing subscriber as it is.
* **Update existing:** fill in blank fields only.
* **Overwrite existing:** replace values with the file's.
Rows with an unknown package or router, or no username, are counted as errors and not imported.
## Spreadsheet safety
Treat imported formulas, leading `=`, macros, hidden columns, and altered phone/account number formatting as risks. Use CSV/plain values where the workflow expects them. Inspect files from external parties before upload.
## Data minimization
Exports may include personal, financial, message, network, or support data. Share the minimum scope with authorized recipients and follow retention/deletion policy.
# Collections and withdrawals
Source: https://docs.centipidbilling.com/billing/collections-and-withdrawals
For Ugandan ISPs on Centipid Collections: check the wallet balance, review collected money, request withdrawals, see the fees, and handle a failed payout.
## Manage the Centipid wallet
For ISPs with the Centipid wallet capability, **Payments** includes views for Payments, Collections, and Withdrawals. ISPs without it see the normal payment ledger only.
The wallet is offered to ISPs in Uganda that collect with [Centipid Collections](/billing/payment-gateways/centipid). Only administrators see it. Every view starts with a **Wallet balance** card: the amount available to withdraw. Amounts are in Ugandan shillings (UGX).
## Collections
Collections represent qualifying customer money received into the wallet flow. Use the collection view to compare gross inflow, fees/adjustments where shown, status, subscriber/receipt context, and available balance.
The Collections view has five cards:
* **Collected:** all confirmed collections to date;
* **Today:** confirmed today;
* **This month:** since the 1st;
* **Pending:** awaiting confirmation;
* **Failed:** not collected.
A collection is added to the balance as soon as the mobile-money provider confirms it. The list shows the latest 50 collections.
Do not equate the sum of every payment method with withdrawable wallet balance. Manual/offline methods and unsettled transactions may not fund the wallet.
## Request a withdrawal
1. Open the Withdrawals view/action.
2. Review the current available amount and request a quote where provided.
3. Enter an amount meeting the displayed minimum. The minimum is UGX 500 and the maximum is UGX 5,000,000 per withdrawal.
4. Enter the recipient mobile-money number (required, maximum 32 characters).
5. Enter the recipient name when useful (optional, maximum 120).
6. Request the six-digit action OTP. OTP requests are rate-limited. The code is emailed to you and expires after 5 minutes. You can request 3 codes per 15 minutes, with 60 seconds between requests. After 5 wrong tries, request a new code.
7. Review fees/net amount/recipient in the confirmation.
8. Submit once and track the resulting withdrawal status.
### Withdrawal fees
Fees are fixed amounts by band, not percentages. They come out of the amount you enter. The quote shows each fee and what the recipient receives.
| Amount (UGX) | iOtec fee | Centipid fee |
| - | - | - |
| 500 – 60,000 | 600 | 100 |
| 60,001 – 500,000 | 1,200 | 200 |
| 500,001 – 1,000,000 | 2,000 | 300 |
| 1,000,001 – 5,000,000 | 2,400 | 400 |
The recipient must receive more than zero after fees. So the smallest withdrawal that goes through is UGX 701. Only one withdrawal can be in progress at a time.
Verify the recipient number and name before submitting. A successful request can dispatch money externally and may not be reversible from the application.
## Status and reconciliation
Separate request acceptance, dispatch, provider processing, success, and failure. The Withdrawals view shows each status as **pending**, **processing**, **success** or **failed**. It has four cards: **Paid out**, **This month**, **Active** (pending or processing) and **Failed**. The list shows the latest 50 withdrawals. A pending withdrawal should not be resubmitted until its provider state is understood. Reconcile the wallet ledger with provider/bank settlement and the payment records that funded it.
## Failed withdrawal
Read the failure reason and whether the failure is retryable. Confirm balance, recipient format, provider availability, and any earlier dispatch reference. Retry only through the supported action and never by creating a second manual payment/collection record. The retry action is limited to Centipid staff, so contact support with the withdrawal ID.
## Security
* Never share the action OTP.
* If money goes to a new number within 7 days of an email or password change, the account owner gets an alert email.
* Use an administrator account with 2FA.
* Review staff finance permissions regularly.
* Do not store recipient lists or OTPs in notes.
* Escalate with the withdrawal ID/reference, status, timestamps, and sanitized error—not gateway secrets.
# Expenses
Source: https://docs.centipidbilling.com/billing/expenses
Record operating costs such as bandwidth, hardware, salaries and rent in the expense ledger, correct or delete entries, and see how they feed into analytics.
## Record money out
Open **Billing → Expenses** to track operational costs alongside revenue analytics. Staff need the **Expenses** permission.
The **Expense ledger** shows four totals at the top:
| Card | What it adds up |
| - | - |
| This month | Expenses since the 1st |
| Last 7 days | A rolling 7-day window |
| Today | Expenses so far today |
| All time | Every expense, with the record count |
These totals cover all expenses. They do not change when you filter the list.
## Fields
* **Category (type):** required, maximum 60 characters. Pick one of 9: Hardware, Bandwidth, Electricity, SMS, Salaries, Marketing, Rent, Utilities or Other. Other is the default.
* **Date and time:** required. It defaults to now.
* **Amount:** required, numeric, zero or greater.
* **Description:** optional, maximum 2,000 characters.
* **Receipt:** optional reference, maximum 120 characters.
* **Payment method:** optional, maximum 60 characters. Pick Cash, M-Pesa, Bank, Card or Other.
## Create an expense
1. Choose **Record an expense**.
2. Use a consistent type/category suitable for reporting.
3. Enter the amount in the account currency.
4. Add a useful description, receipt/reference, and payment method.
5. Save and verify it appears in the list and analytics period.
An expense record is not a file-attachment store or full accounting journal. Retain supporting invoices/receipts in the organization's approved system and use the reference field to connect them.
## Find an expense
Search matches the description, receipt and payment method. Filter by category, or by a **From** and **To** date. The list shows the newest expense first and loads 50 rows at a time. Each row shows the date, category, description, receipt, method and amount.
## Correct or delete
Open a row's menu to **Edit** or **Delete** it. Delete asks you to confirm. It removes the expense for good and it cannot be restored.
Edit factual errors promptly. Delete only duplicate/invalid entries and preserve any required audit or accounting record outside this workspace. If a correction changes a closed reporting period, notify the person responsible for reconciliation.
## Reporting hygiene
Use a controlled set of expense types, consistent currency assumptions, real transaction dates, and unique receipt references. Large swings in payments-versus-expenses analytics should be reconciled against underlying records before business decisions.
## How expenses reach analytics
The **Payments vs expenses** card in Analytics groups expenses by their date and time. It shows payments as bars and expenses as a line. **Net** is payments minus expenses. Expenses always count the whole ISP: the router filter does not apply to them. The card refreshes every 2 minutes.
# Invoices
Source: https://docs.centipidbilling.com/billing/invoices
Create itemized subscriber invoices with due dates, record full or partial payments, issue credit notes, send reminders, and see how status affects service.
## Bill subscribers with invoices
Open **Billing → Invoices**. An invoice records an amount due from a subscriber, its line items, due date, status, payments, and activity.
## Create an invoice
Required:
* subscriber;
* due date;
* at least one line item;
* line-item description (maximum 255 characters);
* line-item price greater than zero.
Quantity is optional but, when present, must be greater than zero. Notes are optional up to 2,000 characters.
Verify identity and current service context before billing.
Describe each charge clearly, enter quantity and price, and review subtotal/tax/total shown by the form.
Use the account timezone and write notes suitable for the subscriber-facing document.
Confirm the ISP's branding, subscriber, line items, totals, currency, and due date.
Save, open the invoice detail, and verify its number/status/activity.
## Invoice states
* **Pending:** amount remains due.
* **Partial:** some payment is linked/recorded but a balance remains.
* **Paid:** outstanding balance is zero.
* **Credited:** credit notes cover the whole invoice amount; nothing is owed.
* **Cancelled:** invoice was voided; do not record new payment against it.
* **Overdue:** a pending invoice has passed its due date.
## Record a payment
The amount is required, must be at least 0.01, and cannot exceed the remaining balance. Method can be Cash, Mpesa, or Bank. Receipt is optional up to 120 characters.
If a matching M-Pesa/payment record already exists, enter its receipt to link that payment rather than recording a duplicate. After saving, verify both the invoice payment list and main payment ledger.
## Issue a credit note
Use a credit note, not Cancel, when an invoice billed too much. The invoice and the correction both stay on file.
1. Open the invoice, then **⋯ → Issue credit note**.
2. Enter the amount (the full invoice, or part of it) and a reason. You cannot credit more than what is left to credit on the invoice.
3. The credit note gets its own number (`CN-YYYYMM-0001`) and PDF. The subscriber sees it next to the invoice in the customer portal.
What the subscriber owes becomes the invoice amount minus payments minus credit notes. If the credit is more than what was still unpaid, the difference goes to the subscriber wallet as credit for their next renewal. It is never paid out, so this needs the subscriber wallet turned on. Every credit note is recorded in the audit log with the staff member who issued it, and is sent to Sage as a Sales Credit Note when invoice sync is on.
## Other actions
* **Send reminder:** notify the subscriber through the supported channel/template.
* **Send STK:** initiate a supported gateway request for the outstanding amount.
* **Preview / Download PDF:** review or distribute the official document.
* **Edit:** change an unpaid/current invoice with care.
* **Reset payments:** detach/reset recorded payment state only after reconciling why.
* **Cancel:** preserve the invoice while voiding collection.
* **Delete:** permanently remove it and detach linked payments; use only when retention is not required.
## Automatic service impact
The detail page can show whether an unpaid invoice affects connection state and whether payment auto-reconnects the subscriber. Read that current indicator rather than assuming every invoice suspends service.
## Customer portal
Subscribers can list/open invoices and initiate payment from the customer portal when the ISP's gateway supports it. Portal payment status is polled; returning from provider checkout is not alone proof of settlement.
# Airtel Money
Source: https://docs.centipidbilling.com/billing/payment-gateways/airtel-money
Set up Airtel Money collections through the Airtel Africa API: credentials, callback URLs and how payments complete, plus why no country catalog lists it today.
## Collect payments with Airtel Money
`AIRTEL_MONEY` collects through the Airtel Africa open API. Centipid Billing
pushes a payment request to the payer's Airtel wallet, the payer authorizes it
on their handset, and the transaction status is read back from Airtel.
**Airtel Money is not offered by the country catalog.** Every country list in
the application offers some other set of gateways, and none of them includes
Airtel Money — so it does not appear in the **Settings → Payments**
marketplace and cannot be selected there, even though the credential form and
the integration both exist and work.
In practice this means the gateway is reachable only for an account already
configured on it. Do not plan a migration onto Airtel Money without first
confirming with support that it can be enabled for your country.
## Before you start
1. Confirm with support that Airtel Money is available for your account, given
the limitation above.
2. Complete Airtel Africa developer onboarding in an account owned by the ISP,
and collect the **client ID** and **client secret**.
3. Confirm which country and currency Airtel has approved for your merchant
account — they decide the overrides below.
## Configure the gateway
Available only where the gateway is already enabled for the account.
**Airtel client ID** and **Airtel client secret** are both required. The
secret is stored as a secret and is not echoed back after saving.
**Country code override** and **currency code override** are optional. Left
blank, requests use your account's own country and currency, falling back to
`UG` and `UGX`. Set them only when Airtel has approved a different explicit
value for your merchant account.
Pay a small amount and confirm the wallet prompt arrives and the payment
reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Airtel client ID | Yes | From the Airtel Africa developer portal. |
| Airtel client secret | Yes | Secret. |
| Country code override | No | ISO two-letter, maximum 3 characters, for example `UG`. Blank uses your account's country, then `UG`. |
| Currency code override | No | ISO three-letter, maximum 3 characters, for example `UGX`. Blank resolves from the country, then your account's currency, then `UGX`. |
Country and currency are sent as `X-Country` and `X-Currency` headers on every
request, so a wrong override is rejected by Airtel rather than silently
converted.
## Callback URLs
None are shown in Settings → Payments. Completion is established by reading the
transaction status back from Airtel rather than by waiting for a callback.
## What the payer must provide
An Airtel mobile money number, which is normalized for the resolved country
before the request is sent. Authorization happens on the handset, so no Airtel
domain needs to be added to the captive walled garden.
## How a payment completes
Centipid Billing authenticates against the Airtel API and posts the payment
request with the resolved country and currency.
The payer approves the request on their handset.
The transaction status is queried back from Airtel. A completed transaction
is recorded as a payment and the subscriber's package applied; a failed one
is marked failed with the status Airtel returned.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| Airtel Money does not appear in Settings → Payments | The country catalog does not offer it — see the warning above. | Contact support. Do not attempt to configure it another way. |
| *"Airtel Money credentials are not configured…"* | The client ID or secret is missing. | Enter both in Settings → Payments. |
| *"Unable to authenticate with Airtel Money. Please try again later."* | Airtel rejected the credentials. | Re-copy the client ID and secret. Confirm the app is approved for production. |
| *"Unable to reach Airtel Money at the moment. Please try again shortly."* | The request could not connect. | Check outbound connectivity from the application host, then retry. |
| *"Payment initiation failed. Please try again later."* | Airtel refused the request. | Check the payer's number is a valid Airtel wallet in the configured country, and that the country and currency overrides match what Airtel approved. |
| *"Payment failed: …"* | Airtel returned a terminal failure status. | Read the status in the message; ask the payer to confirm their wallet balance and status. |
| *"Payment is still pending."* | Airtel has not settled the transaction yet. | Re-check the status before advising a retry — a retry can charge the payer twice. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# AzamPay
Source: https://docs.centipidbilling.com/billing/payment-gateways/azampay
Set up AzamPay mobile money checkout in Tanzania: app name, client ID and secret, sandbox or production base URLs, and the callback password payments need.
## Collect payments with AzamPay
`AZAMPAY` pushes a payment request to the payer's mobile money wallet through
AzamPay's MNO checkout. The payer authorizes on their handset, and AzamPay
confirms the result on a callback.
Available to ISPs in **Tanzania (TZ)**, alongside ClickPesa, PalmPesa, PawaPay,
PesaPal, Relworx, ZenoPay, PayPal, and DPO.
## Before you start
1. Complete AzamPay merchant onboarding in an account owned by the ISP.
2. From the AzamPay portal collect the **app name**, **client ID**, **client
secret**, the **authenticator base URL**, the **checkout base URL**, and the
**callback password**.
3. Decide whether you are configuring **sandbox** or **production** — the base
URLs differ, and mixing them is the most common setup failure.
**Set the callback password before taking live payments.** The form marks it
optional, because sandbox may not send one. In production the callback
verification fails closed: with no callback password saved, **every** AzamPay
callback is rejected as unauthorized, so payers are charged and never
provisioned. There is no partial mode — configure it, or do not go live.
## Configure the gateway
Select AzamPay from the payment marketplace.
**Environment** (required) is `Sandbox` or `Production`. Use sandbox while
testing.
**App name** (required) must match the AzamPay portal exactly. **Client ID**
and **client secret** (required) come from the same place.
**Authenticator base URL** and **checkout base URL** (both required, full
URLs) must match the environment you selected. Checkout requests are sent to
`/azampay/mno/checkout`.
Required in practice for live payments — see the warning above.
Pay a small amount and confirm both halves: the wallet prompt arrives,
**and** the payment lands in the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Environment | Yes | `Sandbox` or `Production`. |
| App name | Yes | Exactly as configured at AzamPay. |
| Client ID | Yes | Also checked against the callback when AzamPay includes one. |
| Client secret | Yes | Secret. |
| Authenticator base URL | Yes | Full URL, matching the environment. |
| Checkout base URL | Yes | Full URL, matching the environment. |
| Callback password | Marked optional | Secret. Callbacks are rejected without it — treat it as required for production. |
The six fields above the callback password are what gate the switch; the
callback password does not, which is exactly why it is easy to miss.
## Callback URLs
Register `https:///api/azampay/callback` in the AzamPay portal.
Callbacks are accepted only when the password in the callback body matches your
saved callback password. When AzamPay includes a client id, that must match too.
Repeated callbacks for a transaction already recorded are ignored rather than
double-credited.
## What the payer must provide
* **A Tanzanian mobile money number**, normalized before the request is sent.
* **A provider choice.** The payer picks their wallet at checkout: Airtel, Tigo,
Halopesa, Azampesa, or Mpesa. A request with no supported provider is refused
before it reaches AzamPay.
Authorization happens on the handset, so no AzamPay domain needs to be added to
the captive walled garden.
## How a payment completes
Centipid Billing authenticates against the authenticator base URL, caches
the token, and posts the checkout with the amount, currency, provider, and a
unique external id.
The payer approves on their handset.
AzamPay posts the result to the callback. Only `success` credits the
payment; any other status is recorded against the transaction and nothing is
provisioned.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Please select a supported AzamPay provider."* | The checkout carried no provider, or one AzamPay does not support. | Have the payer pick Airtel, Tigo, Halopesa, Azampesa, or Mpesa. |
| *"AzamPay credentials are incomplete. Please update the payment settings."* | One of the required fields is blank. | Complete every field in Settings → Payments. |
| *"Unable to authenticate with AzamPay at the moment. Please try again."* | The authenticator rejected the client ID or secret. | Re-copy both. Confirm the authenticator base URL matches the selected environment. |
| *"AzamPay is unreachable right now…"* | The checkout endpoint could not be connected to. | Check outbound connectivity and the checkout base URL. |
| *"AzamPay rejected the payment request."* | AzamPay refused it; its own message is shown when it sends one. | Read the message. Check the app name matches the portal exactly. |
| Prompts succeed, ledger stays empty | Callbacks are being rejected — most often no callback password saved. | Save the callback password from the AzamPay portal, then re-test. |
| Sandbox works, production does not | The base URLs still point at sandbox. | Change both base URLs together with the environment. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Bank account
Source: https://docs.centipidbilling.com/billing/payment-gateways/bank
Collect M-Pesa payments in Kenya straight into your business bank account through your bank's paybill and account number, with no Daraja API keys needed.
## Collect payments into your bank account
`BANK` sends an M-Pesa STK push to the payer against **your bank's official
M-Pesa paybill**, with your bank account number as the account reference. The
money moves from the payer's M-Pesa directly into your bank account. No Daraja
API keys are requested — the prompt is raised with the platform's Daraja
credentials.
Available to ISPs in **Kenya (KE)**.
## Before you start
1. Have a **business** bank account for the ISP.
2. Know which M-Pesa paybill your bank uses for deposits — you select it from a
list in the form.
Use a business bank account registered to your ISP, not a personal account.
Personal accounts that receive many subscriber deposits can be suspended by
your bank or by M-Pesa.
## Configure the gateway
Select the method from the payment marketplace.
**Receiving bank** (required) is searchable by bank name or paybill number,
and is the official M-Pesa paybill for deposits into that bank.
**Bank account number** (required) is digits only, maximum 40 characters. It
is sent as the account reference, so a wrong value sends money to the wrong
account. Check it twice.
Both fields must be present to switch. Changing the receiving bank clears
the account number on purpose, so an account belonging to the previous bank
cannot be saved by accident — re-enter it after every bank change.
Pay a small amount from the captive portal and confirm it reaches the bank
account, not just the M-Pesa prompt.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Receiving bank | Yes | Selected from the current bank list; a previously saved paybill is kept as an option. |
| Bank account number | Yes | Digits only, maximum 40 characters. Cleared automatically whenever the receiving bank changes. |
## Callback URLs
None. The callback address is sent with every payment request.
## What the payer must provide
A Safaricom phone number, which receives the STK prompt. The bank account number
is filled in as the account reference for them.
## How a payment completes
Centipid Billing raises the STK push against the bank's M-Pesa paybill, with
your bank account number as the account reference.
The payer enters their M-Pesa PIN. The money is deposited to your bank
account by the bank's paybill.
Safaricom posts the result to the platform callback, which records the
payment and applies the subscriber's package asynchronously.
Bank settlement is not instant in the way a paybill or till is. Reconcile
against your bank statement, not only against the ledger.
## Payments typed in by hand
An invoice can offer pay-by-hand instructions, and a TV screen shows a number
the customer types into M-Pesa themselves. On this method **that number is the
Centipid paybill, not your bank's** — money paid that way is collected by the
platform against the subscriber's account reference and remitted to you, rather
than landing in your bank account directly. Prove both flows with a controlled
test payment before moving subscribers onto this method.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| The account number field emptied itself | The receiving bank was changed, which clears it deliberately. | Re-enter the account number for the new bank and save. |
| Payer confirms payment, money is not in the bank account | The account reference did not match an account at that bank. | Verify the saved account number against your bank records, then raise the specific M-Pesa reference with your bank. |
| *"Unable to process payment. Please try again later."* | The STK push failed or Safaricom was unreachable. | Retry. If it persists, raise it with support. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference), and for
symptoms common to all gateways, see
[Payment troubleshooting](/billing/payment-gateways/troubleshooting).
# Centipid Collections
Source: https://docs.centipidbilling.com/billing/payment-gateways/centipid
Let Centipid collect subscriber payments for you, with no provider credentials, then withdraw the balance to your own mobile money number. Listed for Uganda.
## Collect payments through Centipid
`CENTIPID` is the managed collection path. Payments are collected by Centipid on
your behalf rather than into an account you hold with a provider, and the
balance is paid out to you through the **Withdrawals** flow on the Payments
page. You hold no provider credentials at all.
Listed in the country catalog for **Uganda (UG)**. Where it is enabled for an
ISP in Kenya, the form asks for a payout number instead of provider keys.
## Before you start
1. Confirm with support that Centipid Collections is enabled for your account —
this is a commercial arrangement, not a self-service switch.
2. Decide which mobile money number receives your payouts.
## Configure the gateway
Select it from the payment marketplace.
**Payment number** (required in Kenya, maximum 10 characters, starts with
`0`) is the number that receives payouts from Centipid. Outside Kenya the
form asks for nothing — you enter the recipient at withdrawal time instead.
In Kenya the payment number gates the switch. Elsewhere nothing does.
Pay a small amount from the captive portal, confirm the prompt arrives and
the payment reaches the ledger, then confirm it appears under
Collections.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Payment number | Kenya only | Maximum 10 characters, starts with `0`. The number Centipid pays out to. |
Outside Kenya there is no stored recipient: withdrawal details are entered each
time you withdraw, so a compromised login cannot quietly redirect a standing
payout destination.
## Callback URLs
None to register. In Uganda, collections run over the Iotec rail using the
platform's Iotec credentials, and results are posted to
`https:///iotec/callback`.
## What the payer must provide
A mobile money number, which receives the payment prompt. In Kenya the payment
method is labelled **Mpesa** throughout the application; elsewhere it is
labelled **Mobile Money**.
## How a payment completes
Centipid Billing raises the prompt using the platform's own provider
credentials — the M-Pesa rail in Kenya, the Iotec rail in Uganda.
The payer authorizes on their handset.
The provider result records the payment and applies the subscriber's package
asynchronously. The money is held by Centipid, and appears under
Collections.
You request a withdrawal from the Payments page. It is OTP-protected, has a
minimum amount, and dispatches money externally — see
[Collections and withdrawals](/billing/collections-and-withdrawals).
Do not read the payment ledger as your withdrawable balance. Manual and
offline payments, and unsettled transactions, do not fund the wallet. Use the
available balance shown in the withdrawal flow.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | The prompt could not be raised on the platform's provider credentials. | Retry. If it persists, raise it with support — these credentials are not yours to correct. |
| Uganda: payment shows as pending long after the payer confirms | The collection reached the provider but its terminal status has not been read back yet. | Wait for the status sweep to settle it, then raise the transaction reference with support. Do not record a second manual payment. |
| Collections balance is lower than the payment total | Manual, offline, or unsettled payments do not fund the wallet. | Compare against the collections view, not the payments total. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# ClickPesa
Source: https://docs.centipidbilling.com/billing/payment-gateways/clickpesa
Set up ClickPesa hosted checkout for mobile money and bank payments in Tanzania: API key, client ID, the webhook URL, and walled-garden entries for Hotspot.
## Collect payments with ClickPesa
`CLICKPESA` uses a **hosted checkout**: Centipid Billing asks ClickPesa for a
checkout link and sends the payer's browser to it. The payer completes the
payment on ClickPesa's page, and ClickPesa confirms the result on a webhook.
Available to ISPs in **Tanzania (TZ)**, alongside AzamPay, PalmPesa, PawaPay,
PesaPal, Relworx, ZenoPay, PayPal, and DPO.
## Before you start
1. Complete ClickPesa merchant onboarding in an account owned by the ISP.
2. From the ClickPesa dashboard collect the **API key** and the **client ID**.
3. Confirm your workspace has a public HTTPS domain, so ClickPesa can reach the
webhook.
4. **Plan the walled garden.** Because the payer's own browser must load
ClickPesa's checkout page, a Hotspot subscriber who is not yet online cannot
pay unless ClickPesa is reachable pre-authentication.
## Configure the gateway
Select ClickPesa from the payment marketplace.
**API key** (required) is stored as a secret and is not echoed back into the
form after saving.
**Client ID** (required) identifies your ClickPesa account.
Add ClickPesa's checkout domain to the walled garden on every Hotspot
router, then confirm from a device that is not yet authenticated. See
[Captive portal](/network/captive-portal).
Pay a small amount from the captive portal on a real unauthenticated device
— not from an already-online laptop, which would not prove the walled garden
works.
## Credentials
| Field | Required | Notes |
| - | - | - |
| API key | Yes | Secret. |
| Client ID | Yes | Identifies the ClickPesa account. |
## Callback URLs
Settings → Payments shows `https:///api/clickpesa/webhook`. Register
it in the ClickPesa dashboard, and confirm it is not blocked by a firewall or
WAF rule.
## What the payer must provide
Whatever ClickPesa's own checkout page asks for — the payment method is chosen
there, not in the captive portal. The amount and the order reference are fixed
by Centipid Billing before the payer arrives.
The currency is your account's configured currency, defaulting to `TZS`.
## How a payment completes
Centipid Billing exchanges the API key and client ID for a ClickPesa token.
If a checkout request is rejected as unauthorized, the token is refreshed
once and the request retried, so a merely expired token does not fail a
payment.
A checkout URL is generated for the order reference, amount, and currency,
and a local transaction row is written against that reference.
The payer's browser is redirected to ClickPesa and the payment is completed
there.
ClickPesa posts the result to the webhook, which records the payment and
applies the subscriber's package.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"…ClickPesa credentials are not configured."* | The API key or client ID is missing. | Enter both in Settings → Payments. |
| *"…Failed to generate ClickPesa token."* or *"…ClickPesa token missing in response."* | ClickPesa refused the credentials, or answered without a token. | Re-copy the API key and client ID. Confirm the merchant account is live. |
| *"…ClickPesa API request failed with status: 401…"* | The token was rejected even after one refresh. | Verify the credentials belong to the live account, not a sandbox one. |
| *"…Checkout link not found in ClickPesa response"* | ClickPesa accepted the request but returned no checkout URL. | Retry. If it persists, raise the order reference with ClickPesa. |
| The checkout page never loads on a Hotspot device | The walled garden does not allow ClickPesa. | Allow ClickPesa's checkout domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payment completed on ClickPesa, ledger empty | The webhook did not arrive or was not accepted. | Confirm the webhook URL is registered and publicly reachable, then see [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Gateway credential reference
Source: https://docs.centipidbilling.com/billing/payment-gateways/credentials-reference
Every credential field each payment gateway asks for, from Safaricom and Paybill to PawaPay and PayPal, with which values are required and where to find them.
## Review gateway credential requirements
Obtain every value from the provider/merchant account belonging to the ISP. “Required” below reflects the current credential component, except in the explicitly marked backend-only section, where it reflects backend readiness rules. A provider can impose additional dashboard configuration such as callback URLs, IP allowlists, product activation, or settlement verification.
## Kenya and manual instruction methods
### `SAFARICOM`
[Full setup guide](/billing/payment-gateways/safaricom)
* Collection method: Paybill or Till.
* Paybill number **or** normal till number (required, maximum 20 digits).
* M-Pesa shortcode (required; same as paybill in paybill mode, distinct Daraja shortcode in till mode).
* Consumer key (required, secret field).
* Consumer secret (required).
* Passkey (required for STK push).
### `PAYBILL`
[Full setup guide](/billing/payment-gateways/paybill)
* Paybill number (required, digits only, 4–20 characters).
* Account number (optional, up to 20 characters — letters, digits, hyphens and slashes). Only for a SACCO paybill, or one shared with other businesses; it is your account on that paybill. Blank keeps the default account reference.
No Daraja keys are requested: the STK push is raised with the platform's Daraja credentials. See [Paybill](/billing/payment-gateways/paybill).
### `TILL_NUMBER`
[Full setup guide](/billing/payment-gateways/till-number)
* Till number (required, maximum 20 characters).
No Daraja keys are requested: the Buy Goods STK push is raised with the platform's Daraja credentials. See [Till number](/billing/payment-gateways/till-number).
### `BANK`
[Full setup guide](/billing/payment-gateways/bank)
* Receiving bank/paybill (required; selected from the current bank list or saved option).
* Bank account number (required).
Changing the bank/paybill clears the account number so an account for the previous bank is not saved accidentally. Use a business account owned by the ISP.
### `KOPOKOPO`
[Full setup guide](/billing/payment-gateways/kopokopo)
* STK till number (required, starts with `K`, maximum 30 characters).
* Client ID (required).
* Client secret (required).
* API key (required).
### `CENTIPID`
[Full setup guide](/billing/payment-gateways/centipid)
* Kenya: payment number (required, maximum 10 characters, starts with `0`).
* Other supported countries: no stored recipient field in this form; withdrawal recipient details are entered at withdrawal time.
## Regional/mobile-money APIs
### `IOTEC`
[Full setup guide](/billing/payment-gateways/iotec)
* Iotec wallet ID (required).
* Iotec client ID (required).
* Iotec API secret (required).
### `AIRTEL_MONEY`
[Full setup guide](/billing/payment-gateways/airtel-money)
* Airtel client ID (required).
* Airtel client secret (required).
* Country code override (optional ISO two-letter code, maximum 3 characters in the form).
* Currency code override (optional ISO three-letter code, maximum 3 characters).
Leave overrides blank to use your account's country and currency unless provider onboarding requires a different explicit value.
### `PAWAPAY`
[Full setup guide](/billing/payment-gateways/pawapay)
* PawaPay API token (required).
### `CLICKPESA`
[Full setup guide](/billing/payment-gateways/clickpesa)
* API key (required).
* Client ID (required).
### `PALMPESA`
[Full setup guide](/billing/payment-gateways/palmpesa)
* API token (required, secret field).
* API host (optional URL; blank uses the default PalmPesa endpoint).
The API token is the only field required to switch to PalmPesa. Checkout also needs a payer email address and a Tanzanian phone number — see [PalmPesa](/billing/payment-gateways/palmpesa).
### `AZAMPAY`
[Full setup guide](/billing/payment-gateways/azampay)
* Environment: Sandbox or Production (required).
* App name (required; exactly as configured at AzamPay).
* Client ID (required).
* Client secret (required).
* Authenticator base URL (required URL).
* Checkout base URL (required URL).
* Callback password (optional in Sandbox; follow provider requirements for Production).
### `HUBTEL`
[Full setup guide](/billing/payment-gateways/hubtel)
* Hubtel client ID (required).
* Hubtel client secret (required).
* Merchant account number (required; your Hubtel POS Sales ID).
### `ORANGE_MONEY`
[Full setup guide](/billing/payment-gateways/orange-money)
* Merchant key (required; Web Payment key).
* Consumer key (required).
* Consumer secret (required).
Customers complete payment on Orange's hosted checkout and return to the application; verify both return and provider notification behavior.
### `VODACOM_MPESA`
[Full setup guide](/billing/payment-gateways/vodacom-mpesa)
Settings requires:
* merchant code (`vodacom_merchant_code`);
* API key (`vodacom_api_key`, secret);
* public key (`vodacom_public_key`, secret).
Currency (`vodacom_currency`) is optional: `CDF` or `USD`, and `CDF` when not set. The country catalog offers this gateway for the Democratic Republic of the Congo. The gateway page displays the callback URL to register on the Vodacom portal.
## MTN Mobile Money Collections
### `MTN_MOMO`
[Full setup guide](/billing/payment-gateways/mtn-momo)
Settings requires:
* subscription key (`mtn_momo_subscription_key`);
* API user (`mtn_momo_api_user`);
* API key (`mtn_momo_api_key`, secret).
The country catalog includes MTN MoMo for Uganda, Ghana, Côte d’Ivoire, Zambia, Benin, and Cameroon. The gateway page also displays the callback URL your ISP account sends with each RequestToPay.
## Card, bank, and multi-method providers
### `PESAPAL`
[Full setup guide](/billing/payment-gateways/pesapal)
* Consumer key (required).
* Consumer secret (required).
Saving these also registers your IPN URL with PesaPal and stores the id it
issues; PesaPal rejects orders that carry no IPN id, so a registration failure
is reported on the settings page rather than left for checkout.
### `PAYPAL`
[Full setup guide](/billing/payment-gateways/paypal)
* Client ID (required).
* Client secret (required).
* Settlement currency (required; choose from the current currency list).
### `OPAY`
[Full setup guide](/billing/payment-gateways/opay)
* Merchant ID (required).
* Public key (required).
* Private key (required; used for callback signature validation).
### `MONNIFY`
[Full setup guide](/billing/payment-gateways/monnify)
* API key (required).
* Secret key (required; also signs the webhook).
* Contract code (required).
* Environment: Live or Sandbox.
### `RELWORX`
[Full setup guide](/billing/payment-gateways/relworx)
* Relworx account number / `account_no` (required).
* Relworx API key (required).
* Webhook signing key (required).
### `PAYSTACK`
[Full setup guide](/billing/payment-gateways/paystack)
* Live secret key (required; current form expects `sk_live_…`).
* Live public key (required; current form expects `pk_live_…`).
Do not place sandbox keys into this live-key form unless the application/provider configuration explicitly changes.
### `ZENOPAY`
[Full setup guide](/billing/payment-gateways/zenopay)
* API key (required, secret field).
* API host (optional URL; blank uses the default ZenoPay host).
The API key is the only field required to switch to ZenoPay. Checkout also needs
a payer email address and a Tanzanian phone number — see
[ZenoPay](/billing/payment-gateways/zenopay).
### `DPO`
[Full setup guide](/billing/payment-gateways/dpo)
* Company token (required).
* Service type (required numeric product/service code).
### `PAYFAST`
[Full setup guide](/billing/payment-gateways/payfast)
* Merchant ID (required).
* Merchant key (required).
* Passphrase (optional in the form, strongly recommended; it must match PayFast and signs payment/notification data).
## Secret-handling checklist
* [ ] Values come from the provider account owned by this ISP and environment.
* [ ] Secrets are pasted only into masked secret fields.
* [ ] Screenshots/logs do not expose them.
* [ ] Callback signing secrets match the provider dashboard.
* [ ] Test/live credentials are not mixed.
* [ ] A controlled payment proves the full callback and ledger path.
* [ ] Former staff cannot still access the provider account or stored secrets.
# DaliPay
Source: https://docs.centipidbilling.com/billing/payment-gateways/dalipay
Collect Tanzanian mobile money with DaliPay wallet push: the payer approves a PIN prompt without leaving the portal. Covers keys, callback URL and networks.
## Collect payments with DaliPay
`DALIPAY` collects by **wallet push**. The payer enters their number on the
portal, a PIN prompt appears on their phone, and they approve it there. They
never leave the portal page.
Offered in the country catalog for **Tanzania (TZ)**.
Centipid Billing uses two calls from DaliPay's
[Collections API](https://dalipay.co.tz/documentation):
1. `POST /api/v1/collections` sends the PIN prompt to the payer's number.
2. `GET /api/v1/collections/{uuid}/status` reports whether it was paid.
Nothing is credited until the status reads `success`.
## Before you start
Register a merchant account at [dalipay.co.tz](https://dalipay.co.tz) for the
ISP. Test keys work straight away and simulate every payment. Live payouts
("Toa Pesa") need DaliPay to verify the account's KYC first.
## Configure the gateway
Under **API keys**, generate a pair for **Live** (or **Test** to try it
first). Copy the secret key straight away: DaliPay shows it only once.
Enter the **Public key** and **Secret key**.
Copy the **Webhook URL** Centipid shows under Callback URLs into DaliPay's
**Settings**. Copy the **callback secret** DaliPay shows beside it back into
Centipid.
Pay a small amount from the captive portal, approve the prompt on the
phone, and confirm the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Public key | Yes | `gw_pk_test_…` or `gw_pk_production_…`. The key decides test or live. |
| Secret key | Yes | Sent on every request from Centipid's servers only. |
| Callback secret | No | Checks DaliPay's webhook signature. Without it the webhook is ignored and payments connect through the status check alone. |
## Callback URL
Paste `/api/dalipay/callback` on the ISP's domain into DaliPay Settings (the
settings page shows the full URL). DaliPay calls it when a payment succeeds or
fails, and does not retry. So Centipid also checks the payment's status every
5 seconds for about 3 minutes after the prompt is sent. That check is what
connects the payer if the webhook is lost. A webhook whose signature does not
match the callback secret is rejected.
## Networks
DaliPay needs to know the payer's network, and the portal only asks for a
number, so Centipid reads it from the prefix:
| Prefix | Network |
| - | - |
| 074, 075, 076 | Vodacom M-Pesa |
| 068, 069, 078 | Airtel Money |
| 065, 067, 071, 077 | Tigo Pesa (Yas) |
| 061, 062 | HaloPesa |
Any other number, TTCL (073) for example, is refused before a prompt is sent.
AzamPesa is not offered, because its wallets are not tied to a prefix.
## Troubleshooting
* **"Unable to send the DaliPay payment prompt"**: a key is wrong or revoked,
or DaliPay's IP whitelist is on and does not include Centipid's servers
(DaliPay answers `403`). DaliPay's exact response is in the application log.
* **"Enter a Vodacom, Airtel, Tigo or Halotel number"**: the number's prefix is
not in the table above.
* **Test payments succeed but no money arrives**: the keys start `gw_pk_test_`.
Test keys only simulate. Generate a Live pair.
* **The payer paid but did not connect**: search the payment by DaliPay's
reference (`col_…`), shown in the DaliPay Collections ledger.
# DPO Pay
Source: https://docs.centipidbilling.com/billing/payment-gateways/dpo
Set up DPO Pay hosted checkout for cards and mobile money in 12 African countries: company token, service type, callback URLs and Hotspot walled garden.
## Collect payments with DPO Pay
`DPO` uses a **hosted checkout**: Centipid Billing creates a transaction token
with DPO, sends the payer to DPO's payment page, and verifies the token before
crediting anything.
Offered in the country catalog for **Kenya, Uganda, Rwanda, Ghana, Côte
d'Ivoire, South Africa, Tanzania, Zambia, Malawi, Senegal, Zimbabwe, and
Nigeria**.
## Before you start
1. Complete DPO merchant onboarding in an account owned by the ISP.
2. In the DPO dashboard open **Settings → Company Token** and collect the
**company token**.
3. Collect the numeric **service type** for the product you are selling. DPO
issues it per service, and a wrong value is rejected at checkout.
4. Plan the walled garden: the payer's browser must reach
`secure.3gdirectpay.com`, so a Hotspot subscriber who is not yet online
cannot pay unless DPO is reachable pre-authentication.
## Configure the gateway
Select DPO Pay from the payment marketplace.
**Company token** (required, stored as a secret) comes from DPO dashboard →
Settings → Company Token.
**Service type** (required) is the numeric service or product code from your
DPO account.
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal on an unauthenticated device and
confirm the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Company token | Yes | Secret. Identifies your DPO company on every request. |
| Service type | Yes | Numeric service/product code from DPO. |
Both gate the switch.
## Callback URLs
| Name | Path |
| - | - |
| Redirect URL | `https:///tenant/dpo/callback` |
| Back URL | `https:///tenant/dpo/failed` |
Set both in your DPO account. The redirect is where a completed payment returns;
the back URL is where a cancelled or failed one lands.
## What the payer must provide
Whatever DPO's payment page asks for — card or mobile money, depending on what
DPO has enabled for your account and country. The amount and the currency are
fixed before the payer arrives.
## How a payment completes
Centipid Billing posts an XML request to DPO's API and receives a
transaction token.
The payer is redirected to DPO's payment page and completes the payment
there.
On return, the token is verified against DPO. Only a verified successful
result records a payment and applies the package; DPO's own explanation is
stored against the transaction otherwise.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Payment failed: DPO Pay is not fully configured. Please add your company token and service type."* | One of the two fields is missing. | Complete both in Settings → Payments. |
| *"Payment failed: Unable to reach DPO Pay. Please try again later."* | The API could not be reached, or its reply could not be parsed. | Check outbound connectivity to `secure.3gdirectpay.com`, then retry. |
| *"Payment failed: …"* with a DPO explanation | DPO declined the request and returned a reason. | Read the explanation. A wrong service type or an unsupported currency are the usual causes. |
| The payment page never loads on a Hotspot device | The walled garden does not allow DPO. | Allow `secure.3gdirectpay.com` pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| *"Payment not successful"* on return | The token verified, but DPO did not report a successful payment. | Check the transaction on the DPO dashboard. Nothing is credited. |
| *"Payment reference not found"* | The returned token has no matching local checkout. | Raise it with support with the DPO transaction token. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Hubtel
Source: https://docs.centipidbilling.com/billing/payment-gateways/hubtel
Set up Hubtel mobile money collections in Ghana: client ID, client secret and POS Sales ID, the callback URL, and how the payer's mobile network is detected.
## Collect payments with Hubtel
`HUBTEL` sends a mobile money prompt to the payer's phone through Hubtel's
Direct Receive Money API, into the ISP's own Hubtel merchant account. The payer approves it on their handset, and Hubtel
confirms the result on a callback.
Available to ISPs in **Ghana (GH)**, alongside MTN MoMo, PawaPay, Paystack,
PayPal, and DPO.
## Before you start
1. Complete Hubtel merchant onboarding in an account owned by the ISP.
2. In the Hubtel dashboard open **API & Integrations → API Credentials** and
collect the **client ID** and **client secret**.
3. Note your **merchant account number**, which Hubtel also calls the
**POS Sales ID**. Every charge is made to this account, and Hubtel refuses
charges that do not name it.
4. Confirm your workspace has a public HTTPS domain, so Hubtel can reach the
callback.
## Configure the gateway
Select Hubtel from the payment marketplace.
**Hubtel client ID** (required) comes from API & Integrations → API
Credentials.
**Hubtel client secret** (required) is stored as a secret and is not echoed
back into the form after saving. The pair is sent as HTTP basic
authentication on every request.
**Merchant account number** (required) is your Hubtel POS Sales ID.
Pay a small amount from the captive portal and confirm the prompt arrives on
the handset and the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Hubtel client ID | Yes | API & Integrations → API Credentials. |
| Hubtel client secret | Yes | Secret. |
| Merchant account number | Yes | Your Hubtel POS Sales ID. |
## Callback URLs
Settings → Payments shows `https:///api/hubtel/callback`. It is also
sent with every payment request as the primary callback, so there is normally
nothing to register — but confirm it is not blocked by a firewall or WAF rule.
## What the payer must provide
**A Ghanaian mobile money number.** The network is detected from the number's
prefix, and a number whose prefix is not recognized is refused **before** any
request reaches Hubtel:
| Network | Prefixes |
| - | - |
| MTN | `024`, `054`, `055`, `059`, `025` |
| Vodafone | `020`, `050` |
| AirtelTigo | `026`, `056`, `057`, `027` |
| Glo | `023` |
Numbers are accepted with or without the `233` country code and with or without
a leading zero. The currency is your account's configured currency, defaulting
to `GHS`.
Authorization happens on the handset, so no Hubtel domain needs to be added to
the captive walled garden.
## How a payment completes
Centipid Billing posts the charge to Hubtel's receive-mobile-money endpoint
for your merchant account, with the amount, the payer's number, the detected channel, and a unique
client reference.
The payer approves the prompt on their handset.
Hubtel posts the outcome to the callback, which records the payment and
applies the subscriber's package.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Hubtel credentials are not configured."* | The client ID or secret is missing. | Enter both in Settings → Payments. |
| *"Hubtel merchant account number (POS Sales ID) is not configured."* | The merchant account number is missing. No request was sent. | Enter your POS Sales ID in Settings → Payments → Hubtel. |
| *"A phone number is required to initiate a Hubtel payment."* | Checkout had no phone number. | Collect one before retrying. |
| *"Unable to determine the customer's mobile money network from the provided phone number."* | The prefix is not in the table above. No request was sent, and the payer was not charged. | Re-enter the number in Ghanaian format. If the prefix is genuinely new, raise it with support. |
| A message from Hubtel on a failed request | Hubtel refused the charge and its own error is shown. | Read the message — it usually names the credential or the wallet at fault. |
| *"Hubtel did not confirm the request. If a prompt arrives on your phone, approve it; otherwise try again in a moment."* | Hubtel did not answer in time. The charge is not re-sent, because the prompt may already be on the phone; if the payer approves it, the callback still grants the package. | If it keeps happening, check outbound connectivity from the application host. |
| Prompt approved, ledger stays empty | The callback did not arrive. | Confirm `https:///api/hubtel/callback` is publicly reachable, then see [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Payment gateways
Source: https://docs.centipidbilling.com/billing/payment-gateways/index
Compare the 30 payment gateways across 72 countries, see which need your own API keys or a hosted checkout, then configure, test and safely switch your gateway.
## Choose a payment gateway
Open **Settings → Payments**. Which gateways you are offered depends on three
things: your country, account enablement, and commercial onboarding with the
provider. The catalog contains 30 gateway codes across 72 countries. Each one
has a credential form in the current interface.
Every gateway below has a setup guide of its own. It covers what to collect
before you start, the exact fields, and the callback URLs. It also explains how
a payment completes and what each error means.
## Current gateway catalog
| Code | Method | Integration style |
| - | - | - |
| [`SAFARICOM`](/billing/payment-gateways/safaricom) | Safaricom M-Pesa | STK push with your own Daraja API keys, paybill or till |
| [`PAYBILL`](/billing/payment-gateways/paybill) | Paybill without API keys | STK push to your paybill using the platform's Daraja keys; supports a SACCO or shared paybill via an account number |
| [`TILL_NUMBER`](/billing/payment-gateways/till-number) | Till without API keys | Buy Goods STK push to your till using the platform's Daraja keys |
| [`BANK`](/billing/payment-gateways/bank) | Bank account | STK push against your bank's M-Pesa paybill, to your account number |
| [`KOPOKOPO`](/billing/payment-gateways/kopokopo) | Kopo Kopo | STK collection through the Kopo Kopo API |
| [`CENTIPID`](/billing/payment-gateways/centipid) | Centipid Collections | Managed collection with withdrawals |
| [`IOTEC`](/billing/payment-gateways/iotec) | Iotec | Ugandan mobile money, status read back from Iotec |
| [`RELWORX`](/billing/payment-gateways/relworx) | Relworx | Mobile money aggregator with a signed webhook |
| [`AIRTEL_MONEY`](/billing/payment-gateways/airtel-money) | Airtel Money | Airtel Africa API — **not offered by the country catalog** |
| [`PAWAPAY`](/billing/payment-gateways/pawapay) | PawaPay | Pan-African mobile money on one API token, polled to completion |
| [`PALMPESA`](/billing/payment-gateways/palmpesa) | PalmPesa | Tanzanian wallet push, polled to completion |
| [`CLICKPESA`](/billing/payment-gateways/clickpesa) | ClickPesa | Hosted checkout, webhook confirmation |
| [`AZAMPAY`](/billing/payment-gateways/azampay) | AzamPay | Wallet push, callback authenticated by a callback password |
| [`ZENOPAY`](/billing/payment-gateways/zenopay) | ZenoPay | Wallet push, polled to completion |
| [`HUBTEL`](/billing/payment-gateways/hubtel) | Hubtel | Ghanaian mobile money, network detected from the payer's number |
| [`PAYSTACK`](/billing/payment-gateways/paystack) | Paystack | Hosted checkout, verified against Paystack |
| [`OPAY`](/billing/payment-gateways/opay) | OPay | Hosted cashier, signed callback |
| [`MONNIFY`](/billing/payment-gateways/monnify) | Monnify | Hosted checkout, signed webhook re-verified against Monnify |
| [`PESAPAL`](/billing/payment-gateways/pesapal) | PesaPal | Hosted checkout, IPN URL registered on save |
| [`PAYPAL`](/billing/payment-gateways/paypal) | PayPal | Approve-then-capture; sets your dashboard's billing currency |
| [`DPO`](/billing/payment-gateways/dpo) | DPO Pay | Hosted checkout, token verified against DPO |
| [`PAYFAST`](/billing/payment-gateways/payfast) | PayFast | Signed redirect and signed ITN confirmation |
| [`ORANGE_MONEY`](/billing/payment-gateways/orange-money) | Orange Money | Web Payment hosted checkout |
| [`MTN_MOMO`](/billing/payment-gateways/mtn-momo) | MTN Mobile Money (MoMo) | Handset RequestToPay, callback hint plus verified polling |
| [`VODACOM_MPESA`](/billing/payment-gateways/vodacom-mpesa) | Vodacom M-Pesa (DRC, Tanzania) | Open API C2B prompt on the handset, confirmed by callback |
| [`RAZORPAY`](/billing/payment-gateways/razorpay) | Razorpay | Hosted payment link for Indian UPI, cards, netbanking and wallets, signed webhook re-verified against Razorpay |
| [`SELCOM`](/billing/payment-gateways/selcom) | Selcom | Tanzanian wallet push |
| [`DALIPAY`](/billing/payment-gateways/dalipay) | DaliPay | Tanzanian wallet push |
| [`STRIPE`](/billing/payment-gateways/stripe) | Stripe | Hosted Checkout on your own Stripe account in Stripe's 44 self-serve countries, signed webhook re-verified against Stripe |
| [`XENDIT`](/billing/payment-gateways/xendit) | Xendit | Hosted payment page on your own Xendit account for GCash, Maya, QRIS, PromptPay and FPX in five South-East Asian countries, webhook re-verified against Xendit |
## Know before you choose
Four things decide whether a gateway will work for you. None of them is
visible from the marketplace card.
**One gateway cannot be selected through full self-service today.**
[Airtel Money](/billing/payment-gateways/airtel-money) has a working form,
but no country offers it, so it never appears in the marketplace.
Do not plan a migration onto it without talking to support first.
### Where the payer authorizes
**On their handset** — Safaricom, Paybill, Till, Bank, Kopo Kopo, Centipid,
Iotec, Relworx, Airtel Money, PawaPay, PalmPesa, ZenoPay, AzamPay, Hubtel,
MTN MoMo, Vodacom M-Pesa, Selcom, DaliPay. Nothing extra is needed in the captive walled garden.
**In a hosted checkout page** — ClickPesa, Paystack, OPay, Monnify,
PesaPal, PayPal, DPO, PayFast, Orange Money, Razorpay, Stripe, Xendit. The payer's own browser
must reach the provider. So a Hotspot subscriber who is not yet online **cannot
pay unless that provider is reachable pre-authentication**. Allow it in the
walled garden. Then test from a device that is genuinely not logged in.
### Whether you need provider API keys
Paybill, Till, and Bank collect M-Pesa without any Daraja keys of your own.
The prompt is raised with the platform's Daraja credentials. They are real STK
pushes, not printed instructions. Centipid Collections goes further: it needs no
provider account at all. The balance is paid out through Withdrawals.
Every other gateway needs credentials from an account the ISP owns.
### What completes a payment
A payment is only complete when the money is confirmed back to Centipid Billing.
Gateways differ in how that happens: a signed webhook, a status poll, or a
capture call. The failure mode is the same in every case: **the payer is charged
and never provisioned.** Each guide names what to check first for that gateway.
## Configure a gateway
Obtain credentials from an account owned by the ISP. Confirm four things
with the provider: live versus sandbox status, settlement currency,
supported country, and callback requirements.
Select the intended method and read its guide before filling the form.
Paste each value into its matching field. Never reuse credentials from
another ISP's account, and never mix test and live values.
Switching may require an OTP or a confirmation dialog. Saving validates the
form. It does not prove the provider accepts your credentials.
Use a controlled amount. Verify initiation, provider authorization and
confirmation. Then check the payment ledger, the subscriber's package and the
receipt. Finally, confirm settlement into your own account.
## Switch an existing account
1. Resolve or record pending transactions on the old gateway.
2. Confirm the new credentials and callback configuration.
3. Check captive walled-garden reachability for the new provider.
4. Update payment instructions and subscriber communications.
5. Switch during a monitored window.
6. Run a controlled payment from both the captive portal and the customer portal.
7. Retain the old reconciliation data according to policy.
See the [credential reference](/billing/payment-gateways/credentials-reference)
for every gateway's fields in one place. See
[Payment troubleshooting](/billing/payment-gateways/troubleshooting) for symptoms
that are not specific to one gateway.
# Iotec
Source: https://docs.centipidbilling.com/billing/payment-gateways/iotec
Collect Ugandan mobile money through Iotec Pay: enter your wallet ID, client ID and API secret, check the callback URL, and see when a subscriber goes live.
## Collect payments with Iotec
`IOTEC` collects Ugandan mobile money through Iotec Pay. Centipid Billing posts
a collection request, the payer authorizes it on their handset, and the
subscriber is provisioned once Iotec reports the collection successful.
Available to ISPs in **Uganda (UG)**, alongside Centipid Collections, MTN MoMo,
PawaPay, PesaPal, and DPO.
## Before you start
1. Complete Iotec merchant onboarding in an account owned by the ISP.
2. From the Iotec dashboard collect the **wallet ID**, the **client ID**, and
the **API secret**.
3. Confirm your workspace has a public HTTPS domain, so Iotec can post results.
## Configure the gateway
Select Iotec from the payment marketplace.
**Iotec wallet ID** and **Iotec client ID** are both required. The wallet ID
decides which Iotec wallet the money lands in.
**Iotec API secret** (required) is stored as a secret and is not echoed back
into the form after saving.
All three fields must be present to switch.
Pay a small amount from the captive portal and confirm the prompt arrives,
the payment reaches the ledger, and the package is applied.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Iotec wallet ID | Yes | Identifies the collecting wallet. |
| Iotec client ID | Yes | API client identity. |
| Iotec API secret | Yes | Secret. |
## Callback URLs
Settings → Payments shows `https:///iotec/callback`. Confirm it is
not blocked by a firewall or WAF rule.
The callback is treated as a hint, not as proof. Centipid Billing re-reads the
collection's status from Iotec before crediting anything, so a callback alone
never provisions a subscriber.
## What the payer must provide
A Ugandan mobile money number, which receives the authorization prompt. Because
authorization happens on the handset, no Iotec domain needs to be added to the
captive walled garden.
## How a payment completes
Centipid Billing authenticates against Iotec (the access token is cached for
just under five minutes) and posts the collection.
Iotec answers with a collection id and a status. `Pending`, `SentToVendor`,
and `Success` all count as accepted — the request is on its way to the
mobile money vendor and the payer may already have been charged.
The payer approves on their handset.
The status is read back from Iotec — by callback, and by a background sweep
for collections that never got one. On `Success` the payment is recorded and
the package applied.
Iotec's collect response returns only a status and an id — it does not echo
back the amount or the phone number that was sent. Reconcile against what
Centipid Billing sent, not against the response.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Failed to authenticate with Iotec"* | Iotec rejected the client ID or API secret. | Re-copy both from the Iotec dashboard. Confirm the account is live. |
| *"Payment failed"* | Iotec returned a terminal failure for the collection. | Ask the payer to confirm their wallet balance and status, then retry. |
| *"Payment status unknown"* or *"Error code…"* | The request may or may not have reached Iotec. | **Do not retry blindly** — the payer may already have been charged. Let the status sweep settle it, then check the ledger. |
| Payment sits pending long after the payer confirms | The terminal status has not been read back yet. | Wait for the sweep. If it stays pending, raise the collection id with Iotec. |
| Payer charged, service not applied | The status never reached `Success` locally. | Check the collection on the Iotec dashboard, then see [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Kopo Kopo
Source: https://docs.centipidbilling.com/billing/payment-gateways/kopokopo
Send M-Pesa STK prompts in Kenya through Kopo Kopo into your K-prefixed STK till: client ID and secret, API key, callback URL, and next-business-day settlement.
## Collect payments with Kopo Kopo
`KOPOKOPO` raises an M-Pesa STK prompt through Kopo Kopo's Incoming Payments
API, against your Kopo Kopo STK till. Money settles to the bank account attached
to your Kopo Kopo account, typically the next business day.
Available to ISPs in **Kenya (KE)**.
## Before you start
1. Complete Kopo Kopo merchant onboarding in an account owned by the ISP.
2. From the Kopo Kopo dashboard collect the **STK till number** (it starts with
`K`), the **client ID**, the **client secret**, and the **API key**.
3. Confirm your workspace has a public HTTPS domain — Kopo Kopo posts the result
to a callback on it.
## Configure the gateway
Select Kopo Kopo from the payment marketplace.
**STK till number** (required, maximum 30 characters) must start with `K`.
This is the Kopo Kopo STK till, not the plain M-Pesa Buy Goods number your
customers see.
**Client ID**, **client secret**, and **API key** are all required. The
secret and the API key are stored as secrets and are not echoed back into
the form after saving.
All four fields must be present to switch. Switching gateways may require an
OTP confirmation.
Pay a small amount from the captive portal and confirm the STK prompt names
your business and the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| STK till number | Yes | Must start with `K`, maximum 30 characters. |
| Client ID | Yes | From the Kopo Kopo dashboard. |
| Client secret | Yes | Secret. |
| API key | Yes | Secret. |
The Kopo Kopo access token is cached for 10 minutes. After rotating
credentials, allow up to 10 minutes — or a controlled test failure — before
concluding that new keys are not working.
## Callback URLs
The callback address is sent with every payment request, so there is nothing to
register in the Kopo Kopo dashboard. Requests are sent to
`https://api.kopokopo.com`, and the result is posted back to
`https:///api/kopokopo/callback`. Confirm that address is not blocked
by a firewall or WAF rule.
## What the payer must provide
A Safaricom phone number, which receives the STK prompt. The subscriber's first
and last name are sent with the request, so keep subscriber profiles accurate —
they appear on the Kopo Kopo transaction.
## How a payment completes
Centipid Billing authenticates against Kopo Kopo, then posts an incoming
payment for the STK till with the amount, the payer's phone number, and
`KES` as the currency.
The payer enters their M-Pesa PIN.
Kopo Kopo posts the outcome to the callback, which records the payment and
applies the subscriber's package asynchronously.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to initialize payment. Please try again later."* | Kopo Kopo returned no access token. | Re-check the client ID, client secret, and API key. Confirm the account is live, then allow for the 10-minute token cache. |
| *"Unable to process payment. Please try again later."* | Authentication or the STK request failed. | Verify the credentials and that the STK till starts with `K` and is active. |
| Prompt arrives but the ledger stays empty | The callback did not arrive or did not match a checkout. | Confirm `https:///api/kopokopo/callback` is publicly reachable, then see [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
| Money in Kopo Kopo, not in the bank | Kopo Kopo settles to your bank on its own schedule. | Reconcile against the Kopo Kopo settlement report, not only the ledger. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Monnify
Source: https://docs.centipidbilling.com/billing/payment-gateways/monnify
Set up Monnify hosted checkout for bank transfer, card and USSD payments in Nigeria: API key, secret key, contract code, live or sandbox, and the webhook.
## Collect payments with Monnify
`MONNIFY` uses a **hosted checkout** offering bank transfer, card, and USSD.
Centipid Billing initializes a transaction, sends the payer to Monnify's
checkout page, and confirms the result on a signed webhook that is re-verified
against Monnify before anything is credited.
Offered in the country catalog for **Nigeria (NG)**.
## Before you start
1. Complete Monnify merchant onboarding in an account owned by the ISP.
2. From the Monnify dashboard collect the **API key**, the **secret key**, and
the **contract code**.
3. Decide whether you are configuring **Live** or **Sandbox** — they are
different hosts, and credentials are not interchangeable.
4. Plan the walled garden: the payer's browser must reach Monnify's checkout
page, so a Hotspot subscriber who is not yet online cannot pay unless Monnify
is reachable pre-authentication.
## Configure the gateway
Select Monnify from the payment marketplace.
Both are required and stored as secrets. The secret key does double duty: it
authenticates requests **and** signs the webhook Monnify sends back.
**Contract code** (required) identifies the contract the money settles
against.
**Environment** is `Live` or `Sandbox`. Live requests go to
`https://api.monnify.com`, sandbox to `https://sandbox.monnify.com`.
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal on an unauthenticated device, and
confirm the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| API key | Yes | Secret. |
| Secret key | Yes | Secret. Also signs the webhook. |
| Contract code | Yes | From the Monnify dashboard. |
| Environment | No | `Live` or `Sandbox`. Decides which host requests go to. |
The API key, secret key, and contract code gate the switch; the environment does
not, so check it deliberately.
## Callback URLs
| Name | Path |
| - | - |
| Webhook URL | `https:///api/monnify/callback` |
| Redirect URL | `https:///api/monnify/return` |
Register the webhook URL in the Monnify dashboard. The redirect is where the
payer's browser returns after checkout.
Webhooks carry an HMAC-SHA512 `monnify-signature` computed with your **secret
key**. A wrong secret key means every webhook is rejected with HTTP 400, so
payers are charged and never provisioned.
## What the payer must provide
Whatever the Monnify checkout page asks for — card, bank transfer, or USSD. The
payer's name and email are sent with the request when known; when no email is
available a placeholder is sent so the transaction can be initialized, so do not
rely on the email shown in Monnify to identify a subscriber.
The currency is your account's configured currency, defaulting to `NGN`.
Amounts are sent in **naira**, not kobo. Monnify does not use the smallest
unit here, so the ledger amount and the Monnify amount should match exactly —
a factor-of-100 difference means something is wrong, not a unit convention.
## How a payment completes
Centipid Billing authenticates, initializes the transaction with the amount,
reference, and contract code, and receives a checkout URL. A pending row is
written against the payment reference.
The payer completes the payment on Monnify's page.
Monnify posts the signed webhook. The signature is validated, the result is
then re-verified against the Monnify API, and only then is the payment
recorded and the package applied. Repeated webhooks are ignored rather than
double-credited.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | Credentials are missing, authentication failed, or initialization was refused. | Check the API key, secret key, and contract code, and that the environment matches the credentials. |
| Sandbox works, live does not | The environment still says `Sandbox`, or live credentials were pasted into a sandbox configuration. | Change the environment and the credentials together. |
| The checkout page never loads on a Hotspot device | The walled garden does not allow Monnify. | Allow Monnify's checkout domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments complete at Monnify, ledger stays empty | Webhooks are being rejected — usually a wrong secret key, or a webhook URL that is not publicly reachable. | Re-copy the secret key, confirm the webhook URL is registered and reachable, then re-test. |
| *"Monnify payment verification failed"* | The re-verification against Monnify did not confirm the payment. | Check the transaction on the Monnify dashboard before recording anything by hand. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# MTN Mobile Money (MoMo)
Source: https://docs.centipidbilling.com/billing/payment-gateways/mtn-momo
Connect MTN MoMo Collections in Uganda, Ghana, Côte d'Ivoire, Zambia, Benin or Cameroon: callback host, sandbox or production, and verified settlement.
## MTN Mobile Money (MoMo)
`MTN_MOMO` collects through MTN's MoMo Collections API. Centipid sends a
RequestToPay to the subscriber's MoMo number, the subscriber approves it on
their handset, and Centipid verifies the result directly with MTN before
recording the payment or restoring service.
The gateway catalog offers MTN MoMo in **Uganda, Ghana, Côte d'Ivoire, Zambia,
Benin, and Cameroon**.
## Before you start
Your MTN account must be approved for the **Collections** product in the target
market. Obtain these values from MTN:
| Value | Settings field |
| - | - |
| Collections subscription key | Collections subscription key |
| API user UUID | API user |
| API key issued for that user | API key |
The API user's registered callback host must match the hostname shown on the
Centipid gateway page. Production activation, credentials, settlement currency,
and commercial approval are handled by the MTN operation in each country.
## Connect MTN MoMo
Go to **Settings → Payments → MTN Mobile Money (MoMo)**.
Copy the displayed callback URL when MTN asks for it. The callback host must
be your current Centipid workspace hostname.
Enter the Collections subscription key, API user, and API key, then save.
The subscription key and API key are handled as secret inputs.
Complete the payment-gateway change verification and connect MTN MoMo.
## How settlement works
1. Centipid saves the checkout reference and subscriber/package context before
sending RequestToPay.
2. MTN returns `202 Accepted` and prompts the subscriber's handset.
3. MTN may call the workspace callback URL. Because that callback is unsigned,
Centipid treats it only as a signal to query MTN.
4. A background job polls MTN independently, so settlement still completes when
the callback is missed or the payer closes the browser.
5. Successful status creates one checkout-keyed payment and runs the normal
exactly-once subscriber provisioning pipeline.
The captive payment screen also performs a throttled verified status query after
the callback has been silent, so cancellation or failure can be shown promptly.
## Sandbox and production
| Environment | API host | Target environment | Currency |
| - | - | - | - |
| Sandbox / non-production | `https://sandbox.momodeveloper.mtn.com` | `sandbox` | `EUR` (required by MTN sandbox) |
| Production | `https://proxy.momoapi.mtn.com` | Country-specific MTN environment | Your country's MTN settlement currency |
Sandbox payments use MTN's published test numbers and outcomes. Never use a real
subscriber wallet as a sandbox fixture.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| Credentials are required when connecting | One or more Collections credentials are missing. | Re-enter all three values from the same MTN API user/subscription. |
| *"Unable to authenticate with MTN Mobile Money…"* | MTN rejected the subscription key, API user, or API key. | Confirm the product subscription and rotate the API key if necessary. |
| Request remains pending | The handset has not approved yet, MTN has not reached a terminal state, or MTN is temporarily unreachable. | Check the subscriber handset, then allow the built-in polling window to finish before initiating another request. |
| Callback does not arrive | MTN could not reach the registered host, or callback delivery was missed. | Confirm the API user's callback host. Background polling still verifies settlement. |
| Production returns resource-not-found or access-denied | Sandbox credentials or the wrong country product are being used against production. | Ask the relevant MTN operation to confirm production activation and credentials. |
Do not advise a payer to retry while the first request is still pending. An
ambiguous network response can still represent an accepted RequestToPay; the
saved reference and background query are the safe way to determine its result.
# OPay
Source: https://docs.centipidbilling.com/billing/payment-gateways/opay
Set up OPay hosted checkout for card, bank transfer and wallet payments in Nigeria, Pakistan and Egypt: merchant ID, public and private keys, and callbacks.
## Collect payments with OPay
`OPAY` uses a **hosted cashier**: Centipid Billing creates a checkout session,
sends the payer to OPay's page, and confirms the result on a signed callback.
Offered in the country catalog for **Nigeria (NG)**, **Pakistan (PK)** and **Egypt (EG)**.
## Before you start
1. Complete OPay merchant onboarding in an account owned by the ISP.
2. From the OPay dashboard collect the **merchant ID**, the **public key**, and
the **private key**.
3. Plan the walled garden: the payer's browser must reach OPay's cashier page,
so a Hotspot subscriber who is not yet online cannot pay unless OPay is
reachable pre-authentication.
## Configure the gateway
Select OPay from the payment marketplace.
**Merchant ID** (required) is sent as a header on every request.
**Public key** (required) authenticates outgoing checkout requests.
**Private key** (required, stored as a secret) is what validates the
callback signature. Without the right value, confirmations are rejected.
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal on an unauthenticated device, and
confirm both the cashier page loads and the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Merchant ID | Yes | Sent as the `MerchantId` header. |
| Public key | Yes | Bearer token on checkout requests. |
| Private key | Yes | Secret. Validates the HMAC-SHA512 callback signature. |
Requests go to OPay's live API. There is no sandbox switch on this form, so test
with a small real amount rather than with test credentials.
## Callback URLs
Settings → Payments shows three:
| Name | Path |
| - | - |
| Webhook URL | `https:///api/opay/callback` |
| Return URL | `https:///api/opay/return` |
| Cancel URL | `https:///api/opay/cancel` |
All three are also sent with every checkout request. Register them in the OPay
dashboard where OPay requires it, and confirm they are not blocked by a firewall
or WAF rule.
Callbacks are verified with an HMAC-SHA512 signature computed with your
**private key**. A wrong private key means every callback is rejected — payers
are charged and never provisioned. If checkout works but the ledger stays
empty, suspect this key first.
## What the payer must provide
Whatever OPay's cashier page asks for — bank transfer, card, or the OPay wallet.
The payer's email, phone number, and name are sent with the request when known,
so keep subscriber profiles accurate.
The country and currency come from your account's country. A checkout session
expires **30 minutes** after it is created.
## How a payment completes
Centipid Billing creates the cashier session with the amount in minor units,
the reference, and the return, cancel, and callback URLs.
The payer completes the payment on OPay's page.
OPay posts a signed callback. The signature is verified, the transaction
matched on its reference, and the payment status re-read from OPay rather
than trusted from the callback body alone. Repeated callbacks for a
transaction already recorded are ignored, not double-credited.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Failed to initiate OPay payment"* | OPay refused the checkout request; its own message is shown when it sends one. | Verify the merchant ID and public key, and that the account is live for your country. |
| *"An error occurred while processing your payment: …"* | The request threw before completing. | Check outbound connectivity to OPay, then retry. |
| The cashier page never loads on a Hotspot device | The walled garden does not allow OPay. | Allow OPay's cashier domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments complete at OPay, ledger stays empty | Callbacks are being rejected — most often a wrong private key, or a callback URL that is not publicly reachable. | Re-copy the private key, confirm the URL is reachable, then re-test. |
| The payer waited too long and the page expired | Sessions expire after 30 minutes. | Start a fresh checkout rather than reusing the old page. |
| *"Failed to verify payment status"* | The status query to OPay failed. | Retry the verification; check the reference on the OPay dashboard before recording anything by hand. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Orange Money
Source: https://docs.centipidbilling.com/billing/payment-gateways/orange-money
Set up Orange Money Web Payment in Côte d'Ivoire, Burkina Faso, Cameroon, DR Congo and Senegal: merchant key, consumer key and secret, and the walled garden.
## Collect payments with Orange Money
`ORANGE_MONEY` uses Orange's **Web Payment** hosted checkout: Centipid Billing
creates a payment, sends the payer to Orange's page, and reads the payment state
back from Orange before crediting anything.
Offered in the country catalog for **Côte d'Ivoire, Burkina Faso, Cameroon,
DR Congo, and Senegal**.
## Before you start
1. Create an application in the [Orange Developer portal](https://developer.orange.com)
under an account owned by the ISP, and subscribe it to Web Payment.
2. Collect the **merchant key** (the Web Payment key), the **consumer key**, and
the **consumer secret**.
3. Plan the walled garden: the payer's browser must reach Orange's checkout
page, so a Hotspot subscriber who is not yet online cannot pay unless Orange
is reachable pre-authentication.
## Configure the gateway
Select Orange Money from the payment marketplace.
**Merchant key** (required) is the Web Payment merchant key from your Orange
Developer app — not the consumer key.
Both are required and stored as secrets. They authenticate against the
Orange Money API using client credentials.
Pay a small amount from the captive portal on an unauthenticated device.
Confirm the Orange checkout page loads, the payer is returned, and the
payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Merchant key | Yes | The Web Payment key from your Orange Developer app. |
| Consumer key | Yes | Secret. |
| Consumer secret | Yes | Secret. |
All three gate the switch.
## Callback URLs
None to register by hand. The return address and the notification address are
both sent with each payment, carrying that payment's own order id.
## What the payer must provide
Whatever Orange's checkout page asks for. The amount is formatted for the
currency before the payment is created — most currencies served here have no
minor unit, while `CDF` carries two decimals — so the amount the payer sees
should match the ledger exactly.
## How a payment completes
Centipid Billing exchanges the consumer key and secret for a bearer token,
which is cached until it expires.
A Web Payment is created for the order id and amount. Orange returns a
checkout URL and a pay token.
The payer completes the payment on Orange's page and is returned.
The payment state is read back from Orange: `SUCCESS`, `PENDING`, `FAILED`,
or `EXPIRED`. Only `SUCCESS` records a payment and applies the package.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| Checkout fails before Orange's page loads | Credentials are missing, or Orange rejected them. | Confirm all three fields are saved, and that the app is subscribed to Web Payment in the Orange Developer portal. |
| *"Orange Money payment initiation failed."* | Orange refused to create the payment; its own message is shown when it sends one. | Read the message. A merchant key that is not a Web Payment key is a common cause. |
| The checkout page never loads on a Hotspot device | The walled garden does not allow Orange. | Allow Orange's checkout domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payment shows `PENDING` long after the payer confirms | Orange has not settled it. | Re-check the state before advising a retry — a retry can charge the payer twice. |
| Payment shows `EXPIRED` | The payer took too long on Orange's page. | Start a fresh checkout. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# PalmPesa
Source: https://docs.centipidbilling.com/billing/payment-gateways/palmpesa
Collect Tanzanian mobile money with PalmPesa: add the API token from your verified account, optionally override the API host, and test a small payment.
## Collect payments with PalmPesa
PalmPesa (Eagle Star Technology) is a Tanzanian mobile-money collection gateway. Centipid Billing pushes a payment request to the payer's wallet, the payer authorizes it on their handset, and the subscriber is provisioned once PalmPesa confirms the order.
PalmPesa is offered to ISPs in **Tanzania (TZ)**, alongside ClickPesa, AzamPay, PawaPay, PesaPal, Relworx, ZenoPay, PayPal, and DPO. Provider API documentation is published at [documentation.palmpesa.co.tz](https://documentation.palmpesa.co.tz).
## Before you start
1. Complete PalmPesa merchant onboarding in an account owned by the ISP, and have the account verified.
2. Collect the **API token** from the PalmPesa dashboard.
3. Confirm the settlement account and the currency PalmPesa will settle in.
4. Confirm your Centipid Billing host is reachable from the public internet, so PalmPesa can deliver callbacks.
## Configure the gateway
Select PalmPesa from the payment marketplace to open its configuration form.
**API token** (required) is issued on your PalmPesa dashboard once the account is verified. It is stored as a secret and is not echoed back into the form after saving.
**API host** (optional) overrides the endpoint Centipid Billing calls. Leave it empty to use the default PalmPesa endpoint. Only set it if PalmPesa has issued your account a different host.
Saving validates the form; it does not prove the token works. Switching to PalmPesa requires the API token to be present and may require an OTP confirmation.
Pay a small amount from the **captive portal**. Verify the wallet prompt arrives, the payment lands in the ledger with method **PalmPesa**, and the subscriber's package is applied. See the limitation below before testing from the customer portal.
The callback URL is sent to PalmPesa on every payment request, so there is nothing to register in the PalmPesa dashboard. Settings → Payments still shows it under **Callback URLs** (`https:///api/palmpesa/callback`) so you can confirm the address PalmPesa will call, and check it is not blocked by a firewall or WAF rule.
## Credentials
| Field | Required | Notes |
| - | - | - |
| API token | Yes | Secret. Issued on the PalmPesa dashboard after account verification. The only field required to switch to PalmPesa. |
| API host | No | Falls back to the platform default endpoint. Enter a full URL, for example `https://palmpesa.co.tz`. |
## What the payer must provide
PalmPesa rejects a payment request that carries no email address. Centipid Billing supplies one for you — payers are never asked to type an address.
* **Email address (supplied automatically).** Neither the captive portal nor the customer portal asks the payer for an email. The subscriber's saved profile email is used when there is one; otherwise an address is derived from the phone number being paid with, on an unroutable domain. A hotspot payer with no account can therefore pay normally. If PalmPesa ever emails a receipt, only payers with a real profile email will receive it.
* **Tanzanian phone number (required).** Accepted as `07…`, `06…`, or with the `255` country code; the number is normalized before it is sent.
* **Amount.** Rounded to a whole number before the request is sent.
Because authorization happens on the payer's handset rather than in a hosted checkout page, no PalmPesa domain needs to be added to the captive walled garden for the payer's browser.
## How a payment completes
Centipid Billing calls PalmPesa's V2 async API, `POST /api/v2/async/payments`. PalmPesa answers with an `order_id`, which becomes the local transaction reference that everything afterwards reconciles against.
The payer approves the request on their phone.
A background job polls `GET /api/v2/async/payments/{order_id}` every 5 seconds, for up to 40 attempts (about 3 minutes 20 seconds), until the order reaches a terminal state. **This poller — not the callback — is what completes the payment**, so a payment still completes when the payer closes the captive browser mid-checkout.
The captive portal never asks PalmPesa itself. It shows whatever the poller last recorded, so a payer who declined the prompt sees the failure on the next status check instead of waiting out the 2-minute checkout timeout.
On `COMPLETED`, a payment is recorded with method **PalmPesa** and the subscriber's package is applied asynchronously. On `FAILED`, `CANCELLED`, `EXPIRED` or `REJECTED`, PalmPesa's failure reason is stored against the transaction and nothing is credited.
PalmPesa's callback carries no signature, HMAC, or shared secret, so it cannot prove it came from PalmPesa. Centipid Billing treats it as a hint only: nothing is credited from the callback body. Every credit is made against a status read from PalmPesa itself, so a spoofed "completed" callback cannot provision a subscriber.
A failed request is deliberately **not** retried automatically. PalmPesa documents no idempotency on the request reference, so an automatic retry after a lost response could raise a second order and prompt the payer twice. The payer retries by choice instead.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"PalmPesa API token not configured"* | No API token is saved. | Enter the API token in Settings → Payments → PalmPesa. |
| *"PalmPesa authentication failed. Check the API token"* | PalmPesa rejected the token (HTTP 401). | Re-copy the token from the PalmPesa dashboard. Confirm the account is verified and the token has not been rotated. |
| *"A valid Tanzanian phone number is required for PalmPesa payments"* | The number could not be normalized to a Tanzanian MSISDN. | Re-enter the number as `07…`, `06…`, or `2557…`. |
| *"Could not reach PalmPesa. Please try again"* | The request could not reach the PalmPesa endpoint. | Check outbound connectivity from the application host, and any custom **API host** value. |
| Customer portal shows *"Unable to start the payment"* but the payer still got a wallet prompt | The known customer-portal limitation above. The push succeeded; only the portal's response is wrong. | Check the ledger before advising anything. Do not tell the payer to retry. Use the captive portal for PalmPesa payments. |
| Payer paid, but the transaction sits pending | The order never reached a terminal state within the polling window. | Confirm the payment on the PalmPesa dashboard, then raise it with support with the order id and the payer's phone number. |
For symptoms that are not specific to PalmPesa, see [Payment troubleshooting](/billing/payment-gateways/troubleshooting). For every other gateway's fields, see the [credential reference](/billing/payment-gateways/credentials-reference).
# PawaPay
Source: https://docs.centipidbilling.com/billing/payment-gateways/pawapay
Collect mobile money in 19 African countries through PawaPay with one API token: check which providers are enabled, set your country, and track deposits.
## Collect payments with PawaPay
`PAWAPAY` aggregates mobile money across much of Africa behind one API token.
Centipid Billing posts a deposit request, the payer authorizes on their handset,
and the deposit is polled to completion.
Offered in the country catalog for **Uganda, Rwanda, Ghana, Côte d'Ivoire,
Tanzania, Zambia, Malawi, Benin, Burkina Faso, Cameroon, DR Congo,
Republic of the Congo, Senegal, Sierra Leone, Nigeria, Ethiopia, Gabon,
Lesotho, and Mozambique**.
## Before you start
1. Complete PawaPay merchant onboarding in an account owned by the ISP.
2. Collect the **API token** from the PawaPay dashboard.
3. Confirm which mobile money providers ("correspondents") PawaPay has enabled
for your account — the payer picks one at checkout, and an unsupported choice
is refused.
4. Confirm your account's country is set correctly. PawaPay requires both a
three-letter country code and the matching currency, and both are derived
from it.
## Configure the gateway
Select PawaPay from the payment marketplace.
**PawaPay API token** (required) is the only field. It is stored as a secret
and is not echoed back into the form after saving.
PawaPay charges in your account's billing currency, not one set on this
form, and that currency must be one PawaPay accepts in your country. DR
Congo accepts `CDF` or `USD`; every other country accepts one. An account
with no currency set is charged the country's default:
Kenya `KES`, Uganda `UGX`, Tanzania `TZS`, Ghana `GHS`, Nigeria `NGN`,
Rwanda `RWF`, Zambia `ZMW`, Malawi `MWK`, Sierra Leone `SLE` (an account
set to the old `SLL` is charged in `SLE`), DR Congo `CDF` or `USD`,
Ethiopia `ETB`, Lesotho `LSL`, Mozambique `MZN`, the CFA countries `XOF`
or `XAF`. A checkout whose prices are in a currency PawaPay does not bill
your country in is refused rather than charged in the wrong currency.
Pay a small amount from the captive portal, choose a correspondent, and
confirm the prompt arrives and the payment lands in the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| PawaPay API token | Yes | Secret. The only field, and the only one that gates the switch. |
Requests go to `https://api.pawapay.io` in production and to
`https://api.sandbox.pawapay.io` everywhere else, so a sandbox token cannot be
tested against production or the other way round.
## Callback URLs
Settings → Payments shows `https:///api/pawapay/callback`. Register
it with PawaPay.
PawaPay callbacks are best-effort and do go missing, so the callback is not
what a payment depends on. Every accepted deposit is also polled: the captive
portal queries it while the payer's browser is open, and a background job
keeps polling after the payer has moved on. A payment therefore still
completes when the callback never arrives.
## What the payer must provide
* **A mobile money number**, normalized to the country's international format.
* **A correspondent** — the mobile money provider to charge. Checkout refuses to
send a request without a supported one.
Authorization happens on the handset, so no PawaPay domain needs to be added to
the captive walled garden.
## How a payment completes
A deposit is posted with a unique deposit id, the amount, the country and
currency resolved from your account, the correspondent, and the payer's
number. The deposit id is what everything afterwards reconciles against.
PawaPay answers `ACCEPTED`. The request is stored and polling is scheduled.
The payer approves on their handset.
The deposit settles to `COMPLETED`, `FAILED`, or `REJECTED`. Only
`COMPLETED` records a payment and applies the package; the failure reason
PawaPay returns is stored against the transaction.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Mobile money provider not selected or configured correctly."* | No correspondent reached the request, the one picked does not serve your country, or PawaPay does not serve your country at all. | Have the payer pick a provider. Confirm with PawaPay which correspondents your account may use, or use a different gateway in a country PawaPay does not serve. |
| *"PawaPay API token not configured."* | No token is saved. | Enter it in Settings → Payments. |
| *"PawaPay authentication failed. Check API token."* | PawaPay rejected the token (HTTP 401). | Re-copy it. Confirm it is a production token if this is production. |
| *"…country configuration error for PawaPay."* | Your country could not be resolved to a three-letter code. | Set the country correctly on your account. |
| *"PawaPay bills in NGN here, but your prices are in USD…"* (payers see *"Mobile money is not set up correctly on this network."*) | Your account's currency is not one PawaPay bills your country in. | Contact Centipid support to change your billing currency, then reprice your packages in it. |
| *"PawaPay request failed."*, or a message from PawaPay | PawaPay rejected the deposit and its own reason is shown when it sends one. | Read the message; it usually names the field or the correspondent at fault. |
| Deposit stays pending | It has not reached a terminal state yet. | Let polling settle it. `BUSY` and `NOT_FOUND` are transient — do not record a manual payment, and do not ask the payer to retry until the deposit is resolved. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Paybill (without API keys)
Source: https://docs.centipidbilling.com/billing/payment-gateways/paybill
Send real M-Pesa STK prompts in Kenya into your own paybill, including a shared SACCO paybill with an account number, using the platform's Daraja keys.
## Collect payments with your paybill, without API keys
`PAYBILL` sends a real M-Pesa STK push to the payer, using **the platform's
Daraja credentials** rather than your own. You supply only your paybill number —
no Daraja onboarding required.
Available to ISPs in **Kenya (KE)**.
A **SACCO paybill, or any paybill you share with other businesses**, is
supported: add your account number on that paybill and every payment is filed
against it. Leave it blank when the paybill is yours alone.
This is not a "show the customer instructions" method. The payer receives an
STK prompt and enters their M-Pesa PIN, exactly as with
[Safaricom M-Pesa](/billing/payment-gateways/safaricom). The difference is
where the Daraja API keys come from: with `SAFARICOM` they are yours, here
they are the platform's, so you can start collecting before Daraja onboarding
is finished.
## Before you start
1. Have an active M-Pesa paybill registered to your business. It must be a
Safaricom paybill — not a bank paybill. To collect into a bank account, use
[Bank](/billing/payment-gateways/bank) instead.
2. If that paybill belongs to a **SACCO**, or is shared with other businesses,
have the account number the paybill files your money under. Your SACCO or the
paybill's owner issues it — it is usually your member or account number, and
it is what you would type yourself when paying into that paybill by hand.
## Configure the gateway
Select the method from the payment marketplace.
**Paybill number** (required) is digits only, at least 4 and at most 20
characters. It is shown to subscribers and is the account the money lands in.
**Account number** (optional) is your account on that paybill — up to 20
characters, made of letters, digits, hyphens and slashes. Set it and every
payment, collected or paid out, carries it as the account reference, so the
SACCO allocates the money to you.
**Leave it blank when the paybill is yours alone.** Payments then keep the
default account reference they have always used, and nothing changes.
The paybill is the only field that gates the switch. Switching gateways may
require an OTP confirmation.
Pay a small amount from the captive portal, and confirm the prompt shows
your paybill and that the money arrives in it.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Paybill number | Yes | Digits only, 4–20 characters. Your own Safaricom paybill, not a bank paybill. No Daraja keys are requested. |
| Account number | No | Only for a SACCO paybill, or one shared with other businesses. Up to 20 characters: letters, digits, hyphens and slashes. Blank keeps the default account reference. |
## Callback URLs
None. The callback address is sent with every payment request, so there is
nothing to register with Safaricom.
## What the payer must provide
A Safaricom phone number, which receives the STK prompt. The account reference
is filled in for the payer — your **Account number** when you have set one, and
a default reference otherwise. The payer never types it.
## How a payment completes
Centipid Billing raises the STK push against your paybill using the
platform's Daraja app, as a `CustomerPayBillOnline` transaction.
The payer enters their M-Pesa PIN.
Safaricom posts the result to the platform callback, which records the
payment and applies the subscriber's package asynchronously.
## Payments typed in by hand
Not every payment on this method starts as an STK prompt. An invoice can offer
pay-by-hand instructions, and a TV screen shows a number the customer types into
M-Pesa themselves. On this method **that number is the Centipid paybill, not
yours** — money paid that way is collected by the platform against the
subscriber's account reference and remitted to you.
That remittance is a paybill-to-paybill transfer into your paybill, and it
carries your **Account number** as the reference when you have set one. This is
what makes a SACCO or shared paybill work: without an account number the SACCO
receives the transfer with nothing to allocate it against.
Prove where money lands, in both flows, with a controlled test payment before
you move subscribers onto this method.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | The STK push failed or Safaricom was unreachable. | Confirm the paybill is active and accepts Buy Goods/Paybill payments, then retry. If it persists, raise it with support — the platform credentials are not yours to correct. |
| The prompt shows an unexpected paybill | The saved paybill is wrong. | Correct it in Settings → Payments. |
| Money reaches the SACCO or shared paybill but is not credited to you | No account number is saved, or the saved one is not the account that paybill knows you by. | Set **Account number** in Settings → Payments to the account your SACCO issued you, then re-test. |
| Payer paid, service not applied | The callback did not arrive or did not match a checkout. | See [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
To hold your own Daraja keys instead, see
[Safaricom M-Pesa](/billing/payment-gateways/safaricom). For every gateway's
fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# PayFast
Source: https://docs.centipidbilling.com/billing/payment-gateways/payfast
Set up PayFast in South Africa: merchant ID, merchant key, the passphrase that signs every payment and ITN notification, and the walled garden for Hotspot.
## Collect payments with PayFast
`PAYFAST` posts a signed payment request to PayFast's hosted page. The payer
completes the payment there, and PayFast confirms it with an **ITN** (Instant
Transaction Notification) that is signature-checked before anything is credited.
Available to ISPs in **South Africa (ZA)**, alongside Paystack, PayPal, and DPO.
## Before you start
1. Complete PayFast merchant onboarding in an account owned by the ISP.
2. In the PayFast dashboard open **Settings → Integration** and collect the
**merchant ID** and **merchant key**.
3. Set a **passphrase** in the same place, and be ready to enter the identical
value here — see the warning below.
4. Plan the walled garden: the payer's browser must reach
`www.payfast.co.za`, so a Hotspot subscriber who is not yet online cannot
pay unless PayFast is reachable pre-authentication.
## Configure the gateway
Select PayFast from the payment marketplace.
Both are required, and both come from PayFast dashboard → Settings →
Integration.
**Passphrase** is optional in the form — PayFast allows unsigned merchants —
but it is strongly recommended. It must be **character-for-character
identical** to the passphrase saved in your PayFast dashboard.
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal on an unauthenticated device and
confirm the payment reaches the ledger.
A passphrase that differs from PayFast's — including a stray space — makes
every signature mismatch. Payments are then rejected, or notifications are
discarded, in a way that looks like an intermittent gateway fault rather than
a configuration error. Set it on both sides at the same time, or leave it
blank on both.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Merchant ID | Yes | PayFast dashboard → Settings → Integration. |
| Merchant key | Yes | Same place. |
| Passphrase | No | Secret. Signs payment data and validates notifications. Must match PayFast exactly. |
The merchant ID and key gate the switch; the passphrase does not, which is
exactly why a mismatch is easy to ship.
## Callback URLs
| Name | Path |
| - | - |
| Notify URL (ITN) | `https:///api/payments/payfast/notify` |
| Return URL | `https:///tenant/payfast/return` |
| Cancel URL | `https:///tenant/payfast/cancel` |
Set all three in the PayFast dashboard, and confirm the notify URL is publicly
reachable — it is what completes a payment.
## What the payer must provide
Whatever PayFast's page asks for — card, instant EFT, or another method enabled
on your account. The amount, reference, and signature are fixed before the payer
arrives.
PayFast is always live here. There is no sandbox switch on this form, so test
with a small real amount rather than with sandbox credentials.
## How a payment completes
Centipid Billing builds the payment fields in PayFast's canonical order,
signs them with your passphrase, and redirects the payer to PayFast with the
signature attached.
The payer completes the payment on PayFast's page.
PayFast posts the ITN. Its signature is recomputed with your passphrase and
compared; only a matching notification records a payment and applies the
package.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Payment failed: PayFast is not fully configured. Please add your merchant ID and key."* | One of the two required fields is missing. | Complete both in Settings → Payments. |
| PayFast's page rejects the request as an invalid signature | The passphrase here does not match the one in the PayFast dashboard. | Re-enter it on both sides, watching for trailing spaces. |
| Payments complete at PayFast, ledger stays empty | ITNs are being discarded — a passphrase mismatch, or a notify URL that is not publicly reachable. | Check both, then re-test with a small payment. |
| The payment page never loads on a Hotspot device | The walled garden does not allow PayFast. | Allow `www.payfast.co.za` pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# PayPal
Source: https://docs.centipidbilling.com/billing/payment-gateways/paypal
Set up PayPal, the fallback gateway for most countries: create an app's client ID and secret, pick a settlement currency, and see how it changes reports.
## Collect payments with PayPal
`PAYPAL` sends the payer to PayPal's approval page, then **captures** the
approved order. Nothing is credited until the capture succeeds.
PayPal is the fallback gateway for any country without its own catalog entry, so
it is available almost everywhere: Kenya, Rwanda, Ghana, Côte d'Ivoire, South
Africa, Egypt, Tanzania, Zambia, Malawi, Benin, Burkina Faso, Cameroon, DR
Congo, Republic of the Congo, Senegal, Sierra Leone, Zimbabwe, Nigeria, and
Pakistan among them.
## Before you start
1. Create an app in the [PayPal Developer dashboard](https://developer.paypal.com)
under a business account owned by the ISP, and collect its **client ID** and
**client secret**.
2. Decide the **settlement currency** — see the warning below, because it
changes more than PayPal.
3. Plan the walled garden: the payer's browser must reach PayPal, so a Hotspot
subscriber who is not yet online cannot pay unless PayPal is reachable
pre-authentication.
## Configure the gateway
Select PayPal from the payment marketplace.
Both are required. The secret is stored as a secret and is not echoed back
into the form after saving.
**Settlement currency** (required) is searchable by name or code.
Pay a small amount from the captive portal on an unauthenticated device.
Confirm the approval page loads, the payment is captured, and the amount in
the ledger matches what PayPal captured.
The settlement currency becomes **your dashboard's billing currency and
symbol**, not just PayPal's. Changing it changes how amounts are displayed and
billed across the workspace. Decide it once, deliberately, before you take
live payments.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Client ID | Yes | From the PayPal Developer dashboard. |
| Client secret | Yes | Secret. |
| Settlement currency | Yes | Three-letter code, chosen from the current currency list. Also drives dashboard display. |
All three gate the switch.
## Callback URLs
None to register. PayPal returns the payer to a return URL generated per order,
and a cancel URL for an abandoned checkout. PayPal webhooks are accepted and
de-duplicated, but the capture is what credits a payment.
## What the payer must provide
A PayPal account or a card, on PayPal's own page. The amount is fixed before the
payer arrives, and must be greater than zero.
## How a payment completes
Centipid Billing authenticates against PayPal and creates an order in the
settlement currency, with return and cancel URLs.
The payer approves the order on PayPal's page and is returned.
The order is captured. Only a completed capture records a payment and
applies the package — an approved but uncaptured order is not money.
A repeated capture of an order already recorded is rejected as a duplicate
rather than credited twice.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Payment initiation failed: PayPal credentials are not configured."* | The client ID or secret is missing. | Enter both in Settings → Payments. |
| *"Payment initiation failed: Unable to authenticate with PayPal."* | PayPal rejected the credentials. | Re-copy them. Confirm the app is live, not sandbox. |
| *"Payment initiation failed: Invalid currency code."* | The settlement currency is not a three-letter code. | Re-select it from the list. |
| *"Payment initiation failed: Payment amount must be greater than zero."* | The checkout amount was zero. | Check the package price. |
| *"PayPal did not return an approval link."* | PayPal accepted the order but returned no approval URL. | Retry, then raise the order id with PayPal. |
| *"Order has not been approved by the customer yet."* | Capture ran before the payer approved. | Have the payer complete the approval, then retry the capture. |
| *"Order is in … state and cannot be captured."* | The order expired or was voided. | Start a fresh checkout. |
| *"Payment not completed."* | The capture did not complete. | Check the order on PayPal before recording anything by hand. |
| The approval page never loads on a Hotspot device | The walled garden does not allow PayPal. | Allow PayPal's domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Paystack
Source: https://docs.centipidbilling.com/billing/payment-gateways/paystack
Set up Paystack hosted checkout for cards, mobile money and bank transfers in Kenya, Ghana, Nigeria, South Africa and more, with live secret and public keys.
## Collect payments with Paystack
`PAYSTACK` uses a **hosted checkout**: Centipid Billing initializes a
transaction, sends the payer's browser to Paystack's authorization page, and
verifies the result against Paystack before crediting anything.
Offered in the country catalog for **Kenya, Rwanda, Ghana, Côte d'Ivoire,
South Africa, Egypt, and Nigeria**.
## Before you start
1. Complete Paystack merchant onboarding in an account owned by the ISP, and
have the business verified so live keys are issued.
2. From the Paystack dashboard collect the **live secret key** (`sk_live_…`) and
the **live public key** (`pk_live_…`).
3. Plan the walled garden: the payer's browser must reach Paystack's checkout
page, so a Hotspot subscriber who is not yet online cannot pay unless
Paystack is reachable pre-authentication.
## Configure the gateway
Select Paystack from the payment marketplace.
**Secret key** (required) starts with `sk_live_`. It is stored as a secret
and is not echoed back into the form after saving.
**Public key** (required) starts with `pk_live_`.
Add Paystack's checkout domain to the walled garden on every Hotspot router,
then confirm from a device that is not yet authenticated. See
[Captive portal](/network/captive-portal).
Pay a small amount from the captive portal on a real unauthenticated device,
and confirm the payment reaches the ledger with method **Paystack**.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Secret key | Yes | Secret. The form expects a live key (`sk_live_…`). |
| Public key | Yes | The form expects a live key (`pk_live_…`). |
This form is for live keys. Do not paste test keys into it — a `sk_test_…`
secret initializes transactions that never move real money, and the mismatch
is easy to miss because checkout still appears to work.
## Callback URLs
Settings → Payments shows `https:///tenant/paystack/callback`, which
is where Paystack returns the payer after checkout.
## What the payer must provide
Whatever Paystack's own checkout page asks for — card details, mobile money, or
a bank transfer, depending on what Paystack has enabled for your account. The
amount and reference are fixed before the payer arrives.
## How a payment completes
Centipid Billing calls `https://api.paystack.co/transaction/initialize` and
receives an authorization URL, then stores the local transaction against the
reference.
The payer's browser is sent to Paystack and the payment is completed there.
On return, the reference is verified against Paystack. Only a verified
successful transaction records a payment and applies the package — the
return itself proves nothing.
A repeated verification of an already-settled reference is rejected as a
duplicate rather than credited twice.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Payment initiation failed: Paystack secret key not configured…"* | No secret key is saved. | Enter it in Settings → Payments. |
| *"Payment initiation failed: Paystack API request failed with status: 401…"* | Paystack rejected the secret key. | Re-copy it. Confirm the business is verified and the key is live. |
| *"…Payment authorization URL not found in Paystack response"* | Paystack accepted the request but returned no checkout URL. | Retry, then raise the reference with Paystack. |
| The checkout page never loads on a Hotspot device | The walled garden does not allow Paystack. | Allow Paystack's checkout domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| *"Payment not successful"* | The transaction verified, but Paystack did not report it as successful. | Have the payer check with their bank or wallet. Nothing is credited. |
| *"Payment reference not found"* | The reference verified at Paystack has no matching local checkout. | Raise it with support with the Paystack reference. |
| Money in Paystack, not in the bank | Paystack settles on its own schedule. | Reconcile against the Paystack settlement report, not only the ledger. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# PesaPal
Source: https://docs.centipidbilling.com/billing/payment-gateways/pesapal
Set up PesaPal hosted checkout in 14 countries, from Kenya and Uganda to Zambia and Senegal, with your consumer key and secret. The IPN URL is set on save.
## Collect payments with PesaPal
`PESAPAL` uses a **hosted checkout**: Centipid Billing submits an order, sends
the payer's browser to PesaPal's payment page, and reads the transaction status
back from PesaPal before crediting anything.
PesaPal is offered in 14 countries in the catalog — Kenya, Uganda,
Rwanda, Tanzania, Zambia, Malawi, Benin, Burkina Faso, Cameroon, DR Congo,
Republic of the Congo, Senegal, Sierra Leone, and Zimbabwe.
## Before you start
1. Complete PesaPal merchant onboarding in an account owned by the ISP.
2. Collect the **consumer key** and **consumer secret** from the PesaPal
dashboard.
3. Confirm your workspace has a public HTTPS domain. PesaPal validates the IPN
URL when it is registered, and rejects one it cannot accept.
4. Plan the walled garden: the payer's browser must reach PesaPal's page, so a
Hotspot subscriber who is not yet online cannot pay unless PesaPal is
reachable pre-authentication.
## Configure the gateway
Select PesaPal from the payment marketplace.
Both are required. The secret is stored as a secret and is not echoed back
into the form after saving.
Saving registers your IPN (Instant Payment Notification) URL with PesaPal
and stores the id it issues. Every order carries that id, so this step is
what makes checkout possible at all. If registration fails you are told so
on this page, with PesaPal's reason.
Pay a small amount from the captive portal on an unauthenticated device, and
confirm the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Consumer key | Yes | From the PesaPal dashboard. |
| Consumer secret | Yes | Secret. |
Both gate the switch. The IPN id is not a field — it is registered for you and
stored automatically.
## Callback URLs
Nothing to paste into the PesaPal dashboard by hand. The order carries its own
return address, and the IPN URL — `https:///api/pesapal/webhook` — is
registered with PesaPal when you save your credentials.
The IPN is re-registered automatically if your workspace domain changes, so
notifications follow the move. If a re-registration fails while a working id
is already stored, payments keep running on the stored id rather than
stopping.
The notification is not what credits a payment: the transaction status is read
back from PesaPal. But PesaPal will not accept an order without a registered
IPN id at all, which is why registration gates checkout.
## What the payer must provide
A phone number, and an email address when one is available — both are sent as
the billing address on the order. The payment method itself is chosen on
PesaPal's page: card, mobile money, or Airtel, depending on what PesaPal has
enabled for your account.
## How a payment completes
Centipid Billing authenticates, submits the order with the amount, the
reference, the billing address, and the registered IPN id, and receives a
redirect URL.
The payer completes the payment on PesaPal's page.
The transaction status is read back from PesaPal by its order tracking id.
Only a completed status records a payment and applies the package.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"…registering the Pesapal IPN URL failed: …"* when saving | PesaPal refused the IPN URL. Its own reason follows the message. | Confirm your workspace domain is a public HTTPS address that resolves from outside your network, then save again. |
| *"Payment failed: could not register the Pesapal IPN URL…"* at checkout | No IPN id is stored and registration failed just now. No payer was charged. | Re-save your PesaPal credentials and read the error there; it is the same failure with more room to act on it. |
| *"Payment failed: Unable to authenticate with Pesapal"* | PesaPal rejected the consumer key or secret. | Re-copy both from the dashboard. Confirm the account is live. |
| *"Payment failed: No redirect URL received…"* | PesaPal accepted the order but returned no payment page. | Retry, then raise the reference with PesaPal. |
| The payment page never loads on a Hotspot device | The walled garden does not allow PesaPal. | Allow PesaPal's domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| *"Payment not successful"* | The status read back from PesaPal was not a completed payment. | Check the transaction on the PesaPal dashboard. Nothing is credited. |
| *"Payment reference not found"* | The reference has no matching local checkout. | Raise it with support with the PesaPal tracking id. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Razorpay
Source: https://docs.centipidbilling.com/billing/payment-gateways/razorpay
Set up Razorpay payment links for UPI, card, netbanking and wallet payments in India: key ID, key secret, a separate webhook secret, and sending SMS in India.
## Collect payments with Razorpay
`RAZORPAY` uses a **hosted payment link** offering UPI, cards, netbanking, and
wallets. Centipid Billing creates the link, sends the payer to its short URL,
and confirms the result on a signed webhook that is re-verified against Razorpay
before anything is credited.
Offered in the country catalog for **India (IN)**.
## Before you start
1. Complete Razorpay onboarding in an account owned by the ISP, and activate the
payment methods you intend to offer — which of UPI, cards, netbanking, and
wallets a payer sees is configured on the Razorpay account, not per request.
2. From **Settings → API Keys** in the Razorpay dashboard, generate a key and
collect the **Key ID** and **Key secret**. The secret is shown once.
3. From **Settings → Webhooks**, create a webhook and collect its **webhook
secret**. This is issued separately and is **not** the key secret.
4. Plan the walled garden: the payer's browser must reach the payment link, so a
Hotspot subscriber who is not yet online cannot pay unless Razorpay is
reachable pre-authentication.
## Configure the gateway
Select Razorpay from the payment marketplace.
**Key ID** (required) starts with `rzp_live_` on a live account and
`rzp_test_` in test mode. The prefix is how you tell the two apart.
**Key secret** (required) is stored as a secret and authenticates every
request to Razorpay.
**Webhook secret** is optional and does not gate the switch, but until it is
set every webhook is rejected — see [Callback URLs](#callback-urls).
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal on an unauthenticated device, and
confirm the payment reaches the ledger. Test a real UPI payment, not only a
sandbox one.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Key ID | Yes | `rzp_live_…` or `rzp_test_…`. |
| Key secret | Yes | Secret. Authenticates API requests. |
| Webhook secret | No | Secret. Issued separately from the key secret; signs the webhook. |
The Key ID and Key secret gate the switch. The webhook secret does not, so it is
easy to leave blank by accident — see the warning below for what that costs.
## Callback URLs
| Name | Path |
| - | - |
| Webhook URL | `https:///api/razorpay/callback` |
| Redirect URL | `https:///api/razorpay/return` |
Register the webhook URL in the Razorpay dashboard against the
`payment_link.paid` event. The redirect is where the payer's browser returns
after payment; Razorpay appends the reference itself.
Webhooks carry an HMAC-SHA256 `x-razorpay-signature` computed with the
**webhook secret**, not the key secret. A wrong or missing webhook secret
means every webhook is rejected with HTTP 400. Payers are still provisioned
when they return to the site, but a payer who closes the tab before the
redirect is charged and left disconnected until someone reconciles by hand.
## What the payer must provide
Whatever the Razorpay payment link asks for — a UPI ID or app approval, card
details, netbanking credentials, or a wallet. The payer's name, email, and phone
are sent with the link when known; when no email is available a placeholder is
sent so the link can be created, so do not rely on the email shown in Razorpay
to identify a subscriber.
Centipid Billing sends its own receipts, so the link is created with Razorpay's
own SMS and email notifications switched off. Turning them back on in the
dashboard double-messages the subscriber.
The currency is your account's configured currency, defaulting to `INR`.
Amounts are sent in **paise**, the smallest unit — ₹500 is sent as `50000`.
This is the opposite convention to Monnify, which takes major units. A
ledger amount that is 100× the Razorpay amount is the expected relationship,
not a bug.
## How a payment completes
Centipid Billing creates a payment link for the amount with our own
reference and receives its short URL. A pending row is written against that
reference.
The payer completes the payment on Razorpay's page.
Razorpay posts the signed webhook. The signature is validated against the
raw request body, the link is then re-queried against the Razorpay API, and
only a link whose status is `paid` records a payment and applies the
package. Repeated webhooks are ignored rather than double-credited.
A payment link exists from the moment it is created, with status `created`.
Only `paid` provisions. This is why a link that exists is not evidence a
payment was made.
## Sending SMS in India
Razorpay handles the money; it does not solve messaging. India's DLT rules mean
an unregistered sender's messages are dropped at the carrier while the delivery
report still reads as success. Pair Razorpay with **MSG91** or **Fast2SMS** and
your registered header and templates — see
[providers and sender IDs](/communications/providers-and-sender-ids).
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | Credentials are missing or Razorpay refused the link. | Check the Key ID and Key secret, and that a live key is not being used in test mode or the reverse. |
| Test payments work, live does not | The key pair is still `rzp_test_…`. | Generate live keys and replace both the ID and the secret together. |
| The payment page never loads on a Hotspot device | The walled garden does not allow Razorpay. | Allow `api.razorpay.com`, `checkout.razorpay.com`, and `rzp.io` pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments complete at Razorpay, ledger stays empty | Webhooks are being rejected — usually a missing or wrong webhook secret, or a webhook URL that is not publicly reachable. | Re-copy the webhook secret from the dashboard, confirm the URL is registered and reachable, then re-test. |
| Subscribers get two receipts | Razorpay's own notifications were re-enabled on the account. | Turn off SMS and email notifications for payment links in the Razorpay dashboard. |
| The amount looks 100× too large in Razorpay | It is not — amounts are sent in paise. | Divide by 100 to compare against the ledger. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Relworx
Source: https://docs.centipidbilling.com/billing/payment-gateways/relworx
Collect mobile money in Kenya and Tanzania through Relworx: account number, API key, webhook signing key, and why the signed webhook completes a payment.
## Collect payments with Relworx
`RELWORX` collects mobile money through the Relworx aggregator. Centipid Billing
posts a request, the payer authorizes it on their handset, and Relworx confirms
the result on a **signed webhook**.
Offered in the country catalog for **Kenya (KE)** and **Tanzania (TZ)**.
## Before you start
1. Complete Relworx merchant onboarding in an account owned by the ISP.
2. From the Relworx dashboard collect the **account number** (shown as
`account_no`), the **API key**, and the **webhook signing key**.
3. Confirm your workspace has a public HTTPS domain — Relworx must reach the
callback, and the callback is what completes a payment.
## Configure the gateway
Select Relworx from the payment marketplace.
**Relworx account number** (required) is the `account_no` from your
dashboard, not your merchant name.
**Relworx API key** (required) authenticates outgoing payment requests.
**Webhook signing key** (required, stored as a secret) verifies callbacks.
Get it exactly right — see the warning below.
Pay a small amount from the captive portal and confirm both halves: the
prompt arrives, **and** the payment appears in the ledger. A prompt that
succeeds while the ledger stays empty means the webhook is being rejected.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Relworx account number | Yes | The `account_no` from your Relworx dashboard. |
| Relworx API key | Yes | Sent as a bearer token on every request. |
| Webhook signing key | Yes | Secret. Verifies the callback signature. |
## Callback URLs
Settings → Payments shows `https:///api/payments/relworx/callback`.
Register it in your Relworx dashboard.
Every callback must carry a valid `Relworx-Signature`. Centipid Billing
recomputes an HMAC-SHA256 over the URL, the timestamp, and the reference and
status fields, using your webhook signing key, and rejects the callback with
HTTP 400 if it does not match — or if its timestamp is more than 10 minutes
from now.
A wrong signing key therefore fails silently in the worst possible way:
**payers are charged and never provisioned**, because every confirmation is
rejected. If test payments prompt but never land, suspect this key first.
## What the payer must provide
A mobile money number. It is normalized to international format using your
account's country before it is sent — numbers that cannot be normalized are
refused before any request reaches Relworx.
The currency is taken from the payment, then your configured currency, then your
country (`UG` → `UGX`, `KE` → `KES`, `TZ` → `TZS`). If none resolves to a
three-letter code, the request is refused rather than sent in the wrong currency.
## How a payment completes
Centipid Billing posts the request to the Relworx API (v2), with a short
timeout and two retries.
The payer approves on their handset. The local transaction stays in progress.
Relworx calls the signed webhook. The signature is verified, the transaction
matched on its customer or internal reference, and the payment recorded.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Relworx configuration incomplete. Please contact support."* | One of the three fields is missing. | Complete all three in Settings → Payments. |
| *"Phone number format is invalid for Relworx payments."* | The payer's number could not be normalized for your country. | Re-enter it in local or international format. Check your account's country is set correctly. |
| *"Currency configuration missing or unsupported for Relworx."* | No three-letter currency could be resolved. | Set the currency on your account, or confirm the country is one Relworx supports. |
| *"Unable to reach Relworx. Please try again later."* | The request could not connect. | Check outbound connectivity from the application host. |
| *"Relworx rejected the payment request."* | Relworx refused it — commonly bad credentials or an unsupported number. | Verify the account number and API key against the dashboard. |
| Prompts succeed, ledger stays empty | Callbacks are being rejected — usually a wrong webhook signing key, sometimes a URL that is not publicly reachable. | Re-copy the signing key, confirm the callback URL is registered and reachable, then re-test. |
| Callbacks rejected only intermittently | The webhook timestamp fell outside the 10-minute tolerance. | Check the clock on the application host. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Safaricom M-Pesa
Source: https://docs.centipidbilling.com/billing/payment-gateways/safaricom
Collect M-Pesa in Kenya with your own Daraja API keys, into a paybill or Buy Goods till: consumer key and secret, passkey, shortcode and callback URLs.
## Collect payments with Safaricom M-Pesa
`SAFARICOM` collects M-Pesa payments with **your own Daraja API keys**. Centipid
Billing sends an STK push to the payer's phone, the payer enters their M-Pesa
PIN, and money settles into your own paybill or till.
Available to ISPs in **Kenya (KE)**, alongside Kopo Kopo, Bank, Paybill, Till,
Paystack, PesaPal, Relworx, PayPal, and DPO.
If you do not have Daraja API keys, use [Paybill](/billing/payment-gateways/paybill)
or [Till](/billing/payment-gateways/till-number) instead — they send the same
STK push using the platform's Daraja credentials, and money still settles into
your own paybill or till.
## Before you start
1. Have an active Safaricom paybill or Buy Goods till registered to your business.
2. Create an app on the [Daraja portal](https://developer.safaricom.co.ke) and
collect its **consumer key**, **consumer secret**, and **passkey**. The
passkey is normally emailed to the address registered in Daraja.
3. Confirm your Daraja app is on **production** credentials, not sandbox.
4. Confirm your workspace has a public HTTPS domain — Safaricom must be able to
reach it to deliver callbacks, and callback registration is refused without one.
## Configure the gateway
Select the gateway from the payment marketplace to open its form.
**Paybill** — the payer pays your paybill and enters an account number.
**Till** — the payer pays your till number (Buy Goods). The rest of the form
changes with this choice.
In paybill mode, **Paybill number** and **M-Pesa shortcode** are the same
value, so the shortcode field mirrors the paybill and is read-only. In till
mode, enter your **Till number** and the separate Daraja **M-Pesa shortcode**
— the shortcode must be different from the till number, or the switch is
refused.
**Consumer key**, **consumer secret**, and **passkey** are all required and
stored as secrets. They are not echoed back into the form after saving.
See [Callback URLs](#callback-urls) below.
Pay a small amount from the captive portal. Verify the STK prompt arrives,
the payment lands in the ledger, and the subscriber's package is applied.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Collection method | Yes | `Paybill` or `Till`. Decides which fields below apply. |
| Paybill number | Yes, in paybill mode | Digits only, at least 4, maximum 20. |
| Till number | Yes, in till mode | Digits only, maximum 20. |
| M-Pesa shortcode | Yes | Digits only. In paybill mode it must equal the paybill (the form fills it for you). In till mode it is the separate Daraja shortcode and must differ from the till number. |
| Consumer key | Yes | Secret. From your Daraja app. |
| Consumer secret | Yes | Secret. From your Daraja app. |
| Passkey | Yes | Secret. Required for STK push; usually emailed to the address registered in Daraja. |
Saving validates the form; it does not prove the credentials work at Safaricom.
Only a test payment does that.
## Callback URLs
Settings → Payments shows two URLs once your workspace has a domain:
| Name | Path |
| - | - |
| Confirmation URL | `https:///api/safaricom/callback` |
| Validation URL | `https:///api/safaricom/validation` |
In **paybill** mode the form also shows a **Register callbacks** button, which
registers both URLs with Safaricom's C2B v2 API for you. It is enabled only when
the configuration is saved and complete — while there are unsaved edits it is
disabled with *"Save your changes before registering callbacks."*
Till mode does not offer registration: Buy Goods STK results return on the
callback URL sent with each request, so there is nothing to register.
## What the payer must provide
* **A Safaricom phone number**, which receives the STK prompt.
* **An account number**, in paybill mode. Centipid Billing sends the
subscriber's account reference with the request, so the payer does not type it.
The payer authorizes on their handset, so no Safaricom domain has to be added to
the captive walled garden.
## How a payment completes
Centipid Billing requests a Daraja access token and posts the STK push.
Both calls run inside the payer's checkout request and are deliberately
short — a 5-second connect timeout, 10 seconds for the token, and 10 seconds
for the push acknowledgement — so Safaricom degradation fails fast instead of
hanging the captive page.
The acknowledged request is written locally with its `MerchantRequestID` and
`CheckoutRequestID`. If that write fails, it is retried on a durable queue
rather than dropped: the push already reached the payer, so the record has to
survive for the callback to be matched to a checkout.
The payer enters their M-Pesa PIN. Money moves into your own paybill or till.
Safaricom calls back — `/api/safaricom/paybill/callback` in paybill mode, or
`/api/till-number/callback` in till mode. The callback is processed
asynchronously, then the payment is recorded and the subscriber's package
applied.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* at checkout | The token request or the STK push failed, or Safaricom was unreachable within the timeouts above. | Check the Daraja consumer key, secret, passkey, and shortcode. Confirm the credentials are production, not sandbox. |
| *"Unable to process payment without a resolved payment user."* | Safaricom accepted the push, but the checkout could not be tied to a subscriber. | Raise with support with the phone number and the time — the payer may have been charged. |
| *"Safaricom authentication failed. Check the saved consumer key and secret."* when registering callbacks | Daraja refused the credentials. | Re-copy both values from the Daraja app. Confirm the app is live. |
| *"Safaricom rejected the callback registration. Reason: The saved paybill or shortcode is not recognized…"* | The shortcode is not one Daraja recognizes for this app. | Verify the paybill in Daraja and correct it in Settings → Payments. |
| *"…The callback URLs may already be registered…"* | Safaricom already holds URLs for this shortcode. | Check the active URLs in Daraja, or ask Safaricom to reset them. |
| Callback registration reports both URLs were rejected | Safaricom would not accept one or both URLs. | Confirm your workspace domain is a public HTTPS address that resolves from outside your network. |
| *"Safaricom could not be reached. Try again."* | The registration request could not connect. | Check outbound connectivity from the application host, then retry. |
| STK prompt never arrives | The push was acknowledged but not delivered. | Confirm the number is on Safaricom and can receive STK, and that the paybill or till is active. |
| Payer paid, service not applied | The callback did not arrive or did not match a checkout. | See [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Selcom
Source: https://docs.centipidbilling.com/billing/payment-gateways/selcom
Collect Tanzanian mobile money with Selcom wallet push: get Checkout API access, enter the Vendor ID and keys, and see how an order is confirmed as paid.
## Collect payments with Selcom
`SELCOM` collects by **wallet push**. The payer enters their number on the
portal, a PIN prompt appears on their phone, and they approve it there. They
never leave the portal page.
Offered in the country catalog for **Tanzania (TZ)**.
Centipid Billing uses three calls from Selcom's
[Checkout API](https://developers.selcommobile.com/#checkout-api):
1. `create-order-minimal` opens an order for the amount.
2. `wallet-payment` sends the PIN prompt for that order to the payer's number.
3. `order-status` reports whether the order was paid.
Nothing is credited until `order-status` reports the order `COMPLETED`.
## Before you start
Ask Selcom's business team for Checkout API access on an account owned by the
ISP. They issue three values: a **Vendor ID** (the till, often starting with
`TILL`), an **API key**, and an **API secret**. Selcom's public docs list no
test environment. If you want to test before going live, ask Selcom for test
keys and the test host that goes with them.
## Configure the gateway
Select Selcom from the payment marketplace.
All three are required. The key and secret are stored as secrets.
Leave **API host** blank for Selcom's live gateway
(`https://apigw.selcommobile.com`). Enter the test host here while testing,
then clear it when you switch to live keys.
Pay a small amount from the captive portal, approve the prompt on the
phone, and confirm the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Vendor ID | Yes | The till Selcom settles into. |
| API key | Yes | Sent, base64-encoded, on every request. |
| API secret | Yes | Signs every request and checks Selcom's webhook. Never sent. |
| API host | No | Blank means the live gateway. Must be `https://`. Changing it needs the same verification as a credential change. |
## Callback URL
There is nothing to paste into Selcom. Every order carries its own webhook
(`/api/selcom/callback`) on the ISP's domain.
Selcom calls the webhook only when a payment succeeds. So Centipid also asks
Selcom for the order's status every 5 seconds for about 3 minutes after the
prompt is sent. That check is what connects the payer, and what tells the
portal when a payer declined the prompt. A webhook whose signature does not
match the API secret is rejected.
## Troubleshooting
* **"Unable to send the Selcom payment prompt"**: the Vendor ID, API key, or
API secret is wrong, or the account has no Checkout API access. Selcom's
exact response is in the application log.
* **No prompt arrives**: check the number is a Tanzanian mobile-money number.
Selcom only accepts it as `255…`, and Centipid converts `07…` numbers
automatically.
* **The payer paid but did not connect**: search the payment by the
transaction ID on their receipt. Payments are stored under Selcom's
transaction ID.
# Stripe
Source: https://docs.centipidbilling.com/billing/payment-gateways/stripe
Set up Stripe Checkout for card payments on your own Stripe account in 44 countries: the secret key, the webhook URL and its two events, and the signing secret.
## Collect payments with Stripe
`STRIPE` sends the payer to a **Stripe-hosted Checkout page** to pay by card.
Apple Pay and Google Pay can appear there too, because Stripe treats them as
cards. Centipid Billing
creates the Checkout Session, sends the payer to it, and confirms the result on
a signed webhook that is re-checked against Stripe before anything is credited.
The money goes into **your own Stripe account**. Centipid Billing never holds
it, and this is not Stripe Connect: you open the account with Stripe yourself
and paste its keys here.
Offered in the country catalog for the 44 countries where Stripe opens accounts
online: Australia, Austria, Belgium, Brazil, Bulgaria, Canada, Croatia, Cyprus,
the Czech Republic, Denmark, Estonia, Finland, France, Germany, Gibraltar,
Greece, Hong Kong, Hungary, Ireland, Italy, Japan, Latvia, Liechtenstein,
Lithuania, Luxembourg, Malaysia, Malta, Mexico, the Netherlands, New Zealand,
Norway, Poland, Portugal, Romania, Singapore, Slovakia, Slovenia, Spain, Sweden,
Switzerland, Thailand, the United Arab Emirates, the United Kingdom and the
United States.
Stripe is not offered in Kenya, Nigeria, Ghana, South Africa or Côte d'Ivoire.
Stripe serves those countries through Paystack, which is already in the
catalog. India and Indonesia are invite-only at Stripe.
## Before you start
1. Open a Stripe account owned by the ISP and finish activation, so it can take
live payments.
2. Make sure **Cards** is turned on in **Settings → Payment methods**. Centipid
Billing asks Stripe for card payments only. Bank debits and voucher methods
(SEPA, Bacs, ACH, OXXO, Konbini, Boleto) are left out on purpose: the money
arrives hours or days later, so the payer could not go online at once.
3. Plan the walled garden: the payer's browser must reach Stripe's Checkout
page, so a Hotspot subscriber who is not yet online cannot pay unless Stripe
is reachable before login. Centipid Billing adds Stripe's hosts to your
routers' walled garden when Stripe is your connected gateway.
Some cards, common in the UK and EU, need a 3-D Secure check on the card
issuer's own website. That website is the bank's, so it cannot be added to the
walled garden in advance. A Hotspot payer who is not yet online may fail that
check and be unable to pay with that card. Subscribers paying from PPPoE or
from the customer portal are already online and are not affected.
## Configure the gateway
Select Stripe from the payment marketplace.
In Stripe, open **Developers → API keys** and copy the **Secret key**. It
starts with `sk_live_` on a live account and `sk_test_` in test mode. A
restricted key (`rk_live_…`) also works if it has write access to Checkout
Sessions. The publishable key (`pk_…`) is not needed and is refused.
Copy the **Webhook URL** shown under Callback URLs on the Stripe settings
page. In Stripe, open **Developers → Webhooks → Add endpoint**, paste the
URL, and select exactly these two events:
* `checkout.session.completed`
* `checkout.session.async_payment_succeeded`
On the endpoint you just created, reveal the **Signing secret**. It starts
with `whsec_`. Paste it into **Webhook signing secret**.
Pay a small amount from the captive portal on a device that is not logged
in, and confirm the payment reaches the ledger and the subscriber connects.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Secret key | Yes | Secret. `sk_live_…`, `sk_test_…`, or a restricted `rk_…` key. |
| Webhook signing secret | Yes | Secret. `whsec_…`, from the webhook endpoint in Stripe. |
Both fields gate the switch. Each webhook endpoint has its own signing secret,
so if you delete and re-create the endpoint, paste the new secret too.
## Callback URLs
| Name | Path |
| - | - |
| Webhook URL | `https:///api/stripe/callback` |
The payer's browser returns to `https:///api/stripe/return` after
Checkout. Centipid Billing sends that address with every payment, so there is
nothing to register for it.
Stripe signs each webhook with the endpoint's **signing secret** and a
timestamp. A wrong or missing secret means every webhook is rejected with
HTTP 400. Payers who wait for the return page are still connected, but a
payer who closes the tab before it loads is charged and left disconnected
until someone reconciles by hand.
## What the payer must provide
An email address and card details, or an Apple Pay or Google Pay approval
where the payer's device offers one. Stripe may also ask the card's bank for a
3-D Secure check, which opens a page on the bank's own website.
The currency is your account's billing currency, defaulting to `USD`. Stripe
must support that currency for your country.
Amounts are sent in the currency's smallest unit: £5.50 is sent as `550`.
Currencies without minor units, such as JPY, are sent as they are: ¥500 is
`500`.
### Minimum charge
Stripe refuses a payment below its minimum for the currency, so a very cheap
package cannot be paid through Stripe. Among the currencies its countries use:
| Currency | Minimum |
| - | - |
| USD | 0.50 |
| GBP | 0.30 |
| EUR | 0.50 |
| JPY | 50 |
| THB | 10 |
| MXN | 10 |
The full list, and how it works when Stripe converts to another payout
currency, is in Stripe's
[minimum and maximum charge amounts](https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts).
Price packages sold through Stripe at or above the minimum.
## How a payment completes
Centipid Billing creates a Checkout Session for the amount, tagged with our
own reference, and writes a pending row against that reference.
The payer pays on Stripe's Checkout page and is sent back to the return page.
Stripe posts the signed webhook. The signature and its timestamp are
checked, the session is then read back from the Stripe API, and only a
session whose `payment_status` is `paid` records a payment and applies the
package. The return page runs the same check. A repeated webhook updates the
same payment rather than crediting it twice.
Card payments settle before the payer returns, so
`checkout.session.completed` normally carries them. Subscribing to
`checkout.session.async_payment_succeeded` as well covers a payment Stripe
confirms later.
Events for sessions that other software, or another Centipid Billing account,
created on the same Stripe account are acknowledged and ignored. Sharing the
Stripe account is safe.
If Stripe's API cannot be reached when a webhook arrives, Centipid Billing
answers with HTTP 503 so Stripe sends the webhook again later.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | The secret key is missing or Stripe refused the session. | Check the secret key, and that the account is activated for live payments. |
| *"Unable to process payment"* only on cheap packages | The package price is below Stripe's [minimum charge](#minimum-charge) for your currency. | Raise the price to at least the minimum, or sell that package another way, such as vouchers. |
| A Hotspot payer's card fails at the bank check | The card needs 3-D Secure, and the bank's page is not reachable before login. | Ask the payer to try another card, or to buy a voucher instead. |
| Test payments work, live does not | The key is still `sk_test_…`. | Replace it with the live secret key, and re-create the webhook in live mode: test-mode and live-mode webhooks have different signing secrets. |
| The Checkout page never loads on a Hotspot device | The walled garden does not allow Stripe. | Confirm Stripe is the connected gateway so the routers are synced, then see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments succeed in Stripe, ledger stays empty | Webhooks are being rejected or not sent. | In Stripe, open the endpoint's event log. A 400 means the signing secret is wrong: re-copy it. No attempts means the two events are not selected. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Till number (without API keys)
Source: https://docs.centipidbilling.com/billing/payment-gateways/till-number
Send M-Pesa Buy Goods STK prompts in Kenya into your own till using the platform's Daraja keys, so you can collect before your own Daraja setup is done.
## Collect payments with your till, without API keys
`TILL_NUMBER` sends a real M-Pesa Buy Goods STK push to the payer, using **the
platform's Daraja credentials** rather than your own. You supply only your till
number; the money settles into that till.
Available to ISPs in **Kenya (KE)**.
The payer receives an STK prompt and enters their M-Pesa PIN — this is not an
instructions-only method. The difference from
[Safaricom M-Pesa](/billing/payment-gateways/safaricom) in till mode is that
the Daraja API keys are the platform's, so you can collect before your own
Daraja onboarding is finished.
## Before you start
1. Have an active M-Pesa Buy Goods till registered to your business.
Need a till number? We can help Kenyan clients get one. Contact support with
a copy of your ID, your primary phone number, and a contact email. The service
costs KES 2,500 and the application is submitted after payment is confirmed.
## Configure the gateway
Select the method from the payment marketplace.
**Till number** (required, maximum 20 characters) is the M-Pesa till shown
to subscribers and the account the money lands in. No Daraja keys are
requested.
The till number is the only field that gates the switch. Switching gateways
may require an OTP confirmation.
Pay a small amount from the captive portal, and confirm the money arrives in
the till.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Till number | Yes | Maximum 20 characters. Your own Buy Goods till. |
## Callback URLs
None. The callback address is sent with every payment request, so there is
nothing to register with Safaricom.
## What the payer must provide
A Safaricom phone number, which receives the Buy Goods STK prompt.
## How a payment completes
Centipid Billing raises a `CustomerBuyGoodsOnline` STK push against your
till, using the platform's Daraja app.
The payer enters their M-Pesa PIN.
Safaricom posts the result to the platform callback, which records the
payment and applies the subscriber's package asynchronously.
## Payments typed in by hand
A till has no account-number field, so there is no pay-by-hand instruction for
an invoice on this method — a customer paying by hand cannot tell you which
subscriber the money is for. TV payments are the exception: the TV screen shows
the Centipid paybill, and that money is collected by the platform against the
TV code and remitted to you.
Prove where money lands with a controlled test payment before moving subscribers
onto this method.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Unable to process payment. Please try again later."* | The STK push failed or Safaricom was unreachable. | Confirm the till is active and accepts Buy Goods payments, then retry. If it persists, raise it with support — the platform credentials are not yours to correct. |
| The prompt names an unexpected till | The saved till number is wrong. | Correct it in Settings → Payments. |
| Payer paid, service not applied | The callback did not arrive or did not match a checkout. | See [Payment troubleshooting](/billing/payment-gateways/troubleshooting). |
To hold your own Daraja keys instead, see
[Safaricom M-Pesa](/billing/payment-gateways/safaricom). For every gateway's
fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Payment troubleshooting
Source: https://docs.centipidbilling.com/billing/payment-gateways/troubleshooting
Find where a payment failed: a form that will not save, no phone prompt, a rejected callback, a duplicate, or a paid subscriber who still has no access.
## Trace the payment lifecycle
Determine the failing stage before changing credentials:
1. **Readiness:** required fields saved and gateway selected.
2. **Initiation:** application/provider accepts the request.
3. **Customer authorization:** prompt or hosted checkout completes.
4. **Callback/verification:** provider result reaches and passes signature checks.
5. **Ledger:** payment reaches correct status with unique reference.
6. **Entitlement:** subscriber/package/invoice updates.
7. **Receipt/notification:** customer communication is generated.
8. **Settlement:** provider funds reconcile externally.
## Credential form will not save
Read field-level errors. Common causes:
* missing required values;
* test/live mismatch;
* malformed URL/currency/country;
* invalid paybill/till format;
* a secret entered in the wrong field.
Compare [Credential reference](/billing/payment-gateways/credentials-reference).
## Request is rejected immediately
Check:
* account activation;
* environment endpoints;
* merchant/product/service code;
* credential revocation;
* amount/currency and phone format;
* provider availability.
Do not repeatedly send the same request while rate-limited.
## Customer receives no phone prompt
Confirm the gateway actually uses a phone prompt. Then check the phone country/format, provider account permissions, shortcode/till/paybill, and provider request status. Hosted-checkout providers require browser redirect rather than STK.
## Captive device cannot reach checkout
Check router DNS/internet, the gateway domain and walled-garden rules. Confirm the configured endpoint is correct for the environment. Use **Sync walled garden** rather than opening unrestricted internet access.
## Payment remains pending
Search by provider reference/receipt. Inspect the provider dashboard, and check callback/return status. Browser return is not final verification. Do not create a manual payment until the provider transaction is conclusively failed/unmatched.
## Callback rejected
Likely causes:
* wrong signing secret;
* wrong environment;
* provider callback URL drift;
* missing merchant activation;
* timestamp/body mismatch;
* duplicate reference.
Preserve sanitized request ID, HTTP status, provider event/reference, and timestamp. Never log or share full secrets.
## Duplicate payment or credit
Compare receipt/provider reference, amount, subscriber, and time. Preserve both records while investigating. Reverse/delete only through an approved reconciled process. Avoid changing subscriber expiry first and explaining the ledger later.
## Successful payment but wrong subscriber
Stop further entitlement changes. Verify account-number/phone/receipt mapping and identify the intended payer. Then use supported reassignment/correction with an audit trail. Do not solve it by creating another subscriber/payment.
## Successful payment but no access
Check the entitlement stage:
* subscriber association and package;
* expiry and pause/block;
* device limit and active session;
* NAS/RADIUS state;
* invoice linkage.
The payment gateway is no longer the likely fault once ledger and entitlement update are confirmed.
## Settlement differs from ledger
Reconcile provider fees, reversals/refunds and pending transactions. Also check manual methods, date/timezone cutoffs, and wallet eligibility. The application ledger is operational evidence, not a substitute for provider/bank settlement records.
## Escalation evidence
Provide:
* gateway code/environment and the ISP account;
* amount/currency and masked phone/account;
* application payment ID and provider reference;
* timestamps/timezone and the stage reached;
* the sanitized error and actions tried.
Exclude API keys, passkeys, private keys, passwords and OTPs. Also exclude full callback payloads containing secrets/personal data.
# Vodacom M-Pesa
Source: https://docs.centipidbilling.com/billing/payment-gateways/vodacom-mpesa
Collect Vodacom M-Pesa in DR Congo and Tanzania through the M-Pesa Open API: API key, public key, merchant code, CDF or USD in DRC, and callback URLs.
## Vodacom M-Pesa
`VODACOM_MPESA` collects through Vodacom's M-Pesa Open API in the Democratic
Republic of the Congo and Tanzania: a customer-to-business request is pushed to the payer's
M-Pesa wallet, the payer approves it on their handset, and Vodacom's callback
records the payment.
The country catalog offers it for the **Democratic Republic of the Congo (CD)**
and **Tanzania (TZ)**. Your account's country picks the Vodacom market:
DRC requests go to `vodacomDRC`, Tanzanian requests to `vodacomTZN`.
## Before you start
1. Create an application on the Vodacom M-Pesa Open API portal under an account
owned by the ISP, for your market (DRC or Tanzania).
2. Collect the **API key**, the **public key**, and the **merchant code** (the
service provider code money is collected into).
3. DRC only: decide the currency subscribers pay in, Congolese franc (`CDF`) or
US dollar (`USD`). Tanzania always settles in Tanzanian shillings (`TZS`).
## Configure the gateway
Select Vodacom M-Pesa from the payment marketplace.
**Merchant code** (required) is the service provider code payments are
collected into.
Both are required and stored as secrets. Leave a stored key blank when
editing to keep it.
**Currency** is `CDF` unless you choose `USD`. Tanzanian ISPs don't see
this field; prompts are in `TZS`.
Copy the callback URL shown on the page into your application on the
Vodacom portal.
Pay a small amount from the captive portal and confirm the prompt reaches
the handset and the payment reaches the ledger.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Merchant code | Yes | The service provider code money is collected into. |
| API key | Yes | Secret. From the Vodacom M-Pesa Open API portal. |
| Public key | Yes | Secret. Used to encrypt the session key on every request. |
| Currency | No | DRC only: `CDF` or `USD`; `CDF` when not set. Tanzania uses `TZS`. |
The merchant code, API key, and public key gate the switch.
## Callback URLs
The payment request carries no callback address, so register this one on the
Vodacom portal:
```
https:///api/vodacom-mpesa/callback
```
It is shown on the gateway page, built from your primary domain. It is not
updated by Centipid Billing after a domain change, so update it on the portal
yourself.
## How a payment completes
Centipid Billing fetches a session key and encrypts it with the configured
public key.
A customer-to-business payment is pushed to the payer's M-Pesa number,
normalized to `243…` (DRC) or `255…` (Tanzania), for the merchant code.
The payer approves the prompt on their handset.
Vodacom calls the callback URL, and the payment is recorded and the package
applied. A repeated callback for the same transaction is ignored.
Requests go to Vodacom's production Open API host for your market. There is no
sandbox switch.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Vodacom M-Pesa credentials are incomplete. Please update the payment settings."* | The API key, public key, or merchant code is missing. | Complete all three in **Settings → Payments → Vodacom M-Pesa**. |
| *"Unable to authenticate with Vodacom M-Pesa. Please try again."* | The session key could not be obtained. | Re-enter the API key; a rotated key is the usual cause. |
| *"Vodacom M-Pesa session encryption failed."* | The stored public key could not encrypt the session key. | Paste the public key again in full; it is malformed or truncated. |
| *"Unable to connect to Vodacom M-Pesa. Please try again later."* | The request could not connect. | Check outbound connectivity from the application host, then retry. |
| The payer approved but no payment appears | The callback did not arrive. | Confirm the callback URL on the Vodacom portal matches the one on the gateway page. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Xendit
Source: https://docs.centipidbilling.com/billing/payment-gateways/xendit
Set up Xendit on your own account in the Philippines, Indonesia, Thailand, Malaysia or Vietnam: the secret API key, the session webhook and verification token.
## Collect payments with Xendit
`XENDIT` sends the payer to a **Xendit-hosted payment page**. There the payer
picks a local method: GCash or Maya in the Philippines, QRIS, e-wallets or bank
transfer in Indonesia, PromptPay in Thailand, FPX online banking in Malaysia,
e-wallets in Vietnam, or a card. Which methods appear is up to you: Xendit
shows every method you have activated on your account.
Centipid Billing creates a Xendit payment session, sends the payer to its
payment link, and confirms the result on a webhook that is re-checked against
Xendit before anything is credited.
The money goes into **your own Xendit account**. Centipid Billing never holds
it. You open the account with Xendit yourself and paste its keys here.
Offered in the country catalog for the five countries where Xendit opens
accounts: the Philippines, Indonesia, Thailand, Malaysia and Vietnam.
## Before you start
1. Open a Xendit account owned by the ISP and finish verification, so it can
take live payments.
2. Activate the payment methods you want payers to see, under **Payment
methods** in the Xendit dashboard.
3. Check your billing currency. Xendit bills each country in one currency:
`PHP` in the Philippines, `IDR` in Indonesia, `THB` in Thailand, `MYR` in
Malaysia and `VND` in Vietnam. Your Centipid Billing account must be in that
currency, or every payment is refused before it reaches Xendit.
4. Plan the walled garden: the payer's browser must reach Xendit's payment
page, so a Hotspot subscriber who is not yet online cannot pay unless Xendit
is reachable before login. Centipid Billing adds Xendit's hosts to your
routers' walled garden when Xendit is your connected gateway.
An e-wallet or online-banking payment can hand the payer over to the
provider's own website (GCash, Maya, a Malaysian bank's FPX page). That
website is not Xendit's, so it cannot be added to the walled garden in
advance. A Hotspot payer who is not yet online may be stopped there. QR
methods (QRIS, PromptPay, QR Ph) are paid in the payer's banking app over
mobile data and are not affected. Subscribers paying from PPPoE or from the
customer portal are already online and are not affected either.
## Configure the gateway
Select Xendit from the payment marketplace.
In Xendit, open **Settings → Developers → API keys** and create a secret
key with write access to Money-in. It starts with `xnd_production_` on a
live account and `xnd_development_` in test mode. The public key is not
needed and is refused.
Copy the **Webhook URL** shown under Callback URLs on the Xendit settings
page. In Xendit, open **Settings → Developers → Webhooks** and paste it
into **Payment Session – Completed**. Leave the legacy **Payment Link**
(invoice) webhook alone: Centipid Billing does not use it.
On the same Webhooks page, reveal the **verification token** and paste it
into **Webhook verification token**.
Pay a small amount from the captive portal on a device that is not logged
in, and confirm the payment reaches the ledger and the subscriber connects.
## Credentials
| Field | Required | Notes |
| - | - | - |
| Secret API key | Yes | Secret. `xnd_production_…` or `xnd_development_…`. |
| Webhook verification token | Yes | Secret. From **Settings → Developers → Webhooks** in Xendit. |
Both fields gate the switch. Test mode and live mode have separate keys and
separate verification tokens.
## Callback URLs
| Name | Path |
| - | - |
| Webhook URL | `https:///api/xendit/callback` |
The payer's browser returns to `https:///api/xendit/return` after
paying. Centipid Billing sends that address with every payment, always over
HTTPS because Xendit refuses anything else, so there is nothing to register
for it.
Xendit sends the verification token in the `x-callback-token` header of every
webhook. A wrong or missing token means every webhook is rejected with HTTP
400\. Payers who wait for the return page are still connected, but a payer who
closes the tab before it loads is charged and left disconnected until someone
reconciles by hand.
## What the payer must provide
Whatever the chosen method asks for: an e-wallet approval, a QR scan in a
banking app, an online-banking login or card details.
Amounts are sent in the main currency unit, not cents: ₱50 is sent as `50`.
Rupiah and dong are sent as whole numbers; pesos, baht and ringgit keep two
decimals.
## How a payment completes
Centipid Billing creates a Xendit payment session for the amount, tagged
with our own reference, and writes a pending row against that reference.
The payer pays on Xendit's page and is sent back to the return page. A
payer who chose a method paid later, such as an Indonesian virtual account
or an Alfamart code, is told the payment is being confirmed and not to pay
again.
Xendit posts the `payment_session.completed` webhook. The token is checked,
then the session Centipid Billing created for this payment is read back
from the Xendit API. Only a session that is `COMPLETED` records a payment
and applies the package. The return page runs the same check. A repeated
webhook updates the same payment rather than crediting it twice.
Webhooks for sessions that other software created on the same Xendit
account are acknowledged and ignored, and so are expired sessions.
A Xendit account has one **Payment Session – Completed** webhook URL. Two
ISPs can share one Xendit account without a payment ever being credited to
the wrong one, but only the ISP whose URL is registered receives webhooks.
The other connects payers only when they reach the return page, so a payer
who closes the tab first stays disconnected until someone reconciles by
hand. Give each ISP its own Xendit account.
If Xendit's API cannot be reached when a webhook arrives, Centipid Billing
answers with HTTP 503 so Xendit sends the webhook again later.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"Xendit bills in PHP here, but your prices are in USD."* | Your billing currency is not the one Xendit uses in your country. | Contact Centipid support to change your billing currency. |
| *"Unable to process payment. Please try again later."* | The secret key is missing, lacks Money-in write access, or Xendit refused the payment session. | Check the key and its permissions, and that the account is verified for live payments. |
| A Hotspot payer is stopped on GCash, Maya or a bank page | The provider's own website is not reachable before login. | Ask the payer to pay by QR from mobile data, or to buy a voucher instead. |
| Test payments work, live does not | The key is still `xnd_development_…`. | Replace it with the live key, and copy the live-mode verification token too. |
| The payment page never loads on a Hotspot device | The walled garden does not allow Xendit. | Confirm Xendit is the connected gateway so the routers are synced, then see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments succeed in Xendit, ledger stays empty | Webhooks are being rejected or not sent. | In Xendit, open the webhook log. A 400 means the verification token is wrong: re-copy it. No attempts means the URL is not under **Payment Session – Completed**. |
For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# ZenoPay
Source: https://docs.centipidbilling.com/billing/payment-gateways/zenopay
Collect Tanzanian mobile money through ZenoPay with a single API key: the payer approves a wallet prompt, and the order is checked until the payment completes.
## Collect payments with ZenoPay
`ZENOPAY` pushes a payment request to the payer's mobile-money wallet. The payer
authorizes it on their handset, and the order is polled to completion.
Available to ISPs in **Tanzania (TZ)**, alongside ClickPesa, AzamPay, PalmPesa,
PawaPay, PesaPal, Relworx, PayPal, and DPO.
## Before you start
1. Complete ZenoPay merchant onboarding in an account owned by the ISP.
2. Collect the **API key** from the ZenoPay merchant dashboard.
3. Confirm your workspace is reachable from the public internet, so ZenoPay can
deliver its webhook.
## Configure the gateway
Select ZenoPay from the payment marketplace.
**API key** (required) is stored as a secret and is not echoed back into the
form after saving. It is sent as the `x-api-key` header on every request.
**API host** (optional) overrides the endpoint Centipid Billing calls. Leave
it empty to use the default ZenoPay host.
Pay a small amount from the captive portal. Verify the wallet prompt
arrives, the payment lands in the ledger with method **ZenoPay**, and the
subscriber's package is applied.
## Credentials
| Field | Required | Notes |
| - | - | - |
| API key | Yes | Secret. From the ZenoPay merchant dashboard. The only field required to switch to ZenoPay. |
| API host | No | Falls back to the default ZenoPay host. Enter a full URL. |
## Callback URLs
The webhook address is sent with every payment request, so there is nothing to
register in the ZenoPay dashboard. Settings → Payments still shows it under
**Callback URLs** (`https:///api/zenopay/webhook`) so you can confirm
the address ZenoPay will call, and check it is not blocked by a firewall or WAF
rule.
## What the payer must provide
* **Email address (supplied automatically).** ZenoPay rejects an order without
one, but no payer is asked to type an address. The subscriber's saved profile
email is used when there is one; otherwise an address is derived from the
phone number being paid with, on an unroutable domain. A hotspot payer with no
account can therefore pay normally. If ZenoPay ever emails a receipt, only
payers with a real profile email will receive it.
* **Tanzanian phone number (required).** Accepted in local or international
form; it is normalized before it is sent.
* **Amount.** Rounded to a whole number before the request is sent.
Because authorization happens on the payer's handset rather than in a hosted
checkout page, no ZenoPay domain needs to be added to the captive walled garden.
## How a payment completes
Centipid Billing posts the order to
`/api/payments/mobile_money_tanzania` with an **order id it generates
itself**. That id is the local transaction reference, so the handle
everything reconciles against exists before ZenoPay answers.
The payer approves the request on their phone.
A background job polls `/api/payments/order-status` every 5 seconds, for up
to 40 attempts (about 3 minutes 20 seconds), until the order reaches a
terminal state. **This poller — not the webhook — is what completes the
payment**, so a payment still completes when the payer closes the captive
browser mid-checkout.
On `COMPLETED`, a payment is recorded with method **ZenoPay** and the
subscriber's package is applied asynchronously. On `FAILED`, the reason is
stored against the transaction and nothing is credited.
ZenoPay's webhook carries no signature, HMAC, or shared secret in its body, so
it cannot prove it came from ZenoPay. Centipid Billing treats it as a hint
only: nothing is credited from the webhook body. Every credit is made against
a status read from ZenoPay with your own API key, so a spoofed "completed"
webhook cannot provision a subscriber.
A failed request is deliberately **not** retried automatically. An automatic
retry after a lost response could raise a second prompt on the same order and
charge the payer twice. The payer retries by choice instead.
## Troubleshooting
| Symptom | What it means | What to do |
| - | - | - |
| *"ZenoPay API key not configured."* | No API key is saved. | Enter it in Settings → Payments → ZenoPay. |
| *"ZenoPay authentication failed. Check the API key."* | ZenoPay rejected the key. | Re-copy it from the merchant dashboard. Confirm the account is live. |
| *"A valid Tanzanian phone number is required for ZenoPay payments."* | The number could not be normalized. | Re-enter it in local or international form. |
| *"Could not reach ZenoPay. Please try again."* | The request could not reach ZenoPay. | Check outbound connectivity from the application host, and any custom **API host** value. |
| A message from ZenoPay on a failed request | ZenoPay refused the order and its own reason is shown. | Read the message — it usually names the field at fault. |
| Payer paid, but the transaction sits pending | The order never reached a terminal state within the polling window. | Confirm the payment on the ZenoPay dashboard, then raise it with support with the order id and the payer's phone number. |
For symptoms that are not specific to ZenoPay, see
[Payment troubleshooting](/billing/payment-gateways/troubleshooting). For every
other gateway's fields, see the
[credential reference](/billing/payment-gateways/credentials-reference).
# Payments
Source: https://docs.centipidbilling.com/billing/payments
Search the payment ledger by receipt, phone or reference, tell pending from confirmed, record manual payments, issue receipts and fix paid-but-offline cases.
## Use the payment ledger
Open **Billing → Payments**. The ledger is the ISP's operational view of money received or initiated for subscriber service. It supports search, method/status/date filters, incremental loading, detail pages, manual records, import/export, receipts, and—when the Centipid wallet is enabled—collection and withdrawal tabs.
## Payment status
The list distinguishes confirmed and pending records. A provider initiation, request ID, or customer prompt is not a confirmed payment. Treat access activation and reconciliation as complete only when the payment reaches the successful/final state expected by the current integration.
## Find a payment
Search using a stable value such as receipt, provider reference, subscriber name/username, phone, account number, or amount/date context. Apply status, method, date-window, and wallet-view filters before exporting or taking a bulk operational decision.
If two records appear similar, compare provider reference, receipt, amount, timestamp, subscriber, and gateway before deciding one is a duplicate.
## Payment detail
The detail page can show:
* amount, method, status, receipt/reference, and timestamps;
* subscriber and package/network context;
* invoice linkage;
* payout/disbursement state where applicable;
* related payments and activity;
* receipt actions and safe edit/delete actions allowed by policy.
Use the detail page when a subscriber reports “paid but offline.” Confirm the record belongs to that subscriber before changing expiry or access.
## Record a manual payment
Use manual creation only for money received outside an automatic callback and supported by the business process.
1. Select the subscriber when available.
2. Enter the amount and current payment method/reference fields.
3. Use the real receipt/reference; do not invent one to satisfy a workflow.
4. Review the resulting package/expiry/invoice effects.
5. Save once and verify the ledger/profile.
### Installation fees collected on site
If your technician collects an install fee at the customer's premises, enter it in the **Installation fee** card when you add the PPPoE or static-IP subscriber. For an existing subscriber, record it here with **Payment for** set to **Installation fee**. It counts as revenue in the ledger, but it never renews the subscriber's plan or adds wallet credit. Recorded as Hotspot or PPPoE instead, the same amount would renew the plan when it matches a package price, or be banked as wallet credit.
Installation fees are saved as reconciled, so they cannot be edited afterwards. If you enter one wrongly, delete it and record it again.
Do not record a manual payment merely because an online payment is still pending. First check the provider and callback state to avoid double credit.
## Receipts
A payment can expose a PDF receipt, resend action, and email-receipt dialog. The email defaults to the subscriber address when available and must be a valid address if supplied. Receipt resend/email endpoints are rate-limited; repeated clicking is not a delivery troubleshooting strategy.
Verify the amount, receipt number, subscriber, the ISP's identity, and email before sending.
## Import and export
The import/export workspace supports controlled payment migration/reporting. Export requires a valid start/end date with end on or after start. Limit columns and date range to the business need, protect exported personal/financial data, and reconcile totals with the filtered ledger.
When importing, preview a small set, preserve provider references, and identify duplicates before writing. Never upload a bank/provider export to an unrelated ISP account.
## Editing and deletion
Editing a payment can affect subscriber, invoice, and reporting relationships. Deletion is destructive and should be limited to demonstrably incorrect records. Reconciliation adjustments should preserve an audit trail whenever possible.
## Paid but service not active
1. Confirm successful status and provider/receipt uniqueness.
2. Verify subscriber association.
3. Check package, expiry, account pause/block status, and device limit.
4. Review active sessions and NAS health.
5. Confirm invoice state if the payment was intended for an invoice.
6. Apply one targeted correction; do not create duplicate payments.
See [Invoices](/billing/invoices), [Payment troubleshooting](/billing/payment-gateways/troubleshooting), and [Subscriber profile](/subscribers/profile).
# Subscription and renewal
Source: https://docs.centipidbilling.com/billing/subscription-renewal
Keep your own Centipid platform subscription active: check the expiry date and amount due, pay unpaid invoices in the app, and restore service after it lapses.
## Renew your Centipid subscription
Your **Centipid subscription** is your own account with the platform — the monthly charge that keeps your operator console running. It is separate from the invoices and payments you raise against *your* subscribers. Open it from the **account menu**: click your avatar in the top-right corner, then choose **Plan & billing** under **Workspace**. That opens the **My subscription** page (`/subscription`).
Open that page to see three things at the top:
* **Expires** — the date your subscription runs to.
* **Days left** — how long until renewal (shows **Expired** once it has lapsed).
* **Amount due** — the balance on your current unpaid invoice, or **all paid up**.
Below the strip is your full invoice history, newest first, with an in-app **Pay** button on every unpaid invoice.
The **Plan & billing** item only appears for administrators and finance staff. Support, technician, and marketing accounts do not see it — ask an admin or finance user to renew.
## What happens when it expires
Centipid warns you as expiry approaches and then locks the console until you renew.
* **From 5 days out**, a **Renew** card appears in the sidebar with a shortcut to the subscription page.
* **On the expiry day**, the account admins receive an email — *"Your subscription expires today."*
* **Once it lapses**, every operator page redirects to **My subscription**. You can still reach the subscription and payment pages, sign out, and open your own account settings (profile, security, password) — but nothing else until you renew.
Renew before the lapse whenever you can. An expired subscription locks you out of day-to-day operations — you cannot manage subscribers, routers, or payments while it is down.
## Renew
You can renew as soon as the invoice is payable — immediately if you are already expired, or within the 5-day run-up to the due date (see [the payment window](#the-payment-window)).
Open the **account menu** (your avatar, top-right) and choose **Plan & billing** — or click **Renew now** on the sidebar card. If you are locked out, you are taken there automatically.
Click **Pay** on the outstanding invoice (or the **Pay \[amount]** button in the page header). A modal shows the line items and the total due — review them before paying.
Pick a method in the modal:
* **Card** — you are redirected to Paystack's secure checkout to pay by card, then returned to Centipid.
* **Mobile Money** *(Uganda)* — enter the phone number, then approve the prompt on that phone. The amount is charged in UGX.
* **M-Pesa** *(Kenya)* — enter the M-Pesa number, then enter your PIN on the STK prompt that arrives on that phone.
The number defaults to your registered admin phone; you can change it.
For Mobile Money and M-Pesa, the modal waits and updates on its own once you approve. For card, complete the checkout on Paystack.
On success the page refreshes, the invoice moves to **Paid**, and your expiry date advances. Service is restored automatically.
Returning from the card checkout page is **not** by itself proof of payment. Confirm the invoice shows **Paid** and the expiry date has moved forward.
## What renewal gives you
Each renewal settles the outstanding invoice and adds **one month** to your subscription. How the new date is calculated depends on your current state:
* **Renewing after expiry** — the new month runs from the **day you pay**, not from the old lapsed date. You do not get the lapsed days back, but you also do not lose a full month.
* **Renewing early** — the extra month is added on top of the time you have left, so no remaining days are lost.
Behind the scenes, a successful renewal also:
* marks the current subscription invoice **Paid** and records it in your payment history;
* re-pushes your routers so any interrupted service comes back online;
* sends a renewal-confirmation SMS to your admin phone (Kenya).
If your subscription was expired for more than about a month, the confirmation notes that the new period *started from today due to long expiry* — the same "runs from the day you pay" rule, spelled out.
## The payment window
A subscription invoice is due on your expiry date, so the **Pay** flow opens only inside the **5 days before** that due date — or any time **after** it has passed. This stops you paying weeks early by mistake.
* **Already expired?** The invoice is past due, so you can pay immediately.
* **Not yet in the window?** The modal shows *"Payment for this invoice opens on \[date]"* and keeps the Pay button disabled until then. You can still review the charges.
## Amounts and invoices
* The renewal amount is your subscription invoice total, carried forward from your usage and last invoice, with a small country minimum applied.
* Every invoice — paid or unpaid — has a **PDF** link for your records.
* Expand the **charged PPPoE** line on your current invoice to see which users the charge covers.
## Troubleshooting
The modal polls for roughly two minutes. If you approved the prompt, close it and refresh the page in a moment — Ugandan mobile-money payments are also reconciled automatically by a background check, so a missed confirmation still renews you.
Either the invoice is not yet inside its 5-day payment window (the modal shows when it opens) or your account lacks finance access. If you are expired, the button is always active.
The **Plan & billing** menu item is finance-only. Sign in as an administrator or a finance user, or ask one to renew on your behalf.
Check that the invoice shows **Paid** and the expiry date advanced. Payments settle exactly once, so a retry never double-charges an already-paid invoice.
## Stay ahead of expiry
* Keep expiry notifications enabled so admins get the reminder email — see [Notifications and templates](/communications/notifications-and-templates).
* Renew inside the 5-day window rather than waiting for the lock-out.
* Keep your admin phone and email current under [Settings](/getting-started/settings) so reminders and confirmations reach you.
# Message campaigns
Source: https://docs.centipidbilling.com/communications/message-campaigns
Schedule one-time or recurring SMS and email campaigns to chosen subscriber audiences, check when they send, and avoid duplicate sends when editing or deleting.
## Schedule subscriber messages
Open **Communications → Message campaigns**. This tool is for scheduled SMS/email, not captive banners.
The list shows four cards: **Total**, **Scheduled** (upcoming sends), **Completed** and **Failed**. Tabs filter by All, Scheduled, Processing, Completed and Failed. Each row shows the channel, audience, next send, recurrence, status and the number sent.
## Required fields
* Name: required, maximum 120 characters.
* Channel: SMS or Email.
* Email subject: required for Email, maximum 255.
* Message: required, 1–1,600 characters.
* Audience type: Everyone, Segments, Mikrotiks, or Specific users.
* Scheduled time: required.
* Audience selection: required when the type is not Everyone.
Optional recurrence ends must be after the scheduled start.
## Recurrence
Current options are one-time, daily, weekly, monthly, yearly, and holiday (annually). Holiday repeats on the same date each year, like yearly. Choose the rule whose calendar semantics match the message. Set an end when the campaign should not continue indefinitely.
After a successful run, a recurring campaign schedules its next send. A run that fails is not rescheduled. Fix the cause, then edit the campaign to set a new time.
## When campaigns send
Centipid checks for due campaigns every 5 minutes. So a send can start a few minutes after its scheduled time. Each check sends up to 25 due campaigns per ISP. A run is not retried automatically.
A run fails with a clear reason when:
* the SMS gateway is not configured;
* no recipients match the audience filters;
* the message could not be delivered to any recipient.
Open the campaign to see its last run: status, sent and failed counts.
## Create safely
1. Give the campaign an internal name describing purpose/audience.
2. Select SMS or Email and configure the corresponding provider first.
3. For Email, write a subject suitable for every selected recipient.
4. Choose the smallest correct audience.
5. Insert only supported variables and preview representative output.
6. Set schedule and recurrence in the account timezone.
7. Review consent, cost, and operational impact.
8. Save and confirm status/scheduled time in the campaign list.
## Editing and deletion
Editing an upcoming recurring campaign affects later dispatches according to its current schedule. Before changing audience or message, confirm whether an earlier run has already been sent. Delete only when future sends should stop and history retention is not required. The list offers Edit and Delete; there is no pause.
## Avoid duplicate sends
Do not create a second campaign merely because an immediate status is unclear. Check scheduled time, recurrence, sent/failed counts, queue/provider state, and the existing campaign record first.
# Notifications and templates
Source: https://docs.centipidbilling.com/communications/notifications-and-templates
Set up automated subscriber messages such as payment confirmations and expiry reminders, plus router alerts, outage compensation notices and sales reports.
## Automate messages deliberately
Open **Settings → Message templates** for subscriber-event copy and **Settings → Operator alerts** for operational notifications.
## Subscriber templates
Current template switches include:
* PPPoE payment/renewal confirmation;
* Hotspot payment confirmation;
* Hotspot confirmation for new users only;
* voucher SMS;
* PPPoE expiry notice;
* Hotspot expiry notice;
* PPPoE pre-expiry reminder;
* bundle-usage warning and trigger percentage.
Message fields enforce a 320-character maximum. Insert variables only from the UI. Test with records that have and lack optional values. That keeps messages readable.
## Pre-expiry reminders
PPPoE reminder timing is configured under **Settings → PPPoE**. The template controls content. Both must be enabled. The subscriber also needs a valid phone and provider path.
## Router-status alerts
Enable MikroTik status notifications. Then pick the phone numbers to alert, or leave the list empty to use the administrator default. You can also prefer WhatsApp when it is configured.
Test provider delivery separately from router monitoring. An outage can be detected even if the notification provider is unavailable.
## Outage compensation
When enabled, monitoring can compensate qualifying outages based on:
* credit percentage of downtime (1–100);
* minimum outage duration (0–1,440 minutes);
* PPPoE, Hotspot, or all connection types;
* selected time-based packages or all;
* optional subscriber notification and message variables.
This setting can change subscriber service time at scale. Model a sample outage and credit first. Review the package selection, and use a controlled rollout.
## Sales reports
Operator alerts can turn on sales reports for the recipients and channel you set. Confirm the timezone. Also confirm each recipient may see financial information.
## Troubleshooting automation
If an expected message is missing, check:
* that the event qualifies and its switch is on;
* the template and the subscriber's phone;
* the provider setup and balance;
* the send record, its status and queue timing;
* any new-users-only, percentage or reminder condition.
Do not trigger the business event again before checking the first result.
# Communications overview
Source: https://docs.centipidbilling.com/communications/overview
Pick the right tool for one-off SMS or WhatsApp, recurring campaigns, captive portal banners or automated notices, and test before you message subscribers.
## Use the right communication workflow
The **Communications** menu sits under **Outreach** in the sidebar. It contains four distinct operator tools. They share audiences and provider configuration in places, but they produce different records and outcomes. WhatsApp and SMS need the **sms** permission. Message campaigns and Promo banners need the **campaigns** permission.
| Tool | Best for | Key behavior |
| - | - | - |
| WhatsApp | Immediate WhatsApp messages to selected/segmented subscribers | Uses the active WhatsApp provider; up to 480 characters; tracks send status in the channel log |
| SMS | Immediate SMS to selected/segmented subscribers | Estimates recipients/segments/cost; supports templates, resend, and provider balance |
| Message campaigns | Scheduled or recurring SMS/email | Requires schedule; supports audience filters and recurrence; checked every 5 minutes |
| Promo banners | Visual placements on the captive portal | Tracks views/clicks; uses media/destination and run window |
Automated receipts, expiry notices, voucher delivery, bundle warnings, router alerts, outage notices, and sales reports are configured under **Settings**, not created as ordinary campaigns.
## Before sending
1. Confirm the active provider for the intended channel.
2. Send a controlled test to a staff-owned address/number.
3. Select the smallest correct audience.
4. Review variables with a representative subscriber.
5. Check SMS segment/cost estimate or provider quota.
6. Confirm the sender ID/from number and legal/customer-consent requirements.
7. Schedule in the account timezone.
## Delivery interpretation
“Sent” can mean the provider accepted a request. Delivered/failed status depends on provider callbacks and handset/network reporting. Do not repeatedly resend every non-final record. Investigate the provider and recipient format first.
## Protect customer data
Export/recipient lists and message histories can contain phone numbers, emails, names, account data, and message content. Limit access, avoid unnecessary sensitive details in messages, and never send passwords, OTPs, recovery codes, API secrets, or complete payment credentials.
## Related guides
* [Send SMS](/communications/sms)
* [Message campaigns](/communications/message-campaigns)
* [Promo banners](/communications/promo-banners)
* [WhatsApp](/communications/whatsapp)
* [Providers and sender IDs](/communications/providers-and-sender-ids)
* [Notifications and templates](/communications/notifications-and-templates)
# Captive promo banners
Source: https://docs.centipidbilling.com/communications/promo-banners
Create scrolling text, image or video banners at the top or bottom of the Hotspot captive portal, schedule them, and track views and clicks for each campaign.
## Promote offers on the captive portal
Open **Communications → Promo banners**. These campaigns render promotional placements on captive pages and count views and clicks. They do not send SMS/email.
## Creative fields
* **Name:** required, maximum 120; internal reporting label.
* **Type:** banner (scrolling text, the default), image or video. For a banner, the Name is the text subscribers see.
* **Placement:** top or bottom of the captive page. Campaigns saved with an older placement (middle, sidebar) now show at the bottom.
* **Destination/media URL:** optional, maximum 500; meaning depends on type.
* **Media upload:** optional; uploaded file takes precedence over URL.
* **Display size:** small, medium, or large for media: up to 120, 200 or 300 pixels tall. Medium is the default.
* **Start/end:** optional; blank start begins now and blank end runs indefinitely.
Supported media:
* images: PNG, JPEG, WEBP up to 2 MB (SVG is refused because it can carry scripts);
* video: MP4, WEBM up to 10 MB.
End must be on or after start.
## Create a campaign
1. Choose a clear internal name.
2. Select type and placement.
3. For a link/banner, use a destination reachable by captive users.
4. For image/video, upload sanitized optimized media or use a trusted HTTPS URL.
5. Choose display size and preview on mobile/desktop captive layouts.
6. Set a deliberate run window.
7. Save and test from a real captive network.
## Walled-garden considerations
A destination or hosted media URL may be unreachable before authentication unless the router allows it. Prefer controlled domains, keep the allowlist narrow, and test without using an already authenticated browser session.
## Performance
A view is counted when the portal shows the creative, once per device every 10 minutes. The operator's theme preview does not count. Views are saved in batches about every 5 minutes, so the campaign list trails the portal slightly.
Views and clicks allow a click-through-rate calculation. They measure portal interaction, not completed purchase or revenue unless another analytics path links the outcome. Compare campaigns with similar audience/window before drawing conclusions.
## Find and track campaigns
The list shows four cards: **All campaigns**, **Live now**, **Impressions** and **Clicks** with the click-through rate. Tabs filter by All, Live, Scheduled and Ended. A campaign with no start or end date shows **Always** as its window.
Each slot on the portal shows one active banner of each type. The list of active banners refreshes every 60 seconds, so a change can take up to a minute to appear. Clicks are counted on image and video creatives.
## Remove media
The edit form's Remove action persists deletion of the saved creative. After removal, save the campaign and confirm the portal no longer renders the old cached asset.
# Messaging providers and sender IDs
Source: https://docs.centipidbilling.com/communications/providers-and-sender-ids
Choose an SMS or WhatsApp provider from the country-aware catalog, connect its credentials, set sender IDs and low-balance alerts, and switch providers safely.
## Configure messaging delivery
The provider marketplace is country-aware and allows one active provider per channel. Credential fields are generated from the current provider catalog and saved values feed the live sender implementations.
## Current SMS catalog
| Provider | Region | Credential fields |
| - | - | - |
| Centipid SMS | Kenya / platform default | No external keys; prepaid balance/top-up in application |
| Africa's Talking | Pan-African | Username, API key, sender ID |
| Arkesel | Ghana / West Africa | API key, sender ID |
| SMS Online GH | Ghana / West Africa | API key, sender ID |
| Infobip | Global | API key, base URL, sender ID |
| Twilio | Global | Account SID, auth token, from number |
| Beem | East Africa | API key, secret key, sender ID |
| MobileSasa | Kenya | API token, sender ID |
| TalkSasa | East Africa | API token, sender ID |
| Bonga SMS | Kenya | Client ID, API key, API secret, service ID |
| BlessedTexts | Kenya | API key, sender ID |
| Texin Bulk SMS | Kenya | API key, sender ID |
| UGSMS | Uganda | Username, password |
| Pandora SMS | East Africa | Username, password, sender ID |
| BulkSMS (Host Pinnacle) | Kenya | Choose API-key mode or username/password mode; sender ID |
| NextSMS | Tanzania | Username, password, sender ID |
| KiboNet | Tanzania | API key, API secret, sender ID |
| TextBee | Global via Android | API key, registered device ID |
The provider catalog can be filtered by country. A provider in the code catalog may not appear for every account/region. NextSMS and KiboNet both serve Tanzania only: an account whose country is set to anything else does not see them, and KiboNet also stays hidden until the account has set a country at all.
NextSMS and KiboNet both report their prepaid credit and their own delivery status. The provider page shows the remaining credit read-only (KiboNet as an SMS count), and Centipid polls the vendor for each message rather than marking it delivered at send time — a message stays pending in the log until the vendor confirms it.
## Current WhatsApp catalog
Notiva, Apiwap, Infobip, and Twilio. See [WhatsApp](/communications/whatsapp) for exact fields.
## Connect a provider
1. Complete the provider's merchant/business onboarding.
2. Open the matching channel in Settings.
3. Select the provider.
4. Enter each required field; conditional Host Pinnacle fields change with authentication method.
5. Save to make it active.
6. Send a controlled test and verify the provider dashboard/log.
## Sender IDs
A sender ID is the name shown as the SMS sender where networks support alphanumeric identity. Approval is provider/country specific. A configured text value is not proof that carriers have approved it.
Use **Settings → Sender ID** where available to follow the request/payment/status process. Do not advertise a new sender identity until approval and a live-network test are complete.
## Low-balance alerts
Centipid SMS can show current balance, top up, enable a low-balance threshold, and notify one or more phone numbers. A top-up request can have its own payment-status lifecycle; verify balance changed before sending a large campaign.
## Switching providers
Resolve queued/failed messages, record the old provider configuration owner, connect/test the new provider, verify sender identity, then enable automated templates. Old failed records should not be bulk-resubmitted through a new provider without reviewing content, recipients, and duplication risk.
# SMS
Source: https://docs.centipidbilling.com/communications/sms
Send an SMS now to chosen subscribers, segments, router users or everyone, check the cost estimate first, then review the delivery log and resend failures.
## Send an SMS now
Open **Communications → SMS**. The SMS log shows volume, today, delivered, failed, recent spend, provider status, and message rows. Use **New message** for an immediate send.
## Choose recipients
The compose page supports:
* **Specific users:** search subscribers and select their phone numbers;
* **Segments:** choose one or more current subscriber groups;
* **Mikrotiks:** target subscribers associated with selected routers;
* **Everyone:** all eligible recipients.
Recipients without usable phone numbers are excluded by the send pipeline. Review the estimate rather than assuming the selected record count equals delivered messages.
## Compose and estimate
1. Choose the audience mode and selection.
2. Write a plain-language message.
3. Insert only variables offered by the UI.
4. Review character count, SMS segment count, recipient estimate, and estimated cost.
5. Confirm the active gateway is configured.
6. If the gateway requires prepaid balance, confirm balance covers the estimate.
7. Send once and monitor the log.
The composer estimates GSM-style segments: up to 160 characters is one segment, then concatenated thresholds apply. Unicode/provider encoding can affect real billing; use the displayed estimate as operational guidance, not a provider invoice guarantee.
## Templates
Reusable one-off SMS templates have a required unique name (maximum 120 characters) and message (1–480 characters). Templates save operator time but can become stale; review variables, dates, prices, and support contact before sending.
## Delivery log and resend
Use channel/status/search filters to find failures. Resend one message only after correcting the cause. Bulk resend is scoped to failed records in the current channel; review the filter and count first.
Common failure causes:
* missing/invalid international phone format;
* unconfigured/revoked provider credentials;
* unapproved sender ID;
* insufficient prepaid credit;
* provider rate/recipient restrictions;
* temporary provider or handset/network failure.
## SMS balance
Centipid SMS exposes a prepaid balance and self-service top-up. Low-balance alerts can notify configured administrator numbers when credit drops below a threshold. NextSMS and KiboNet report their own prepaid credit read-only on the provider page — KiboNet as a remaining SMS count — with top-up done in the vendor's own portal. Other providers manage billing in their own account and may not report balance here.
Avoid sending to **Everyone** while testing provider setup or templates.
# WhatsApp
Source: https://docs.centipidbilling.com/communications/whatsapp
Connect a WhatsApp Business provider (Notiva, Apiwap, Infobip or Twilio), send subscriber messages of up to 480 characters, and get operator alerts there.
## Send through WhatsApp
Open **Communications → WhatsApp**. The list/compose workflow mirrors SMS but uses the ISP's active WhatsApp provider and its own channel-scoped delivery history.
## Supported audience modes
* specific subscribers;
* subscriber segments;
* subscribers associated with selected MikroTik routers;
* everyone eligible.
The compose form requires a configured gateway, non-empty message, and a non-empty selection for targeted audience modes. A message can be up to 480 characters. Each recipient's number gets one message, even if it appears twice.
The outbox shows four cards: **Today**, **Sent**, **Failed** and **Spend · 30d**.
## Configure the provider
Open **Settings → WhatsApp**, choose one current provider, and enter its exact fields:
* Notiva: API key;
* Apiwap: API key;
* Infobip: API key, base URL, sender number;
* Twilio: account SID, auth token, WhatsApp from number.
There are 4 providers. Notiva is the default and is listed as \$5 a month for unlimited WhatsApp messages. Apiwap is offered in Kenya only. Only one provider is active at a time. Provider onboarding, WhatsApp Business approval, sender registration, templates, opt-in, and region rules remain provider/Meta requirements even if the form saves successfully.
### Notiva
### Apiwap
### Infobip
### Twilio
## Send and monitor
1. Send a controlled test to an opted-in number.
2. Verify sender identity and message rendering.
3. Choose the production audience.
4. Avoid sensitive account/access information in the body.
5. Send once and monitor the **Sent** and **Failed** tabs.
WhatsApp providers do not send delivery reports back to Centipid, so the WhatsApp outbox has no Delivered count. **Sent** means the provider accepted the message; **Failed** means it refused it. **Today** counts messages since midnight.
Resend (single or bulk) only picks **Failed** WhatsApp messages. Sent messages are skipped so subscribers never get the same message twice. Correct sender/template/recipient/provider problems before resending. One bulk resend covers up to 2,000 messages; run it again for the rest.
Messages you compose here do not fall back to SMS if WhatsApp fails. Automatic messages do: expiry reminders, payment and bundle notices try WhatsApp first, then SMS.
## Operator alerts over WhatsApp
**Settings → Operator alerts** can prefer WhatsApp for router-status notifications when a WhatsApp gateway is configured. This does not automatically move all subscriber SMS templates to WhatsApp.
# Portal access and profile
Source: https://docs.centipidbilling.com/customer-portal/access-and-profile
How subscribers sign in to the customer portal with PPPoE credentials, the limits of phone-code sign-in, expired links, and keeping contact details current.
## Sign in to the customer portal
The portal currently presents two sign-in methods, but only PPPoE credentials provide a complete production sign-in path:
* PPPoE username and password.
* phone number plus a verification code, whose SMS delivery is not implemented in this version.
## Use PPPoE credentials
Enter the PPPoE username (maximum 191 characters) and password. This method is intended for a matching PPPoE subscriber account. If rejected, verify the exact credentials and account state through the operator profile; do not create a second subscriber as a shortcut.
## Phone verification-code limitation
Do not direct subscribers to phone-code sign-in in production. The current screen can generate a code in the server session and write a development/testing log record, but it does not dispatch that code through an SMS provider.
The phone-code controls remain visible in the portal, but the flow is incomplete for subscribers who cannot inspect development records. Requesting a code is not currently rate-limited. Incorrect code verification attempts are rate-limited.
Until SMS dispatch is implemented and verified, subscribers without working PPPoE credentials need ISP support through an approved identity-verification and credential-recovery process. Operators must not retrieve a generated code from logs and disclose it as a production workaround.
## Expired links
Payment/access links expire for security. The expired-link page directs the subscriber toward portal sign-in. In this version, use PPPoE credentials when available; otherwise contact the ISP instead of relying on the incomplete phone-code flow.
## Update the profile
The phone number is displayed read-only in the current profile. The subscriber can update:
* first name (optional, maximum 60);
* last name (optional, maximum 60);
* email (optional, valid email, maximum 120);
* address (optional, maximum 300).
Phone changes require operator support so account identity and contact data can be protected. Before changing a phone, the operator should verify the subscriber using approved account evidence.
## Sign out and shared devices
Sign out after using a shared device. Do not save PPPoE credentials in an untrusted browser. If access is suspected to be compromised, contact the ISP and change credentials through the supported process.
# Customer portal overview
Source: https://docs.centipidbilling.com/customer-portal/overview
What subscribers can do in the self-service customer portal on your domain: sign in, view their account, pay invoices, top up, use vouchers and get support.
## Self-service for subscribers
The customer portal is separate from the ISP operator dashboard. A subscriber can see only records associated with their own portal session/account. They cannot open operator settings, manage other subscribers, or configure routers/gateways.
## Sign in
The portal is at `/portal/login` on the ISP's own domain. There are 2 ways in:
* **Phone code:** enter your phone number and choose **Send code**. A 6-digit code arrives by WhatsApp, SMS or email, in that order of preference. It expires after 10 minutes. After 5 wrong codes, wait 15 minutes. You can request up to 5 codes per phone number every 15 minutes.
* **PPPoE credentials:** PPPoE subscribers can sign in with their PPPoE username and password. After 5 failed tries, wait 15 minutes.
A payment link from the ISP signs you straight in to an invoice. The link works for 7 days.
## Portal navigation
* **Account:** connection state, current plan, expiry/FUP context, month usage, recent payments, unpaid invoices, contact, and 7-day usage.
* **Invoices:** invoice list, detail, status, line items, due/paid/remaining, and supported payment.
* **Packages:** packages the subscriber has purchased/holds.
* **Usage:** monthly and daily/session usage details.
* **WiFi:** manage your home WiFi settings, shown only when the ISP can reach your router remotely.
* **Support:** open, read, and reply to tickets.
* **Top up:** buy an eligible package through the configured gateway.
* **Redeem:** activate a voucher code, shown only when the ISP sells vouchers for your plan type.
* **Receipts:** payment history and PDF receipt downloads.
* **Profile:** update supported contact information.
## What the Account page means
**Connected/Offline** reflects current session visibility. Offline does not necessarily mean the account is invalid. The device can be disconnected while the package remains active.
The Account page shows **Current plan** with days left, **Data bundle left** for bundle plans, **Usage this month**, **Your contact**, a **Last 7 days** usage chart and your 5 most recent payments. A plan shows as urgent when 3 days or fewer remain. Data sizes use 1,024-based units (1 GB = 1,024 MB). **Current plan** and expiry describe entitlement, while usage and FUP show consumed service data where available.
Outstanding invoice totals are billing records and can differ from the price of a new top-up package.
## Operator prerequisites
For a good portal experience, the ISP should configure:
* accurate branding, currency, timezone, support phone/email, and terms;
* subscriber phone/email and portal access fields;
* compatible packages and portal visibility;
* a tested payment gateway and walled garden;
* invoice/receipt branding;
* messaging provider/templates;
* portal support tickets.
## Troubleshooting
If the subscriber sees another person's data, stop using the portal and report it immediately with the portal URL/time—do not capture unnecessary personal information. For missing data, verify the operator-side subscriber association before recreating payments, invoices, packages, or tickets.
# Packages, top-ups, and vouchers
Source: https://docs.centipidbilling.com/customer-portal/packages-topups-and-vouchers
How subscribers review their packages, top up with an eligible plan and redeem vouchers in the customer portal, and what to check if a paid plan stays the same.
## Add service from the portal
The portal distinguishes packages already associated with the subscriber from packages currently available for purchase.
## Your packages
Open **Packages** to review current/past package cards and their service details. The newest plan is listed first. If the list is empty, no package is associated with the account in the portal result; the operator should verify subscriber/package assignment.
## Top up
1. Open **Top up**.
2. Choose an eligible package.
3. Review name, price, speed, duration, and type.
4. Continue to the payment request.
5. Authorize through the configured gateway (for example a phone prompt/hosted checkout).
6. Keep the page open while payment status is polled.
7. Wait for the paid confirmation and verify the current plan/expiry.
The request sends the selected `package_id`. Availability is determined by the ISP and subscriber context. PPPoE subscribers see PPPoE plans. Other subscribers see Hotspot, Data Plan, Free Trial and TV plans. Hidden and inactive plans never appear. Plans are sorted cheapest first.
With a phone prompt, the page checks the payment every 2 seconds for up to 2 minutes. If nothing arrives by then, it says it has not seen the payment yet. Hosted checkouts, such as Paystack or PesaPal, send you to the provider's page instead. You need a phone number on your profile before paying. A page that says “waiting” has not confirmed payment. Do not submit again until checking the first attempt.
## Redeem a voucher
1. Open **Redeem**.
2. Enter the voucher code exactly (required, maximum 32 characters).
3. Submit once.
4. Confirm the success result and current package/expiry.
Spaces and dashes in the code are ignored, and letters are read as capitals. After 10 failed tries, wait 15 minutes before trying again.
Voucher errors can mean mistyped, wrong ISP, already used, expired, incompatible package, or another operational rejection. The message says which: for example "Voucher has already been used" or "Voucher has expired". The operator can search the voucher record before issuing a replacement.
## Payment succeeds but plan is unchanged
Record the payment/checkout reference and time. Refresh Account once, then contact the ISP. The operator should reconcile the payment, subscriber, package, expiry, and gateway callback before asking for another payment.
# Plan page: what your customers see
Source: https://docs.centipidbilling.com/customer-portal/plan-page
What customers see when they buy: the hotspot buy page and the portal Top up and Packages pages, and how plan Availability decides which plans appear.
## What customers see when they buy
Your customers see your plans in two places:
* **The hotspot buy page** (captive portal). Hotspot customers land here when they join your Wi-Fi. It lists plans they can pay for, and login, voucher, and free-trial options.
* **The customer portal**. Subscribers sign in, then use **Top up** to buy a plan and **Packages** to see the plans on their account.
Both pages build their list from **Network → Plans**. Nothing is copied by hand, so a change to a plan shows on the pages within about a minute.
## Which plans appear
Each plan has an **Availability** setting on its form:
| Availability | Buy page and Top up | You can assign it in the console |
| - | - | - |
| **Live** | Shown | Yes |
| **Hidden** | Not shown | Yes |
| **Off** | Not shown | No |
On top of that, each page has its own rules.
**Hotspot buy page**
* Shows Hotspot and data bundle plans, a free-trial option if you have a trial plan, and TV plans when the visitor is a TV.
* Shows only plans allowed on the router the customer is connected through. A plan limited to other routers does not appear. A plan limited only to routers that no longer exist is flagged **Off portal** on the Plans list and appears nowhere.
* Hides a plan outside its schedule window, if you turned on a schedule for it.
* Lists plans in the order you set on the Plans page, then by price.
* Shows the plan name, price, duration, speed, data limit, and description, with **Popular** and **On offer** highlights where the theme supports them.
**Customer portal Top up**
* PPPoE subscribers see Live PPPoE plans. Everyone else sees Live Hotspot, bundle, trial, and TV plans.
* Router limits and schedules are not applied here.
* Plans are listed from cheapest to most expensive.
## See the page yourself
* **Hotspot buy page:** open **Settings → Hotspot** and use the theme preview. It shows your real plans and branding, with buying and login switched off so you can click around safely.
* **Customer portal:** sign in to the portal with a test subscriber account.
## A plan is missing
1. Open the plan and check that **Availability** is **Live**.
2. On the buy page, check that the plan is allowed on the router the customer is using and that its schedule, if any, covers the current time.
3. In the portal, check the subscriber's type. A PPPoE subscriber never sees hotspot plans, and the other way round.
4. If the whole buy page shows "Network maintenance" instead of plans, the router is in [maintenance mode](/network/maintenance-mode).
## Related
* [Packages](/network/packages)
* [Captive portal](/network/captive-portal)
* [Packages, top-ups, and vouchers](/customer-portal/packages-topups-and-vouchers)
# Portal support tickets
Source: https://docs.centipidbilling.com/customer-portal/support-tickets
How subscribers open a support request in the customer portal, follow its status and reply, and what details to include, since attachments are not supported.
## Ask the ISP for support
Open **Support** to list existing requests or choose **New request**. The list shows your 50 most recently updated requests. Attachments are not supported, so describe screenshots in words.
## Create a request
Required:
* subject, maximum 160 characters;
* details, maximum 8,000 characters.
1. Open **Support** and choose **New request**.
2. Enter a short **Subject** that names the problem.
3. Describe it in **Details**: what happened, when, and on which device.
4. Choose **Submit request**. A "Support request submitted" message confirms it.
The ISP's administrators and support staff get an email. If the ISP sends SMS, you also get a text confirming they received it.
Write what happened, when it started, whether it affects one/all devices, and what was tried. Include receipt/invoice/voucher/router context only when relevant. Do not include passwords, PINs, OTPs, recovery codes, API keys, or full bank/mobile-money credentials.
## Track a request
The ticket shows status, opened/updated time, original details, operator resolution when present, and conversation. Open requests accept replies up to 5,000 characters. Closed requests no longer show the reply form.
A request moves through 5 statuses: **open**, **in progress**, **waiting**, **resolved** and **closed**. Replying to a resolved request sets it back to waiting. Staff replies appear in the conversation; check the ticket for updates. The ISP may text you when a request is resolved.
Until staff reply, the conversation says the team will update you there. Each request in the list shows when it was last updated, so you can see new activity at a glance.
Use one ticket for the same ongoing incident. Opening duplicates can split investigation history.
## Useful evidence
* date/time/timezone;
* device and service type;
* exact error text;
* whether other devices/subscribers are affected;
* invoice/payment/receipt ID without secrets;
* steps already attempted.
For an urgent network-wide outage, use the ISP's support phone/WhatsApp shown in the ISP's branding in addition to recording the ticket when instructed by the ISP.
# Usage, invoices, and receipts
Source: https://docs.centipidbilling.com/customer-portal/usage-invoices-and-receipts
How subscribers read data usage and recent sessions, view and pay invoices, and download payment receipts in the customer portal, and how to dispute an amount.
## Review service and billing history
The portal keeps 3 records of your service: what you used, what you were billed, and what you paid. All of your invoices and payments load on one page, with no paging.
## Usage
Open **Usage** for current month totals, package/FUP context, a 30-day daily chart, and session rows containing start/stop, duration, download/upload, and IP where available. **Recent sessions** lists your latest 10 sessions. Sizes use 1,024-based units.
Usage depends on RADIUS accounting. A session still open or delayed accounting record can change later. Use the displayed units and period; router-interface totals are not necessarily the same as one subscriber's accounted usage.
## Invoices
Open **Invoices** to see invoice number, amount, due date, and status. Open a row for line items, total, paid, remaining, issue/due dates, and current payment action.
Statuses can include pending, partial, paid, cancelled, and overdue display state. An open invoice shows **Overdue** once its due date has passed.
### Pay an invoice
1. Confirm invoice number, line items, total, paid, and remaining.
2. Choose the payment action when the invoice is payable.
3. Confirm the prompt/checkout for the remaining amount.
4. Authorize payment.
5. Wait while the page polls the checkout status. It checks every 2 seconds for up to 2 minutes.
6. Verify the invoice reloads as paid/partial and the payment appears in receipts.
The current page can present an M-Pesa prompt depending on the ISP's gateway. A provider/browser return does not by itself prove the invoice is settled.
## Receipts
Open **Receipts** for payment date, amount, method, and receipt/reference. A PDF download is available when the payment has a receipt number. The file is named after it, for example `receipt-SJK4H7Y2LM.pdf`.
If a receipt is missing or incorrect, contact the ISP with payment date, amount, masked phone/account, and provider reference. Do not send a PIN, OTP, password, or full financial credential.
## Disputing an amount
Do not pay twice while asking for clarification. Record the invoice/payment identifiers and use [Portal support tickets](/customer-portal/support-tickets). The operator can compare the invoice activity, linked payments, package, and provider record.
# Admin sign-in, 2FA, and verification codes
Source: https://docs.centipidbilling.com/getting-started/account-security
Secure operator sign-in: where each verification code comes from, what to do when one does not arrive, recovery codes, passkeys, and resetting staff 2FA.
## Secure operator access
Every authenticated user owns their personal **Profile** and **Password & 2FA** settings. Account configuration is more restricted, but account security is available to operator admins, permitted staff, agents, affiliates, and platform users for their own sign-in.
This page is about signing in to the operator console. Your subscribers sign in to the customer portal differently; see [Portal access and profile](/customer-portal/access-and-profile).
## Where each code comes from
| Code | Where it comes from |
| - | - |
| The 6-digit code asked for after your password | Your authenticator app. Centipid never sends it by SMS or email. |
| A recovery code | The list you saved when you turned on 2FA. Each one works once. |
| A magic sign-in link | Email. Choose **Continue with magic link** on the sign-in page. Only Admin accounts can use it. The link works once and expires after 15 minutes. |
| A verification code before a sensitive action | Your passkey or authenticator app if you have one, otherwise a 6-digit code emailed to the address on your own profile. It expires after 5 to 10 minutes, depending on the action. |
Sensitive actions include deleting a router, adding, editing or removing staff, resetting a staff password, requesting a withdrawal, and changing the payment gateway.
## When a code does not arrive
* **Sign-in 2FA code:** nothing is sent. Open your authenticator app and type the current code. If you no longer have the app, choose **use a recovery code** on the same screen.
* **Emailed verification code or magic link:** check that the email on **Settings → Profile** is correct, and look in spam or quarantine. Wait about a minute before asking again; asking repeatedly locks requests for up to 15 minutes. If email is unreliable for you, turn on 2FA or add a passkey, and the dialog asks for those instead.
* **Code rejected:** make sure your phone sets its clock automatically. Five wrong codes in a row lock code checks for 15 minutes.
## Who has to use 2FA
Two-factor is optional for Admin and Support staff. Other staff account types are sent to **Password & 2FA** and cannot use the console until they set it up. Signing in with a passkey counts as the second factor.
## Update the password
1. Open the user menu and choose **Settings**.
2. Select **Password & 2FA**.
3. Enter the current password.
4. Enter and confirm a long, unique new password that satisfies the form rules.
5. Save the change and confirm the success message.
Use a password manager. Do not reuse the router password, email password, provider dashboard password, or an API key.
If the current password is rejected, use password recovery rather than repeatedly guessing. A user already signed in through an impersonation or support workflow should return to their own account before changing credentials.
## Enable two-factor authentication
In **Password & 2FA**, choose to enable two-factor authentication. The setup dialog presents an authenticator secret or QR code.
Scan the QR code with a trusted TOTP authenticator. Do not photograph it, paste it into chat, or send it in a ticket.
Enter the current authenticator code to complete setup. If a code fails, confirm the device clock is set automatically and try the next generated code once.
Save the recovery codes outside the device that holds the authenticator. A password manager or controlled offline record is appropriate. Each code should be treated like a password.
Regenerating recovery codes invalidates the old set. Replace every stored copy immediately after regeneration.
## Add a passkey
The security page can register a passkey backed by Face ID, Touch ID, Windows Hello, Android screen lock, or a hardware security key, depending on browser/device support.
1. Choose **Add passkey**.
2. Follow the browser or operating-system prompt.
3. Give the credential a recognizable device context if prompted.
4. Test sign-in before relying on it as the only convenient authentication method.
A passkey does not remove the need to retain controlled recovery access. Browser private mode, remote desktops, and older devices may not expose the required authenticator.
## Recovery and lockout
### Lost authenticator but recovery codes available
Use one recovery code at the two-factor challenge, sign in, remove the lost authenticator, enroll a new one, and regenerate recovery codes.
### Lost authenticator and no recovery codes
If you have a passkey on this account, sign in with it, then set up 2FA again. Otherwise contact [Centipid support](/reference/support). Your own ISP admin cannot remove 2FA from a staff account; only Centipid support can, after checking who you are. After it is removed, set it up again at your next sign-in. Support should never ask for your password, API keys, router secrets, or payment-provider secrets.
### Forgot which email or domain you signed up with
Open `/recover` on the main Centipid site. The registration page also links to it (**Recover your account**) when you try to register an email or phone that is already in use. Prove you own the email or phone number you registered with, using a one-time code, and you can reset the admin password for your ISP.
### Password-reset email does not arrive
Confirm the address, check spam/quarantine, and avoid repeated rapid submissions. Record the timestamp and error if escalation is needed.
## Staff and shared access
Never share the owner account. Create a separate staff identity and grant only the permissions needed for the role. When a staff member leaves, remove or disable their access and review API tokens, webhooks, payment credentials, and router access they managed.
See [Staff and permissions](/subscribers/staff-and-permissions) and [Settings](/getting-started/settings).
# Navigate Centipid Billing
Source: https://docs.centipidbilling.com/getting-started/navigation
Find your way around Centipid Billing: role-aware sidebar groups, global search, breadcrumbs, settings, the mobile layout, and why a menu item is missing.
## Find your way around the application
Centipid Billing navigation is role- and permission-aware. Two users in the same ISP account may see different menu groups. Hidden navigation does not imply a feature was removed; it can mean the current role lacks access or the ISP account has not enabled the related capability.
## Operator sidebar
An operator administrator can see groups such as:
* **Customers** — Subscribers, Leads, and Tickets;
* **Network** — Active users, Packages, Routers, and Equipment;
* **Billing** — Payments, Invoices, and Expenses when money features are available;
* **Vouchers** — Vouchers, Agent sales, Batches, and Agents;
* **Communications** — WhatsApp, SMS, Message campaigns, and Promo banners;
* **Analytics** — reports and trends;
* account links such as Settings, What's new, feedback, and sign out.
The exact rows are filtered by permissions. A staff member with subscriber access but no finance access will not receive the billing rows. Voucher-selling agents receive a reduced agent workspace. Affiliates and platform roles use their own navigation and are outside the operator workflow documented here.
## Expand and collapse groups
Devices, Billing, Vouchers, and Communications use collapsible groups. Select the group to reveal its child pages. On a collapsed desktop sidebar, hover or focus an icon to read its label. The highlighted row follows the current page, including sub-pages such as a subscriber profile or ticket detail.
## Global search
Use the global search control or its displayed keyboard shortcut to search across supported records. Results can include:
* active sessions;
* subscribers;
* leads and tickets;
* packages and routers;
* payments, invoices, expenses, and vouchers;
* SMS records, equipment, and campaigns.
Search results respect ISP account and permission boundaries. Search by a stable identifier when possible—account number, username, phone, email, MAC address, invoice, or receipt—then verify the record before acting.
The search panel can also show page-context actions, such as creating a subscriber while browsing Subscribers or composing a message while browsing SMS.
## Breadcrumbs and back links
Detail and form pages provide breadcrumbs or a page-level back link. Use them to preserve the intended workflow. Browser Back can return to an earlier filter or tab state, but a deliberate page link is more predictable after writes or redirects.
## Settings navigation
Open **Settings** from the account menu. On desktop, settings use a grouped sidebar with a **Find a setting** search for operator administrators. On mobile, the same pages appear as horizontally scrollable tabs.
Operator administrators can see ISP account configuration. Other users in the workspace generally see only their personal **Profile** and **Password & 2FA** pages. Platform administrators receive a separate workspace/account settings set.
## Mobile behavior
On a narrow viewport:
* open the sidebar from the menu control;
* choose a destination to close the navigation drawer;
* swipe horizontally through settings tabs where necessary;
* tables may expose row actions through a compact action menu;
* use filters deliberately because wide data sets may present only the most important columns.
## Live and deferred information
Some lists update from real-time events, while heavy charts and aggregates load when their section becomes visible. A loading skeleton is not necessarily an error. If a deferred section never resolves, refresh once and check [Troubleshooting](/reference/troubleshooting).
## Permission problems
If a direct URL returns an authorization error or redirects away:
1. Confirm you are in the intended ISP account and not the customer portal.
2. Check the current user's staff role and individual grants.
3. Ask an operator administrator to review access.
4. Do not work around the restriction by using another person's account.
See [Staff and permissions](/subscribers/staff-and-permissions).
# Registration and provisioning
Source: https://docs.centipidbilling.com/getting-started/registration
Register a new ISP workspace: verify the owner email with a six-digit code, pick an available company name, and fix stuck provisioning or a missing code.
## Register an ISP workspace
Start at the [Centipid Billing account creation page](https://auth.centipidbilling.com/isp/registration). The ISP registration wizard creates both the owner account and the ISP workspace. Registration is a multi-step operation: email verification happens first, the company details are validated second, and workspace provisioning continues in the background after the account is accepted.
## Registration inputs
| Input | Requirement | Notes |
| - | - | - |
| Name | Required by the registration wizard | Use the account owner's real working name. |
| Email | Required, valid email, maximum 191 characters | It must be verified and cannot already be an administrator email. |
| Six-digit code | Required | Valid for 10 minutes. Resend is rate-limited for 60 seconds. |
| Company | Required, maximum 191 characters | Becomes the basis of the workspace slug; reserved or existing names are rejected. |
| Country | Required | Determines available timezone/currency choices and can affect product options. |
| Timezone | Required, valid timezone | Single-option countries may be filled automatically. |
| Currency | Required, three-letter code | Confirm it before creating billing records. |
| Phone | Required, must contain digits | The selected country can prefill the dialling prefix. |
| Password and confirmation | Required | Use a unique password; the form displays the current password rules. |
| Terms acceptance | Required | Registration cannot continue without acceptance. |
| How you heard about us | Optional | Referral is assigned automatically when a valid referral link is used. |
## Complete the wizard
Open the [account creation page](https://auth.centipidbilling.com/isp/registration), enter the owner name and email, and check the spelling before requesting the code. The application normalizes the email address and sends the OTP asynchronously.
Enter all six digits. The verified-email token is valid for 30 minutes. If you edit the email after verification, the token is discarded and the new address must be verified.
Enter the ISP/company name. The system checks the derived workspace slug. When the name is already taken, choose one of the offered alternatives rather than repeatedly submitting the same name.
Select the country, then confirm timezone, currency, and phone prefix. Automatic values are conveniences, not substitutes for review.
Submit once and continue to the provisioning-progress page. The workspace is not ready merely because the account record was accepted; wait for provisioning to finish before signing into the workspace URL.
## Referral links
A registration URL can include a referral code. A valid code associates the new account with the referral automatically. If the registration page reports an invalid code, either obtain a correct link or explicitly continue without the referral. Do not manually type or guess codes.
## Common registration failures
### No verification email
1. Confirm the email address on the form.
2. Check spam and quarantine folders.
3. Wait until the resend timer reaches zero.
4. Request one new code.
5. If delivery still fails, record the address, approximate time, and visible error for support—never include the OTP itself.
### Code expired or rejected
Codes expire after 10 minutes and are replaced when a new code is issued. Return to the email step, request a new code, and enter only the latest one. A verified-email token can also expire if the details step remains open too long.
### Company name unavailable
The workspace slug must be unique and cannot use a reserved platform name. Use an offered suggestion or a meaningful qualifier such as a location or business suffix. Changing capitalization alone may not create a distinct slug.
### Email already has an account
Use the normal sign-in or password-recovery flow. Do not register a second ISP account to work around an existing owner account unless the business deliberately needs another workspace.
### Provisioning appears stuck
Keep the progress URL available and refresh once after a reasonable wait. Do not resubmit the full registration form. Capture the provisioning token shown in the URL only when a trusted support channel requests it; treat it as sensitive account context.
## After provisioning
Sign in using the workspace address presented by the provisioning flow, then follow [Account security](/getting-started/account-security) and the [Quickstart](/quickstart).
# Settings
Source: https://docs.centipidbilling.com/getting-started/settings
A map of ISP workspace settings: branding, country and currency, domain, PPPoE and Hotspot lifecycle, payments, messaging, alerts, loyalty and integrations.
## Configure the ISP workspace
Account-wide settings are reserved for the operator administrator. Staff, agents, and affiliates normally manage only their own profile and sign-in security. Settings shown in the UI remain subject to route authorization and ISP account capabilities.
## Settings map
| Group | Page | What it controls |
| - | - | - |
| General | Branding | Network name, logo, brand colour, font, country/timezone/currency, support contacts, and captive-portal terms |
| General | Domain | Workspace URL and domain-switch workflow |
| Network | PPPoE | Inactive pruning, expiry reminders, FUP alerts, automatic invoicing, and invoice prefix |
| Network | Hotspot | Portal template/background, redirect, portal sections, inactive pruning, username prefix, voucher expiry, and purchase instructions |
| Billing & messaging | Payments | Payment method selection, readiness, credentials, and gateway switching |
| Billing & messaging | Communications | SMS provider and credentials |
| Billing & messaging | Email | SMTP provider and credentials |
| Billing & messaging | WhatsApp | WhatsApp provider and credentials |
| Billing & messaging | Message templates | Payment receipts, voucher messages, expiry notices, reminders, and bundle warnings |
| Billing & messaging | Loyalty points | Payment earning thresholds, points, minimum redemption, and value per point |
| Notifications | Operator alerts | Router status recipients, WhatsApp preference, outage compensation, and sales reports |
| Integrations | AI Assistant | AI provider and optional your own API key |
| Integrations | Developer | API keys for AI assistant access, and outbound webhooks |
| Account | Profile | The signed-in user's name and contact information |
| Account | Password & 2FA | Password, two-factor authentication, recovery codes, and passkeys |
## Branding
Open **Settings → Branding** to configure the identity shared across the operator panel, subscriber portal, emails, and captive portal.
### Important behavior
* Saving **Country** also updates the billing currency and workspace timezone shown by the form.
* **Support email** is verified by a six-digit code before it becomes the public contact.
* Enabling **Terms & Conditions** requires non-empty terms content.
* The rich-text terms field sanitizes scripts and unsafe HTML when saved.
* Removing or replacing a logo changes subscriber-facing surfaces; verify the portal after saving.
## Domain
The domain page manages the workspace URL. The custom subdomain field is required when starting a switch. Before confirming a production change:
1. Notify staff and subscribers who use saved links.
2. Record integrations that call the old hostname.
3. Complete the confirmation workflow.
4. Test sign-in, captive pages, customer portal, router downloads, payment callbacks, and webhooks.
Do not assume that a domain switch updates external provider dashboards or DNS you control outside Centipid Billing.
## PPPoE lifecycle
Use **Settings → PPPoE** to control:
* pruning of inactive subscriber records;
* pre-expiry reminder behavior;
* fair-usage-policy alerts;
* automatic invoice behavior;
* invoice number prefix.
Changes affect automated processing. Review message templates and a representative subscriber before enabling reminders or invoice generation for the whole subscriber base.
## Hotspot and captive portal
Use **Settings → Hotspot** to select a portal template, upload a background, set the post-purchase redirect, arrange portal sections, control inactive pruning, choose a username prefix, set unused-voucher expiry, and provide manual purchase instructions.
The redirect field should point to a valid destination intended for customers. Test it from an actual captive flow; a normal browser session does not reproduce every captive-network restriction.
See [Captive portal](/network/captive-portal).
## Payments
Use **Settings → Payments** to choose a gateway, complete the required credential fields, and switch from the current gateway. Sensitive changes may require an OTP and a readiness confirmation. Follow [Payment gateways](/billing/payment-gateways/index) instead of copying credentials from another ISP account.
## Communication providers
The SMS and WhatsApp pages open channel-specific provider marketplaces. Email opens a single SMTP configuration form rather than a provider list. Configure only services for which the ISP has valid commercial access and credentials. After saving:
1. send a controlled message;
2. confirm the provider accepted it;
3. inspect delivery state where available;
4. verify sender identity and reply behavior;
5. then enable automated templates.
## Message templates
Templates can control:
* PPPoE renewal confirmation;
* Hotspot purchase confirmation and new-users-only behavior;
* voucher delivery;
* PPPoE and Hotspot expiry notices;
* PPPoE pre-expiry reminders;
* bundle-usage warnings and their trigger percentage.
Template variables are inserted from the UI. Do not invent variable names: unsupported placeholders may be delivered literally. Keep SMS length in mind; message fields enforce a 320-character maximum.
## Loyalty points
When enabled, the loyalty program awards points when configured payment thresholds are crossed and allows redemption subject to a minimum balance and value-per-point rule. Before enabling it, model a normal payment and redemption so the commercial value is intentional.
## Operator alerts and outage compensation
Router alerts can be sent to specified phone numbers or, when the list is empty, the administrator audience defined by the application. WhatsApp can be preferred when a gateway is configured.
Outage compensation can credit a percentage of qualifying downtime, filtered by minimum duration, connection type, and package. A subscriber is never credited more than the time their subscription still had left when the link dropped, so a three-hour outage adds ten minutes — not three hours — for someone with ten minutes to run, and the credit is granted from the moment service returned. It can optionally notify affected subscribers. Review the percentage, qualifying packages, and notification copy carefully because this setting can change subscriber expiry/credit state at scale.
## AI Assistant
Select the supported AI provider and optionally store your own API key. If the key is blank, the application can use the platform default when available. API keys are secrets: do not paste them into messages, screenshots, or webhook payloads.
To reach the same assistant from a client outside the application, see [AI assistant access (MCP)](/reference/mcp-access).
## Developer settings
### API keys
An API key connects an external AI client to this workspace over MCP; see [AI assistant access (MCP)](/reference/mcp-access) for the endpoint and client setup. A key acts as the account that created it and reaches only what that account's role allows.
The key name is required. Name each key after the single client that will use it, copy the plaintext value when it is shown — it is shown once — and store it in a secret manager. Revoke keys that are unused, exposed, or associated with former staff; revoking takes effect immediately and affects only the client using that key.
### Webhooks
A webhook requires a label, valid HTTPS URL, and selected events. A signing secret is generated when left blank. Verify signatures in the receiver, make processing idempotent, return quickly, and monitor failed deliveries. Pausing a webhook is safer than deleting it during a temporary incident.
## Safe change procedure
For settings that affect money, access, bulk messaging, domains, or automated credits:
1. record the current value;
2. identify affected subscribers and integrations;
3. make one coherent change;
4. save and verify the success response;
5. test with a controlled account/device/transaction;
6. review logs or visible status;
7. roll back promptly if the expected result does not occur.
# Centipid Billing
Source: https://docs.centipidbilling.com/index
Centipid Billing docs: run subscribers, MikroTik routers, PPPoE and Hotspot access, payments, invoices and customer messaging for your ISP in one workspace.
Already have an account? [Log in to Centipid Billing](https://auth.centipidbilling.com/recover).
## Run your ISP with Centipid Billing
Centipid Billing brings subscriber management, network access, payments, communications, and reporting into one workspace. It supports ISP workflows built around MikroTik NAS devices, RADIUS-backed PPPoE and Hotspot access, recurring billing, vouchers, and subscriber self-service.
This guide documents the current billing application. Screens, fields, and capabilities can vary by your role, country, configured services, payment gateway, and enabled account features.
Secure the operator account, configure your ISP, create a package, and provision a router.
Create and support Hotspot, PPPoE, and binding subscribers throughout their lifecycle.
Provision NAS devices, configure access services, and investigate router health.
Track payments, invoices, expenses, receipts, collections, and withdrawals.
Send messages, run campaigns, configure providers, and manage notifications.
Understand the self-service experience for packages, usage, billing, and support.
## Core operating areas
### Subscribers and customer service
The subscriber workspace covers onboarding, package assignment, account state, active sessions, usage, payments, invoices, vouchers, messages, leads, and support tickets. Staff only see areas allowed by their assigned permissions.
### Network and access
The network workspace manages NAS and MikroTik provisioning, PPPoE and Hotspot services, package policy, captive portals, vouchers, equipment, device limits, and operational diagnostics.
### Billing and finance
The billing workspace records payments, receipts, invoices, expenses, and—when enabled for the ISP—collections and withdrawals. Payment methods and required credentials depend on the ISP's configured gateway and commercial availability.
### Communications and reporting
Operators can use one-off messages, recurring message campaigns, captive-portal promo banners, templates, provider settings, dashboards, analytics, audits, search, import, and export tools according to role permissions.
## CRM, helpdesk and OSS/BSS in one platform
Centipid Billing is ISP billing and OSS/BSS in one platform. The business side (BSS) and the network side (OSS) share one subscriber record, so sales, support, billing and network staff all work from the same account.
**CRM: leads and sales pipeline.** [Leads](/subscribers/leads) tracks prospects through 6 stages, from New to Converted or Lost, on a Kanban board or a list. Each lead has an owner, a source, a hot/warm/cold rating and a next action with a due date. The pipeline shows its monthly value, conversion rate and average days to close. **Convert** turns a won lead into a subscriber without retyping their details.
**CRM: subscriber management.** [Subscribers](/subscribers/overview) holds every Hotspot, PPPoE and static-IP customer. Each [profile](/subscribers/profile) shows the plan, expiry, live sessions, data usage, payments, invoices, messages and tickets for that customer.
**Helpdesk: support tickets.** [Tickets](/subscribers/tickets) is a full helpdesk:
* Staff open tickets, and subscribers raise them from the [customer portal](/customer-portal/support-tickets).
* Each ticket has an assignee, 4 priorities and 5 statuses, with a comment and activity history.
* Each priority sets a response deadline (SLA): 4 hours for urgent, 24 for high, 72 for normal and 168 for low.
* Admin and support staff get an email for each new ticket. The subscriber can get an SMS when a ticket opens and when it is resolved.
* A ticket analytics page shows the backlog, ticket age and tickets past their deadline.
**BSS: billing and payments.** Recurring billing, [invoices](/billing/invoices), [payments](/billing/payments) through 28 [payment gateways](/billing/payment-gateways/index) including M-Pesa, [vouchers](/network/vouchers) and [expenses](/billing/expenses).
**OSS: network operations.** [Router provisioning](/network/router-provisioning) for MikroTik, RADIUS-backed [PPPoE and Hotspot](/network/pppoe-and-hotspot) access, [router health](/network/router-health) monitoring and [equipment](/network/equipment) tracking.
## Before you begin
You need an operator account and a provisioned ISP account. Network automation additionally requires a compatible router with internet access. Online collections require an enabled payment method and valid provider credentials.
Never share passwords, API secrets, router credentials, recovery codes, or payment-provider keys in tickets or screenshots. Use the masked credential views and the support process described in [Getting support](/reference/support).
## Recommended path
1. Complete the [quickstart](/quickstart).
2. Read [Account security](/getting-started/account-security).
3. Create and verify your [packages](/network/packages).
4. Provision your first [router](/network/router-provisioning).
5. Add a [subscriber](/subscribers/create-and-manage).
6. Configure and test a [payment gateway](/billing/payment-gateways/index).
7. Review the [customer portal](/customer-portal/overview) your subscribers will use.
# Captive portal
Source: https://docs.centipidbilling.com/network/captive-portal
Set up the Hotspot captive portal: pick one of 19 themes, choose which plans are on sale, and configure logins, vouchers, free trials, terms and extra devices.
## Configure the Hotspot customer experience
The captive portal is the browser experience presented to Hotspot users. It can show packages, branding, campaigns, support, terms, login options, voucher redemption, free trials, active-session resume, and device-purchase flows.
## Select and preview a theme
Open **Settings → Hotspot**. The current application includes these themes:
Lumen, Lumen Dark, Aurora, Neon, Monochrome, Simple, Classic, Sunrise, Marigold, Lagoon, Linen, Clay, Pebble, Nimbus, Halo, Slip, Vault, Badge, and Grid.
Neon, Vault, Monochrome, and Lumen Dark are forced-dark themes. Use the built-in preview with the ISP's real branding/data before saving. Different themes can support different background or section-order behavior.
## Configure portal content
* Select the template.
* Upload a background only for themes that support it.
* Set the post-purchase redirect if customers should leave the Hotspot flow after activation.
* Configure terms acceptance and terms content in Branding.
* Reorder supported portal blocks where the selected theme allows it.
* Add numbered manual purchase instructions for Simple or Classic when needed.
* Confirm the support contact and payment instructions.
## Package purchase
1. The portal identifies router/device context.
2. The customer chooses a visible package.
3. The purchase dialog collects the gateway-specific required fields, often including phone/account context.
4. The application initiates the provider flow.
5. The status dialog polls the transaction.
6. On success, the customer is redirected into the MikroTik login/authorized path or configured destination.
Closing the status dialog or refreshing does not cancel a provider request. Before starting a second payment, check the first transaction status.
## Other authentication methods
The current captive flow can support:
* username/password login;
* voucher code redemption;
* receipt-based login;
* free trial when configured/eligible;
* resume of an existing session;
* Lite purchase/voucher pages;
* explicit terms acceptance where required.
Available methods vary with account and router configuration.
## Add another device or TV
The portal can let a customer identify another device using nearby-device discovery or manual MAC entry, verify the masked device identifier, choose a package, and purchase for that device. A TV-specific connection/status flow supports browserless devices where enabled.
Treat MAC identity as sensitive network context. The customer should match the last characters against the actual device settings before purchase.
## Promo banners
Captive campaigns can appear as portal banners and record clicks. Keep the banner destination reachable from the walled garden and relevant to the current location/package audience.
## Troubleshooting
* **Blank/no packages:** check package type, status, portal visibility, NAS restriction, and router context.
* **Payment site unreachable:** sync the walled garden and confirm provider domains/network DNS.
* **Pending never resolves:** check the payment ledger/provider callback before retrying.
* **Terms error:** enable acceptance only with saved terms and ensure the customer checked it.
* **Login loops:** check credentials/voucher/receipt, expiry, device limits, existing sessions, and MikroTik redirect.
* **Theme works in preview but not router:** redownload Hotspot assets and verify the router's selected captive configuration.
# Equipment inventory
Source: https://docs.centipidbilling.com/network/equipment
Track routers, access points, modems, ONTs, CPEs, cables and switches by status, from in stock to assigned or sold, with prices paid and online monitoring.
## Track physical hardware
Open **Network → Devices → Equipment** for inventory that is not the managed NAS record itself. Equipment can be searched by name, model, serial number, IP, MAC, subscriber name, or phone. It streams additional rows as you scroll, 50 at a time. Staff need the **equipment** permission.
## Supported types and statuses
Types: router, access point, modem, ONT, CPE, cable, switch, and other.
Statuses: in stock, assigned, returned, damaged, and sold. Each status has its own tab with a count, next to **All**.
The page summarizes stock, assigned count, total cost/value, and amount collected:
| Card | What it shows |
| - | - |
| In stock | Items ready to deploy |
| Assigned | Items in subscriber hands |
| Inventory | Total of all prices: the cost basis |
| Collected | Total paid against equipment |
The table shows each item's type, monitoring state, subscriber, price, amount paid and status.
## Add equipment
**Name** is required (maximum 160 characters). Optional fields include description (maximum 2,000), serial number/model (maximum 120 each), type, non-negative price, non-negative amount paid, status, and subscriber assignment.
1. Choose **Add equipment**.
2. Enter a recognizable name, type, model, and serial number.
3. Record price and amount collected using the account currency.
4. Choose status and the subscriber when assigned/sold.
5. Add a factual description for condition/accessories where useful.
6. Save and verify it appears in the matching status tab.
## Monitor online status
Turn on **Monitoring** to track whether a device is online or offline. Monitoring needs a parent router and the device's IP or MAC address. Centipid checks monitored devices every 10 minutes. A result stays current for 5 minutes.
## Operational rules
* Do not mark equipment assigned without selecting the correct subscriber where assignment is tracked.
* Update returned/damaged state promptly so stock totals remain useful.
* Serial numbers should be copied exactly and searched before creating another record.
* Equipment payment fields are inventory context; use the formal payment/invoice workflow for customer financial records when required.
* Before deleting, confirm the item is not needed for subscriber history, warranty, or reconciliation. Delete is permanent: a removed record cannot be restored.
# Maintenance mode
Source: https://docs.centipidbilling.com/network/maintenance-mode
What maintenance mode does to connected users, PPPoE subscribers and new hotspot logins on one router, and how to turn it on or off. Live sessions stay up.
## Put a router in maintenance mode
Maintenance mode changes one thing: the **hotspot buy page** (captive portal) for one router. Instead of plans, customers who open that page see a "Network maintenance" screen with your message, your support number, and the time you expect to be back.
It does not touch the router, RADIUS, or anyone's session.
## What happens to each kind of customer
| Customer | During maintenance mode |
| - | - |
| Already connected (hotspot or PPPoE) | Stays connected. Maintenance mode does not disconnect anyone. |
| PPPoE subscriber who reconnects | Connects as normal. PPPoE never shows the buy page. |
| Hotspot customer who opens the buy page | Sees the maintenance screen. No plans are listed, so nobody can buy. |
| Hotspot customer who already paid, with **Allow existing customers to log in** on | Sees the maintenance screen plus the login options (voucher, receipt, username and password), under "Already paid? Log in to reconnect." |
| Hotspot customer who already paid, with that switch off | Sees only the maintenance screen. They cannot log in from the page until you turn maintenance mode off. |
If you need to take people offline, maintenance mode will not do it. Disconnect sessions from **Network → Live sessions**, or do the work on the router itself.
## Turn it on
1. Open **Network → Devices → Routers** and open the router.
2. Choose **Actions → Enable maintenance mode**.
3. Fill in the dialog. Every field is optional:
* **Allow existing customers to log in**: keeps the login options on the page. New purchases stay blocked either way.
* **Back online by**: the time maintenance ends. Customers see it on the page. When it passes, maintenance mode switches off by itself. A background check runs every 5 minutes, and the buy page stops showing the maintenance screen as soon as the time has passed.
* **Maintenance message**: up to 500 characters. If you leave it empty, customers see a standard "performing scheduled maintenance" message with your brand name.
4. Choose **Enable**. The router header shows a **Maintenance** badge.
The support number on the screen is the router's own support number, or your account's number if the router has none. Change it with **Actions → Change support number**.
## Turn it off
Open the router and choose **Actions → Disable maintenance mode**, then confirm. The buy page shows plans again straight away. If you set **Back online by**, you do not need to do this: it switches off at that time.
## Who can do it
Anyone whose role allows editing routers.
## Related
* [Routers and NAS](/network/routers)
* [Captive portal](/network/captive-portal)
* [Live sessions](/subscribers/active-sessions)
# Packages
Source: https://docs.centipidbilling.com/network/packages
Create internet plans that set price, duration, speed, data limits, device limits and router availability, then order, publish, duplicate or retire them.
## Define the service you sell
Packages connect commercial terms—price and duration—with network policy such as access type, speed, data, device limits, schedule, burst, and NAS availability.
## Plan before creating
Decide:
* subscriber/access type;
* customer-facing name;
* price in the account currency;
* duration or data allowance;
* upload/download or combined speed policy;
* allowed devices;
* schedule and burst behavior;
* whether the package is visible/available on buy pages;
* whether it is limited to selected NAS devices.
## Create a package
1. Open **Network → Plans** and choose **Create Package**.
2. Select the package type.
3. Enter the name, price, duration, and current form-required fields.
4. Set speed, data, device, and other policy limits.
5. Configure advanced burst/schedule behavior only when the network supports it.
6. Add NAS restrictions if the plan should exist only at selected sites.
7. Save and review the detail page.
8. Test with one subscriber or captive purchase before broad publication.
## Visibility and merchandising
The package workspace supports status, popular/on-offer flags, ordering, and portal visibility. An active internal package can still be hidden from public buy pages. The package list calls out plans hidden from buy pages so operators can resolve accidental merchandising gaps.
Reordering changes how offers appear where ordering is respected. Use clear names and avoid several indistinguishable plans with different hidden limits.
## NAS restrictions
Leave the restriction empty to allow the package on every applicable NAS. Select routers to limit it. A restricted package can disappear from a captive portal reached through another NAS and cannot be assigned everywhere.
Use **Clear NAS restriction** only when the plan is intentionally becoming account-wide.
## Duplicate and edit
Duplicate a package to create a related plan while preserving an auditable source. Immediately review every copied field—especially price, duration, status, portal visibility, schedule, and NAS restriction—before enabling it.
Editing a package can affect future assignment and, depending on how network policy is applied, existing subscribers. Test consequential changes and communicate commercial changes deliberately.
## Retire or delete
Prefer disabling/hiding a package when subscriber or historical records still refer to it. Before deletion, review subscriber count, portal visibility, vouchers, invoices, and NAS restrictions. The application may block deletion when related records make it unsafe.
## Common issues
* **No packages in subscriber form:** choose the subscriber type first and confirm a compatible active package exists.
* **No packages on captive portal:** check Hotspot type, active/on-offer/public visibility, NAS restriction, and router context.
* **Wrong expiry:** inspect package duration and account timezone, then the subscriber's explicit expiry override.
* **Speed policy not applied:** verify subscriber assignment, active session reauthentication, NAS/RADIUS policy, and router service state.
# PPPoE and Hotspot
Source: https://docs.centipidbilling.com/network/pppoe-and-hotspot
Compare PPPoE, Hotspot and Binding access, the five package types, and the settings each one uses, then enable the right services on your MikroTik router.
## Understand access services
Centipid Billing manages PPPoE and Hotspot access through packages, subscribers, NAS configuration, RADIUS authentication/accounting, and service-specific settings.
There are 3 subscriber types: **PPPoE**, **Hotspot** and **Binding**. Packages come in 5 types: Hotspot, PPPoE, Data Plan, Free Trial and TV.
## PPPoE
Use PPPoE for fixed-line subscriber sessions authenticated with a username/password. Typical controls include:
* PPPoE-compatible packages and credentials;
* expiry and account status;
* speed/data/FUP policy;
* pre-expiry reminders;
* automatic invoicing and invoice prefix;
* active-session disconnect/pause/block actions;
* NAS/service assignment and monitoring.
### PPPoE settings in numbers
| Setting | Values |
| - | - |
| Pre-expiry reminders | SMS sent 2, 4, 12, 24, 48 or 72 hours before expiry. Pick several. |
| FUP alerts | When monthly data use crosses 50%, 80%, 95% or 100% |
| Auto-generate invoices | On by default. Made ahead of expiry, using the reminder hours. |
| Invoice number prefix | Default **INV**, up to 8 characters (INV → INV-001234) |
| Monthly renewal | A 1-month plan renews on the same date each month: 4 Aug → 4 Sep. 31 Jan becomes 28 Feb. |
| Accounting updates | The router reports session usage every 30 minutes |
A new invoice is not created while the subscriber already has a pending, partial or overdue one.
PPPoE troubleshooting should compare subscriber state, package, RADIUS session/accounting, router service, transport, and local CPE configuration.
## Hotspot
Use Hotspot for captive-portal access, package purchase, vouchers, trials, receipt/credential login, and device policy. Typical controls include:
* Hotspot-compatible packages and portal visibility;
* captive theme, branding, terms, purchase instructions, and redirect;
* device limit and anti-sharing;
* vouchers and voucher agents;
* manual or online payment flows;
* session resume and disconnect-until-purchase;
* bindings for bypass/reserved-IP devices.
### Hotspot settings in numbers
* **Devices per account** is set on each package, from 1 to 50. New packages start at 1. When the limit is reached, the subscriber is told to disconnect another device.
* **Free Trial** is a package type. Set **Offer again after** to 1–365 days, or leave it blank to allow one trial per device.
* **Fair Use Policy** applies to Hotspot purchases as well as PPPoE. It can throttle or block, and reset with each purchase or every day at midnight.
* **Rate-limit** is written upload first: 2M/10M means 2M up and 10M down.
* Routers report usage every 5 minutes for a capped data plan and every 15 minutes for other plans.
* **Disconnect till purchase** is an action on a subscriber's session, for Hotspot and Data Plan subscribers. The subscription ends at once, and the subscriber must buy a new package to reconnect.
## Binding
Binding is presented as a subscriber type but uses the Hotspot network path. It requires a router, MAC/device, and reserved IP. See [IP and MAC bindings](/subscribers/ip-bindings).
## Enable services on a router
During provisioning, select the intended services and ports. On an existing router, the detail page shows configured PPPoE/Hotspot state and exposes supported service toggles. Disabling Hotspot or changing bridge ports is high impact. Inspect active sessions and schedule the change.
## Choose the right model
| Requirement | Usually choose |
| - | - |
| Fixed-line home/business login | PPPoE |
| Public Wi-Fi with package purchase | Hotspot |
| Voucher access | Hotspot |
| Device bypass with reserved IP | Binding |
| Customer portal account management | Either subscriber type, subject to configured features |
Do not change an existing subscriber's type only to work around a package or router problem. Type conversion can alter credentials, package compatibility, and network policy. Validate the desired migration first.
# Router health and diagnostics
Source: https://docs.centipidbilling.com/network/router-health
Check a router before changing it: read reachability history, live CPU and bandwidth, and top users, run Diagnose, and pick a targeted recovery action.
## Diagnose a router before changing it
Open the router detail page and read several signals together. Centipid Billing can show reachability history/incidents, live bandwidth/system metrics, top consumers, service state, monitoring, trends, collections, and diagnostic findings.
## Signal interpretation
| Signal | What it tells you | What it does not prove alone |
| - | - | - |
| Online/reachability | The router's management tunnel (SSTP) is up and it answers | That every subscriber can authenticate, or that local LAN/Hotspot ports are correct |
| Active sessions | RADIUS accounting sessions | That all sessions are current or healthy |
| CPU/memory/system metrics | Router resource pressure | The cause of a payment/access failure |
| Bandwidth/top consumers | Current traffic distribution | Package-policy correctness without subscriber context |
| Monitoring findings | Checks detected by the diagnostic pipeline | That every finding is safe to auto-remediate |
| Daily collections | Payments associated with the router/context | Provider settlement or bank reconciliation |
## Run diagnostics
1. Verify the router identity and incident time.
2. Choose **Diagnose**.
3. Wait for findings to complete.
4. Review **Issues**, **Passed**, and the full result set.
5. Open a finding and read its evidence and proposed remediation.
6. Apply remediation only when it matches the observed failure.
7. Re-run the check and an end-to-end subscriber test.
## Targeted recovery actions
* **Sync router time:** correct clock drift that affects certificates, schedules, accounting, or logs.
* **Sync walled garden:** refresh captive destinations needed for payment/login flows.
* **Redownload Hotspot:** refresh portal assets/configuration when the router copy is stale.
* **Reprovision:** give the router a new tunnel identity and a fresh script to paste. Use it when the management tunnel will not come back or setup is incomplete; the router stays offline until the new script runs.
* **Reboot:** use only after understanding service impact and having a recovery path.
## Monitoring and alerts
Add the router to monitoring, then configure **Settings → Operator alerts**. Verify recipient numbers and whether WhatsApp is preferred. Alert delivery depends on communication-provider readiness; a monitoring finding and a delivered SMS are separate states.
## High CPU or bandwidth
Use live metrics and top consumers to identify timing and scope. Check whether load corresponds to expected traffic, a package without limits, a subscriber/device anomaly, or router process pressure. Avoid changing every package or rebooting before capturing the active evidence.
## Escalation packet
Provide support with sanitized evidence:
* the ISP and router identity (not secrets);
* start/end time and timezone;
* affected access type and approximate subscriber count;
* reachability, management tunnel, and service state;
* diagnostic finding text;
* RouterOS version where available;
* one test subscriber result;
* actions already attempted and their outcomes.
# Provision a router
Source: https://docs.centipidbilling.com/network/router-provisioning
Connect a MikroTik router to Centipid: check prerequisites, run the generated script in its terminal, confirm the NAS is found, then set up PPPoE and Hotspot.
## Provision a MikroTik router
The provisioning wizard links a router to the current ISP account, detects the created NAS, and then applies selected service configuration. Use a router you are authorized to manage and schedule production changes appropriately.
## Prerequisites
* The router can reach the internet and resolve required service hostnames.
* RouterOS and hardware are compatible with the generated script shown by this application version.
* You can open the MikroTik terminal with sufficient privileges.
* The router clock, DNS, firewall, and outbound HTTPS are not intentionally blocking provisioning.
* You know which physical ports/bridge should serve Hotspot and PPPoE users.
## Complete the wizard
Open **Network → Devices → Routers**, choose to add a router, and enter a recognizable identity such as the site and device role. Avoid generic names that become ambiguous in alerts.
Copy the entire provisioning command from the wizard. Do not edit embedded tokens, URLs, quoting, or arguments unless the product explicitly asks for a value.
Paste the command, watch for RouterOS syntax/network errors, and let it finish. Do not publish the command or screenshot its secrets.
Return to the wizard and wait for the connection-status step to detect the NAS. The wizard polls current state; leaving and returning to an already created NAS should reuse its progress rather than create another device.
Select PPPoE, Hotspot, or both as appropriate. Choose bridge/interface ports deliberately and enable anti-sharing only when it matches the Hotspot policy.
Start service configuration and keep the progress/log view open. Configuration runs in the background. A completed NAS should report the enabled services and appear in the router inventory.
Check status, router time, services, captive portal, RADIUS authentication/accounting, and one test subscriber. Do not rely on the wizard's final screen alone.
## Why the script creates a `centipid_user` account
The provisioning command adds a RouterOS user named `centipid_user` (group `full`, comment *"Centipid User. Do not delete this user."*). Everything the platform does on the router after the initial paste goes through that account over the RouterOS API:
* **Service configuration.** The wizard's PPPoE and Hotspot setup, captive-portal file downloads, and later reprovision actions are applied through the API, not by more terminal commands.
* **Health, audits, and repair.** Router health readings, the configuration audit, and its one-click fixes read and write the router through the same login.
* **Backups.** Scheduled configuration backups are pulled from the router with it.
The account is safe to leave in place:
* It has its **own random password**, generated per router and separate from the RADIUS secret. A leaked RADIUS secret does not grant router access, and the password is never shown or reused elsewhere.
* The script **restricts the API service to the Centipid management hub address**, so the login is only reachable through the router's management tunnel, never from the internet or the LAN.
If the user is removed or disabled, service configuration, health checks, and audit fixes stop working for that router. The configuration audit reports this as a critical finding, **Centipid management user exists**, and offers the command to restore it. Rerunning the provisioning command also recreates the account.
## If detection fails
1. Inspect the router terminal output for download, certificate, DNS, permission, or syntax errors.
2. Confirm the router was not already registered under another identity or ISP.
3. Check outbound HTTPS (TCP 443); the script download and the SSTP tunnel both use it.
4. Use the wizard's current status/log rather than rerunning the command repeatedly.
5. If a NAS record exists, open it and run diagnostics.
6. Capture sanitized error text, router identity, RouterOS version, and approximate time for support.
## If service configuration fails
Do not delete the NAS immediately. Review the configuration log and existing router services/bridges. Correct port selection or conflicting local configuration, then use the targeted setup/reprovision action indicated by the UI.
## After provisioning
* Set the router-specific support number and captive theme if needed.
* Confirm walled-garden access for the selected payment gateway.
* Add fallback RADIUS where offered and intended.
* Enable monitoring and review alert destinations.
* Create packages with deliberate NAS restrictions.
* Test reconnect behavior after a controlled router reboot only during an approved window.
# Routers and NAS
Source: https://docs.centipidbilling.com/network/routers
Use the router (NAS) inventory to see each MikroTik's online state, PPPoE and Hotspot services and settings, run router actions safely, and remove a router.
## Manage network access servers
Centipid Billing uses a NAS record to represent a MikroTik/router participating in subscriber authentication, accounting, captive access, and monitoring. Open **Network → Devices → Routers** to see the router inventory.
## What the inventory shows
The router list summarizes registered devices and live/recent state. A router detail page can expose:
* identity, RouterOS/network identifiers, and service configuration;
* online/reachability over the management tunnel;
* PPPoE and Hotspot service state and bridge ports;
* anti-sharing, accounting interval, captive template, and support settings;
* live bandwidth, system metrics, top consumers, trends, and daily collections;
* monitoring state, diagnostics, and remediation findings;
* maintenance mode and scheduled router actions.
Live metrics depend on a reachable router and the configured management path. A missing live card does not prove the subscriber service itself is down; compare reachability, RADIUS sessions, and the device's local state.
## Router actions
Depending on current state and permission, the detail page can:
* check status or run diagnostics;
* add/remove monitoring;
* reboot or reprovision;
* change router identity;
* redownload Hotspot files;
* regenerate Winbox access;
* add fallback RADIUS;
* synchronize router time and walled-garden rules;
* enable/disable Hotspot, anti-sharing, Winbox, or maintenance mode;
* adjust accounting time, captive portal, support number, and port settings;
* create/delete router schedules;
* remove the NAS through an OTP-protected workflow.
These actions are not interchangeable. Run diagnostics before reprovisioning; use walled-garden sync for captive payment reachability; and reprovision only when the management tunnel will not come back or the existing configuration is known to be incomplete or incompatible.
## Safe operating sequence
1. Confirm the router identity and the ISP.
2. Check reachability and the time of the last successful signal.
3. Review affected services and subscriber sessions.
4. Run diagnostics.
5. Apply one targeted remediation.
6. Wait for current status/metrics to refresh.
7. Test authentication and accounting from a controlled subscriber.
8. Record what changed and the result.
## Maintenance mode
Maintenance mode swaps the router's hotspot buy page for a maintenance screen so nobody can buy during planned work. It does not disconnect anyone who is already online. See [Maintenance mode](/network/maintenance-mode) for what each kind of customer sees and how to turn it on and off.
To reboot a router on a timetable, or to understand what Centipid does for WAN failover, see [Scheduled reboot and failover](/network/scheduled-reboot-and-failover).
## Removing a router
Router deletion is high impact and requires action verification. Before removal:
* move or disable subscribers/packages bound to the NAS;
* confirm no active sessions or binding records still depend on it;
* preserve required router configuration and monitoring context;
* understand the effects on the management tunnel, monitoring, captive files, and access paths;
* enter the action OTP only in the application's confirmation flow.
Prefer leaving an offline historical device disabled until dependencies are understood rather than deleting it immediately.
See [Router provisioning](/network/router-provisioning), [Router health](/network/router-health), and [Network troubleshooting](/network/troubleshooting).
# Scheduled reboot and failover
Source: https://docs.centipidbilling.com/network/scheduled-reboot-and-failover
Reboot a MikroTik now or on a daily or weekly schedule from Centipid, and what Centipid does and does not manage for WAN failover and multi-WAN links.
## Schedule a router reboot, and what about failover
Centipid manages your MikroTik's subscriber side: RADIUS, PPPoE, Hotspot, and the management tunnel. It can reboot a router now, and it can add entries to the router's own task scheduler. It does not set up backup internet links.
## Reboot now
Open the router from **Network → Devices → Routers** and choose **Actions → Reboot MikroTik**. The router must be online, because the reboot is sent over its management connection. If it is offline, the action is greyed out.
Everyone connected through the router drops while it restarts.
## Schedule a reboot
Centipid has no reboot timetable of its own. Instead, the router's **Scheduler** tab adds a task to the MikroTik's built-in scheduler (`/system scheduler`), and the router runs it.
1. Open the router and select the **Scheduler** tab. It lists the tasks already on the router.
2. Choose **Add task** and fill in:
* **Name**: letters, numbers, `-` and `_`, for example `nightly-reboot`.
* **Interval**: how often it repeats. Use a preset (`5m`, `15m`, `1h`, `1d`), type your own such as `7d` for weekly, or turn on **Run once**.
* **Start**: **At a set time**, for example `03:00`. (**On startup** runs the task every time the router boots, so do not use it for a reboot.)
* **Script / command**: `/system reboot`
* **Comment** (optional): who added it and why.
3. Choose **Create task**. The task appears in the list.
To stop the scheduled reboot, delete the task from the same tab.
The router runs the task by its own clock, so check the clock first. Use **Sync router time** from the router's menu on the **Routers** list if it is wrong. The router must be online for the Scheduler tab to load, add, or delete tasks.
Schedule the reboot for your quietest hour and tell customers if they will notice it.
## Failover, load balancing, and multi-WAN
Centipid does not configure a second internet link on routers you manage from the console. There is no setting for failover, load balancing (for example PCC), or multi-WAN.
Set these up on the router itself, with WinBox or the RouterOS terminal. A common failover setup gives each internet link a default route with a different `distance`, plus `check-gateway=ping` so the router moves traffic when a link stops answering. See MikroTik's own documentation for the details.
Things to know when you do:
* Centipid reaches the router through a management tunnel that the router opens over its internet connection. After any routing change, check that the router shows as online in Centipid and that a test subscriber can sign in.
* Do not remove or rename the Centipid RADIUS, tunnel, or hotspot settings while you change routing. If something breaks, see [Network troubleshooting](/network/troubleshooting).
* Some older routers also carry a backup RADIUS server so customer logins keep working over the internet link if the management tunnel drops. For those routers, the **Script** tab shows the command under **Fallback RADIUS**. This keeps logins working; it does not add a backup internet link.
## Related
* [Routers and NAS](/network/routers)
* [Router health](/network/router-health)
* [Maintenance mode](/network/maintenance-mode)
# Network troubleshooting
Source: https://docs.centipidbilling.com/network/troubleshooting
Fix common network problems step by step: an offline router, NAS not detected, rejected logins, paid but offline, no plans on the portal, or a bad voucher.
## Start with the smallest failing path
Record the ISP, router, service type, subscriber/device, start time/timezone, and exact symptom. Determine whether the incident affects one device, one subscriber, one NAS, one service type, or the whole network before changing configuration.
## Router is offline
1. Check when the router was last reachable over its management tunnel.
2. Verify power, ISP uplink, DNS, time, and local RouterOS access.
3. Run diagnostics if the management path responds.
4. If the router has internet but its tunnel stays down, confirm outbound TCP 443 is open; the SSTP tunnel uses it.
5. Avoid reboot/reprovision until configuration and impact are understood.
## Provisioning does not detect the NAS
Inspect terminal output, outbound HTTPS/DNS, RouterOS permissions/version, duplicate identity, and wizard status. If a NAS record exists, continue from it instead of creating another.
## Subscriber credentials rejected
Check subscriber type, exact username/password, active/paused/blocked state, expiry, compatible package, router service, and RADIUS reachability. Disconnect a stale session only after identifying it.
## Subscriber paid but remains offline
Verify final payment status and subscriber association, then package/expiry/account state, device limit, active sessions, NAS health, and access credentials/binding. Do not create a duplicate payment or user while investigating.
## No packages on captive portal
Check Hotspot type, active/on-offer/public visibility, price/duration, NAS restriction, and the NAS identifier reaching the portal. Then redownload/sync portal state if the router has stale assets.
## Payment prompt cannot open provider
Confirm router DNS/internet and walled-garden destinations for the selected gateway. Sync the walled garden and test from the captive device. Do not broadly allow the internet as a workaround.
## Voucher rejected
Confirm code spelling, ISP, unused/expiry state, package, router context, and terms. Search the voucher record to see whether it redeemed elsewhere.
## Binding device has no access
Verify router, normalized MAC, reserved IP/subnet, conflict, package, expiry, and bypass rules. Compare the current device MAC—phones can use randomized MAC addresses per network.
## Escalate with evidence
Provide sanitized diagnostic text, relevant IDs, router/service state, one affected subscriber example, timestamps, scope, and actions already tried. Never provide router passwords, API secrets, payment credentials, OTPs, recovery codes, or full provisioning commands.
# Voucher agents
Source: https://docs.centipidbilling.com/network/voucher-agents
Create voucher agent accounts that sell prepaid codes, give them an opening float, issue voucher batches against it, and reconcile sales in the float ledger.
## Distribute vouchers through agents
Voucher agents are separate `AGENT` users with a reduced portal, prepaid float, assigned voucher batches, sales/redemption reporting, and a complete float ledger.
## Create an agent
Required:
* name (maximum 120 characters);
* password (minimum 6 characters).
Optional:
* unique email;
* phone;
* initial float (zero or greater).
Use a unique account and deliver the temporary password securely. Agents should change it and enable available sign-in protection.
## Float model
Float is the prepaid balance used to receive voucher stock. Issuing a batch debits:
`package price × voucher quantity`
Top-ups create ledger entries with actor, amount, balance after, description, and time. Add a useful note for cash/bank reconciliation; do not use an unexplained top-up to hide a prior error.
## Issue stock
You can generate a new batch for an agent or assign existing stock. An existing batch is assignable only when it:
* has no agent;
* has not expired;
* uses a Hotspot package;
* has no redeemed voucher;
* can be covered by available float.
Batch assignment is atomic so two operators cannot safely issue the same stock. If the UI says a batch was just issued, refresh and choose another—do not retry with stale state.
## Reconcile performance
The agent detail/report shows float balance, issued and available vouchers, sold/redeemed count, expired stock, revenue, redemption rate, sales by package, recent batches, trend, and float ledger.
Use the ledger as the money trail. A voucher is counted as sold/redeemed through code usage, not merely because it was assigned to the agent.
## Password reset and removal
Sensitive actions are OTP-gated. Password reset produces a temporary 14-character password; share it securely and clear it from communication history.
Removing an agent leaves issued voucher batches valid because codes may already be in circulation, but clears the agent float/ledger relationship according to the current workflow. Reconcile stock and cash before removal.
# Vouchers
Source: https://docs.centipidbilling.com/network/vouchers
Generate Hotspot voucher codes singly or in batches, including numbers-only codes, then print, export, send by SMS, extend expiry and fix failed redemptions.
## Sell or issue prepaid access codes
Open **Vouchers → Vouchers**. Voucher codes apply Hotspot-compatible packages and can be generated individually or in batches, printed/exported, sent by SMS, issued to agents, and redeemed through captive or customer-portal flows.
## Voucher status
* **Unused:** still available subject to expiry/package policy.
* **Used:** redeemed and associated with an access outcome.
* **Expired:** past its allowed redemption date.
* **Errored:** generation/redemption state requires investigation.
## Generate vouchers
Required inputs:
* package;
* quantity (at least 1 and subject to the current batch maximum);
* code characters: **Letters & numbers** (the default) or **Numbers only**;
* code length: 4 to 12 characters for letters and numbers, 8 to 12 digits for numbers only.
Optional inputs:
* design template;
* agent;
* prefix up to 6 characters (for numbers-only codes: digits only, starting with 1–9);
* future expiry date;
* SMS delivery for a single voucher.
Phone is required when SMS delivery is enabled, and SMS delivery is intentionally limited to quantity 1.
### Numbers-only codes
Choose **Numbers only** when your customers find digits easier to read and type than letters — a code like `58372914` instead of `AB7K9X2P`. Both generators (Vouchers and Agents) offer it, and your browser remembers the last choice.
* Codes are at least 8 digits long. Shorter numeric codes are too easy to guess.
* A numeric code never starts with 0, so a spreadsheet cannot drop the first digit.
* A code is never the same as an existing subscriber's username, such as a phone number or account number.
* The XLSX export keeps long numeric codes as text, so Excel shows every digit.
Letters-and-numbers codes leave out I, L, O, 0 and 1, which are easy to misread. Numbers-only codes use every digit.
Select a Hotspot package and optional printable template. Verify price/duration because generated codes inherit the package entitlement.
Leave agent blank for ISP stock or issue to a voucher agent. Agent issuance debits prepaid float by quantity multiplied by package price.
Pick letters and numbers or numbers only, then enter quantity, length, optional prefix, and a future expiry. Longer/random codes reduce guessing risk.
Submit and wait for the result. If an error occurs, inspect whether any batch/codes were already created before retrying.
## Print and export
Print options include compact, 50-per-page, and thermal layouts plus black/white or colour output. Use voucher templates to control branding and fields. Exported/printed unused codes are bearer credentials—limit copies and physical access.
The first template becomes default. A default template cannot be deleted while alternatives exist; set another default first. Preview changes before printing a production batch.
## Extend expiry and resend SMS
Bulk expiry extension requires a new valid date/time. Extending a used code does not make it unused. Resend SMS only after confirming the original send failed or the recipient requests another copy; the same bearer code is being disclosed again.
## Redemption troubleshooting
Verify the exact code, unused status, expiry, package, router/NAS availability, ISP, and terms acceptance. Do not issue a replacement until checking whether the original code redeemed on another device/session.
# Quickstart
Source: https://docs.centipidbilling.com/quickstart
Set up a new Centipid Billing account in order: register, secure sign-in, brand your ISP, create a first package, provision a router and add a subscriber.
Already have an account? [Log in to Centipid Billing](https://auth.centipidbilling.com/recover).
## Go from registration to a working service
This quickstart is for the ISP owner or operator administrator responsible for initial setup. It takes you through the shortest safe path: create the ISP account, secure the account, brand the customer experience, create an access package, provision a router, add a subscriber, and verify billing.
Review [Centipid Billing pricing](/reference/pricing) before choosing the service model for the account.
Do not start collecting live payments until the selected gateway credentials and callback flow have been verified with the provider. A saved credential form proves configuration was accepted; it does not prove that the provider will settle a payment.
## Before you start
Have the following ready:
* an email address you can verify;
* your ISP/company name, country, timezone, currency, and support contact;
* a MikroTik router with internet access if you will use automated network access;
* the price, duration, speed, data, and device policy for at least one package;
* payment-provider credentials if you intend to collect online payments immediately.
## 1. Register the ISP account
Open the [ISP account creation page](https://auth.centipidbilling.com/isp/registration), enter your name and email address, and request the six-digit verification code. The code is valid for 10 minutes; requesting another code is limited by a 60-second resend cooldown.
Enter the code sent to the same email address. Changing the email invalidates the earlier verification. If the code expires, return to the email step and request another.
Provide the company name, country, timezone, three-letter currency, phone number, password, and acceptance of the displayed terms. Country selection may prefill a timezone, currency, and telephone prefix, but confirm every value before submitting.
Registration creates the account and queues workspace provisioning. Keep the provisioning page open until the workspace is ready. Do not submit the registration form repeatedly while provisioning is in progress.
See [Registration and provisioning](/getting-started/registration) for duplicate-name, expired-code, and provisioning recovery steps.
## 2. Secure the operator account
1. Sign in to the new ISP account.
2. Open **Settings → Password & 2FA**.
3. Replace any temporary or reused password with a long, unique password.
4. Enable two-factor authentication and verify the authenticator code.
5. Store recovery codes in a password manager or another controlled location.
6. Add a passkey if your browser and device support it.
Read [Account security](/getting-started/account-security) before creating staff accounts or API tokens.
## 3. Configure the ISP identity
Open **Settings → Branding** and review:
* **Network name** — the label subscribers see;
* **Logo** — the operator and portal identity;
* **Brand colour** and **Font** — applied across operator and subscriber experiences;
* **Country** — also updates the workspace timezone and billing currency when saved;
* **Support phone** and verified **Support email**;
* **Terms & Conditions** — enable acceptance only after supplying the terms subscribers must read.
Then open **Settings → Domain** and confirm the workspace URL. Changing a live domain can affect bookmarks, portal links, router downloads, and external integrations; follow the confirmation flow and retest those entry points.
## 4. Create the first package
1. Open **Network → Plans**.
2. Choose **Create Package**.
3. Select the service type that matches the intended subscriber: Hotspot, PPPoE, or another type offered by the form.
4. Enter a clear name, price, duration, and the applicable speed/data/device limits.
5. Configure schedule, burst, NAS restriction, and portal visibility only when needed.
6. Save the package and open its detail page to verify the policy summary.
Package type matters: a PPPoE subscriber cannot use a Hotspot-only package, and a package restricted to selected NAS devices will not be available everywhere. See [Packages](/network/packages).
## 5. Provision a router
1. Open **Network → Devices → Routers**.
2. Start the router provisioning wizard.
3. Give the device a recognizable identity.
4. Copy the generated provisioning command exactly as displayed.
5. Run it in the MikroTik terminal using an appropriately privileged router account.
6. Wait for the wizard to detect the NAS before configuring PPPoE or Hotspot services.
7. Confirm the router appears in the inventory and review reachability and service status.
If detection does not complete, stop and use [Router provisioning](/network/router-provisioning) and [Network troubleshooting](/network/troubleshooting). Repeatedly running a provisioning command without checking the existing device can create confusing partial state.
## 6. Add and verify a subscriber
1. Open **Customers → Subscribers** and choose **New subscriber**.
2. Select the correct subscriber type.
3. Enter the required identity/contact and access fields shown for that type.
4. Select a compatible package and NAS when required.
5. Save the subscriber.
6. Open the profile and verify account status, package, expiry, access identifiers, and the expected portal/network action.
7. Connect a test device and confirm the session appears under **Network → Live sessions**.
For bulk onboarding, finish one verified subscriber first, then use [Subscriber import and export](/subscribers/import-export).
## 7. Configure billing and communications
Open **Settings → Payments**, select the intended payment method, complete its credential readiness check, and save. Follow the provider-specific fields in the [Payment gateway credential reference](/billing/payment-gateways/credentials-reference).
Then configure the channels you will actually use:
* **Settings → Communications** for SMS;
* **Settings → Email** for SMTP email;
* **Settings → WhatsApp** for WhatsApp;
* **Settings → Message templates** for receipts, expiry notices, reminders, and voucher messages;
* **Settings → Operator alerts** for router state, outage compensation, and sales reports.
Send a controlled test message before enabling automated notifications for all subscribers.
## Readiness checklist
* [ ] Operator password is unique and 2FA recovery material is stored safely.
* [ ] Brand, country, timezone, currency, support contact, and terms are correct.
* [ ] At least one package has the intended price and network policy.
* [ ] A router is online and its intended services are enabled.
* [ ] A test subscriber can authenticate and appears in active sessions.
* [ ] Payment credentials are saved and a controlled payment reaches the expected final status.
* [ ] Receipt/invoice behavior matches the selected workflow.
* [ ] A test notification reaches the intended recipient and uses the correct template.
* [ ] The [customer portal](/customer-portal/overview) shows the expected packages, support contact, and billing options.
# Glossary
Source: https://docs.centipidbilling.com/reference/glossary
Plain definitions of the network, subscriber, billing and portal terms used in Centipid Billing, such as active session, binding, captive portal and FUP.
## Product terminology
**Account number** — A stable reference the operator sets for a subscriber. It appears beside the subscriber and works in search, imports and payments.
**Active session** — A RADIUS accounting session that is still open. It is separate from the account's active, paused or blocked state. A session counts as stale after 4 missed usage reports.
**Binding** — A device's MAC address tied to a reserved IP on one router. It uses the Hotspot access path.
**Captive portal** — The Hotspot web page where people buy packages, log in, use vouchers or receipts, start trials and read terms.
**Collection** — Customer money received through a managed wallet. Not every payment method funds a wallet.
**Disbursement / payout** — Money sent from an account to an outside recipient through a supported provider.
**FUP** — Fair Usage Policy. A data limit on a package that throttles or blocks use once it is reached. PPPoE alerts can fire at 50%, 80%, 95% or 100% of the limit.
**Gateway** — A configured provider or manual method for payments, SMS, email or WhatsApp. There are 30 payment gateways across 72 countries.
**Hotspot** — Network access through the captive portal. It is common for prepaid packages, vouchers and Wi-Fi customers.
**Invoice** — An itemized amount due from a subscriber, with a due date, status, payments and activity.
**MikroTik** — A router running RouterOS. Centipid Billing usually sets it up as a NAS.
**NAS** — Network Access Server. The router that signs subscribers in, counts their usage and gives them access.
**PPPoE** — Point-to-Point Protocol over Ethernet. Fixed-line access where the subscriber signs in with a username and password.
**RADIUS** — The protocol that checks subscriber logins, applies their plan, and records their sessions.
**Receipt** — The reference or document for a recorded payment. A provider reference can exist before the payment is confirmed, so read the status too.
**Settlement** — The provider or bank finishing a money transfer. It can happen later than the payment shows in Centipid Billing.
**Subscriber** — An ISP customer's access account. There are 3 types: Hotspot, PPPoE and Binding.
**ISP account (workspace)** — A separate workspace with its own subscribers, settings, network, billing and branding.
**Voucher** — A code that gives whoever redeems it a Hotspot package. Codes are up to 32 characters.
**Voucher agent** — A separate seller account. It holds prepaid float and receives voucher batches.
**Walled garden** — Sites people can reach before they log in to the Hotspot. Payment pages usually need to be in it.
**Withdrawal** — A protected request to send wallet funds to a mobile-money number. Each one is UGX 500 to UGX 5,000,000.
# AI assistant access (MCP)
Source: https://docs.centipidbilling.com/reference/mcp-access
Connect Claude or another MCP client to your ISP data with an API key: the endpoint, what it can read, which actions need your approval, and common errors.
## Connect an AI assistant to your ISP
**Centipid ISP Billing** is the Model Context Protocol (MCP) server for your workspace. It lets an external AI client — Claude, or any client that supports an HTTP MCP server — read your ISP data and answer questions in plain language. It reaches the same information the built-in AI Assistant reaches, through the same tools.
This is separate from the in-app assistant. The in-app assistant needs no setup; this page is for connecting a client that runs outside the billing application.
## Who can do this
Any operator user whose role grants **AI Chat** access. The key you create acts as you: it reaches exactly what your account reaches in the application, and no more. A member of staff without AI Chat access cannot create a working key.
## Prerequisites
* An operator account with AI Chat access.
* A client that supports an HTTP MCP server with custom request headers.
* Somewhere safe to store the key, such as a password manager or secret store.
## The endpoint
| | |
| - | - |
| Server name | Centipid ISP Billing |
| URL | `https://mcp.centipidbilling.com/mcp` |
| Method | `POST` |
| Authentication | `Authorization: Bearer YOUR_KEY` |
The URL is the same for every ISP. **Your key is what identifies your workspace** — it decides whose data the endpoint returns. Nothing in the address distinguishes one ISP from another.
The endpoint also answers on your own workspace URL, at `/mcp`. Either address works; the shared address above is easier to remember and is the one to use unless you have a reason to prefer your own domain.
## Connect a client
Open **Settings → Developer** and create a key. The key name is required. Name it after the device or client that will use it, such as `claude-desktop` or `office-laptop`, so you can revoke the right one later.
The plaintext key is shown once, immediately after creation. Copy it then. It is not shown again, and a lost key cannot be recovered — revoke it and create another.
In Claude Code, one command registers it:
```bash theme={null}
claude mcp add --transport http centipid \
https://mcp.centipidbilling.com/mcp \
--header "Authorization: Bearer YOUR_KEY"
```
Any client that accepts an HTTP MCP server with custom headers takes the same two values:
```json theme={null}
{
"mcpServers": {
"centipid": {
"type": "http",
"url": "https://mcp.centipidbilling.com/mcp",
"headers": { "Authorization": "Bearer YOUR_KEY" }
}
}
}
```
Your client should now list the server as **Centipid ISP Billing** with 23 tools available. `centipid` in the commands above is only the local shorthand you type; the name the client displays comes from the server itself.
Ask the assistant something only your ISP would know, such as how much was collected today, or who expires in the next 24 hours. Real figures in the answer confirm the connection.
To check from a terminal instead, list the available tools. A working key returns 23 of them:
```bash theme={null}
curl -sS https://mcp.centipidbilling.com/mcp \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```
## What the assistant can do
Twenty-three tools. Twenty read only. Three can change something, and never do so on their own — see [Actions require your approval](#actions-require-your-approval).
| Area | Tools |
| - | - |
| Money | `revenue_summary`, `payments_report`, `outstanding_invoices`, `amount_due`, `voucher_stock` |
| Subscribers | `subscriber_lookup`, `subscriber_status`, `list_subscribers`, `expiring_subscribers`, `top_data_users` |
| Network and routers | `active_sessions`, `nas_status`, `router_resources`, `mikrotik_config`, `mikrotik_logs`, `mikrotik_read_command`, `run_mikrotik_diagnosis` |
| Plans and support | `packages`, `open_tickets`, `search_documentation` |
| Requires approval | `reconnect_subscriber`, `disconnect_no_expiry`, `apply_mikrotik_fix` |
Router tools read live configuration and logs over the RouterOS API. `mikrotik_read_command` accepts read-only commands only; writes are refused.
## Actions require your approval
The three tools in the last row above do not perform their action when an assistant calls them. They record a request and return a pending status.
Nothing on your network changes at the moment an assistant asks. The request appears in the application's AI Chat panel, in a conversation named **MCP session**, and waits for an administrator to confirm it. No subscriber is disconnected and no router configuration is altered until someone confirms it there.
If an assistant reports one of these actions as completed, that report is wrong. Check the panel.
Confirming is subject to the same permission the equivalent screen requires. An account that cannot disconnect a subscriber in the application cannot confirm a disconnection here either.
## What a key can reach
* **Only your ISP.** Every figure comes from your own workspace. A key cannot read another operator's subscribers, payments, or routers, and no other operator's key can read yours.
* **Only your own permissions.** The key acts as the account that created it and is limited to that account's role.
* **Everything that account can see.** Anyone holding the key holds that access. Treat it as a password.
Do not paste a key into messages, tickets, screenshots, or webhook payloads. If a key is exposed, revoke it in **Settings → Developer** immediately and create a replacement. Revoking takes effect at once and breaks only the client using that key.
Create one key per client rather than sharing one key across devices, so a single revocation does not disconnect everything.
## Common failures
### The response says the API key is unknown
The key is wrong, has been revoked, or was truncated when copied. A key has the form `12|…`; the digits before the vertical bar are part of it. Copy the whole value. If in doubt, revoke it and create another.
### The response is 403 Forbidden
The key is valid, but the account that created it does not have AI Chat access. An administrator can grant it on that user's role, after which the existing key works.
### Only 15 tools are listed
The client read one page of results and stopped. Restart the client. If the count stays at 15, the client is not reading the tool list to the end; check for an update.
### The assistant returns another ISP's data
Stop and revoke the key. Create a replacement from the workspace you intend to use, and report the incident to Centipid support. This should not be possible.
### An approved-tool request appears to do nothing
Expected. Open the AI Chat panel in the application and confirm the request there. Until then, nothing has happened.
## Related pages
* [Settings](/getting-started/settings) — where keys are created and revoked, under Developer.
* [Staff and permissions](/subscribers/staff-and-permissions) — granting AI Chat access to a role.
* [Support](/reference/support) — reporting a suspected access problem.
# Pricing
Source: https://docs.centipidbilling.com/reference/pricing
Centipid Billing pricing: Hotspot at 3% of revenue, PPPoE at USD 0.25 per user a month, a USD 5 (KES 500) monthly minimum, the 14-day trial and setup help.
## Choose a plan that grows with your ISP
Centipid Billing uses usage-based monthly pricing for Hotspot and PPPoE operators. The rates below were verified against the [Centipid Billing website](https://centipidbilling.com/) on 16 July 2026. Check the website or request a formal quote before making a purchasing decision because published pricing can change.
**3% of Hotspot revenue**
Monthly usage-based pricing with no user limit.
**USD 0.25 per user/month**
Monthly per-user pricing with no revenue limit.
## Hotspot Plan
The Hotspot Plan is charged at **3% of Hotspot revenue** and includes:
* unlimited MikroTik devices;
* no user limit;
* remote WinBox management;
* multiple payment gateways (30 gateways across 72 countries);
* multiple SMS gateways;
* email support;
* voucher management.
## PPPoE Plan
The PPPoE Plan is charged at **USD 0.25 per user per month** and includes:
* unlimited MikroTik devices;
* unlimited users;
* no revenue limit;
* automated invoicing;
* automated payments;
* multiple payment gateways (30 gateways across 72 countries);
* real-time notifications.
## Monthly minimum
Each monthly invoice is your Hotspot and PPPoE charges added together, or the monthly minimum if that total is lower. The minimum is **USD 5** a month, or **KES 500** a month for ISPs in Kenya.
## Start with a 14-day trial
New ISP accounts get a **14-day trial** with no card required. If you leave within the 14 days, you pay nothing. If you stay, your first invoice covers the 14 trial days at the normal rates above, including the monthly minimum. [Create an ISP account](https://auth.centipidbilling.com/isp/registration) to get started.
## Optional MikroTik installation support
If you ask Centipid to install and configure the Centipid system on your MikroTik, the documented support fee is a **one-off USD 10**. This is separate from the monthly Hotspot or PPPoE plan price and covers Centipid system installation and configuration only. Other router or device configuration work is quoted separately.
Pricing on this page does not define taxes, currency conversion, promotions, or custom work. Use the current official Centipid sales or support channel for a formal quote or commercial confirmation.
For setup steps, continue to the [quickstart](/quickstart). For account-specific pricing or support questions, read [Getting support](/reference/support). Legal conditions are described in the [Terms of Use](https://centipidbilling.com/terms).
# Getting support
Source: https://docs.centipidbilling.com/reference/support
Escalate product, account, network, payment or subscriber problems to Centipid support: what to check first, what evidence to include, and what never to send.
## Use the support route for the affected account
Subscribers should use the ISP support contact shown in their branded portal and, when possible, open a portal ticket. A portal ticket takes a subject of up to 160 characters and details of up to 8,000. Replies can be up to 5,000 characters. The ISP's administrators and support staff get an email for each new ticket. See [Portal support tickets](/customer-portal/support-tickets). ISP operators should use the official Centipid support channel associated with their account or application. Avoid relying on phone numbers or demo links copied from an older document.
For published subscription rates, plan inclusions, the 14-day trial, and optional MikroTik installation support, read [Pricing](/reference/pricing). Request a formal quote through the official Centipid channel when you need account-specific commercial confirmation.
## Before escalating
1. Identify the smallest failing scope.
2. Read the relevant troubleshooting guide.
3. Verify the record/status in the current ISP account.
4. Try one safe, targeted recovery action.
5. Preserve current evidence before changing configuration.
## Include
* ISP/company and your role;
* affected subscriber/router/payment/invoice/ticket ID;
* exact start time and timezone;
* expected versus actual behavior;
* exact sanitized error/status;
* affected scope/count;
* relevant provider/reference with sensitive portions masked;
* steps already attempted and outcome.
## Never include
* passwords or temporary passwords;
* OTPs, two-factor/recovery codes, or passkeys;
* API/client/private keys, passphrases, signing secrets;
* router/admin credentials or full provisioning commands;
* payment PINs or complete financial credentials;
* broad database/customer exports unless an approved secure transfer is arranged.
## Incident updates
Keep one incident thread/ticket. Add new evidence with timestamps, and confirm recovery with a real end-to-end test. For financial issues, keep 4 things apart:
1. application status: what Centipid Billing recorded;
2. provider status: what the payment provider reports;
3. subscriber entitlement: whether the package and expiry changed;
4. external settlement: whether the money reached the bank or wallet.
# Troubleshooting index
Source: https://docs.centipidbilling.com/reference/troubleshooting
Start from a symptom and jump to the guide that fixes it, with a table of timers and limits behind common sign-in, router, billing and portal problems.
## Find the right recovery path
Find your symptom below and follow the link to the guide that fixes it. Many problems turn out to be a timer or a limit doing its job. Check the table first.
## Timers and limits that explain common symptoms
| Symptom | Likely cause |
| - | - |
| Subscriber's portal sign-in code fails | The 6-digit code expires after 10 minutes. After 5 wrong codes, the subscriber waits 15 minutes. |
| Voucher refused in the portal | After 10 failed tries, the account waits 15 minutes |
| Portal says it has not seen the payment | The portal waits up to 2 minutes for a phone payment, then stops checking |
| Second device cannot connect | **Devices per account** on the package is reached (1–50; new packages start at 1) |
| Session looks stuck online | Routers report usage every 30 minutes for PPPoE and every 5 or 15 minutes for Hotspot. A session counts as stale after 4 missed reports. |
| Scheduled campaign is late | Due campaigns are checked every 5 minutes |
| Banner change not on the portal yet | The portal refreshes active banners every 60 seconds |
| Withdrawal code rejected | The withdrawal code expires after 5 minutes; you can request 3 every 15 minutes |
## Account and access
* Cannot register / OTP expired / company taken → [Registration](/getting-started/registration)
* Lost authenticator or recovery codes → [Account security](/getting-started/account-security)
* Missing menu / authorization → [Navigation](/getting-started/navigation) and [Staff permissions](/subscribers/staff-and-permissions)
* Subscriber credentials rejected → [Network troubleshooting](/network/troubleshooting)
* Stale/duplicate active session → [Active sessions](/subscribers/active-sessions)
## Router and captive portal
* Router not detected → [Router provisioning](/network/router-provisioning)
* Router offline / high load / tunnel down → [Router health](/network/router-health)
* No packages on portal → [Packages](/network/packages) and [Captive portal](/network/captive-portal)
* Voucher rejected → [Vouchers](/network/vouchers)
* Binding does not work → [IP and MAC bindings](/subscribers/ip-bindings)
## Billing
* Payment pending/rejected/callback failure → [Payment troubleshooting](/billing/payment-gateways/troubleshooting)
* Paid but subscriber offline → [Payments](/billing/payments) and [Subscriber profile](/subscribers/profile)
* Invoice amount/status/linkage → [Invoices](/billing/invoices)
* Wallet/withdrawal issue → [Collections and withdrawals](/billing/collections-and-withdrawals)
## Communications
* SMS not sent/delivered → [SMS](/communications/sms)
* Provider/sender ID issue → [Messaging providers](/communications/providers-and-sender-ids)
* Scheduled campaign missing/duplicated → [Message campaigns](/communications/message-campaigns)
* Automated message missing → [Notifications and templates](/communications/notifications-and-templates)
## Portal
* Subscriber cannot sign in → [Portal access](/customer-portal/access-and-profile)
* Top-up/voucher not applied → [Packages, top-ups, vouchers](/customer-portal/packages-topups-and-vouchers)
* Invoice/receipt/usage issue → [Usage, invoices, receipts](/customer-portal/usage-invoices-and-receipts)
## Gather evidence before escalation
Record:
* the ISP and the affected record or device;
* the exact time and timezone;
* the scope: one subscriber, one router, or everyone;
* the status or reference, and the exact sanitized error;
* the actions already attempted.
Never include passwords, OTPs, recovery codes, provider secrets or router passwords. Also leave out complete provisioning commands and unnecessary customer data.
# Live sessions and blocked devices
Source: https://docs.centipidbilling.com/subscribers/active-sessions
Monitor online subscribers (active users), disconnect, pause, block, or message them, and see where blocked devices and blocked subscribers are listed.
## Monitor active users
Open **Network → Live sessions** to inspect RADIUS sessions currently visible in this workspace. The page refreshes its list approximately every 10 seconds and shows when data was last refreshed.
## Filters and session data
Use the All, PPPoE, and Hotspot tabs, expiry filters, search, and sortable columns. A row can include subscriber identity, username, router, MAC, framed IP, start time, duration, data transferred, rate estimate, idle time, and a session-end value when RADIUS provides one.
Some RADIUS rows do not map to an application subscriber (`user_id`). Those sessions can be inspected/disconnected, but subscriber-only actions such as pause or SMS are unavailable until a matching account exists.
## Session identity
A disconnect request uses both username and session start time where available. This prevents a bulk selection from treating several reconnects as one session. Recheck the row after auto-refresh before disconnecting a high-impact account.
## Actions
### Disconnect
Terminates the selected session through the supported network path. The subscriber may reconnect immediately if credentials, account status, package, expiry, and router policy still allow access.
### Disconnect until purchase
Where available for the selected service/session, disconnects and requires a qualifying purchase before normal access resumes. Use it only when that matches the commercial policy.
### Pause
Changes the linked subscriber's service state and interrupts access. Rows without a linked subscriber cannot be paused.
### Block
Select one or more sessions, choose **Block device**, add an optional reason (up to 200 characters), and confirm. Centipid then:
* disconnects the subscriber now;
* rejects their username at sign-in until you unblock them;
* rejects the device's MAC address, unless another subscriber who is not blocked also uses that device.
Confirm the target MAC where shown. Blocking the wrong device identifier can affect the wrong user.
### Send SMS
Sends one message per selected subscriber through the ISP's SMS gateway. The action filters out rows without subscriber IDs. If a prepaid SMS provider reports insufficient credit, top up or switch the configured provider before retrying.
## Where to see blocked devices
Centipid blocks the subscriber account and their devices together, so you find blocked devices by finding blocked subscribers:
* **Dashboard:** the **Churned** tile ("disabled subscribers") counts every blocked (disabled) subscriber. Select it to open the list at `/users?view=churned`.
* **Customers → Subscribers:** a blocked subscriber's row carries the **Churned** label.
* **Subscriber profile:** the status reads **Blocked**, and **Unblock subscriber** (in the profile's action menu) lifts the block and releases their devices.
There is no separate page that lists blocked MAC addresses on their own.
## Bulk-action safety
1. Filter by type and expiry first.
2. Select only the intended rows.
3. Review the count and the confirmation summary.
4. Remember that one subscriber can have more than one session.
5. Perform one bulk action and let the page refresh before doing another.
## Troubleshooting stale sessions
If a disconnected row remains:
* wait for the next refresh;
* check whether the device immediately reconnected;
* compare start time and session identifier;
* review router reachability/accounting;
* use the subscriber profile to check pause/block/package state.
Do not repeatedly disconnect without identifying whether each row is the same session or a new reconnect.
# Create and manage subscribers
Source: https://docs.centipidbilling.com/subscribers/create-and-manage
Create Hotspot, PPPoE and IP binding subscribers with a compatible package, then pause, block, change expiry, compensate, override FUP or delete them.
## Create a subscriber
You need permission to create subscribers and at least one compatible package. Bindings additionally require a configured, reachable router so the form can discover devices.
## Required and conditional fields
The current form marks **User type** and **Package** as required. Identity, access credentials, expiry, contact details, and router fields vary by type and by create/edit mode. Follow the required markers and server errors shown by the form.
For a binding, the form requires:
* a router;
* a discovered or entered device MAC;
* a static IP address;
* a compatible package.
The range end is optional and is only appropriate when the binding represents an address range. SMS expiry reminders require a phone number.
## Create a Hotspot or PPPoE subscriber
From **Customers → Subscribers**, choose **New subscriber**.
Supply the name and any required username/phone/access fields. Account number and physical location can provide stable operational references where offered.
Select Hotspot or PPPoE. Changing the type can change the available package list and type-specific fields.
Search by name, speed, type, duration, or price. Verify the package summary rather than selecting by a similar name alone.
The package can set the expiry automatically. The date/time is editable, and clearing it creates no explicit expiry only when that is operationally intended.
Confirm whether the account starts active. Use unique access credentials and deliver them through the supported credential action rather than an insecure channel.
Save, open the profile, and confirm type, package, expiry, status, and credentials/service context before asking the subscriber to connect.
## Create a binding
1. Choose **Binding** as the type.
2. Choose the NAS/router the device is behind.
3. Wait for the device picker to load ARP, DHCP, or Hotspot observations.
4. Select the intended MAC address after matching hostname/IP/device ownership.
5. Enter the reserved IP address and an optional range end.
6. Choose the compatible Hotspot package.
7. Decide whether expiry reminders should be sent.
8. Save and test from the bound device.
If the device list cannot load, do not choose a different router merely to bypass the error. Check router reachability and the device's real network attachment.
## Manage service state
### Pause and resume
Pause preserves the subscriber but interrupts service. The action can offer an optional subscriber notification. Resume only after verifying the reason for the pause has been resolved.
### Block and unblock
Block is appropriate for a deliberate access prohibition. Record a useful reason. Unblock restores eligibility but does not guarantee a session will start if the package, expiry, credentials, router, or payment state is still invalid. To find blocked subscribers and devices, see [Where to see blocked devices](/subscribers/active-sessions#where-to-see-blocked-devices).
### Change expiry
Use the profile action to set a deliberate date/time. Confirm the workspace timezone before communicating the result.
### Compensate
To add free time after an outage, for one subscriber or many, see [Outage compensation](/subscribers/outage-compensation).
### FUP override
Where available, use the fair-usage override for a controlled exception. Record why it was needed and avoid turning an exception into an undocumented package policy.
### Delete
Deletion can affect access records and related operational history. Read the confirmation dialog, check related records, export when necessary, and prefer pause/block when the business needs to retain the customer account.
## Duplicate and validation errors
Phone/email/username conflicts can indicate an existing subscriber. Search before creating a replacement. Package errors usually mean the chosen package no longer exists or is incompatible with the selected type. Binding errors commonly indicate missing NAS, MAC, or valid IP information.
After resolving the specific field error, resubmit once. Avoid refreshing during a write because it can obscure whether the first request succeeded.
# Subscriber import and export
Source: https://docs.centipidbilling.com/subscribers/import-export
Bulk import subscribers from a template or straight from a MikroTik router, preview before saving to avoid duplicates, and export filtered subscriber lists.
## Move subscriber data safely
Use **Subscribers → Import / export** for controlled bulk onboarding, migration, or reporting. The application supports a downloadable template, parse/preview, final import, MikroTik preview/import, and filtered export.
## Before importing
1. Create and verify packages and routers first.
2. Export the current subscriber list as a rollback/reference snapshot.
3. Start with a small representative file.
4. Normalize user types to supported values.
5. Match package names exactly to current compatible packages.
6. Use unambiguous usernames, account numbers, phones, emails, and MACs.
7. Remove formulas and unexpected formatting from spreadsheet exports.
## Standard import
Use the template provided by this version rather than an older spreadsheet. Column names and supported values can change.
Keep one subscriber per row. Preserve the header. Use explicit text formatting for phone numbers, account numbers, usernames, and MAC addresses so spreadsheet software does not alter them.
Upload the file and inspect row-level validation. Correct errors in the source file; do not ignore a mismatch simply because other rows are valid.
Complete the import, then verify several profiles, package assignments, expiry values, and access records.
Keep the result summary and do not upload the same file again until duplicate behavior is understood.
## MikroTik import
The MikroTik path previews users discovered from router context before importing. Confirm the router, service type, package mapping, and duplicate strategy. A router username is not automatically the same person as an existing application subscriber—match deliberately.
## Export
Choose the required scope and columns, apply filters, review the count, and generate the export. Exported files can contain personal and network data; store them with access controls and delete temporary copies when the task is complete.
## Common import failures
* **Unknown package:** create/correct the package or fix the exact name.
* **Wrong type:** use a supported subscriber type and compatible package.
* **Duplicate username/phone/email/MAC:** search the existing subscribers and update the intended record instead of cloning it.
* **Invalid date/time:** use the format required by the current template and confirm timezone.
* **Missing binding NAS/MAC/IP:** supply the full binding context.
* **Partial success:** use the result summary to identify created versus rejected rows before retrying.
# IP and MAC bindings
Source: https://docs.centipidbilling.com/subscribers/ip-bindings
Bind a device's MAC address to a reserved IP on one router so it skips the Hotspot login, and fix an empty router or device list or a binding with no access.
## Bind a device to network access
A binding associates a subscriber/device MAC with a reserved IP on a specific NAS. It is useful for devices that should bypass the normal Hotspot login while remaining managed by subscriber/package policy.
## Prerequisites
* A configured router exists in **Network → Devices → Routers**.
* The router is reachable enough for device discovery.
* The device has appeared in ARP, DHCP, or Hotspot observations, or you have verified its MAC independently.
* A compatible Hotspot package exists.
* The reserved IP belongs to the intended network and is not already assigned.
## Create a binding
1. Open **Customers → Subscribers**.
2. Choose **New subscriber** and select **Binding**.
3. Enter subscriber identity and contact information.
4. Select the router.
5. Select the observed device after matching MAC, IP, and hostname.
6. Enter the static **IP address**.
7. Add **Range end** only for a deliberate multi-address pool.
8. Select the compatible package and review expiry.
9. Enable SMS expiry reminders only when a valid phone and reminder configuration exist.
10. Save and test from the actual device.
## Legacy routes
Older `/ip-bindings` links redirect to the Bindings view inside Subscribers. Use the current subscriber workspace for new documentation, bookmarks, and support instructions.
## Troubleshooting
### Router picker is empty
No NAS is configured or the current user lacks router access. Provision the router or ask an administrator to review permissions.
### Device list is empty
Connect the device to the intended network, generate traffic, confirm router reachability, and refresh the picker. Do not invent a MAC address from a different interface label.
### Binding saves but device has no access
Check the MAC normalization, reserved IP/subnet, package status, expiry, router selection, IP conflict, and Hotspot/bypass configuration. Review active sessions and router diagnostics.
### Wrong device was selected
Edit or disable the binding immediately, verify the correct device owner, and inspect whether another subscriber was affected. Avoid recycling a reserved IP until stale network state clears.
# Leads and sales pipeline (CRM)
Source: https://docs.centipidbilling.com/subscribers/leads
Built-in ISP CRM: record prospects, move them through a Kanban sales pipeline with owners and stages, export leads, and convert won leads into subscribers.
## Manage the lead pipeline
Leads is the CRM in Centipid Billing. You do not need a separate CRM to track sales: prospects, the pipeline, subscribers and their [support tickets](/subscribers/tickets) all live in one account.
Open **Customers → Leads** to record prospects before they become subscribers. The page supports Kanban and list views, search/filtering, ownership, stage changes, export, bulk delete, and conversion.
Five cards sit at the top:
| Card | What it shows |
| - | - |
| Pipeline value | Monthly revenue if every open lead converts |
| In funnel | Open leads, with the all-time count |
| Conversion | Share of all leads that converted |
| Hot leads | Hot leads and leads past their next-action date. Click to filter. |
| Avg cycle | Average days from first contact to won |
## Create a useful lead
Record enough information to identify and follow up with the prospect:
* name;
* phone and/or email;
* location or service address where offered;
* source and notes;
* owner/assignee;
* current pipeline stage.
**Name** (up to 120 characters) and **phone** (up to 40) are required. Email, address (300), city (120), source (60) and notes (5,000) are optional. Mark a lead **hot**, **warm** or **cold**, and set a next action with a due date.
Search matches name, phone, email and city. You can also filter by stage, owner (me, unassigned or one staff member), source, or hot leads only.
Do not store payment credentials, passwords, identity-document copies, or unrelated sensitive information in free-text notes.
## Move a lead through stages
A lead moves through 6 stages: **New**, **Contacted**, **Qualified**, **Site survey**, **Converted** and **Lost**. The Kanban board shows the first 5 as columns, with up to 50 cards each. The List view loads 50 leads at a time and includes lost leads.
Use Kanban for visual pipeline work or List for scanning/filtering. Stage changes should reflect a real sales event, not merely an intention. Add a concise note when moving a lead after a call, survey, quotation, or installation decision.
## Convert to a subscriber
1. Open the intended lead and verify contact/location.
2. Choose **Convert**.
3. Select the correct subscriber type, package, and network context.
4. Complete the required subscriber fields.
5. Review the created subscriber profile.
6. Confirm the lead is marked converted and is not converted a second time.
If a subscriber already has the lead's phone number, **Convert** links the lead to that subscriber and marks it converted. No second account is created. Otherwise it opens the new-subscriber form.
Conversion should preserve sales context while creating the operational account. If subscriber creation fails, resolve the validation error before attempting another conversion.
## Export and deletion
Use the lead export page for controlled CRM movement. Apply filters and review export counts. Export a date range as CSV or Excel. Bulk delete is appropriate only for confirmed duplicates or records outside retention needs; conversion and loss stages are usually more informative than deletion.
# Outage compensation
Source: https://docs.centipidbilling.com/subscribers/outage-compensation
Give subscribers free time after an outage: in bulk from the Subscribers page, from one profile, or automatically when a router returns, with an optional SMS.
## Compensate subscribers after an outage
Compensation adds time to a subscriber's expiry. There are three ways to do it:
| Way | Use it when |
| - | - |
| **Compensate** on the Subscribers page | You choose who gets how much, for many subscribers at once. |
| **Compensate** on a subscriber's profile | One subscriber needs extra time. |
| Automatic outage compensation | You want Centipid to credit downtime by itself every time a monitored router drops and comes back. |
You need permission to edit subscribers. Staff limited to one router only reach that router's subscribers.
## Compensate many subscribers
1. Open **Customers → Subscribers** and choose **Compensate** at the top of the page.
2. Build a rule that matches the affected subscribers. You can filter by:
* connection type: **Any connection**, **PPPoE**, **Hotspot**, or **IP binding**;
* search text (name, phone, account number, or MAC);
* subscription state: **Has plan**, **Expired**, **No end date**, **At risk**, **VIP**, **Offline now**;
* **Package**, **Router**, **Last online**, and the date the subscriber was created.
For a router outage, pick the **Router** that went down.
3. Add more rules with **Add another rule** if you need to (up to 20). A subscriber who matches several rules is counted, and credited, once.
4. Check the summary: it shows the number of unique recipients and how many can get an SMS.
5. Pick the **Compensation duration** (up to 365 days).
6. Optional: turn on **Notify by SMS** and write the message (up to 480 characters). It is sent exactly as you type it; placeholders such as `@first_name` are not filled in here. This needs an SMS gateway.
7. Choose **Review & compensate**, then **Apply compensation**.
A message confirms the result, for example "Compensated 120 user(s) with +1 day. SMS sent to 118."
## Compensate one subscriber
Open the subscriber's profile and choose **Compensate**. Pick a duration, optionally write an SMS message, and confirm. If you leave the message empty, no SMS is sent.
## How the time is added
* The time is added to whichever is later: now, or the subscriber's current expiry. A subscriber whose plan had already run out gets the time starting now, so they can connect again.
* A paused subscriber is un-paused.
* Payments are not changed. Only the expiry moves.
## Automatic outage compensation
Turn on **Compensate outages** in **Settings → Operator alerts**, under **Outage compensation**. It uses the same monitoring that sends your router offline and online alerts, so it only covers routers that Centipid monitors.
When a router goes offline, Centipid records who was online on it. When the router comes back, each of those subscribers gets credited once. You set:
* **Credit share**: the percentage of the downtime to add back (1 to 100).
* **Minimum outage**, in minutes (0 to 1,440). Shorter outages are ignored.
* **Connection types** (**All types**, **PPPoE**, **Hotspot**) and **Packages** that qualify, or all of them.
* An optional SMS to affected subscribers. The message can use `@first_name`, `@last_name`, `@username`, `@package_name`, `@company_name`, `@expiry_date`, `@outage_minutes`, `@credited_minutes`, and `@credited_hours`.
A subscriber is never credited more than the time they still had left when the router dropped. A three-hour outage adds ten minutes, not three hours, for someone who had ten minutes left.
Subscribers who were not online when the router went down are not included. Use the manual **Compensate** page for them.
## What is not available
The **Live sessions** page has no Compensate action. To compensate the people on a router, use the Subscribers **Compensate** page and filter by **Router**.
## Related
* [Subscriber profile](/subscribers/profile)
* [Notifications and templates](/communications/notifications-and-templates)
* [Settings](/getting-started/settings)
# Subscribers overview
Source: https://docs.centipidbilling.com/subscribers/overview
Find, filter and manage Hotspot, PPPoE and binding subscribers in one list: subscriber types, status and expiry, search, bulk actions, and incremental loading.
## Work with subscribers
The **Customers → Subscribers** workspace is the main record of people and devices receiving service from the ISP. It combines Hotspot, PPPoE, and binding accounts while preserving the fields and actions specific to each access method.
## Subscriber types
| Type | Use it for | Key access data |
| - | - | - |
| Hotspot | Captive-portal sign-in and package purchases | Username/password, compatible Hotspot package, expiry, device policy |
| PPPoE | Fixed-line subscriber sessions | Username/password, PPPoE package, service/NAS context, expiry |
| Binding | A MAC-bypassed device with a reserved IP | NAS, observed MAC/device, static IP or range, Hotspot-compatible package |
Choose the type before the package. The package picker is scoped to compatible plans; Binding uses Hotspot packages because it belongs to the Hotspot access path.
## List views and filters
Use the page tabs and filters to narrow by subscriber type, status, expiry, package, router, or other available criteria. Search can match identity and contact fields such as name, username, account number, phone, and email.
The subscriber list uses incremental loading. Continue scrolling to load more records instead of expecting numbered pages. Filters remain the safer way to work with a large subscriber base.
## Status concepts
Do not treat every “offline” or “expired” indicator as the same condition:
* **Account status** controls whether the application considers the subscriber active.
* **Subscription expiry** records when the current service period ends.
* **Paused** preserves the account while interrupting service until resumed.
* **Blocked** prevents access and can retain a reason for operational context.
* **Active session** means RADIUS currently reports a network session; it can lag the account record until disconnect or accounting updates complete.
* **Disconnect until purchase** is an access action intended to require a new purchase before reconnection where supported.
## Bulk actions
Selection can expose actions such as SMS, compensation, and delete. Active sessions separately support disconnect, pause, block, SMS, and disconnect-until-purchase where the selected records meet the action requirements.
Before a bulk action:
1. Apply a narrow filter.
2. Review the selected count and a sample of records.
3. Confirm that the action is appropriate for every subscriber type selected.
4. Check SMS balance/provider readiness for messaging.
5. Use the confirmation dialog and read its consequence summary.
Bulk delete is destructive. Export the intended records first when retention or recovery may be required.
## Expiry operations
The list and profile expose expiry information and changes. Package duration can set the initial expiry, but an operator can adjust it through supported actions. Compensation adds service time based on the selected duration rather than silently rewriting historical payments.
Automatic expiry reminders depend on network settings, message templates, subscriber phone availability, and provider readiness.
## Next steps
* [Create and manage subscribers](/subscribers/create-and-manage)
* [Subscriber profile](/subscribers/profile)
* [Active sessions](/subscribers/active-sessions)
* [Subscriber import and export](/subscribers/import-export)
# Subscriber profile
Source: https://docs.centipidbilling.com/subscribers/profile
Use the subscriber profile to check identity, sessions, usage, payments and invoices, send credentials or a voucher, change expiry, and fix paid-but-offline.
## Read and act from the subscriber profile
Open a subscriber from the list or global search. The profile combines current account data with related sessions, usage, payments, invoices, tickets, SMS history, and package actions.
## Verify identity first
Before changing access or money:
1. Match the subscriber name with at least one stable identifier—account number, username, phone, email, MAC, or address.
2. Confirm the service type and package.
3. Check the status and expiry.
4. Confirm the router/session context when the issue is network-related.
Similar names are not sufficient verification.
## Profile areas
Depending on data and permission, the profile exposes:
* identity and contact details;
* account/service status and expiry;
* package and access identifiers;
* current and historical session/usage information;
* payment and invoice history;
* tickets and operator notes;
* sent SMS/messages;
* deferred usage and payment aggregates.
Heavy chart/aggregate sections can load after the main profile. A temporary skeleton is normal; actions based on those numbers should wait for the section to resolve.
## Common actions
### Send credentials
Use the dedicated action so the current access details are delivered through the configured channel. Confirm the recipient number/address and never read a password aloud to an unverified caller.
### Send payment information
This action sends the ISP's configured payment instructions. Verify the gateway and instructions in settings first, especially after switching providers.
### Send a message
Write the intended SMS and confirm provider credit/readiness. The profile history should reflect the send result, but provider acceptance is not always final handset delivery.
### Send a voucher
Choose a compatible voucher/package and verify the subscriber phone. Voucher issuance can consume inventory and create an access entitlement; do not repeat the action until checking whether the first voucher was created.
### Generate an invoice
Generate only after verifying the amount/service context and avoiding an existing invoice for the same obligation. The new invoice appears in the subscriber and invoice workspaces.
### Pause, resume, block, or unblock
Read the current state and reason before changing it. A network disconnect may still be needed to terminate an already active RADIUS session after an account-state change.
### Change expiry or compensate
Use expiry change for an explicit target date. Use compensation to add controlled time for an outage/service issue and retain the operational reason. Bulk outage compensation can also be automated by operator-alert settings when enabled. See [Outage compensation](/subscribers/outage-compensation).
### Notes
Add concise factual notes: what happened, what was checked, the action taken, and any follow-up. Do not store passwords, OTPs, API keys, full payment credentials, or unnecessary sensitive personal data in notes.
## Investigate “paid but offline”
1. Verify the payment reached a successful/final state and belongs to this subscriber.
2. Check package, expiry, account status, pause/block state, and device limit.
3. Review active/recent sessions and router health.
4. Confirm the access credential or binding data.
5. Disconnect stale sessions only when needed.
6. Avoid creating a second payment or subscriber while the first record is unresolved.
See [Payments](/billing/payments), [Active sessions](/subscribers/active-sessions), and [Network troubleshooting](/network/troubleshooting).
# Staff and permissions
Source: https://docs.centipidbilling.com/subscribers/staff-and-permissions
Give each staff member their own account and role with only the permissions they need, handle sensitive actions and impersonation, and offboard safely.
## Manage staff access
Operator administrators can manage staff and roles. Staff navigation is generated from effective permissions, while server route guards remain the final authorization boundary.
## Create a staff account
The current staff form requires:
* name;
* unique email;
* password of at least 8 characters (maximum 191);
* optional phone;
* optional role and individual permissions;
* optional NAS restriction;
* active/inactive status.
1. Create a separate account for the person—never reuse the owner account.
2. Assign the narrowest role that covers their job.
3. Add individual grants only when the role is insufficient.
4. Restrict the account to a NAS when its work is location/router-specific.
5. Deliver the initial password securely and require a change after first sign-in.
6. Have the user enable 2FA.
## Permission model
Navigation areas such as Subscribers, Leads, Tickets, Active users, Packages, Routers, Equipment, Billing, Communications, and Analytics appear only when the user has the corresponding capability. Not seeing a row is expected when access is absent.
Do not grant a broad role merely to reveal one menu. Update the role or individual permission deliberately and test using the staff account's actual navigation.
## Sensitive staff actions
Removing staff, resetting passwords, and saving sensitive changes can require an action OTP. Follow the verification dialog; never ask the affected staff member to forward their sign-in OTP.
Password reset generates a temporary password. Copy it only through a secure channel, then clear it from notes/chat and require the user to change it.
## Impersonation
Where authorized, impersonation lets an administrator view the workspace as a staff member for troubleshooting. The application displays an impersonation banner and provides a return action.
Use impersonation to inspect permissions and UI state, not to perform routine work as the user. Record consequential actions, stop impersonating promptly, and never request the user's password.
## Offboarding
1. Disable or remove the staff account.
2. Reassign open tickets and leads.
3. Revoke API tokens created for the person's integrations.
4. Rotate webhook secrets, payment credentials, router credentials, or provider keys they controlled when appropriate.
5. Review recent audit activity.
6. Preserve records required for operations or compliance.
See [Account security](/getting-started/account-security) and [Audits and changelog](/analytics/audits-and-changelog).
# Support tickets (helpdesk)
Source: https://docs.centipidbilling.com/subscribers/tickets
Built-in ISP helpdesk: subscriber support tickets with assignees, priorities, SLA deadlines, SMS and email alerts, ticket analytics and filtered exports.
## Track support work end to end
Tickets is the helpdesk in Centipid Billing. You do not need a separate helpdesk tool: each ticket is linked to the subscriber's account, so staff see the plan, payments and sessions next to the complaint. Sales work lives in the same account under [Leads](/subscribers/leads).
Open **Customers → Tickets**. The Tickets group contains **List** and **Analytics**. Tickets can also be opened by subscribers in the customer portal and then managed by permitted operator staff.
## Create a ticket
Required fields:
* **Subject** — maximum 160 characters;
* **Subscriber** — must resolve to a subscriber in the current ISP account.
Optional/triage fields include description (maximum 8,000 characters), assignee, status, priority, resolution, and SMS notification choices.
1. Choose **Open a ticket**.
2. Select the subscriber before writing account-specific details.
3. Write a concise subject and a factual description: symptom, start time, scope, and checks already completed.
4. Set assignee, status, and priority. New tickets default to open/normal when not specified.
5. Decide whether to send a creation SMS. Custom SMS is optional; blank uses the default behavior.
6. Save and confirm the ticket appears in the list and subscriber profile.
## Status and priority
A ticket has one of 5 statuses:
* **Open**, **In progress** and **Waiting** are active. The ticket still needs work.
* **Resolved** and **Closed** are done. Reports count them as completed.
Priority sets the ticket's response deadline (SLA) from the time it is opened:
| Priority | Deadline |
| - | - |
| Urgent | 4 hours |
| High | 24 hours |
| Normal (default) | 72 hours |
| Low | 168 hours (7 days) |
An active ticket past its deadline is overdue. Resolved and closed tickets are never overdue. Use urgent or high only when the impact justifies it.
Changing status creates an activity entry. When resolving or closing, write the resolution: root cause or confirmed fix, action taken, and any follow-up. Resolution SMS can be enabled independently.
## Alerts
* Every new ticket, from staff or from the [customer portal](/customer-portal/support-tickets), emails each admin and support user who has an email address.
* With the creation SMS turned on, the subscriber gets an SMS when the ticket is opened. This needs a phone number on the account, an SMS gateway and SMS balance.
* When you resolve or close a ticket with resolution SMS turned on, the subscriber gets a second SMS.
## Work from the ticket detail
* Add comments to preserve investigation history.
* Change status as responsibility/progress changes.
* Confirm subscriber context before network or billing actions.
* Avoid pasting secrets, OTPs, or full credentials.
* Use the subscriber profile for account changes and link the result in the ticket comment.
## Ticket analytics
The analytics page summarizes active/resolved volume, priority, age, SLA risk, and other current metrics. Use it to identify backlog and recurring categories, not as a substitute for reading high-impact tickets.
## Export
Filtered exports can include subject, status, priority, subscriber, description, and timestamps according to selected columns. Treat exported descriptions as customer data and limit their distribution.
## Deletion
Delete only when a ticket is an accidental/duplicate record and retention is not needed. Closing preserves history and is normally the correct outcome for completed work.