Skip to content

Event Types

FLUID Network sends webhooks for various transaction lifecycle events. This page describes each event type, when it's triggered, and what data it contains.

Transaction Lifecycle Events

Transaction events follow the payment processing lifecycle from creation to completion or failure.

Event Flow


transaction.created

Description

Triggered when a debit or credit transaction is initially created in the FLUID system, before any processing begins.

When Triggered

  • Payment provider submits a new debit transaction via API
  • Bank initiates a credit transaction
  • Immediately after API request validation succeeds

Use Cases

  • Log transaction initiation
  • Display "pending" status to customers
  • Track transaction creation metrics

Example Payload

json
{
  "event": "transaction.created",
  "event_id": "evt_c1a2b3d4e5f6g7h8",
  "timestamp": "2025-01-28T10:15:00Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12345",
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "FLU-20250128-ABC123",
      "partner_reference": "ORDER-67890",
      "status": "created",
      "amount": 100.0,
      "currency": "GHS",
      "fee": 1.5,
      "narration": "Payment for Order #67890",
      "approval_method": "ussd",
      "bank": {
        "name": "Example Bank Ghana",
        "identifier": "EXB",
        "country_code": "GH"
      },
      "customer": {
        "name": "Kwame Mensah",
        "phone_number": "+233241234567"
      },
      "created_at": "2025-01-28T10:15:00Z",
      "processed_at": null,
      "completed_at": null
    },
    "previous_status": null,
    "metadata": {
      "order_id": "67890",
      "customer_email": "kwame@example.com"
    }
  }
}

transaction.pending

Description

Triggered when a transaction is validated and queued for bank submission. The transaction has passed initial checks and is waiting to be sent to the bank.

When Triggered

  • After transaction creation and internal validation
  • Before submission to the bank's API
  • Typically within seconds of transaction.created

Use Cases

  • Update UI to show "processing" state
  • Log queue timing metrics
  • Prepare for bank processing

Example Payload

json
{
  "event": "transaction.pending",
  "event_id": "evt_d2e3f4g5h6i7j8k9",
  "timestamp": "2025-01-28T10:15:05Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12345",
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "FLU-20250128-ABC123",
      "partner_reference": "ORDER-67890",
      "status": "pending",
      "amount": 100.0,
      "currency": "GHS",
      "fee": 1.5,
      "narration": "Payment for Order #67890",
      "bank": {
        "name": "Example Bank Ghana",
        "identifier": "EXB",
        "country_code": "GH"
      },
      "customer": {
        "name": "Kwame Mensah",
        "phone_number": "+233241234567"
      },
      "created_at": "2025-01-28T10:15:00Z",
      "processed_at": null,
      "completed_at": null
    },
    "previous_status": "created",
    "metadata": {
      "order_id": "67890",
      "customer_email": "kwame@example.com"
    }
  }
}

transaction.processing

Description

Triggered when the transaction has been successfully submitted to the bank's API and is being processed by the bank.

When Triggered

  • After successful submission to bank API
  • Bank has accepted the request
  • Waiting for final bank confirmation (callback or polling)

Use Cases

  • Update transaction status to "processing"
  • Display estimated completion time to customers
  • Monitor bank processing duration

Example Payload

json
{
  "event": "transaction.processing",
  "event_id": "evt_e3f4g5h6i7j8k9l0",
  "timestamp": "2025-01-28T10:15:12Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12345",
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "FLU-20250128-ABC123",
      "partner_reference": "ORDER-67890",
      "status": "processing",
      "amount": 100.0,
      "currency": "GHS",
      "fee": 1.5,
      "narration": "Payment for Order #67890",
      "bank_reference": "BNK-REF-789012",
      "bank": {
        "name": "Example Bank Ghana",
        "identifier": "EXB",
        "country_code": "GH"
      },
      "customer": {
        "name": "Kwame Mensah",
        "phone_number": "+233241234567"
      },
      "created_at": "2025-01-28T10:15:00Z",
      "processed_at": "2025-01-28T10:15:12Z",
      "completed_at": null
    },
    "previous_status": "pending",
    "metadata": {
      "order_id": "67890",
      "customer_email": "kwame@example.com"
    }
  }
}

Bank Reference Available

Once a transaction reaches processing status, the bank_reference field is populated with the bank's unique transaction identifier.


transaction.completed

Description

