Skip to content

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, and meta fields
  • Error responses include success: false, error, and optional details fields
  • Webhook payloads include event, event_id, timestamp, and event-specific data

Base Response Structure

Success Response Schema

All successful API responses follow this base structure:

json
{
  "success": true,
  "data": { /* endpoint-specific data */ },
  "meta": {
    "timestamp": "2025-01-28T10:00:00Z",
    "request_id": "req_abc123",
    "api_version": "v1"
  }
}
FieldTypeRequiredDescription
successbooleanYesAlways true for successful responses
dataobjectYesResponse payload (structure varies by endpoint)
metaobjectYesResponse metadata
meta.timestampstringYesISO 8601 timestamp when response was generated
meta.request_idstringYesUnique request identifier for troubleshooting
meta.api_versionstringYesAPI version used (currently v1)

Error Response Schema

All error responses follow this base structure:

json
{
  "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"
  }
}
FieldTypeRequiredDescription
successbooleanYesAlways false for error responses
errorobjectYesError information
error.codeintegerYesNumeric error code (see Error Codes)
error.messagestringYesHuman-readable error message
error.categorystringYesError category (general, security, connectors, transactions, webhooks, settlements)
error.severitystringYesError severity (low, medium, high, critical)
detailsanyNoAdditional error-specific information (format varies by error type)
metaobjectYesResponse metadata (same as success responses)

Transaction Endpoints

Initiate Debit Transaction

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

Success Response (202 Accepted)

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

FieldTypeRequiredDescription
data.referencestringYesFLUID-generated unique transaction reference
data.statusstringYesInitial transaction status (typically pending)
data.response.uuidstringYesUUID v4 transaction identifier
data.response.statusstringYesCurrent transaction status
data.response.timestampstringYesISO 8601 timestamp of transaction creation

Error Response (422 Unprocessable Content)

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

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

FieldTypeRequiredDescription
data.referencestringYesTransaction reference
data.statusstringYesCurrent transaction status (see Status Codes)
data.response.uuidstringYesUUID v4 transaction identifier
data.response.statusstringYesCurrent transaction status
data.response.timestampstringYesTransaction creation timestamp (ISO 8601)
data.response.processed_atstringNoWhen transaction was submitted to bank (ISO 8601)
data.response.completed_atstringNoWhen transaction completed (ISO 8601)
data.response.bank_referencestringNoBank's unique transaction reference
data.response.approval_methodstringNoApproval method used (ussd, mobile_app, web, direct)
data.response.error_messagestringNoError message if transaction failed

Not Found Response (404 Not Found)

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

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

FieldTypeRequiredDescription
data.idstringYesFLUID transaction ID (format: dt_[id])
data.uuidstringYesUUID v4 transaction identifier
data.referencestringYesFLUID-generated reference
data.statusstringYesTransaction status
data.amountstringYesTransaction amount (string with 2 decimals)
data.currencystringYesISO 4217 currency code
data.feestringYesTransaction fee amount
data.narrationstringYesTransaction description
data.partner_referencestringYesPayment partner's reference
data.bank_referencestringNoBank's transaction reference
data.approval_methodstringNoApproval method used
data.error_messagestringNoError message if failed
data.created_atstringYesCreation timestamp (ISO 8601)
data.processed_atstringNoProcessing timestamp (ISO 8601)
data.completed_atstringNoCompletion timestamp (ISO 8601)
data.customerobjectYesCustomer information
data.customer.namestringYesCustomer name
data.customer.phone_numberstringYesCustomer phone (E.164 format)
data.customer.account_numberstringNoBank account number
data.bankobjectYesBank information
data.bank.namestringYesBank name
data.bank.identifierstringYesFLUID bank code
data.bank.country_codestringYesISO 3166-1 alpha-2 country code

Bank Lookup Endpoints

List Available Banks

GET /api/v1/payment-providers/banks

Success Response (200 OK)

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

FieldTypeRequiredDescription
dataarrayYesArray of bank objects
data[].namestringYesFull bank name
data[].identifierstringYesFLUID bank code (3-5 characters)
data[].country_codestringYesISO 3166-1 alpha-2 country code

Get Bank Details

GET /api/v1/payment-providers/banks/:identifier

