Back to Blog
Payments

Why “Deposit Failed” Isn’t a Reason: 9 Payment Failure Types Every Broker Should Track

Rajiv PatelRajiv Patel
May 3, 20267 min read22 views
Why “Deposit Failed” Isn’t a Reason: 9 Payment Failure Types Every Broker Should Track

Deposit failures are rarely “one problem.” Even with a single PSP, you’re dealing with multiple systems (client device, broker cashier, PSP gateway, acquirer, issuer, fraud tools, 3DS rails, and your own ledger). If your logs collapse all of that into Deposit failed, you’ll burn time, annoy clients, and keep guessing.

Below is a practical taxonomy of common deposit failure modes brokers see in production—and the specific logging you need to fix each one without turning every incident into a war room.

1) Client-side and UI failures (the deposit never really started)

Some “payment failures” never reach the PSP. The client closes a modal, loses connectivity, blocks popups, or your cashier page errors before generating a payment intent/session.

What it looks like: Support sees “I tried 3 times,” but the PSP has zero trace. Your backoffice shows abandoned attempts with no PSP reference.

Log what you need:

  • cashier_session_id (unique per deposit attempt)
  • Frontend events: deposit_click, redirect_initiated, redirect_returned, iframe_loaded, error_shown
  • Client environment: browser/device, IP (coarse), country, user-agent hash
  • Network errors/timeouts and HTTP status codes from your cashier backend

Fix path: instrument the cashier funnel, add clearer error messages, and implement a “resume payment” flow that reuses the same intent/session when appropriate.

2) Broker backend validation failures (you rejected it before the PSP)

Your own rules can block a deposit: KYC status, country restrictions, payment method eligibility, min/max limits, currency mismatches, duplicate requests, or account state (disabled, under review, etc.).

What it looks like: High failure rate clustered around specific segments (new users, certain countries, specific payment methods). PSP sees fewer attempts than your UI.

Log what you need:

  • A structured rejection_code (e.g., KYC_REQUIRED, COUNTRY_BLOCKED, LIMIT_EXCEEDED, CURRENCY_NOT_ALLOWED)
  • Rule evaluation trace (which rule fired, with threshold values)
  • The deposit parameters you validated: amount, currency, method, client jurisdiction flags

Fix path: align ops/compliance rules with product UX, and ensure the client sees an actionable reason (without exposing sensitive risk logic). Always check local regulations for jurisdiction-specific constraints.

3) PSP API request errors (bad payloads, auth, versioning)

These are integration failures: incorrect signatures, missing fields, invalid amount formats, wrong currency codes, expired API keys, or subtle schema changes.

What it looks like: Spikes after a deployment, PSP returns 4xx/401/403, or you see “invalid request” with no issuer involvement.

Log what you need:

  • psp_provider, psp_environment (prod/sandbox), API endpoint name
  • Request/response metadata: HTTP status, PSP error code, PSP error message
  • Correlation IDs: your cashier_session_id + PSP request_id (if provided)
  • Payload hashing (store a hash + key fields, not full PAN/PII)

Fix path: contract-test your PSP integration, monitor error codes by endpoint, and pin API versions where possible.

4) Timeouts and async gaps (you don’t know the final state)

Payments are often asynchronous: redirects, 3DS challenges, delayed webhooks, or PSP processing queues. A timeout doesn’t mean failure—it means unknown.

What it looks like: Client sees “failed,” but later the PSP marks it paid; or funds settle but your ledger never credits. Support sees duplicates from client retries.

Log what you need:

  • A state machine per deposit: created → pending → requires_action → authorized → captured/paid → failed → refunded/chargeback
  • Timestamps for each transition + who triggered it (client return, webhook, polling job)
  • Webhook receipt log: delivery time, signature verification status, payload ID

Fix path: treat timeouts as pending, implement webhook retries + idempotent processing, and show “Processing—check back” instead of “Failed” when state is unknown.

5) 3DS / SCA failures (authentication friction, not “declines”)

If you support cards in regions with SCA, many failures happen during 3DS: challenge not completed, method unavailable, issuer ACS issues, or client abandons.

What it looks like: High drop-off on mobile, “authentication failed,” or PSP indicates requires_action then flips to failed.

Log what you need:

  • 3DS fields: three_ds_version, challenge_required, eci, cavv_present (yes/no), ds_trans_id (if available)
  • Redirect/challenge timings: challenge start/end, user return URL hit
  • PSP reason codes specific to 3DS (don’t collapse them into generic failure)