Triggered when the bank confirms successful transaction processing. This is the final success state for a transaction.

When Triggered

  • Bank sends success callback/confirmation
  • Funds have been debited from customer account (for debits)
  • Funds have been credited to customer account (for credits)

Use Cases

  • Mark transaction as successful in your system
  • Send success notification to customer (SMS/email)
  • Fulfill order or deliver service
  • Update account balances
  • Generate receipts

Example Payload

json
{
  "event": "transaction.completed",
  "event_id": "evt_f4g5h6i7j8k9l0m1",
  "timestamp": "2025-01-28T10:15:45Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12345",
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "FLU-20250128-ABC123",
      "partner_reference": "ORDER-67890",
      "status": "completed",
      "amount": 100.0,
      "currency": "GHS",
      "fee": 1.5,
      "narration": "Payment for Order #67890",
      "approval_method": "ussd",
      "bank_reference": "BNK-REF-789012",
      "bank": {
        "name": "Example Bank Ghana",
        "identifier": "EXB",
        "country_code": "GH"
      },
      "customer": {
        "name": "Kwame Mensah",
        "phone_number": "+233241234567"
      },
      "created_at": "2025-01-28T10:15:00Z",
      "processed_at": "2025-01-28T10:15:12Z",
      "completed_at": "2025-01-28T10:15:45Z"
    },
    "previous_status": "processing",
    "metadata": {
      "order_id": "67890",
      "customer_email": "kwame@example.com"
    }
  }
}

Most Important Event

transaction.completed is the most critical webhook event. This is when you should update your records, fulfill orders, and notify customers of success.


transaction.failed

Description

Triggered when transaction processing fails at any stage. This is a terminal failure state requiring user action or retry.

When Triggered

  • Bank rejects the transaction
  • Customer declines USSD prompt
  • Insufficient funds in customer account
  • Invalid account/phone number
  • Network timeout or connectivity issues
  • Bank system unavailable

Use Cases

  • Mark transaction as failed in your system
  • Send failure notification to customer
  • Display error message with reason
  • Suggest remediation (retry, check account, etc.)
  • Log failure metrics for monitoring

Example Payload

json
{
  "event": "transaction.failed",
  "event_id": "evt_g5h6i7j8k9l0m1n2",
  "timestamp": "2025-01-28T10:16:20Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12346",
      "uuid": "660f9511-f39c-52e5-b827-557766551111",
      "reference": "FLU-20250128-DEF456",
      "partner_reference": "ORDER-67891",
      "status": "failed",
      "amount": 500.0,
      "currency": "GHS",
      "fee": 7.5,
      "narration": "Payment for Order #67891",
      "error_message": "Insufficient funds in customer account",
      "bank_reference": "BNK-REF-789013",
      "bank": {
        "name": "Sample Bank",
        "identifier": "SAM",
        "country_code": "GH"
      },
      "customer": {
        "name": "Ama Asante",
        "phone_number": "+233247654321"
      },
      "created_at": "2025-01-28T10:15:50Z",
      "processed_at": "2025-01-28T10:16:05Z",
      "completed_at": null
    },
    "previous_status": "processing",
    "metadata": {
      "order_id": "67891",
      "customer_email": "ama@example.com"
    },
    "error_details": {
      "message": "Insufficient funds in customer account",
      "code": "insufficient_funds"
    }
  }
}

Common Error Codes

Error CodeDescriptionCustomer Action
insufficient_fundsNot enough balance in accountAdd funds and retry
invalid_accountAccount number or phone invalidVerify account details
transaction_declinedCustomer declined USSD promptRetry transaction
timeoutRequest timed outRetry transaction
network_errorNetwork connectivity issueRetry after some time
unknown_errorUnspecified bank errorContact support

Handle Failures Gracefully

Always check for error_details in failed transactions and display user-friendly error messages. The raw error_message may contain technical details unsuitable for end users.


transaction.reversed

Description

Triggered when a previously completed transaction is reversed (refunded) by the bank or payment provider.

When Triggered

  • Merchant initiates refund
  • Bank reverses transaction due to error
  • Dispute resolution requires reversal
  • Regulatory/compliance requirement

Use Cases

  • Reverse transaction in your system
  • Credit customer account (for reversals)
  • Send reversal notification
  • Update order status to "refunded"
  • Adjust accounting records

Example Payload

