Nyota Imara’s billing system is powered by Paystack and supports three payment paths: a redirect-based card checkout for new cards, an M-Pesa STK push for mobile money, and a one-click charge against a saved payment method. All billing endpoints operate in organization context and require the X-Organization-Id header.
List saved payment methods
Before initiating a payment, check what methods are already on file:
curl https://api.nyotaimara.com/v1/billing/methods \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy"
Response:
{
"success": true,
"data": [
{
"id": "pm_01jb4kqp8a3bvc0nqrtzwmde9xy",
"channel": "card",
"cardType": "visa",
"last4": "4242",
"expMonth": 12,
"expYear": 2027,
"network": "visa",
"phone": null
}
]
}
Initiate a payment
All payment requests go to POST /v1/billing/pay. The method field determines which payment flow is triggered.
New card checkout
M-Pesa STK push
Saved payment method
Redirect the user to a Paystack-hosted checkout page to enter their card details. The server returns a checkoutUrl and a reference.curl -X POST https://api.nyotaimara.com/v1/billing/pay \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy" \
-H "Content-Type: application/json" \
-d '{
"method": "card",
"amount": 5000
}'
Response:{
"success": true,
"checkoutUrl": "https://checkout.paystack.com/access_abc123",
"reference": "NI-7f3a9c1e-..."
}
Redirect your user to checkoutUrl. Paystack returns them to https://accounts.nyotaimara.com/billing after completion. Trigger an STK push directly to an M-Pesa number. The user enters their PIN on their phone to complete payment — no redirect required.curl -X POST https://api.nyotaimara.com/v1/billing/pay \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy" \
-H "Content-Type: application/json" \
-d '{
"method": "mobile_money",
"phone": "0712345678",
"amount": 5000
}'
Response:{
"success": true,
"message": "STK Push sent! Please check your phone to enter your M-Pesa PIN.",
"reference": "NI-9a2f1b4c-..."
}
Only M-Pesa (Safaricom) numbers are supported. Airtel Money numbers return a 400 error. Phone numbers are auto-formatted to the 254XXXXXXXXX format.
Charge a card or send an STK push using a method already saved on the account. Use the id from GET /v1/billing/methods.curl -X POST https://api.nyotaimara.com/v1/billing/pay \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy" \
-H "Content-Type: application/json" \
-d '{
"method": "saved_method",
"paymentMethodId": "pm_01jb4kqp8a3bvc0nqrtzwmde9xy",
"amount": 5000
}'
Response:{
"success": true,
"message": "Payment processed successfully!"
}
Pay for a mail subscription
To purchase or renew a mail subscription, pass metadata describing the plan. The server calculates and enforces the correct price server-side — the amount field in your request body is ignored for subscription payments.
curl -X POST https://api.nyotaimara.com/v1/billing/pay \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy" \
-H "Content-Type: application/json" \
-d '{
"method": "card",
"amount": 0,
"metadata": {
"type": "mail_subscription",
"plan": "core",
"seats": 10,
"billingCycle": "monthly"
}
}'
Never trust a client-provided amount for subscription payments. Nyota Imara’s server always overrides amount with the value calculated from your plan, seat count, and billing cycle. Attempting to submit a lower amount has no effect.
Pricing tiers
Pricing is based on seat volume, plan tier, and billing cycle.
Base price per seat per month (Core plan):
| Seats | Price per seat / month |
|---|
| 1 – 50 | 100 KES |
| 51 – 500 | 80 KES |
| 501 – 5,000 | 60 KES |
| 5,001+ | 40 KES |
Plan markups (added per seat per month):
| Plan | Additional cost per seat |
|---|
| Core | +0 KES |
| Growth | +50 KES |
| Scale | +120 KES |
Yearly billing charges 10 months for the price of 12 — giving you 2 months free.
Example: 20 seats on the Growth plan, billed monthly = (100 + 50) × 20 = 3,000 KES/month. Billed yearly = 3,000 × 10 = 30,000 KES/year.
Preview an upgrade
Before committing to a plan change, fetch a prorated cost breakdown:
curl "https://api.nyotaimara.com/v1/billing/upgrade/preview?newPlan=growth&newSeats=20&newCycle=monthly" \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy"
The response includes amountDueToday — the prorated charge for the remainder of your current billing period.
Execute an upgrade
Once you have confirmed the preview, execute the upgrade. A saved card is required (M-Pesa cannot be used for instant mid-cycle upgrades):
curl -X POST https://api.nyotaimara.com/v1/billing/upgrade \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy" \
-H "Content-Type: application/json" \
-d '{
"newPlan": "growth",
"newSeats": 20,
"newCycle": "monthly",
"paymentMethodId": "pm_01jb4kqp8a3bvc0nqrtzwmde9xy"
}'
Response:
{
"success": true,
"message": "Subscription upgraded successfully!"
}
If you switch from monthly to yearly billing, your next billing date is set to one year from today.
Cancel a subscription
Cancellation takes effect at the end of your current billing period. You retain full access until then.
curl -X POST https://api.nyotaimara.com/v1/billing/cancel \
-H "Authorization: Bearer <your_token>" \
-H "X-Organization-Id: org_01j9kxp8a3bvc0nqrtzwmde4fy"
Response:
{
"success": true,
"message": "Subscription cancelled. You will retain access until 30/11/2025."
}
Endpoint reference
| Method | Endpoint | Description |
|---|
GET | /v1/billing/methods | List saved payment methods |
POST | /v1/billing/pay | Initiate a payment |
GET | /v1/billing/upgrade/preview | Preview prorated upgrade cost |
POST | /v1/billing/upgrade | Execute a plan upgrade |
POST | /v1/billing/cancel | Cancel subscription at period end |