Skip to content
All guides

Payroll · Updated November 9, 2026

Paying Salaries by M-Pesa

Configure Arche's company-specific M-Pesa integration and reconcile salary disbursements.

M-Pesa is a separate action on a completed pay run: the M-PESA button on the run's page. Processing payroll does not automatically send payments. Arche sends a Daraja B2C request using the company's saved credentials and the SalaryPayment command. Payroll can also produce a bank EFT file.

Configure the company

Open Settings, Company Settings, M-PESA Integration with manage_company.

FieldArche expects
Consumer key / secretCredentials for the selected Daraja environment
ShortcodeThe business shortcode used as the payer
Initiator name / passwordCredentials usable for the salary-payment request
Environmentsandbox or production
Callback URLYour publicly reachable API base ending in /api/payroll/mpesa-callback
Public certificateComplete certificate text; required when saving production settings

The URL must include /api, even though the placeholder in the Callback URL field does not show it. Use the backend's public hostname, not an assumed frontend hostname. Do not append /result, /timeout or a query string to the saved callback base: Arche adds the endpoint suffix and callback token.

The consumer secret, initiator password and certificate are encrypted in stored company settings. Settings responses mask credential values; the backend decrypts the secrets internally to send requests. Saving settings replaces the credential configuration, so enter the actual values rather than copying masked text.

To stop disbursements, use Remove Configuration on the same tab and confirm. This deletes the saved M-Pesa settings for the company.

Provider account eligibility, approval timing and onboarding requirements are outside this codebase. Confirm those with Safaricom for your account and environment.

Validate and test

Test Connection currently validates the saved configuration fields only. It does not contact Safaricom or obtain an OAuth token. A successful result does not prove the credentials, funding, certificate or callback route work.

Use a controlled sandbox pay run to exercise the full request/callback flow before switching to production credentials. Payment statuses are pending, success, failed and timeout (a payment's success status is not completed).

The deployment must have MPESA_CALLBACK_SECRET configured, including in sandbox. Without it the backend rejects every result/timeout callback. An operator should confirm the public callback route and token configuration when payments remain unresolved.

Disburse a completed run

Use the M-PESA button on the completed run; it requires approve_payroll. The confirmation shows how many employees will be paid by M-Pesa and the total to send; the rest are paid through the bank file. Only employees whose Salary Payment Method is M-PESA are paid this way. If none are, the confirmation says so and nothing is sent. The disbursement uses each employee's M-Pesa number and net pay. The service normalises supported Kenyan mobile-number formats and records each payment before sending it.

A payment must have a valid number and positive whole-shilling net pay. Fractional-shilling payments are reported as failed preflight checks; use the bank-payment route for those amounts. Inspect per-employee results rather than treating the run as one all-or-nothing payment. After a disbursement, the M-PESA Disbursement card on the run shows the counts of Successful, Pending and Failed payments, and Timed Out when there are any.

Production requests encrypt the initiator password with the saved public certificate. The sandbox path uses the supplied credential directly.

Results and retries

pending means Arche does not yet have a final result; it is not proof of receipt by the employee. Reconcile unresolved payments against the provider's records.

Re-disbursing a run skips employees with pending or successful payments. It also holds attempts with provider conversation identifiers for manual reconciliation, even if their status is failed or timeout. A transport failure may be ambiguous: do not treat an error as proof that no money moved.

Preflight failures and reservations released before a send can be retried after correcting the underlying problem. A successful callback is terminal: later callbacks do not downgrade it. A timeout callback only changes a pending payment.

Troubleshooting

SymptomChecks
Pending or timeoutPublic callback reachability, callback base, server secret, provider transaction records
Missing/invalid certificateProduction certificate field and complete certificate text
Failed authentication or rejected requestActual provider response, environment and saved credentials; configuration validation alone cannot diagnose it
Employee preflight failureM-Pesa number, positive amount, whole-shilling net pay

M-Pesa setup is per company. A working configuration in one company does not configure another.

Failed payments

If M-Pesa payments fail or time out, people with manage_payroll get an alert, at most once a day for each pay run. Open the pay run to review them. See Alerts & Notifications.