json
{
  "event": "transaction.reversed",
  "event_id": "evt_h6i7j8k9l0m1n2o3",
  "timestamp": "2025-01-29T14:30:00Z",
  "api_version": "v1",
  "data": {
    "transaction": {
      "id": "dt_12345",
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "FLU-20250128-ABC123",
      "partner_reference": "ORDER-67890",
      "status": "reversed",
      "amount": 100.0,
      "currency": "GHS",
      "fee": 1.5,
      "narration": "Refund for Order #67890",
      "bank_reference": "BNK-REF-789012",
      "bank": {
        "name": "Example Bank Ghana",
        "identifier": "EXB",
        "country_code": "GH"
      },
      "customer": {
        "name": "Kwame Mensah",
        "phone_number": "+233241234567"
      },
      "created_at": "2025-01-28T10:15:00Z",
      "processed_at": "2025-01-28T10:15:12Z",
      "completed_at": "2025-01-28T10:15:45Z"
    },
    "previous_status": "completed",
    "metadata": {
      "order_id": "67890",
      "reversal_reason": "Customer requested refund",
      "customer_email": "kwame@example.com"
    }
  }
}

Reversal Metadata

Reversed transactions include a reversal_reason in metadata explaining why the reversal occurred.


Event Subscription

Default Subscription

By default, payment providers are subscribed to all transaction events. You'll receive webhooks for:

  • transaction.created
  • transaction.pending
  • transaction.processing
  • transaction.completed
  • transaction.failed
  • transaction.reversed

Custom Subscriptions

To receive only specific events, contact your FLUID integration manager to configure selective event subscriptions.

Example: Minimal subscription (success/failure only)

✅ transaction.completed
✅ transaction.failed
❌ transaction.created (disabled)
❌ transaction.pending (disabled)
❌ transaction.processing (disabled)

Event Dependencies

Some events are sequential. If you disable intermediate events (e.g., transaction.processing), you may miss important state transitions. We recommend keeping all events enabled unless you have specific performance or cost constraints.


Event Identification

Unique Event Identifiers

Each webhook includes multiple identifiers for tracking and deduplication:

json
{
  "event": "transaction.completed",           // Event type
  "event_id": "evt_f4g5h6i7j8k9l0m1",         // Unique event ID (per webhook)
  "data": {
    "transaction": {
      "id": "dt_12345",                       // FLUID transaction ID
      "uuid": "550e8400-...",                 // Universal UUID
      "reference": "FLU-20250128-ABC123",     // FLUID reference
      "partner_reference": "ORDER-67890"      // Your reference
    }
  }
}

Deduplication Strategy

Use event_id or transaction.uuid for idempotency:

javascript
async function handleWebhook(payload) {
  const eventId = payload.event_id;
  
  // Check if we've already processed this event
  const exists = await db.processedEvents.exists(eventId);
  if (exists) {
    console.log(`Event ${eventId} already processed, skipping`);
    return { skipped: true };
  }
  
  // Process the event
  await processTransaction(payload.data.transaction);
  
  // Mark as processed
  await db.processedEvents.insert({ eventId, processedAt: new Date() });
  
  return { processed: true };
}

Testing Events

Sandbox Environment

Test webhook events in the sandbox environment:

bash
# Create a test transaction
curl https://sandbox-api.fluid-network.com/api/v1/payment-providers/debit-transactions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+233241234567",
    "bank_identifier": "ECO",
    "amount": 10.00,
    "currency": "GHS",
    "narration": "Test webhook events",
    "partner_reference": "test-001"
  }'

# Expected webhooks received (in order):
# 1. transaction.created
# 2. transaction.pending
# 3. transaction.processing
# 4. transaction.completed (or transaction.failed)

Mock Bank Responses

In sandbox, you can trigger specific outcomes using test phone numbers:

Phone NumberOutcomeEvents Triggered
+233241234567Successcreated → pending → processing → completed
+233241111111Insufficient fundscreated → pending → processing → failed
+233242222222Timeoutcreated → pending → failed
+233243333333Declinedcreated → pending → processing → failed

Next Steps

Payload Structure →

Understand the complete webhook payload schema and all available fields.

Signature Verification →

Implement secure signature verification to prevent spoofed webhooks.

Retry Logic →

Learn how FLUID handles failed webhook deliveries with automatic retries.


See Also