Success Response (200 OK)

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

json
{
  "event": "transaction.completed",
  "event_id": "evt_abc123def456",
  "timestamp": "2025-01-28T10:00:00Z",
  "api_version": "v1",
  "data": { /* event-specific data */ }
}
FieldTypeRequiredDescription
eventstringYesEvent type (see Event Types)
event_idstringYesUnique event identifier (use for idempotency)
timestampstringYesISO 8601 timestamp when event occurred
api_versionstringYesAPI version (currently v1)
dataobjectYesEvent-specific payload

Transaction Completed Webhook

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

json
{
  "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 CodeNameUsage
200OKSuccessful GET request
201CreatedSuccessful POST that created a resource
202AcceptedRequest accepted for async processing
204No ContentSuccessful DELETE request
400Bad RequestInvalid request format or missing required fields
401UnauthorizedInvalid or missing API key
403ForbiddenValid API key but insufficient permissions
404Not FoundResource not found
422Unprocessable ContentValidation error in request payload
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
502Bad GatewayBank/upstream service error
503Service UnavailableMaintenance mode or service down

Common Error Responses

Validation Error (422)

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

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

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

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

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

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

HeaderDescriptionExample
Content-TypeResponse content typeapplication/json; charset=utf-8
X-Request-IDUnique request identifierreq_abc123def456
X-RateLimit-LimitRate limit maximum1000
X-RateLimit-RemainingRemaining requests in window999
X-RateLimit-ResetUnix timestamp when limit resets1706443200

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: 1706443260

Webhook Signature Headers

Webhook requests include HMAC signature headers for verification:

HeaderDescriptionExample
X-FLUID-SignatureHMAC-SHA256 signaturesha256=abc123def456...
X-FLUID-EventEvent typetransaction.completed
X-FLUID-Event-IDEvent identifierevt_abc123def456
X-FLUID-Delivery-IDDelivery attempt identifier12345
X-FLUID-TimestampUnix timestamp1706440800

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"
MethodDescription
ussdCustomer approved via USSD prompt (e.g., *326#)
mobile_appCustomer approved via bank mobile app
webCustomer approved via web interface
directAutomatic approval (no customer interaction)

Connector Type Enum

"ussd" | "mobile_api" | "both"
TypeDescription
ussdBank supports USSD-based transactions only
mobile_apiBank supports mobile API integration only
bothBank supports both USSD and mobile API

JSON Schema Validation

Transaction Response Schema (JSON Schema)

json
{
  "$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 success field (true for success, false for 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 success field
  • Relying solely on status codes misses important error cases

Implementation:

  • Always parse the JSON response body
  • Check if (response.success) before accessing response.data
  • Handle errors by checking response.error when success is false

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:

  1. Extract from response: Found in response.meta.request_id
  2. Log with errors: Include in error logs and monitoring systems
  3. Display to users: Show in error messages for user-reported issues
  4. Send to support: Always include when reporting API problems
  5. 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 success field 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_after seconds from response.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:

  1. Extract signature from X-FLUID-Signature header
  2. Get webhook secret from your FLUID dashboard (keep secure)
  3. Compute HMAC-SHA256 of request body using webhook secret
  4. Compare computed signature with header signature (constant-time comparison)
  5. Reject if mismatch - return HTTP 401 Unauthorized

Idempotency handling:

  • Use event_id from webhook payload to deduplicate events
  • Store processed event_id values in database
  • If event_id already 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:

  1. Define success response type with success: true and data field
  2. Define error response type with success: false and error field
  3. Create union type combining both success and error types
  4. Type guard functions to narrow types based on success field
  5. Generic types for endpoint-specific data structures

Key type structures needed:

  • SuccessResponse<T>: Generic success response with typed data
  • ErrorResponse: Standard error response structure
  • ApiResponse<T>: Union type of success or error
  • ResponseMeta: Metadata structure (timestamp, request_id, api_version)
  • ErrorInfo: Error details structure (code, message, category, severity)

Implementation benefits:

  • TypeScript compiler enforces checking success field before accessing data
  • Autocomplete shows available fields based on response type
  • Refactoring is safer with compile-time type checking
  • API changes are caught immediately during development