347 lines
8.1 KiB
Markdown
347 lines
8.1 KiB
Markdown
# ArifPay Payment Gateway Integration
|
|
|
|
This document describes the ArifPay payment gateway integration for subscription payments in the Yimaru LMS application.
|
|
|
|
## Overview
|
|
|
|
The integration **coordinates payment with subscriptions** - users cannot create subscriptions without completing payment. Only admins can bypass this restriction for special cases (e.g., promotional subscriptions).
|
|
|
|
### Key Features:
|
|
- **Payment-first approach**: Subscriptions are only created after successful payment
|
|
- **Multiple payment flows**: Checkout redirect or direct OTP-based payment
|
|
- **Webhook handling**: Automatic subscription creation on payment success
|
|
- **Role-based access**: Regular users must pay; admins can grant free subscriptions
|
|
|
|
The integration supports multiple Ethiopian payment methods including:
|
|
- Telebirr
|
|
- CBE (Commercial Bank of Ethiopia)
|
|
- Awash Bank
|
|
- Amole
|
|
- HelloCash
|
|
- M-Pesa
|
|
- And more
|
|
|
|
## Environment Variables
|
|
|
|
Add the following environment variables to your `.env` file:
|
|
|
|
```env
|
|
# ArifPay Configuration
|
|
ARIFPAY_API_KEY=your_arifpay_api_key
|
|
ARIFPAY_BASE_URL=https://gateway.arifpay.net
|
|
ARIFPAY_CANCEL_URL=https://yourdomain.com/payment/cancelled
|
|
ARIFPAY_SUCCESS_URL=https://yourdomain.com/payment/success
|
|
ARIFPAY_ERROR_URL=https://yourdomain.com/payment/error
|
|
ARIFPAY_C2B_NOTIFY_URL=https://yourdomain.com/api/v1/payments/webhook
|
|
ARIFPAY_B2C_NOTIFY_URL=https://yourdomain.com/api/v1/payments/b2c-webhook
|
|
ARIFPAY_BANK=AWINETAA
|
|
ARIFPAY_BENEFICIARY_ACCOUNT_NUMBER=your_account_number
|
|
ARIFPAY_DESCRIPTION=Yimaru LMS Subscription
|
|
ARIFPAY_ITEM_NAME=Subscription
|
|
```
|
|
|
|
## Database Migration
|
|
|
|
Run the migration to create the payments table:
|
|
|
|
```bash
|
|
migrate -path db/migrations -database "postgres://..." up
|
|
```
|
|
|
|
Or manually run:
|
|
```sql
|
|
-- See db/migrations/000009_payments.up.sql
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Subscription Endpoints
|
|
|
|
#### Subscribe with Payment (Recommended)
|
|
|
|
**POST** `/api/v1/subscriptions/checkout`
|
|
|
|
The primary endpoint for users to subscribe. Initiates payment and returns checkout URL.
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"plan_id": 1,
|
|
"phone": "0912345678",
|
|
"email": "user@example.com"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Payment initiated. Complete payment to activate subscription.",
|
|
"data": {
|
|
"payment_id": 123,
|
|
"session_id": "ABC123DEF456",
|
|
"payment_url": "https://checkout.arifpay.net/...",
|
|
"amount": 299.99,
|
|
"currency": "ETB",
|
|
"expires_at": "2024-01-15T18:30:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Direct Subscribe (Admin Only)
|
|
|
|
**POST** `/api/v1/subscriptions`
|
|
|
|
Creates subscription without payment. Only accessible by admin/super_admin roles.
|
|
|
|
---
|
|
|
|
### Payment Endpoints
|
|
|
|
#### Initiate Subscription Payment
|
|
|
|
**POST** `/api/v1/payments/subscribe`
|
|
|
|
Creates a payment session for a subscription plan.
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"plan_id": 1,
|
|
"phone": "0912345678",
|
|
"email": "user@example.com"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Payment initiated successfully",
|
|
"data": {
|
|
"payment_id": 123,
|
|
"session_id": "ABC123DEF456",
|
|
"payment_url": "https://checkout.arifpay.net/...",
|
|
"amount": 299.99,
|
|
"currency": "ETB",
|
|
"expires_at": "2024-01-15T18:30:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Verify Payment Status
|
|
|
|
**GET** `/api/v1/payments/verify/:session_id`
|
|
|
|
Checks the payment status with ArifPay and updates local records.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Payment status retrieved",
|
|
"data": {
|
|
"id": 123,
|
|
"status": "SUCCESS",
|
|
"subscription_id": 456,
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
### Get Payment History
|
|
|
|
**GET** `/api/v1/payments`
|
|
|
|
Returns the authenticated user's payment history.
|
|
|
|
**Query Parameters:**
|
|
- `limit` (default: 20)
|
|
- `offset` (default: 0)
|
|
|
|
### Get Payment Details
|
|
|
|
**GET** `/api/v1/payments/:id`
|
|
|
|
Returns details of a specific payment.
|
|
|
|
### Cancel Payment
|
|
|
|
**POST** `/api/v1/payments/:id/cancel`
|
|
|
|
Cancels a pending payment.
|
|
|
|
### Payment Webhook
|
|
|
|
**POST** `/api/v1/payments/webhook`
|
|
|
|
Webhook endpoint called by ArifPay when payment status changes.
|
|
|
|
**Note:** This endpoint does not require authentication as it's called by ArifPay servers.
|
|
|
|
### Get Available Payment Methods
|
|
|
|
**GET** `/api/v1/payments/methods`
|
|
|
|
Returns list of supported payment methods.
|
|
|
|
---
|
|
|
|
## Direct Payment Endpoints (OTP-based)
|
|
|
|
Direct payments allow users to pay without being redirected to a payment page. Instead, the payment is processed via OTP verification.
|
|
|
|
### Initiate Direct Payment
|
|
|
|
**POST** `/api/v1/payments/direct`
|
|
|
|
Initiates a direct payment with a specific payment method.
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"plan_id": 1,
|
|
"phone": "0912345678",
|
|
"email": "user@example.com",
|
|
"payment_method": "AMOLE"
|
|
}
|
|
```
|
|
|
|
**Supported Payment Methods:**
|
|
- `TELEBIRR` - Telebirr (push notification)
|
|
- `TELEBIRR_USSD` - Telebirr USSD
|
|
- `CBE` - Commercial Bank of Ethiopia
|
|
- `AMOLE` - Amole (requires OTP)
|
|
- `HELLOCASH` - HelloCash (requires OTP)
|
|
- `AWASH` - Awash Bank (requires OTP)
|
|
- `MPESA` - M-Pesa
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "OTP sent to your phone. Please verify to complete payment.",
|
|
"data": {
|
|
"payment_id": 123,
|
|
"session_id": "ABC123DEF456",
|
|
"requires_otp": true,
|
|
"amount": 299.99,
|
|
"currency": "ETB"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Verify OTP
|
|
|
|
**POST** `/api/v1/payments/direct/verify-otp`
|
|
|
|
Verifies the OTP for direct payment methods (Amole, HelloCash, Awash).
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"session_id": "ABC123DEF456",
|
|
"otp": "123456"
|
|
}
|
|
```
|
|
|
|
**Response (Success):**
|
|
```json
|
|
{
|
|
"message": "Payment completed successfully",
|
|
"data": {
|
|
"success": true,
|
|
"transaction_id": "TXN123456",
|
|
"payment_id": 123
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response (Failed):**
|
|
```json
|
|
{
|
|
"message": "Invalid OTP"
|
|
}
|
|
```
|
|
|
|
### Get Direct Payment Methods
|
|
|
|
**GET** `/api/v1/payments/direct/methods`
|
|
|
|
Returns list of payment methods that support direct payment.
|
|
|
|
---
|
|
|
|
## Payment Flows
|
|
|
|
### Flow 1: Checkout Session (Redirect-based)
|
|
|
|
1. **User selects a subscription plan** and initiates payment via `/payments/subscribe`
|
|
2. **Backend creates a payment record** with status `PENDING`
|
|
3. **Backend calls ArifPay** to create a checkout session
|
|
4. **User is redirected** to ArifPay payment page (using `payment_url`)
|
|
5. **User completes payment** on ArifPay
|
|
6. **ArifPay sends webhook** to notify payment status
|
|
7. **Backend processes webhook:**
|
|
- Updates payment status
|
|
- If successful, creates subscription
|
|
- Links payment to subscription
|
|
8. **User can verify** payment status via `/payments/verify/:session_id`
|
|
|
|
### Flow 2: Direct Payment (OTP-based)
|
|
|
|
1. **User selects plan and payment method** via `/payments/direct`
|
|
2. **Backend creates payment record** and checkout session
|
|
3. **Backend initiates direct transfer** with selected payment method
|
|
4. **For OTP-required methods (Amole, HelloCash, Awash):**
|
|
- User receives OTP via SMS
|
|
- User submits OTP via `/payments/direct/verify-otp`
|
|
- Backend verifies OTP with ArifPay
|
|
- On success, creates subscription
|
|
5. **For push-based methods (Telebirr, CBE):**
|
|
- User receives push notification on their app
|
|
- User approves payment in their app
|
|
- ArifPay sends webhook notification
|
|
- Backend creates subscription
|
|
|
|
## Statuses
|
|
|
|
### Payment Statuses
|
|
- `PENDING` - Payment initiated, waiting for user action
|
|
- `PROCESSING` - Payment is being processed
|
|
- `SUCCESS` - Payment completed successfully
|
|
- `FAILED` - Payment failed
|
|
- `CANCELLED` - Payment cancelled by user
|
|
- `EXPIRED` - Payment session expired
|
|
|
|
### Subscription Statuses
|
|
- `PENDING` - Subscription pending payment
|
|
- `ACTIVE` - Subscription is active
|
|
- `EXPIRED` - Subscription has expired
|
|
- `CANCELLED` - Subscription was cancelled
|
|
|
|
## Error Handling
|
|
|
|
The integration handles various error scenarios:
|
|
- User already has an active subscription
|
|
- Plan not found or inactive
|
|
- Payment verification failures
|
|
- Webhook processing errors
|
|
|
|
## Security Considerations
|
|
|
|
1. Webhook endpoint validates requests from ArifPay
|
|
2. Payment verification double-checks with ArifPay API
|
|
3. User can only access their own payment records
|
|
4. Sensitive data (API keys) stored in environment variables
|
|
|
|
## Testing
|
|
|
|
For sandbox testing, use:
|
|
- Base URL: `https://gateway.arifpay.net` (sandbox mode enabled via API key)
|
|
- Test phone numbers provided by ArifPay
|
|
- Sandbox credentials from ArifPay developer portal
|
|
|
|
## Support
|
|
|
|
For ArifPay-specific issues:
|
|
- Developer Portal: https://developer.arifpay.net
|
|
- Telegram: https://t.me/arifochet
|
|
- Support: info@arifpay.com
|