Skip to main content

How environments work

Fingo Pay uses a single base URL for both sandbox and production. The environment is determined entirely by the API key you send.
Base URL (all environments)
https://api.fingopay.io
SandboxProduction
API key prefixsk_test_***sk_live_***
Real moneyNoYes
M-Pesa STK PushSimulatedLive
WebhooksDelivered (sandbox secret)Delivered (production secret)
Idempotency-KeyOptionalRequired for POST
Rate limitsSame (600 req/min)Same (600 req/min)
Never mix sandbox and production keys. Maintain separate credentials and webhook secrets per environment.

What is the sandbox?

The sandbox is a full simulation of the Fingo Pay API. It exposes the same endpoints, accepts the same request shapes, returns the same response structures, and delivers webhooks in the same format as production — but no real money moves and no real M-Pesa STK prompts are sent to phones. Use sandbox to build, test, and validate your integration before going live.
  • Instant processing. Sandbox transactions are processed immediately. There is no waiting for M-Pesa callbacks — outcomes are simulated and webhooks are fired within seconds.
  • Isolated data. Sandbox transactions, accounts, and balances are completely separate from production. Nothing you do in sandbox affects live data.
  • Pre-loaded balances. Sandbox accounts come with test balances so you can test charges, payouts, and balance queries without provisioning funds.
The sandbox behaves identically to production in terms of validation, error responses, and webhook signatures. If your integration works correctly in sandbox, it will work in production with minimal changes — just swap your API key and webhook secret.

Switching environments

export FINGO_API_KEY=sk_test_***
curl -H "Authorization: Bearer $FINGO_API_KEY" \
  "https://api.fingopay.io/v1/balance?accountNo=ACC-TEST-123456"

Sandbox behaviors

Each API area behaves slightly differently in sandbox. The table below summarizes what is simulated and what remains the same.
API areaSandbox behavior
M-Pesa C2B (STK Push)Simulated. No STK prompt is sent to the phone. The transaction completes automatically based on forceStatus (default: success).
M-Pesa B2CSimulated. Funds are not disbursed to the recipient. A webhook is fired with the simulated outcome.
M-Pesa B2BSimulated. No real transfer occurs between tills or paybills. A webhook is fired with the simulated outcome.
Bank transfersSimulated. No real bank transfer is initiated.
BalancesSandbox accounts have pre-loaded test balances. Transactions debit and credit these balances as they would in production.
WebhooksDelivered to your configured endpoint using your sandbox webhook secret. The signature format is identical to production.
Idempotency-KeyOptional in sandbox (required for POST requests in production).
Validation and errorsIdentical to production. Invalid requests return the same error types and codes.

Testing with forceStatus

In sandbox, you can force specific transaction outcomes using the metadata.forceStatus field. This lets you test success, failure, and timeout flows without waiting for real M-Pesa callbacks.
forceStatus valueBehavior
successTransaction completes successfully
failedTransaction fails with a simulated error
timeoutSimulates customer no-response / STK Push timeout
If you do not include forceStatus in your sandbox request, the default outcome is success.

Example: Successful charge

{
  "phoneNumber": "+254711000000",
  "amount": 150000,
  "merchantTransactionId": "test_success_001",
  "metadata": {
    "forceStatus": "success"
  }
}
Your webhook endpoint receives a transaction.succeeded event with a simulated M-Pesa processor reference.

Example: Failed charge

{
  "phoneNumber": "+254711000000",
  "amount": 150000,
  "merchantTransactionId": "test_failed_002",
  "metadata": {
    "forceStatus": "failed"
  }
}
Your webhook endpoint receives a transaction.failed event with a simulated error message.

Example: Timeout

{
  "phoneNumber": "+254711000000",
  "amount": 150000,
  "merchantTransactionId": "test_timeout_003",
  "metadata": {
    "forceStatus": "timeout"
  }
}
Your webhook endpoint receives a transaction.failed event with a timeout message, simulating a customer who did not respond to the STK Push prompt.
The forceStatus field is ignored in production. Including it in live requests has no effect on the transaction outcome.
Use test phone numbers like +254711000000 in sandbox. These are non-billable and will not trigger real STK prompts.

Pre-go-live testing checklist

Verify each of the following in sandbox before switching to production.
1

Successful charge flow

Create a C2B charge with forceStatus: "success" and confirm your webhook endpoint receives a transaction.succeeded event. Verify that your system correctly updates the order or payment status.
2

Failed charge flow

Create a C2B charge with forceStatus: "failed" and then forceStatus: "timeout". Confirm your webhook endpoint handles both transaction.failed scenarios and that your system surfaces the failure to the user or triggers a retry flow.
3

Payout flows

Test B2C and B2B payouts. Verify that webhooks are received and that your system reconciles by merchantTransactionId and transactionId.
4

Webhook signature verification

Confirm that your endpoint validates the X-Fingo-Signature header using your sandbox webhook secret. Reject requests with invalid or expired signatures. See Webhooks for implementation details.
5

Idempotency handling

Send the same POST request twice with the same Idempotency-Key and verify you receive the original response. Then send a different body with the same key and confirm you receive a 409 conflict error. See Authentication and Idempotency for details.
6

Error handling

Trigger common error scenarios — missing required fields (400), looking up a non-existent transaction (404), and reusing a merchantTransactionId (409). Verify your integration handles each error type correctly. See Errors for the full reference.
7

Balance verification

Check account balances before and after transactions using GET /v1/balance to confirm that sandbox balances update as expected.

Sandbox limitations

The sandbox is designed for integration testing and validation. It does not replicate every aspect of the production environment.
  • No phone interaction. M-Pesa STK Push prompts are not sent to real phones. Transaction outcomes are determined by forceStatus.
  • No real money movement. Balances are simulated. No funds are transferred to or from any M-Pesa wallet or bank account.
  • Instant processing. Sandbox transactions complete immediately. Production transactions depend on M-Pesa and bank processing times, which can range from a few seconds to several minutes.
  • Scale behavior. While sandbox enforces the same rate limits (600 req/min), it does not replicate production-level latency or throughput characteristics under high load.