Fix path: optimize the challenge UX, ensure return URLs work reliably, and segment reporting into issuer decline vs 3DS failure vs abandonment.

6) Issuer declines (the bank said no—now what?)

Issuer declines are the most common and the least actionable if you don’t classify them. “Do not honor” is not the same as insufficient funds, and neither is the same as suspected fraud.

What it looks like: PSP shows declined with issuer response codes; retries sometimes work, sometimes don’t.

Log what you need:

  • Issuer response code + mapped category (e.g., INSUFFICIENT_FUNDS, DO_NOT_HONOR, SUSPECTED_FRAUD, INVALID_CARD, EXPIRED_CARD)
  • Attempt number + spacing between attempts
  • BIN/IIN metadata (country, brand) in a privacy-safe way

Fix path: build client guidance by category (try another card, contact bank, try later) and use analytics to identify where you need additional payment methods or routing options.

7) Risk and fraud rejections (PSP or broker-side)

Fraud tools can reject deposits based on velocity, IP risk, device mismatch, chargeback history, or unusual patterns. These are often correct—but you still need visibility.

What it looks like: “Declined” with minimal detail, clusters by affiliate, country, or campaign. Ops sees more manual reviews.

Log what you need:

  • risk_decision_source (PSP risk, broker risk engine, third-party)
  • risk_outcome (approve/review/deny) + risk_reason_bucket (velocity, geo mismatch, blacklist, device anomaly)
  • Linkage to CRM: client ID, KYC status, affiliate/IB ID (if applicable)

Fix path: tune rules with compliance oversight, add a review queue for borderline cases, and keep an audit trail. Avoid over-collecting data—privacy and data minimization matter, and requirements vary by jurisdiction.

8) Duplicate charges and idempotency failures (retries create chaos)

If the client retries and your system creates a new payment each time, you’ll get duplicates—or worse, “paid at PSP, not credited” disputes.

What it looks like: Two PSP transactions for one intended deposit, or one PSP capture with multiple internal deposit records.

Log what you need:

  • An idempotency_key per logical deposit intent (stable across retries)
  • Mapping table: internal_deposit_id ↔ psp_payment_id ↔ psp_reference
  • Retry reason: user retry vs automatic retry vs webhook replay

Fix path: enforce idempotency at your cashier API boundary, and design retries as “resume the same intent” rather than “create a new one.”

9) Reconciliation breaks (money moved, ledger didn’t)

Even when the PSP succeeds, you can fail to credit: webhook not processed, ledger write failed, FX conversion mismatch, or settlement timing confusion.

What it looks like: Client provides proof of payment, PSP dashboard shows success, but your CRM balance is unchanged.

Log what you need:

  • Ledger events: credit_pending, credit_posted, credit_failed with database transaction IDs
  • Webhook processing outcome: verified, deduped, applied, rejected
  • Reconciliation fields: gross amount, fees, net amount, currency, exchange rate source, settlement batch IDs

Fix path: run daily reconciliation jobs, alert on “PSP paid but not credited within X minutes,” and keep a support-facing trace that explains exactly where the chain broke.

The logging blueprint: the minimum fields that make failures debuggable

You don’t need a giant data lake to diagnose deposit issues—but you do need consistent identifiers and structured failure reasons.

Minimum recommended fields per deposit attempt:

  • Identifiers: cashier_session_id, internal_deposit_id, client_id, psp_payment_id, idempotency_key
  • Context: amount, currency, payment method, country (coarse), device/browser (coarse)
  • State: current status + transition timestamps
  • Errors: failure_stage (ui, broker_validation, psp_api, 3ds, issuer, risk, reconciliation), error_code, error_message
  • Async trace: webhook IDs, signature verification result, processing outcome

If you standardize these fields across payment methods, you can build dashboards that answer: where are we failing, why, and what’s the next best action?

The Bottom Line

A single PSP can produce many different “deposit failed” outcomes—UI drop-offs, broker rule blocks, API errors, 3DS friction, issuer declines, risk rejections, idempotency gaps, and reconciliation breaks.

Treat deposits like a state machine, log by failure stage, and keep stable identifiers that tie UI → PSP → ledger together.

If you want Brokeret to help you design a debuggable cashier flow and payments logging that ops can actually use, start here: /get-started.

Share:TwitterLinkedIn