Commet
  • Pricing
Log InTry out
Introduction

Quickstart

Learn

Invoices and Billing CyclesHandle Failed Payments

Resources

SDK ReferenceError HandlingTestingCLI

Plugins

Better Auth
DocumentationKnowledge BaseBuild with AIAPI ReferenceWebhooks

Handle Failed Payments

What happens when a customer's payment fails and how they can reactivate from the Customer Portal.

When a payment fails, the subscription moves to past_due status and feature access is revoked immediately. Customers can reactivate their subscription from the Customer Portal by retrying payment or updating their card.

What happens when a payment fails

  1. The subscription status changes to past_due
  2. Feature access is revoked immediately
  3. The customer receives an email notification
  4. The failed invoice is marked as uncollectible

The subscription stays in past_due until the customer reactivates from the portal or an admin cancels it manually.

Check subscription status

const { data } = await commet.subscriptions.get('user_123')

if (data.status === 'past_due') {
  // Payment failed — prompt customer to reactivate from the portal
}
response = commet.subscriptions.get(customer_id='user_123')

if response.data['status'] == 'past_due':
    # Payment failed — prompt customer to reactivate from the portal
    pass
result, err := client.Subscriptions.Get(ctx, "user_123")

if result.Data.Status == "past_due" {
    // Payment failed — prompt customer to reactivate from the portal
}
ApiResponse<Subscription> result = commet.subscriptions().get("user_123");

if ("past_due".equals(result.getData().getStatus())) {
    // Payment failed — prompt customer to reactivate from the portal
}
$result = $commet->subscriptions->get('user_123');

if ($result->data['status'] === 'past_due') {
    // Payment failed — prompt customer to reactivate from the portal
}
curl "https://commet.co/api/subscriptions/active?customerId=user_123" \
  -H "x-api-key: $COMMET_API_KEY"

Gate access based on status

Only active and trialing subscriptions have feature access. past_due subscriptions are blocked until the customer reactivates from the portal.

const { data } = await commet.subscriptions.get('user_123')

const hasAccess = data.status === 'active' || data.status === 'trialing'
response = commet.subscriptions.get(customer_id='user_123')

has_access = response.data['status'] in ('active', 'trialing')
result, err := client.Subscriptions.Get(ctx, "user_123")

status := result.Data.Status
hasAccess := status == "active" || status == "trialing"
ApiResponse<Subscription> result = commet.subscriptions().get("user_123");

String status = result.getData().getStatus();
boolean hasAccess = "active".equals(status) || "trialing".equals(status);
$result = $commet->subscriptions->get('user_123');

$hasAccess = in_array($result->data['status'], ['active', 'trialing'], true);
curl "https://commet.co/api/subscriptions/active?customerId=user_123" \
  -H "x-api-key: $COMMET_API_KEY"

Customer Portal reactivation

Customers in past_due see their subscription in the Customer Portal with a Reactivate Subscription button. They can choose:

  • Retry with their current card — useful when the failure was temporary (insufficient funds that are now available, a bank hold that cleared).
  • Update their payment method — enter a new card via Stripe and retry in the same step.

A successful retry moves the subscription back to active, voids the failed invoices, and emits a payment.recovered event. Retry attempts are rate-limited to 3 per day per customer.

Prompt payment update

Redirect customers to the Customer Portal to reactivate:

const portal = await commet.portal.getUrl({ customerId: 'user_123' })

redirect(portal.data.portalUrl)
portal = commet.portal.get_url(customer_id='user_123')

redirect(portal.data['portal_url'])
portal, err := client.Portal.GetURL(ctx, &commet.GetPortalURLParams{
    CustomerID: "user_123",
})

// redirect(portal.Data.PortalURL)
ApiResponse<PortalSession> portal = commet.portal().getUrl("user_123", null, null);

// redirect(portal.getData().getPortalUrl())
$portal = $commet->portal->getUrl(customerId: 'user_123');

redirect($portal->data['portalUrl']);
curl -X POST https://commet.co/api/portal/request-access \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId": "user_123"}'

Related

  • Invoices and Billing Cycles — Invoice types and charge timing
  • Manage Subscriptions — Create and manage customer subscriptions
  • Customer Portal — Self-service billing portal for customers

How is this guide?

Invoices and Billing Cycles

How Commet generates invoices, what they contain, and when customers are charged.

Finance Overview

How money flows through Commet — balances, payouts, and transaction history.

On this page

What happens when a payment fails
Check subscription status
Gate access based on status
Customer Portal reactivation
Prompt payment update
Related