Retry & Failure Handling

Payment failures are normal in recurring billing. This guide shows you how to detect failures, communicate with customers, and implement a retry strategy that recovers revenue without creating a poor customer experience.

Types of Failures

  1. Insufficient funds: the customer's account does not have enough balance at the time of the debit.
  2. Card expired: the tokenized card has expired and the token is no longer valid.
  3. Mandate debit failure: a direct debit mandate debit was rejected by the customer's bank (e.g. account restricted, mandate limit exceeded).
  4. Bank downtime: temporary unavailability on the customer's bank side.
  5. Transaction timeout: the payment session expired before the customer completed it.

Step 1 – Detect Failures

Monnify only sends a webhook notification when a transaction is successful. The event type is SUCCESSFUL_TRANSACTION. There is no webhook for failed or pending transactions.

To detect a failure, your server must actively check the transaction status after the expected payment window:

  1. Listen for the SUCCESSFUL_TRANSACTION webhook on your configured webhook URL.
  2. If the webhook does not arrive within a reasonable window (e.g. 2–5 minutes after initiating the charge), call the Get Transaction Status endpoint with the payment reference.
  3. Inspect the paymentStatus field in the response. A status of PAID means the payment succeeded. Any other status (including PENDING or FAILED) means the transaction did not complete.
status-response.json

Step 2 – Classify the Failure

Not every failure should trigger an immediate retry. Classify failures before acting:

Failure ReasonRetryable?Recommended Action
Insufficient fundsYesRetry after 4–8 hours; notify customer to fund account.
Bank downtime / timeoutYesRetry after 1–6 hours.
Card expiredNoDo not retry. Prompt customer to add a new card.
Mandate limit exceededNoA new mandate is needed with the right amount.
Account restrictedNoCustomer must resolve with their bank before retrying.

Step 3 – Notify the Customer

Send a notification as soon as you confirm the failure via the transaction status check. Timely communication significantly improves recovery rates.

  1. Tell the customer exactly what happened (e.g. "Your payment of ₦5,000 was not completed").
  2. Give them a clear action: fund their account, update their card, or pay manually via a payment link.
  3. Include a direct payment link so they can resolve it in one click. See Payment Links.

Step 4 – Implement Retry Logic

For retryable failures (e.g. insufficient funds, bank downtime), implement a retry schedule on your server. The handler below covers both card token charges and direct debit mandate debits:

retry-scheduler.js

Step 5 – Verify Every Retry

After each retry attempt (whether from your scheduler or a customer paying manually), always verify the transaction status server-side before restoring access.

Only restore access when paymentStatus === "PAID" and amountPaid matches the expected amount. See Verify Transactions for the full response reference.

Direct Debit Retry Flow

For Direct Debit / Mandates, Monnify sends a MANDATE_UPDATE webhook whenever the mandate's status changes (e.g. activated, suspended, cancelled). A failed debit attempt will not always trigger a webhook. To confirm whether a debit succeeded, poll the Get Debit Status endpoint using the debit reference returned when you initiated the debit.

If the debit did not succeed:

  1. Schedule another debit attempt against the same mandate (for retryable failures such as insufficient funds or bank downtime).
  2. Fall back to a payment link or new mandate if the mandate itself is no longer valid (expired, cancelled, or suspended).

Rate this page

How helpful is the content on this page?

Copyright © 2026 Monnify
instagramfacebookicon