Create Debit Request (Charge)
Initiate a debit request to charge a customer's bank account.
Endpoint
POST /api/v1/payment-providers/debit-requests/chargeAuthentication
Requires a valid Bearer token in the Authorization header.
Authorization: Bearer YOUR_API_TOKENRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
phone_number | string | Yes | Customer's phone number in E.164 format |
bank_identifier | string | Yes | FLUID Network bank identifier (from List Banks) |
amount | number | Yes | Transaction amount (decimal, minimum 1.00) |
currency | string | Yes | ISO 4217 currency code (must be "GHS") |
narration | string | Yes | Transaction description (max 100 characters) |
partner_reference | string | Yes | Your unique transaction reference (max 50 characters) |
metadata | object | No | Additional data to attach to the transaction |
Request Constraints
- Amount: Must be >= 1.00 and <= 10,000.00
- Phone Number: Must be in E.164 format with country code
- Partner Reference: Must be unique per transaction
- Narration: Visible to customer in transaction history
Example Request
curl --request POST \
--url https://api.fluid-network.com/api/v1/payment-providers/debit-requests/charge \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"debit_request": {
"phone_number": "+233241234567",
"bank_identifier": "ECO",
"amount": 100.00,
"currency": "GHS",
"narration": "Payment for Order #12345",
"partner_reference": "partner_tx_123456",
"metadata": {
"merchant_id": "merch_123",
"order_id": "order_12345",
"customer_email": "customer@example.com"
}
}
}'Response
Success Response
Status Code: 200 OK
{
"success": true,
"data": {
"reference": "FLU123456789",
"status": "pending",
"response": {
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"timestamp": "2025-01-05T12:00:00Z",
"reference": "FLU123456789"
}
},
"meta": {
"timestamp": "2025-01-05T12:00:00Z",
"request_id": "abc-123",
"api_version": "v1"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
success | boolean | Indicates if the request was accepted |
data.reference | string | FLUID Network transaction reference (use for status checks) |
data.status | string | Initial transaction status (typically "pending") |
data.response.uuid | string | Unique transaction identifier |
data.response.status | string | Transaction status |
data.response.timestamp | string | Transaction initiation timestamp (ISO 8601) |
data.response.reference | string | FLUID Network transaction reference |
meta.timestamp | string | API response timestamp |
meta.request_id | string | Request trace ID for support |
meta.api_version | string | API version used |
Transaction Statuses
| Status | Description |
|---|---|
pending | Transaction initiated, awaiting customer approval |
processing | Customer approved, payment being processed |
completed | Payment successfully completed |
failed | Transaction failed or was declined |
cancelled | Transaction cancelled by customer or timeout |
Error Responses
Validation Error
Status Code: 400 Bad Request
{
"success": false,
"error": {
"code": 1007,
"message": "Validation failed",
"category": "validation",
"details": {
"phone_number": ["must be in E.164 format"],
"amount": ["must be greater than or equal to 1.00"]
}
}
}Bank Not Supported
Status Code: 402 Payment Required
{
"success": false,
"error": {
"code": 1402,
"message": "Bank identifier not supported",
"category": "banks"
}
}Duplicate Reference
Status Code: 409 Conflict
{
"success": false,
"error": {
"code": 3003,
"message": "Duplicate transaction reference",
"category": "transactions"
}
}Solution: Each partner_reference must be unique. Check if transaction already exists using the Get Status endpoint.
Invalid Amount
Status Code: 400 Bad Request
{
"success": false,
"error": {
"code": 3007,
"message": "Invalid transaction amount",
"category": "transactions"
}
}Common Causes:
- Amount below minimum (1.00)
- Amount above maximum (10,000.00)
- Invalid decimal format
Rate Limit Exceeded
Status Code: 429 Too Many Requests
{
"success": false,
"error": {
"code": 1456,
"message": "Payment processing rate limit exceeded",
"category": "security"
}
}Unauthorized
Status Code: 401 Unauthorized
{
"success": false,
"error": {
"code": 1401,
"message": "Unauthorized",
"category": "authentication"
}
}Transaction Flow
Best Practices
Idempotency
- Store
partner_referencebefore making the request - If request fails with network error, retry using same
partner_reference - FLUID will detect duplicate and return existing transaction
Status Polling
Note: Implement webhooks for real-time updates instead of polling. If you must poll:
- Wait at least 30 seconds before first status check
- Use exponential backoff (30s, 60s, 120s...)
- Stop after 5 minutes and treat as timeout
Customer Experience
- Pre-validation: Use Lookup Customer Banks before charging
- Clear narration: Use descriptive text visible to customer
- Show reference: Display
referenceto customer for support queries - Set expectations: Inform customer they'll receive a prompt on their phone
- Timeout handling: Set 5-minute timeout for customer approval
Security
- Never expose your API token in client-side code
- Validate amounts on your backend before submitting
- Store transaction references securely
- Implement request signing for production (HMAC)
Rate Limits
- Production: 1000 requests per minute
- Sandbox: 100 requests per minute
Sandbox Testing: In sandbox, use test phone number +233241234567 and bank identifier ECO. Transactions auto-complete after 30 seconds for testing.
Webhook Notifications
After initiating a charge, you'll receive webhook notifications for status changes:
{
"event": "transaction.completed",
"data": {
"reference": "FLU123456789",
"status": "completed",
"amount": 100.00,
"currency": "GHS",
"partner_reference": "partner_tx_123456",
"timestamp": "2025-01-05T12:05:00Z"
}
}Learn more: Webhook Documentation
Next Steps
- Check transaction status
- Configure webhooks for real-time updates
- Handle errors gracefully
- Test in sandbox before going live