Skip to content

Create Debit Request (Charge)

Initiate a debit request to charge a customer's bank account.

Endpoint

http
POST /api/v1/payment-providers/debit-requests/charge

Authentication

Requires a valid Bearer token in the Authorization header.

http
Authorization: Bearer YOUR_API_TOKEN

Request Body

FieldTypeRequiredDescription
phone_numberstringYesCustomer's phone number in E.164 format
bank_identifierstringYesFLUID Network bank identifier (from List Banks)
amountnumberYesTransaction amount (decimal, minimum 1.00)
currencystringYesISO 4217 currency code (must be "GHS")
narrationstringYesTransaction description (max 100 characters)
partner_referencestringYesYour unique transaction reference (max 50 characters)
metadataobjectNoAdditional 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

bash
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

json
{
  "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

FieldTypeDescription
successbooleanIndicates if the request was accepted
data.referencestringFLUID Network transaction reference (use for status checks)
data.statusstringInitial transaction status (typically "pending")
data.response.uuidstringUnique transaction identifier
data.response.statusstringTransaction status
data.response.timestampstringTransaction initiation timestamp (ISO 8601)
data.response.referencestringFLUID Network transaction reference
meta.timestampstringAPI response timestamp
meta.request_idstringRequest trace ID for support
meta.api_versionstringAPI version used

Transaction Statuses

StatusDescription
pendingTransaction initiated, awaiting customer approval
processingCustomer approved, payment being processed
completedPayment successfully completed
failedTransaction failed or was declined
cancelledTransaction cancelled by customer or timeout

Error Responses

Validation Error

Status Code: 400 Bad Request

json
{
  "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

json
{
  "success": false,
  "error": {
    "code": 1402,
    "message": "Bank identifier not supported",
    "category": "banks"
  }
}

Duplicate Reference

Status Code: 409 Conflict

json
{
  "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

json
{
  "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

json
{
  "success": false,
  "error": {
    "code": 1456,
    "message": "Payment processing rate limit exceeded",
    "category": "security"
  }
}

Unauthorized

Status Code: 401 Unauthorized

json
{
  "success": false,
  "error": {
    "code": 1401,
    "message": "Unauthorized",
    "category": "authentication"
  }
}

Transaction Flow

Best Practices

Idempotency

  • Store partner_reference before 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

  1. Pre-validation: Use Lookup Customer Banks before charging
  2. Clear narration: Use descriptive text visible to customer
  3. Show reference: Display reference to customer for support queries
  4. Set expectations: Inform customer they'll receive a prompt on their phone
  5. 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:

json
{
  "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