Skip to main content

Subscription troubleshooting

The list below covers patterns that are commonly attempted but do not work for activating the first payment of a subscription on a new (inactive) payment instrument. If your subscription appears stuck in pending or the customer's payment is not being collected, check this list first.

For the supported flow, see Create a subscription.

What does not work

What was attemptedResult
POST /transactions with the subscription's invoiceId to pay it directlyThe API accepts the request (201), but the invoiceId is ignored — the invoice stays unpaid and the subscription stays in pending.
GET /customer-invoices/{id} followed by POST /transactions to pay the invoiceA transaction is created, but the subscription is not activated by it. The subscription stays in pending.
POST /customer-invoices/{id}/payReturns 404 — this endpoint does not exist.
Waiting for PaymentsAI to auto-charge the new instrumentNever happens. PaymentsAI does not auto-charge inactive payment instruments.
Frontend checks only status === 'waiting' to decide whether to redirectSubscriptions return status: "pending", not "waiting". Without pending in the accepted-status set, the redirect to the hosted payment form is skipped.

What does work

The only supported path for the first payment of a subscription on a new instrument is the hosted payment form:

  1. Create the subscription. The response returns status: "pending" and recentInvoicePaymentFormUrl.
  2. Your backend surfaces recentInvoicePaymentFormUrl to the frontend.
  3. The frontend treats pending as a redirect status and sends the customer to the hosted form.
  4. The customer completes the payment on the hosted form. PaymentsAI handles 3DS internally, activates the payment instrument, and redirects the customer back to your redirectUrl.

See Hosted payment form for what the form does, and Payment instrument lifecycle for why the inactive instrument needs the hosted form to activate.

Common follow-up checks

  • Frontend redirect status set: does the function that extracts the redirect URL accept pending alongside offsite, processing, and waiting? Many existing 3DS-only implementations only handle the latter three.
  • Backend response propagation: does the backend pass recentInvoicePaymentFormUrl to the frontend (commonly as a top-level redirectUrl field added to the response)?
  • Idempotency-Key (if used): is it deterministic per (customerId, planId), not a fresh UUID? A fresh UUID on every retry creates a new subscription each time.
  • isTrialOnly present: if missing, the API returns 400 before creating anything — the subscription never appears.