Skip to content
recurring-billingusdconchain-payments
Joshua C.

Retrying Onchain Subscription Payments: Patterns That Work

Explore practical retry patterns for failed onchain subscription payments. Learn how timing, limits, and user feedback shape USDC recurring billing reliability.

Retrying Onchain Subscription Payments: Patterns That Work

Recurring stablecoin billing is appealing for SaaS, APIs, and digital goods. Still, onchain payments settle differently than cards or bank debits. If a USDC subscription payment fails, you do not have the same fallback or forgiveness as legacy rails. The right retry logic makes failed collections predictable, manageable, and less likely to annoy your users. Here’s how to approach it.

Why Onchain Payment Retries Matter

Onchain subscription payments fail for familiar reasons: not enough USDC in the wallet, allowance too low, or a stuck transaction. Unlike card systems, there are no chargebacks and no retries at a central processor’s discretion. Your billing logic needs to decide: when to try again, how often, and when to give up.

A retry schedule is not just a technical detail. It shapes how much revenue you can actually collect and how much friction users experience. Too aggressive, and users get spammed with requests that cannot succeed. Too passive, and your churn increases as accounts lapse unnecessarily.

Basic Retry Patterns: Calendar-Based and Event-Based

Two common retry strategies for onchain recurring billing are calendar-based and event-based:

Calendar-Based Retries

This approach tries to collect at fixed intervals after the first failure. For example, if a payment fails on the due date, you might retry after 1 day, 3 days, and 7 days. If all retries fail, the subscription lapses or the user is notified to take action.

Pros: - Simple to implement. - Predictable for users and operators.

Cons: - Ignores wallet state. Retries may occur when the user still has no funds. - Can result in wasted gas and unnecessary onchain activity.

Event-Based Retries

Here, the system waits for a signal that the failure condition has changed, then retries. For example, you might listen for an incoming USDC transfer to the wallet, or a new approval event, before attempting to charge again.

Pros: - Reduces wasted attempts and gas fees. - More likely to succeed on next attempt.

Cons: - More complex to implement. Requires event indexing or wallet monitoring. - Can introduce latency if the event does not happen soon.

Worked Example: Setting a Retry Policy for a SaaS Product

Let’s say you run a SaaS product charging 100 USDC per month per user, settling onchain. A user’s subscription payment fails due to insufficient USDC on the first of the month. What retry logic should you apply?

Option 1: Fixed Retry Schedule

  • Attempt 1: March 1 (original due date) , fails
  • Attempt 2: March 2 , fails (still no funds)
  • Attempt 3: March 4 , fails again
  • Attempt 4: March 8 , still fails
  • After final attempt, send a notice, mark subscription as lapsed

Total gas spent: 4 attempts × 0.0005 ETH per attempt (example on Base) ≈ 0.002 ETH. If USDC appears in the wallet on March 5, you don’t retry until March 8, and miss a chance to collect sooner.

Option 2: Event-Driven Retry

  • Attempt 1: March 1 (original due date) , fails
  • Monitor wallet for USDC top-up
  • March 5: User receives 200 USDC
  • Attempt 2: March 5 , succeeds

Total gas spent: 2 attempts × 0.0005 ETH = 0.001 ETH. Collection happens as soon as funds are available, with less waste and less delay.

Combining the Two

Most production systems combine calendar and event-driven retries. For instance, you can schedule retries every 3 days, but also trigger a retry if you detect a relevant wallet event. This ensures you do not miss long delays, but also respond quickly if users top up or update their approval.

How Many Retries? When to Stop?

There is no universal answer, but there are some best practices for USDC recurring billing:

  • Limit total retries: Three to five attempts per billing cycle is common. More than that increases gas costs and can annoy users.
  • Notify after final failure: Let users know their subscription is at risk, and how to restore service.
  • Mark the subscription as lapsed after retries are exhausted. Do not keep retrying forever.

If you are billing metered usage, consider pausing access after the first or second failed attempt instead of retrying indefinitely.

Should Users Be Notified on Each Failure?

For onchain subscriptions, users expect transparency. Still, you do not want to flood them with emails or push notifications. A good pattern:

  • Notify on the first failure, with a clear call to action.
  • Notify on the last attempt if the subscription will lapse.
  • Make status visible in the customer portal, so users can resolve issues before retries run out.

Handling Allowance and Approval Failures

Not all failures are due to missing funds. If the ERC-20 approval is too low, or has been revoked, retries will not help. The right approach:

  • On approval failure, notify the user immediately.
  • Show a new approval prompt, with the correct recurring cap.
  • Resume retry logic only after the cap is set and signed.

Implementation Notes for Developers

If you are building your own retry logic, you need to:

  • Track the status of each subscription attempt (success, out of funds, approval failure).
  • Store timestamps for each attempt and for each notification sent.
  • Index relevant wallet events if you want to use event-driven retries.
  • Make sure your retry scheduler is idempotent. Do not double-charge.

A basic retry loop might look like this (simplified):

async function retrySubscriptionPayment(subscription) {
  const maxAttempts = 4;
  let attempt = 0;
  let success = false;
  while (attempt < maxAttempts && !success) {
    success = await tryCharge(subscription);
    if (!success) {
      await waitForNextRetry(subscription, attempt);
      attempt++;
    }
  }
  if (!success) {
    notifyUserFailure(subscription);
    markSubscriptionLapsed(subscription);
  }
}

Operator Perspective: Tracking and Reporting

Beyond the code, operators need to see which subscriptions are failing, how many retries have been attempted, and when accounts are at risk of lapsing. Good reporting surfaces these events, lets support resolve specific issues, and helps product teams tune retry timing.

How We Handle Subscription Payment Retries at Reclack

At Reclack, we combine scheduled retries with event triggers. We retry failed USDC subscription payments up to a cap, pausing if the wallet is unchanged and resuming if the user tops up or updates their approval. Merchants see a clear status for each attempt, and customers get a notification only when action is needed. We never keep retrying forever, and users can always restore service by resolving the underlying issue. Learn more about our approach at reclack.com.

recurring-billingusdconchain-payments