Skip to main content

Troubleshooting: Payment Remains Pending

In emerging markets, payments do not always settle instantly. A transaction may linger in PENDING, PENDING_CHALLENGE, or RECOVERING while bank networks or mobile telcos clear funds.

[1. Copy Transaction ID] ➔ [2. Check Status in Gateway Dashboard] ➔ [3. Inspect Inbound Webhook Logs] ➔ [4. Force Verify in Console]

The 3 Common Causes​

CauseWhat HappenedIs Action Needed?SolydFlow Behavior
1. Interbank Clearing DelayUser sent funds via bank transfer or USSD; central bank switch (NIBSS) is lagging.❌ No. Wait for settlement.Sweeper monitors transaction and settles automatically when funds land.
2. Customer Hasn't Entered PINUser is looking at the M-Pesa SIM prompt or waiting for a card OTP.❌ No. User is actively paying.Kept in PENDING_CHALLENGE until customer authorizes.
3. Dropped Gateway WebhookUser paid, but gateway failed to notify SolydFlow due to network timeout.⚠️ Automated Sweeper kicks in.Sweeper queries gateway REST API within 45s and commits SETTLED_CONSENSUS.
Never Grant Access on Pending States

Do not unlock premium features while a transaction is pending. If the customer cancels their PIN prompt or the bank transfer bounces, your app would leak unearned access.


Step-by-Step Diagnostic Walkthrough​

1. Check the Transaction in the Console​

  1. Open the SolydFlow Console and go to Transactions Ledger.
  2. Search by the customer's user ID, email, or transaction reference (ref_...).
  3. Inspect the State Timeline:
    • If state is UNRESOLVED_ORPHAN: The customer likely closed their app. The Sweeper is scheduled to query the bank within 45 seconds.
    • If state is RECOVERING: SolydFlow is actively querying the gateway REST verification endpoint.

2. Compare Against Your Gateway Dashboard​

Log in to your payment provider dashboard (Paystack, Stripe, or Flutterwave):

  • If Gateway shows "Success": The inbound webhook was likely blocked or dropped. Click "Verify Now" in the SolydFlow console to immediately achieve SETTLED_CONSENSUS.
  • If Gateway shows "Abandoned" or "Failed": The customer never completed payment or their card was declined. The state will transition to FAILED_DECLINED.

Client UI Best Practice: Handling Pending States​

Never show an error screen while a payment is pending. Guide the user with clear status messaging:

lib/screens/checkout_screen.dart
void handlePendingState(BuildContext context, CustomerInfo? info) {
// If user paid via bank transfer, access might settle in background
if (info != null && info.activeEntitlements["pro_access"] != true) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text("Payment Processing"),
content: const Text(
"We are waiting for your bank to confirm the transfer. "
"Your access will activate automatically in a few moments.",
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text("Got It"),
),
],
),
);
}
}