MyChurchDocs

Giving, paybills and pledges

Where money comes in: the collection accounts members pay to, the ledger of every collection, the review list for payments that could not be matched, pledges, fundraisers, and the paybills and bank accounts behind them.

The api never credits a payment from a callback alone: each M-Pesa payment is verified with Safaricom first, and anything it cannot place waits on the incoming payments list. Payment verification explains why, and How giving works walks the whole flow. Read routes on this page also accept head_office:churches:view and system:churches:view with an X-Church header, except the paybill and bank routes.

Collection accounts

A collection account is what a member types as the M-Pesa account number: TITHE, BUILDING, OFFERING. Each sits on one paybill or one bank account, and its number is unique on that channel. Numbers may not start with a reserved prefix (FR- OP- MP- CLS- CAR- EV- EVS- MERCH- CH- QR-); see Account numbers.

RoutePermissionPurpose
GET/v1/collection-accountschurch:collections:viewList accounts (q, status, type, page, page_size) with goal and amount achieved.
GET/v1/collection-accounts/statschurch:collections:viewAccounts, active accounts, this month's and this year's collections.
GET/v1/collection-accounts/searchchurch:collections:viewQuick search for pickers.
GET/v1/collection-accounts/optionschurch:collections:viewPaybills, bank accounts and cell groups an account can be tied to.
POST/v1/collection-accountschurch:collections:manageCreate an account.
GET/v1/collection-accounts/{uuid}church:collections:viewOne account.
PUT/v1/collection-accounts/{uuid}church:collections:manageUpdate (PATCH accepted).
POST/v1/collection-accounts/{uuid}/statuschurch:collections:manageActivate or deactivate (status: active | inactive).
PUT/v1/collection-accounts/{uuid}/instructionschurch:collections:manageSet the how-to-pay text members receive by SMS (instruction, send).
POST/v1/collection-accounts/{uuid}/send-instructionschurch:collections:manageText the instructions to a member (member_uuid) or a phone.
DELETE/v1/collection-accounts/{uuid}church:collections:manageRemove an account.

Collection account fields

FieldTypeRequiredDescription
namestringYesShown to members, for example "Building Fund".
accountstringYesThe account number members type. One word, at most 40 characters, stored upper case.
paybill_uuiduuidNoThe paybill payments arrive on. Give this or bank_account_uuid.
bank_account_uuiduuidNoThe bank account payments arrive on.
typestringNofixed (default) or temporary.
statusstringNoactive (default) or inactive.
tithe_offeringstringNonone (default), tithe or offering, for reports.
goalnumberNoA target in KES; progress shows in the app.
send_alertbooleanNoSend the payer a receipt SMS built from message.
messagestringNoReceipt text; must contain [amount] when send_alert is on. Also [name] [fname] [total] [balance] [reference] [account] [account_name] and others.
pledge_messagestringNoText sent when a member pledges to the account: [name] [amount] [account].
hide_from_membersbooleanNoKeep it out of the app's giving list.
cell_group_uuiduuidNoTie the account to a cell group for cell group giving reports.
# Paste your token once (it starts with mc_):
export MYCHURCH_TOKEN="mc_your_token_here"

curl -X POST https://uat-api.mychurch.co.ke/v1/collection-accounts \
  -H "Authorization: Bearer $MYCHURCH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Building Fund",
    "account": "BUILDING",
    "paybill_uuid": "3c9a7b21-0000-4000-8000-00000000b001",
    "goal": 2500000,
    "send_alert": true,
    "message": "Dear [fname], we have received KES [amount] for [account_name]. God bless you."
  }'

The collection ledger

Every credited collection, whatever the channel. Lists are read for a date window (from, to; default the current month).

RoutePermissionPurpose
GET/v1/collection-transactionschurch:transactions:viewCollections (from, to, account, member, mode, verified, q, page, page_size).
GET/v1/collection-transactions/totalschurch:transactions:viewTotals for the same filters, by payment mode.
GET/v1/collection-transactions/export.csvchurch:transactions:exportThe same filters as a CSV download.
POST/v1/collection-transactionschurch:collections:manageRecord a cash, cheque or other collection by hand.
GET/v1/collection-transactions/{uuid}church:transactions:viewOne collection.
# Paste your token once (it starts with mc_):
export MYCHURCH_TOKEN="mc_your_token_here"

curl -X POST https://uat-api.mychurch.co.ke/v1/collection-transactions \
  -H "Authorization: Bearer $MYCHURCH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "account_uuid": "8e4d2f10-0000-4000-8000-00000000a201",
    "amount": 1500,
    "payment_mode": "cash",
    "member_uuid": "0b6f4c1e-1111-4a2b-9c3d-000000000001",
    "reference": "ENV-0412",
    "transaction_time": "2026-11-01"
  }'

