Skip to main content
Once a plan is live, four lifecycle endpoints let you control it: pause billing temporarily, resume it, cancel it permanently, or manually retry a plan whose automatic retries are exhausted. All four operate on the planId returned when the plan was created.

Quick Start

Pause a plan for two months, with automatic resume:

The Basics

Never call these from the browser. Your API key must stay on the server. All four endpoints require only the x-api-key header, and only the merchant that owns the plan can manage it.

Which Actions Are Allowed When

Whether an action is allowed depends on the plan’s current status: Disallowed combinations return a 400 with an error message pointing at the right endpoint.
Plans paused by the system for payment reconciliation (rather than by you) cannot be modified through any of these endpoints and return a 409. Contact support to resolve these — they indicate a charge whose outcome is being verified with the card processor. System-paused plans show pauseReason: "stalled_pending_manual_reconciliation".The system only applies this pause to active or paused plans. If you had already paused the plan yourself, it is converted to a system pause and any scheduled automatic resume (pausedUntil) is cancelled. Cancelled, completed, and failed plans keep their status; the charge is still flagged for reconciliation.

Pause a Plan

Halts all future billing while keeping the plan’s schedule anchor intact. Pausing removes the plan’s next scheduled charge; nothing bills until the plan is resumed.

Request Body (all fields optional)

Send {} (with Content-Type: application/json) for an indefinite pause.

Behavior Notes

  • Pausing an already-paused plan is a re-pause: pausedUntil and pauseReason are replaced with the values you send, and a new paused webhook event fires. Omitting pausedUntil cancels any scheduled automatic resume; omitting pauseReason resets it to "merchant_requested". Treat webhook events as at-least-once.
  • If the automatic resume can’t be scheduled, the pause still succeeds (200), but the plan is paused indefinitely. pausedUntil is null in both the response and the webhook event, and the response message says so. Call resume when you’re ready, or pause again with pausedUntil.
  • An in-flight charge cannot be stopped. If a charge is already being processed at the card processor when you pause, that charge may still complete. The pause takes effect for all subsequent billing either way.
  • nextChargeAt becomes null while paused; nextCycleAt keeps the plan’s billing anchor so resume can compute the right date.

Response

200 with the full plan object (same shape as Query Recurring Plans). Key fields after a pause:

Resume a Plan

Reactivates a paused plan. No request body.

Billing After a Resume

Cycles missed during a pause are skipped — the customer is never retroactively charged. Billing resumes on the next future billing date, preserving the plan’s original anchor day. Example: a monthly plan billing on the 31st is paused in January and resumed on August 15. The missed February–July cycles are skipped, and the next charge lands on August 31 — the original anchor day, not the resume date. (In months without that day, billing clamps to the last day of the month, exactly as it always has.)
  • If the pause was short and the original billing date hasn’t passed yet, the plan charges on that original date — a brief pause-and-resume changes nothing.
  • If the plan’s endDate passed during the pause, the plan is completed instead of resumed (no charge fires), and a completed webhook event is sent.
  • If the plan was paused while a failed charge was waiting on an automatic retry, the first charge after resuming counts as that cycle’s next retry attempt. The cycle does not get a fresh set of maxAttempts. It bills on the next future billing date, like any other resume.
  • Resuming an already-active plan is a harmless no-op (200).
  • If the next charge can’t be scheduled, resume returns 500 and the plan stays paused with its previous settings, including any pausedUntil. It’s safe to call resume again.
  • If another change lands on the plan at the same moment (an automatic resume, a concurrent request, or a pause or cancel), resume returns 409. Query the plan for its current state.

Automatic Resume (pausedUntil)

If the plan was paused with pausedUntil, it resumes automatically at that time — same skip-missed-cycles rules, and a recurringPayment.plan event with status: "active" fires. An explicit resume before pausedUntil simply cancels the scheduled automatic one. If the automatic resume hits a temporary error, it is retried automatically (up to 3 attempts, with backoff). If it still can’t complete, the plan stays paused. Call resume to restart billing.

Cancel a Plan

Permanently stops the plan. Cancellation is terminal and cannot be undone.
  • Allowed from active, paused, and failed (cancelling a failed plan is the normal way to close it out if you don’t intend to retry).
  • A completed plan cannot be cancelled — every contracted cycle was already billed.
  • Cancelling an already-cancelled plan is a harmless no-op (200).
Cancelling stops future billing only. It does not void or refund any charge that has already been processed or is currently in flight — use the refund endpoint for that.
Response: 200 with the plan object showing "status": "cancelled" and a populated cancelledAt timestamp.

Manually Retry a Failed Plan

When a plan exhausts its automatic retries (maxAttempts), it moves to failed and stops billing. After resolving the underlying issue with your customer (e.g. they’ve updated their card balance), use this endpoint to retry the failed cycle immediately.

How It Works

  1. The plan is reactivated and the failed cycle’s charge is queued immediately.
  2. The endpoint returns 202 right away — the charge itself runs asynchronously.
  3. The charge outcome arrives via the recurringPayment.charge webhook event.
  4. On success, the plan resumes its normal schedule on the original billing anchor. Cycles missed while the plan was failed are skipped, never retroactively charged.
  5. On failure, the plan returns to failed. You can retry again or cancel.
Each call retries the cycle once — there is no automatic retry ladder behind a manual retry. If the plan is paused or cancelled at the same moment the retry is being set up, the retry returns 409 and no manual_retry_initiated event fires. As with any pause or cancel, a charge that had already started may still complete, so query the plan to confirm its state. If the retry can’t be scheduled at all, it returns 500 and the plan stays failed, so it’s safe to try again.

Eligibility

  • Only plans with status: "failed".
  • Not available if the plan’s endDate has passed (400) — a lapsed plan can only be cancelled.

Response

202 Accepted with the plan object (now "status": "active"):
A 202 means the retry was queued, not that the charge succeeded. Always confirm the outcome via the recurringPayment.charge webhook or by querying the plan. The charge runs immediately, so the charge result event can arrive before the status: "manual_retry_initiated" event.

Errors

All four endpoints share these responses:

Rate Limits

Webhook Events

Every lifecycle change fires a recurringPayment.plan event with the new status:
  • paused, active (explicit or automatic resume), cancelled, and completed.
  • failed, but only when the plan actually moves to failed. If you pause or cancel a plan while its final retry is in flight, the charge failure is still reported, but no failed plan event fires, because the plan keeps the status you set.
Charges fire recurringPayment.charge events: one per successful or failed charge attempt, plus one with status: "manual_retry_initiated" when you call retry. If a charge is flagged for payment reconciliation, a recurringPayment.charge event fires with status: "stalled_pending_manual_reconciliation", and its planPaused field shows whether the plan was system-paused. Events are delivered at least once and may arrive out of order. Handle duplicates idempotently, and treat the plan’s current state (from querying the plan) as the source of truth.

What’s Next?

Track your plans’ states with Query Recurring Plans, or subscribe to the webhook events above to react to lifecycle changes in real time.