Response Schemas
Complete JSON schema reference for all FLUID Network API responses, including success responses, error responses, and webhook payloads.
Overview
All FLUID Network API responses follow consistent structure patterns:
- Success responses include
success: true,data, andmetafields - Error responses include
success: false,error, and optionaldetailsfields - Webhook payloads include
event,event_id,timestamp, and event-specificdata
Base Response Structure
Success Response Schema
All successful API responses follow this base structure:
{
"success": true,
"data": { /* endpoint-specific data */ },
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Yes | Always true for successful responses |
data | object | Yes | Response payload (structure varies by endpoint) |
meta | object | Yes | Response metadata |
meta.timestamp | string | Yes | ISO 8601 timestamp when response was generated |
meta.request_id | string | Yes | Unique request identifier for troubleshooting |
meta.api_version | string | Yes | API version used (currently v1) |
Error Response Schema
All error responses follow this base structure:
{
"success": false,
"error": {
"code": 1010,
"message": "Validation error",
"category": "general",
"severity": "medium"
},
"details": { /* optional error-specific details */ },
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Yes | Always false for error responses |
error | object | Yes | Error information |
error.code | integer | Yes | Numeric error code (see Error Codes) |
error.message | string | Yes | Human-readable error message |
error.category | string | Yes | Error category (general, security, connectors, transactions, webhooks, settlements) |
error.severity | string | Yes | Error severity (low, medium, high, critical) |
details | any | No | Additional error-specific information (format varies by error type) |
meta | object | Yes | Response metadata (same as success responses) |
Transaction Endpoints
Initiate Debit Transaction
POST /api/v1/payment-providers/debit-requests/charge
Success Response (202 Accepted)
{
"success": true,
"data": {
"reference": "FLU-20250128-ABC123",
"status": "pending",
"response": {
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"timestamp": "2025-01-28T10:00:00Z"
}
},
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Response Schema
| Field | Type | Required | Description |
|---|---|---|---|
data.reference | string | Yes | FLUID-generated unique transaction reference |
data.status | string | Yes | Initial transaction status (typically pending) |
data.response.uuid | string | Yes | UUID v4 transaction identifier |
data.response.status | string | Yes | Current transaction status |
data.response.timestamp | string | Yes | ISO 8601 timestamp of transaction creation |
Error Response (422 Unprocessable Content)
{
"success": false,
"error": {
"code": 1010,
"message": "Validation error",
"category": "general",
"severity": "medium"
},
"details": [
"Phone number is invalid",
"Amount must be at least 1.00"
],
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Get Transaction Status
GET /api/v1/payment-providers/debit-requests/:reference
Success Response (200 OK)
{
"success": true,
"data": {
"reference": "FLU-20250128-ABC123",
"status": "completed",
"response": {
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"timestamp": "2025-01-28T10:00:00Z",
"processed_at": "2025-01-28T10:00:15Z",
"completed_at": "2025-01-28T10:02:30Z",
"bank_reference": "ECO-TXN-789012345",
"approval_method": "ussd",
"error_message": null
}
},
"meta": {
"timestamp": "2025-01-28T10:05:00Z",
"request_id": "req_xyz789",
"api_version": "v1"
}
}Response Schema
| Field | Type | Required | Description |
|---|---|---|---|
data.reference | string | Yes | Transaction reference |
data.status | string | Yes | Current transaction status (see Status Codes) |
data.response.uuid | string | Yes | UUID v4 transaction identifier |
data.response.status | string | Yes | Current transaction status |
data.response.timestamp | string | Yes | Transaction creation timestamp (ISO 8601) |
data.response.processed_at | string | No | When transaction was submitted to bank (ISO 8601) |
data.response.completed_at | string | No | When transaction completed (ISO 8601) |
data.response.bank_reference | string | No | Bank's unique transaction reference |
data.response.approval_method | string | No | Approval method used (ussd, mobile_app, web, direct) |
data.response.error_message | string | No | Error message if transaction failed |
Not Found Response (404 Not Found)
{
"success": false,
"error": {
"code": 1020,
"message": "Resource not found",
"category": "general",
"severity": "low"
},
"details": "Transaction not found",
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Bank Debit Callback (Bank API)
POST /api/v1/banks/debit-transactions/:uuid/callback
Success Response (200 OK)
{
"success": true,
"data": {
"id": "dt_12345",
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"reference": "FLU-20250128-ABC123",
"status": "completed",
"amount": "100.00",
"currency": "GHS",
"fee": "0.80",
"narration": "Payment for Order #12345",
"partner_reference": "order_12345",
"bank_reference": "ECO-TXN-789012345",
"approval_method": "ussd",
"error_message": null,
"created_at": "2025-01-28T10:00:00Z",
"processed_at": "2025-01-28T10:00:15Z",
"completed_at": "2025-01-28T10:02:30Z",
"customer": {
"name": "John Doe",
"phone_number": "+233241234567",
"account_number": "1234567890"
},
"bank": {
"name": "Example Bank Ghana",
"identifier": "EXB",
"country_code": "GH"
}
},
"meta": {
"timestamp": "2025-01-28T10:02:30Z",
"request_id": "req_bank123",
"api_version": "v1"
}
}Response Schema
| Field | Type | Required | Description |
|---|---|---|---|
data.id | string | Yes | FLUID transaction ID (format: dt_[id]) |
data.uuid | string | Yes | UUID v4 transaction identifier |
data.reference | string | Yes | FLUID-generated reference |
data.status | string | Yes | Transaction status |
data.amount | string | Yes | Transaction amount (string with 2 decimals) |
data.currency | string | Yes | ISO 4217 currency code |
data.fee | string | Yes | Transaction fee amount |
data.narration | string | Yes | Transaction description |
data.partner_reference | string | Yes | Payment partner's reference |
data.bank_reference | string | No | Bank's transaction reference |
data.approval_method | string | No | Approval method used |
data.error_message | string | No | Error message if failed |
data.created_at | string | Yes | Creation timestamp (ISO 8601) |
data.processed_at | string | No | Processing timestamp (ISO 8601) |
data.completed_at | string | No | Completion timestamp (ISO 8601) |
data.customer | object | Yes | Customer information |
data.customer.name | string | Yes | Customer name |
data.customer.phone_number | string | Yes | Customer phone (E.164 format) |
data.customer.account_number | string | No | Bank account number |
data.bank | object | Yes | Bank information |
data.bank.name | string | Yes | Bank name |
data.bank.identifier | string | Yes | FLUID bank code |
data.bank.country_code | string | Yes | ISO 3166-1 alpha-2 country code |
Bank Lookup Endpoints
List Available Banks
GET /api/v1/payment-providers/banks
Success Response (200 OK)
{
"success": true,
"data": [
{
"name": "Example Bank Ghana",
"identifier": "EXB",
"country_code": "GH"
},
{
"name": "Sample Bank",
"identifier": "SAM",
"country_code": "GH"
}
],
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Response Schema
| Field | Type | Required | Description |
|---|---|---|---|
data | array | Yes | Array of bank objects |
data[].name | string | Yes | Full bank name |
data[].identifier | string | Yes | FLUID bank code (3-5 characters) |
data[].country_code | string | Yes | ISO 3166-1 alpha-2 country code |
Get Bank Details
GET /api/v1/payment-providers/banks/:identifier
Success Response (200 OK)
{
"success": true,
"data": {
"name": "Example Bank Ghana",
"identifier": "EXB",
"country_code": "GH",
"status": "live",
"connector_type": "mobile_api",
"metadata": {
"ussd_code": "*326#",
"app_config": {
"package_name": "com.examplebank.mobile"
}
}
},
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Webhook Payloads
All webhook payloads share a common structure with event-specific data. See Webhook Payload Structure for complete details.
Webhook Base Schema
{
"event": "transaction.completed",
"event_id": "evt_abc123def456",
"timestamp": "2025-01-28T10:00:00Z",
"api_version": "v1",
"data": { /* event-specific data */ }
}| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Event type (see Event Types) |
event_id | string | Yes | Unique event identifier (use for idempotency) |
timestamp | string | Yes | ISO 8601 timestamp when event occurred |
api_version | string | Yes | API version (currently v1) |
data | object | Yes | Event-specific payload |
Transaction Completed Webhook
{
"event": "transaction.completed",
"event_id": "evt_a1b2c3d4e5f6g7h8",
"timestamp": "2025-01-28T10:02:30Z",
"api_version": "v1",
"data": {
"transaction": {
"id": "dt_12345",
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"reference": "FLU-20250128-ABC123",
"partner_reference": "order_12345",
"status": "completed",
"amount": 100.00,
"currency": "GHS",
"fee": 0.80,
"narration": "Payment for Order #12345",
"approval_method": "ussd",
"bank_reference": "EXB-TXN-789012345",
"created_at": "2025-01-28T10:00:00Z",
"processed_at": "2025-01-28T10:00:15Z",
"completed_at": "2025-01-28T10:02:30Z",
"bank": {
"name": "Example Bank Ghana",
"identifier": "EXB",
"country_code": "GH"
},
"customer": {
"name": "John Doe",
"phone_number": "+233241234567"
}
},
"previous_status": "processing",
"metadata": {
"order_id": "12345",
"customer_email": "john@example.com"
}
}
}Transaction Failed Webhook
{
"event": "transaction.failed",
"event_id": "evt_b2c3d4e5f6g7h8i9",
"timestamp": "2025-01-28T10:02:30Z",
"api_version": "v1",
"data": {
"transaction": {
"id": "dt_12346",
"uuid": "b2c3d4e5-f6g7-8901-bcde-fg2345678901",
"reference": "FLU-20250128-DEF456",
"partner_reference": "order_12346",
"status": "failed",
"amount": 500.00,
"currency": "GHS",
"fee": 1.80,
"narration": "Payment for Order #12346",
"approval_method": "ussd",
"bank_reference": "MOB-TXN-987654321",
"error_message": "Insufficient funds in customer account",
"created_at": "2025-01-28T10:00:00Z",
"processed_at": "2025-01-28T10:00:15Z",
"completed_at": null,
"bank": {
"name": "Sample Bank",
"identifier": "SAM",
"country_code": "GH"
},
"customer": {
"name": "Jane Doe",
"phone_number": "+233247654321"
}
},
"previous_status": "processing",
"error_details": {
"message": "Insufficient funds in customer account",
"code": "insufficient_funds"
},
"metadata": {
"order_id": "12346"
}
}
}HTTP Status Codes
FLUID Network API uses standard HTTP status codes:
| Status Code | Name | Usage |
|---|---|---|
200 | OK | Successful GET request |
201 | Created | Successful POST that created a resource |
202 | Accepted | Request accepted for async processing |
204 | No Content | Successful DELETE request |
400 | Bad Request | Invalid request format or missing required fields |
401 | Unauthorized | Invalid or missing API key |
403 | Forbidden | Valid API key but insufficient permissions |
404 | Not Found | Resource not found |
422 | Unprocessable Content | Validation error in request payload |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Bank/upstream service error |
503 | Service Unavailable | Maintenance mode or service down |
Common Error Responses
Validation Error (422)
{
"success": false,
"error": {
"code": 1010,
"message": "Validation error",
"category": "general",
"severity": "medium"
},
"details": [
"Phone number is invalid",
"Amount must be at least 1.00",
"Currency must be GHS"
],
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Authentication Error (401)
{
"success": false,
"error": {
"code": 2010,
"message": "Authentication failed",
"category": "security",
"severity": "high"
},
"details": "Invalid or expired API key",
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Not Found Error (404)
{
"success": false,
"error": {
"code": 1020,
"message": "Resource not found",
"category": "general",
"severity": "low"
},
"details": "Transaction not found",
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Rate Limit Error (429)
{
"success": false,
"error": {
"code": 2030,
"message": "Rate limit exceeded",
"category": "security",
"severity": "medium"
},
"details": {
"limit": 1000,
"period": "1 minute",
"retry_after": 45
},
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Bank Connector Error (502)
{
"success": false,
"error": {
"code": 2100,
"message": "Bank connector error",
"category": "connectors",
"severity": "high"
},
"details": "Unable to connect to bank API. Bank may be experiencing downtime.",
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Internal Server Error (500)
{
"success": false,
"error": {
"code": 1000,
"message": "Internal server error",
"category": "general",
"severity": "critical"
},
"details": "An unexpected error occurred. Please contact support with request_id: req_abc123",
"meta": {
"timestamp": "2025-01-28T10:00:00Z",
"request_id": "req_abc123",
"api_version": "v1"
}
}Response Headers
Standard Response Headers
All API responses include these headers:
| Header | Description | Example |
|---|---|---|
Content-Type | Response content type | application/json; charset=utf-8 |
X-Request-ID | Unique request identifier | req_abc123def456 |
X-RateLimit-Limit | Rate limit maximum | 1000 |
X-RateLimit-Remaining | Remaining requests in window | 999 |
X-RateLimit-Reset | Unix timestamp when limit resets | 1706443200 |
Rate Limit Headers
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Request-ID: req_abc123def456
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1706443260Webhook Signature Headers
Webhook requests include HMAC signature headers for verification:
| Header | Description | Example |
|---|---|---|
X-FLUID-Signature | HMAC-SHA256 signature | sha256=abc123def456... |
X-FLUID-Event | Event type | transaction.completed |
X-FLUID-Event-ID | Event identifier | evt_abc123def456 |
X-FLUID-Delivery-ID | Delivery attempt identifier | 12345 |
X-FLUID-Timestamp | Unix timestamp | 1706440800 |
Type Definitions
Transaction Status Enum
"pending" | "processing" | "completed" | "failed" | "reversed"See Status Codes for detailed status information.
Currency Code Enum
"GHS"GHANA ONLY
Currently only GHS (Ghanaian Cedi) is supported. Future expansion will include NGN, KES, and ZAR.
See Currency Codes for detailed currency information.
Country Code Enum
"GH" | "NG" | "KE" | "ZA"See Country Codes for detailed country information.
Approval Method Enum
"ussd" | "mobile_app" | "web" | "direct"| Method | Description |
|---|---|
ussd | Customer approved via USSD prompt (e.g., *326#) |
mobile_app | Customer approved via bank mobile app |
web | Customer approved via web interface |
direct | Automatic approval (no customer interaction) |
Connector Type Enum
"ussd" | "mobile_api" | "both"| Type | Description |
|---|---|
ussd | Bank supports USSD-based transactions only |
mobile_api | Bank supports mobile API integration only |
both | Bank supports both USSD and mobile API |
JSON Schema Validation
Transaction Response Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["success", "data", "meta"],
"properties": {
"success": {
"type": "boolean",
"const": true
},
"data": {
"type": "object",
"required": ["reference", "status", "response"],
"properties": {
"reference": {
"type": "string",
"pattern": "^FLU-[0-9]{8}-[A-Z0-9]{6}$"
},
"status": {
"type": "string",
"enum": ["pending", "processing", "completed", "failed", "reversed"]
},
"response": {
"type": "object",
"required": ["uuid", "status", "timestamp"],
"properties": {
"uuid": {
"type": "string",
"format": "uuid"
},
"status": {
"type": "string",
"enum": ["pending", "processing", "completed", "failed", "reversed"]
},
"timestamp": {
"type": "string",
"format": "date-time"
},
"processed_at": {
"type": ["string", "null"],
"format": "date-time"
},
"completed_at": {
"type": ["string", "null"],
"format": "date-time"
},
"bank_reference": {
"type": ["string", "null"]
},
"approval_method": {
"type": ["string", "null"],
"enum": ["ussd", "mobile_app", "web", "direct", null]
},
"error_message": {
"type": ["string", "null"]
}
}
}
}
},
"meta": {
"type": "object",
"required": ["timestamp", "request_id", "api_version"],
"properties": {
"timestamp": {
"type": "string",
"format": "date-time"
},
"request_id": {
"type": "string"
},
"api_version": {
"type": "string",
"const": "v1"
}
}
}
}
}Best Practices
1. Always Check success Field
✅ Recommended approach: Check the success boolean field to determine if the API call succeeded
- Every response includes a
successfield (truefor success,falsefor errors) - The presence of HTTP 200 status does not guarantee operation success
- Some application-level errors may still return HTTP 200 with
success: false
❌ Common mistake: Only checking the HTTP status code
- HTTP status codes indicate transport-level success (request reached server)
- Application-level errors (validation, business logic) need the
successfield - Relying solely on status codes misses important error cases
Implementation:
- Always parse the JSON response body
- Check
if (response.success)before accessingresponse.data - Handle errors by checking
response.errorwhensuccessisfalse
2. Use request_id for Debugging
Every response includes a unique request_id in the meta object:
Why request_id is important:
- Uniquely identifies each API request for troubleshooting
- Essential when contacting support about API issues
- Helps correlate requests with server-side logs
- Useful for debugging production issues
How to use request_id:
- Extract from response: Found in
response.meta.request_id - Log with errors: Include in error logs and monitoring systems
- Display to users: Show in error messages for user-reported issues
- Send to support: Always include when reporting API problems
- Track requests: Store in database alongside transaction records for audit trail
3. Handle All Status Codes
Implement comprehensive error handling for all HTTP status codes:
Status code categories:
2xx Success (200-299):
- 200 OK: Successful GET request
- 201 Created: Resource created successfully
- 202 Accepted: Request accepted for async processing
- Still check
successfield in response body
4xx Client Errors (400-499):
- 400 Bad Request: Malformed request syntax
- 401 Unauthorized: Invalid/missing authentication
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Resource doesn't exist
- 422 Unprocessable Content: Validation errors (show to user)
- 429 Too Many Requests: Rate limit exceeded (implement retry with delay)
5xx Server Errors (500-599):
- 500 Internal Server Error: Unexpected server error
- 502 Bad Gateway: Bank/upstream service error (retry with backoff)
- 503 Service Unavailable: Temporary downtime (retry after delay)
Error handling strategy:
- Validation errors (422): Display field-specific errors to user from
response.details - Rate limits (429): Wait for
retry_afterseconds fromresponse.details - Server errors (5xx): Log error, capture
request_id, alert monitoring system - Connector errors (502): Implement exponential backoff retry (see Error Codes)
4. Validate Webhook Signatures
Always verify webhook signatures before processing webhook payloads:
Why signature verification is critical:
- Ensures webhook came from FLUID (not a malicious actor)
- Prevents replay attacks and webhook spoofing
- Required for PCI compliance and security best practices
- Protects against unauthorized order fulfillment
Verification process:
- Extract signature from
X-FLUID-Signatureheader - Get webhook secret from your FLUID dashboard (keep secure)
- Compute HMAC-SHA256 of request body using webhook secret
- Compare computed signature with header signature (constant-time comparison)
- Reject if mismatch - return HTTP 401 Unauthorized
Idempotency handling:
- Use
event_idfrom webhook payload to deduplicate events - Store processed
event_idvalues in database - If
event_idalready processed, return HTTP 200 without reprocessing - This prevents double-fulfillment if webhooks are retried
Implementation notes:
- Verify signature before parsing JSON payload
- Use constant-time comparison to prevent timing attacks
- Return HTTP 200 quickly to acknowledge receipt
- Process webhook async (queue for background job)
See Webhook Signature Verification for detailed implementation guide.
5. Type-Safe Response Handling
Use strongly-typed interfaces or types to ensure type-safe response handling:
Benefits of type-safe responses:
- Catch errors at compile-time (TypeScript, Flow, etc.)
- Better IDE autocomplete and intellisense
- Prevents accessing undefined properties
- Self-documenting API response structure
- Reduces runtime errors
Type definition approach:
- Define success response type with
success: trueanddatafield - Define error response type with
success: falseanderrorfield - Create union type combining both success and error types
- Type guard functions to narrow types based on
successfield - Generic types for endpoint-specific data structures
Key type structures needed:
SuccessResponse<T>: Generic success response with typeddataErrorResponse: Standard error response structureApiResponse<T>: Union type of success or errorResponseMeta: Metadata structure (timestamp,request_id,api_version)ErrorInfo: Error details structure (code,message,category,severity)
Implementation benefits:
- TypeScript compiler enforces checking
successfield before accessingdata - Autocomplete shows available fields based on response type
- Refactoring is safer with compile-time type checking
- API changes are caught immediately during development
Related Documentation
- Error Codes - Complete error code reference
- Status Codes - Transaction status reference
- Webhook Payload Structure - Detailed webhook schemas
- Webhook Signature Verification - HMAC signature verification
- Event Types - All webhook event types