Incoming payments

Payments that reached a paybill or bank account but could not be credited on their own: an account number no collection account matches, a failed verification, a Safaricom outage. Nothing is dropped. Assigning a payment hands it back to the payments worker, which credits it (verifying it first if Safaricom has not confirmed it yet); the api never credits on its own.

RoutePermissionPurpose
GET/v1/incoming-paymentschurch:collections:reconcileParked payments (status, q, from, to, page, page_size).
GET/v1/incoming-payments/statschurch:collections:reconcileCounts and amounts by status.
GET/v1/incoming-payments/{uuid}church:collections:reconcileOne payment with the body Safaricom sent.
POST/v1/incoming-payments/{uuid}/assignchurch:collections:reconcileCredit it to a collection account on the same channel: account_uuid, optional member_uuid and note.
POST/v1/incoming-payments/{uuid}/retrychurch:collections:reconcileSend a stuck or failed payment back for verification.
POST/v1/incoming-payments/{uuid}/dismisschurch:collections:reconcileClose it with a reason. It stays as evidence and can still be assigned later.
GET/v1/incoming-payments/bank-unverifiedchurch:collections:reconcileBank credits not yet checked against the bank statement.
POST/v1/incoming-payments/bank/{uuid}/verifychurch:collections:reconcileMark a bank credit as seen on the statement.

Staff may read the review list with system:churches:view; head office users cannot.

Pledges

RoutePermissionPurpose
GET/v1/pledgeschurch:pledges:viewPledges with amount paid and balance (page, page_size and filters).
GET/v1/pledges/totalschurch:pledges:viewPledged, paid and outstanding totals.
POST/v1/pledgeschurch:pledges:createRecord a pledge for a member against a collection account.
GET/v1/pledges/{uuid}church:pledges:viewOne pledge.
PUT/v1/pledges/{uuid}church:pledges:editUpdate (PATCH accepted).
POST/v1/pledges/{uuid}/paychurch:pledges:editRecord a payment against the pledge by hand (amount).
DELETE/v1/pledges/{uuid}church:pledges:deleteRemove a pledge.
GET/v1/pledges/reminder-dayschurch:pledges:viewWhich days pledge reminder SMS go out.
PUT/v1/pledges/reminder-dayschurch:pledges:editChange the reminder days.
POST/v1/pledges/remindchurch:pledges:editSend reminders now.

Fundraisers

A fundraiser has its own FR- account number, a target and dates, and takes pledges of its own.

RoutePermissionPurpose
GET/v1/fundraiserschurch:fundraising:viewList fundraisers with raised and pledged amounts.
POST/v1/fundraiserschurch:fundraising:createCreate one; the FR- account number is issued.
GET/v1/fundraisers/{uuid}church:fundraising:viewOne fundraiser.
PUT/v1/fundraisers/{uuid}church:fundraising:editUpdate (PATCH accepted).
POST/v1/fundraisers/{uuid}/statuschurch:fundraising:editOpen or close it.
DELETE/v1/fundraisers/{uuid}church:fundraising:deleteRemove it.
GET/v1/fundraisers/{uuid}/transactionschurch:fundraising:viewContributions received.
POST/v1/fundraisers/{uuid}/paymentschurch:fundraising:editRecord a cash or cheque contribution.
GET/v1/fundraisers/{uuid}/pledgeschurch:fundraising:viewPledges to the fundraiser.
POST/v1/fundraisers/{uuid}/pledgeschurch:fundraising:editRecord a pledge.
PUT/v1/fundraising-pledges/{uuid}church:fundraising:editChange a fundraiser pledge (PATCH accepted).
DELETE/v1/fundraising-pledges/{uuid}church:fundraising:editRemove a fundraiser pledge.

Contribution programs

RoutePermissionPurpose
GET/v1/contribution-programschurch:programs:viewPrograms: an expected amount per member per period (frequency) on one collection account, with how many members are complete.
POST/v1/contribution-programschurch:programs:createCreate a program: name, account_uuid, frequency, expected_amount.
GET/v1/contribution-programs/{uuid}church:programs:viewOne program.
PUT/v1/contribution-programs/{uuid}church:programs:editUpdate (PATCH accepted).
DELETE/v1/contribution-programs/{uuid}church:programs:deleteRemove a program.
GET/v1/contribution-programs/{uuid}/transactionschurch:programs:viewEach member's expected and paid amount.

Paybills and tills

