Chapa
Fiat payment processing via Chapa — deposits with multiple channels and withdrawals to bank/mobile money.
Chapa handles fiat payments in Ethiopian Birr (ETB) through Phoenix Pay. It supports multiple deposit channels and outbound withdrawals.
Capabilities
| Channel | Type | Method | Description |
|---|---|---|---|
checkout | Deposit | — | Redirect to Chapa's hosted checkout page |
ussd_push | Deposit | telebirr | USSD push notification to user's phone |
otp | Deposit | telebirr | Direct charge with OTP verification |
direct_payout | Withdrawal | — | Bank transfer or mobile money payout |
Deposits
Checkout (Redirect)
The simplest integration. User is redirected to Chapa's hosted checkout page.
TIMESTAMP=$(date +%s)
BODY='{"reference_id":"order-12345","amount":100000,"currency":"ETB","channel":"checkout"}'
curl -X POST https://pay.phoenixverse.io/api/deposits \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"{
"intent_id": "01912e4b-...",
"action": "redirect",
"url": "https://checkout.chapa.co/checkout/payment/abc123xyz"
}Redirect the user to url. They complete payment on Chapa's page using bank transfer, mobile money, or Telebirr.
USSD Push (Telebirr)
Sends a payment prompt directly to the user's phone. No redirect needed — better mobile UX.
TIMESTAMP=$(date +%s)
BODY='{"reference_id":"order-12346","amount":100000,"currency":"ETB","channel":"ussd_push","method":"telebirr","fields":{"phone":"+251911234567"}}'
curl -X POST https://pay.phoenixverse.io/api/deposits \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"{
"intent_id": "01912e4c-...",
"action": "await",
"message": "Payment request sent"
}| Required Field | Description |
|---|---|
method | Must be "telebirr" |
fields.phone | User's Telebirr phone number (e.g., "+251911234567") |
OTP (Telebirr Direct Charge)
Multi-step flow: initial request triggers an OTP, which the user enters to confirm.
TIMESTAMP=$(date +%s)
BODY='{"reference_id":"order-12347","amount":100000,"currency":"ETB","channel":"otp","method":"telebirr","fields":{"phone":"+251911234567"}}'
curl -X POST https://pay.phoenixverse.io/api/deposits \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"{
"intent_id": "01912e4d-...",
"action": "collect",
"attempt_id": "01912e4e-...",
"collect": {
"type": "otp",
"hint": "Enter the OTP sent to your phone"
}
}Submit the OTP via the step endpoint:
TIMESTAMP=$(date +%s)
BODY='{"input":{"otp":"123456"}}'
curl -X POST https://pay.phoenixverse.io/api/attempts/01912e4e-.../step \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"{
"intent_id": "01912e4d-...",
"action": "await",
"message": "Payment is being processed"
}Withdrawals
Chapa withdrawals send funds to a recipient's bank account or mobile money number via the direct_payout channel.
TIMESTAMP=$(date +%s)
BODY='{"reference_id":"payout-78901","amount":500000,"currency":"ETB","channel":"direct_payout","fields":{"account_number":"1000123456789","account_name":"Abebe Kebede"}}'
curl -X POST https://pay.phoenixverse.io/api/payouts \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"Supported banks:
| Bank | Code |
|---|---|
| Commercial Bank of Ethiopia | cbe |
| Awash Bank | awash |
| Dashen Bank | dashen |
| Bank of Abyssinia | abyssinia |
| Abay Bank | abay |
| Cooperative Bank of Oromia | coop |
TIMESTAMP=$(date +%s)
BODY='{"reference_id":"payout-78902","amount":250000,"currency":"ETB","channel":"direct_payout","method":"telebirr","fields":{"account_number":"+251911234567","account_name":"Abebe Kebede"}}'
curl -X POST https://pay.phoenixverse.io/api/payouts \
-H "Content-Type: application/json" \
-H "X-Key-Id: your-key-id" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: <signature>" \
-d "$BODY"Supported providers:
| Provider | Code |
|---|---|
| Telebirr | telebirr |
| M-Pesa | mpesa |
| Amole | amole |
Withdrawal Fields
| Field | Required | Description |
|---|---|---|
fields.account_number | Yes | Bank account number or phone number |
fields.account_name | Yes | Account holder's name |
Configuration
Credentials are entered in the Phoenix Pay admin panel under Payment Providers > Chapa:
| Field | Required | Description |
|---|---|---|
credentials.secret_key | Yes | Secret key from the Chapa dashboard under Settings > API |
webhook_secret | Yes | Webhook verification secret from Settings > Webhooks. Phoenix Pay stores this separately and uses it to verify Chapa webhooks |
credentials.base_url | No | Override Chapa API base URL if you need a non-default endpoint |
All credentials are encrypted at rest using AES-256. They are never exposed through the API — only configurable via the admin panel.
Phoenix Pay generates the Chapa callback URL for your tenant automatically. You do not need to add it manually to the credentials JSON.
Setup Steps
Create a Chapa Account
Sign up at chapa.co and complete business verification.
Generate API Credentials
In the Chapa dashboard:
- Go to Settings > API and copy your secret key
- Go to Settings > Webhooks and copy the webhook verification secret
Configure in Admin Panel
Enter the secret key and webhook secret in the Phoenix Pay admin panel. Enable the channels you need (checkout, USSD push, OTP, and/or direct payout).
Test with Sandbox
Enable sandbox mode first. Use Chapa's test credentials to verify deposits and payouts before going live.
Sandbox Testing
When sandbox mode is enabled:
- Use Chapa's test API keys (prefixed with
CHAPUBK_TEST-) - Deposits complete instantly
- Payouts simulate success/failure based on test account numbers
- Sandbox mode is per-tenant and does not affect other tenants