Yimaru-BackEnd/docs/CHAPA_INTEGRATION.md
Yared Yemane fbad083ca4 Add admin payments list API with filters and fix /admin route conflict.
Expose GET /api/v1/admin/payments for filtered gateway transaction listing, constrain /admin/:id to integers so /admin/payments is not mistaken for an admin id, and grant payments.list_all to ADMIN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 05:50:46 -07:00

113 lines
4.4 KiB
Markdown

# Chapa Payment Gateway Integration
Subscription payments for learners use [Chapa](https://developer.chapa.co/docs) hosted checkout, following the same payment-first flow as the previous ArifPay integration.
## Overview
- Subscriptions are created only after Chapa confirms payment (webhook and/or verify).
- `tx_ref` is stored as the payment `nonce` and returned as `session_id` in API responses.
- ArifPay direct-payment routes remain available for legacy flows; subscription checkout uses Chapa.
## Environment Variables
```env
CHAPA_SECRET_KEY=CHASECK_TEST-xxxxxxxx
CHAPA_PUBLIC_KEY=CHAPUBK_TEST-xxxxxxxx
CHAPA_WEBHOOK_SECRET=your_webhook_secret_from_dashboard
CHAPA_BASE_URL=https://api.chapa.co/v1
CHAPA_CALLBACK_URL=https://your-api.example.com/api/v1/payments/chapa/callback
CHAPA_RETURN_URL=https://your-api.example.com/payment/success
CHAPA_RECEIPT_URL=
```
Configure the same webhook URL in the Chapa dashboard:
`https://your-api.example.com/api/v1/payments/webhook`
## Payment Flow
1. Learner calls `POST /api/v1/subscriptions/checkout` or `POST /api/v1/payments/subscribe`.
2. Backend creates a pending payment and calls Chapa `POST /transaction/initialize`.
3. Client redirects the user to `payment_url` (`checkout_url` from Chapa).
4. After payment, Chapa redirects the learner to `return_url` (`/payment/success`) and calls `callback_url`.
5. The success page and callback both verify via Chapa `GET /transaction/verify/{tx_ref}` and activate the subscription when successful.
6. Chapa also sends a webhook; client may poll `GET /api/v1/payments/verify/{tx_ref}` (`session_id` path param is the `tx_ref`).
## API Endpoints
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| POST | `/api/v1/subscriptions/checkout` | Yes | Initiate subscription payment |
| POST | `/api/v1/payments/subscribe` | Yes | Same as checkout |
| GET | `/api/v1/payments/verify/:session_id` | Yes | Verify by `tx_ref` |
| POST | `/api/v1/payments/webhook` | No | Chapa webhook (HMAC signature required) |
| GET | `/api/v1/payments/chapa/callback` | No | Chapa server callback (JSON) |
| GET | `/api/v1/payments/chapa/success` | No | Chapa learner success page (HTML) |
| GET | `/payment/success` | No | Same HTML success page (`CHAPA_RETURN_URL`) |
| GET | `/api/v1/payments/methods` | No | Supported Chapa methods |
| GET | `/api/v1/admin/payments` | Yes (admin) | List/filter all gateway payments (Chapa + ArifPay) |
| GET | `/api/v1/admin/payments/:id` | Yes (admin) | Get any payment by ID |
### Admin: list all gateway payments
`GET /api/v1/admin/payments` requires permission `payments.list_all` (assigned to `ADMIN` by default).
Query filters (all optional):
| Parameter | Description |
|-----------|-------------|
| `user_id` | Learner user ID |
| `plan_id` | Subscription plan ID |
| `subscription_id` | Linked subscription ID |
| `status` | `PENDING`, `PROCESSING`, `SUCCESS`, `FAILED`, `CANCELLED`, `EXPIRED` |
| `provider` or `payment_method` | `CHAPA` or `ARIFPAY` |
| `currency` | e.g. `ETB` |
| `plan_category` | `LEARN_ENGLISH`, `IELTS`, `DUOLINGO` |
| `reference` | Partial match on `session_id`, `nonce`, or `transaction_id` |
| `created_from`, `created_to` | RFC3339 or `YYYY-MM-DD` |
| `paid_from`, `paid_to` | RFC3339 or `YYYY-MM-DD` |
| `min_amount`, `max_amount` | Amount range |
| `limit`, `offset` | Pagination (default limit 20, max 100) |
Example:
`GET /api/v1/admin/payments?provider=CHAPA&status=SUCCESS&limit=50&offset=0`
### Initiate payment request
```json
{
"plan_id": 1,
"phone": "0912345678",
"email": "learner@example.com"
}
```
### Initiate payment response
```json
{
"message": "Payment initiated. Complete payment to activate subscription.",
"data": {
"payment_id": 42,
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"payment_url": "https://checkout.chapa.co/checkout/payment/...",
"amount": 500,
"currency": "ETB",
"expires_at": "2026-05-21T18:00:00Z"
}
}
```
## Webhook Security
Chapa signs the raw JSON body with HMAC-SHA256 using your webhook secret. The handler checks `x-chapa-signature` or `chapa-signature` before processing.
## Testing
Use Chapa test keys and [test credentials](https://developer.chapa.co/test/testing-mobile). After checkout, confirm the subscription via verify endpoint or webhook logs.
### Postman
Import `postman/Chapa-Subscription-Payments.postman_collection.json`. Set collection variables (`base_url`, learner credentials, `chapa_webhook_secret`), then run folders **00 → 02** in order.