A church's own M-Pesa paybill or till, with its Daraja credentials. Secrets are encrypted at rest and never returned: a paybill shows has_pass_key, has_consumer_secret and a consumer_key_hint instead. Leave a secret blank on update to keep the stored one. Step by step: Paybill and till setup.

RoutePermissionPurpose
GET/v1/paybillschurch:paybills:manageThe church's paybills and tills.
POST/v1/paybillschurch:paybills:manageAdd a paybill or till with its Daraja credentials.
GET/v1/paybills/{uuid}church:paybills:manageOne paybill (secrets masked).
PUT/v1/paybills/{uuid}church:paybills:manageUpdate (PATCH accepted); blank secrets keep the stored values.
POST/v1/paybills/{uuid}/testchurch:paybills:manageAsk Daraja for a token with the stored consumer key and secret. The token is never returned.
POST/v1/paybills/{uuid}/register-c2bchurch:paybills:manageRegister MyChurch's validation and confirmation URLs for the shortcode with Safaricom.
POST/v1/paybills/{uuid}/stkchurch:paybills:manageTurn STK push on or off (allow_stk_push).
DELETE/v1/paybills/{uuid}church:paybills:manageRemove a paybill no collection account uses.

Paybill fields

FieldTypeRequiredDescription
short_codestringYesThe paybill or store number. A short code can belong to one church only (409 otherwise).
is_tillbooleanNoA Buy Goods till rather than a paybill.
till_numberstringNoThe till number members pay to, when is_till.
allow_stk_pushbooleanNoLet the app and USSD send payment prompts on this paybill.
settlement_account_uuiduuidNoThe money account the paybill settles into, for the finance ledger.
consumer_keystringNoDaraja app consumer key.
consumer_secretstringNoDaraja app consumer secret.
pass_keystringNoLipa na M-Pesa Online pass key, for STK push.
initiatorstringNoAPI initiator user name, for Transaction Status verification.
initiator_passwordstringNoThe initiator's password.
# Paste your token once (it starts with mc_):
export MYCHURCH_TOKEN="mc_your_token_here"

curl -X POST "https://uat-api.mychurch.co.ke/v1/paybills/3c9a7b21-0000-4000-8000-00000000b001/register-c2b" \
  -H "Authorization: Bearer $MYCHURCH_TOKEN"
200 OK
{
  "success": true,
  "data": {
    "ok": true,
    "code": "0",
    "description": "Success",
    "validation_url": "https://api.mychurch.co.ke/api/v1/callback",
    "confirmation_url": "https://api.mychurch.co.ke/api/v1/confirm"
  }
}

A refusal is still HTTP 200

The test and register routes report Safaricom's answer in data.ok and data.description, so a wrong consumer secret or an unreachable Daraja answers 200 with ok: false. Check ok, not the status code.

Bank accounts and KCB

Bank accounts that receive giving (Equity, KCB, Co-operative Bank, NCBA), with the bank's integration credentials where the bank issues them. Bitwise staff can manage these for a church with system:integrations:manage. See Bank integrations.

RoutePermissionPurpose
GET/v1/bank-accountschurch:bank_accounts:manageThe church's bank accounts (credentials masked).
GET/v1/bank-accounts/currencieschurch:bank_accounts:manageCurrencies an account can hold.
POST/v1/bank-accountschurch:bank_accounts:manageAdd: name, bank_name, account_number, currency_uuid, opening_balance and the bank's credentials.
GET/v1/bank-accounts/{uuid}church:bank_accounts:manageOne account.
PUT/v1/bank-accounts/{uuid}church:bank_accounts:manageUpdate (PATCH accepted); clear_secrets removes stored credentials.
DELETE/v1/bank-accounts/{uuid}church:bank_accounts:manageRemove an account nothing settles into.
GET/v1/kcb-integrationschurch:bank_accounts:manageKCB Buni credentials on file.
POST/v1/kcb-integrationschurch:bank_accounts:manageStore KCB Buni credentials: client_id, client_secret, username, password.
PUT/v1/kcb-integrations/{uuid}church:bank_accounts:manageUpdate or disable them (PATCH accepted).
DELETE/v1/kcb-integrations/{uuid}church:bank_accounts:manageRemove them.

Reconciliation uploads

Upload an M-Pesa organisation portal statement or a bank export. The imports worker matches each credit line by receipt and amount with the ledger and reports rows_matched and rows_unmatched. It credits nothing: a payment missing from the ledger reaches the incoming payments list through the normal verified path.

RoutePermissionPurpose
GET/v1/reconciliation-uploadschurch:collections:reconcileUploaded statements and their match results.
POST/v1/reconciliation-uploadschurch:collections:reconcileUpload a statement (multipart: file, source, paybill_uuid or bank_account_uuid, notes).