Skip to content

Payment Plans API

Overview

The Payment Plans API lets you programmatically create, manage, and control recurring billing schedules. A payment plan generates and processes payment intents automatically on your chosen frequency.

For background on how plans work, see Understanding Plans.

All payment plan operations require a secret key (sk_xxx) with payment_plans:read or payment_plans:write scope.

Create a payment plan

Terminal window
curl -X POST https://api.elasticpay.co/api/v1/payment_plans \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_0abc123def456ghi789jkl012mno",
"name": "Monthly gym membership",
"frequency_type": "monthly",
"recurring_amount_cents": 4900,
"currency": "AUD",
"start_date": "2026-05-01",
"until_further_notice": true
}'

Response

{
"id": "pp_0abc123def456ghi789jkl012mno",
"customer_id": "cus_0abc123def456ghi789jkl012mno",
"name": "Monthly gym membership",
"state": "pending",
"frequency_type": "monthly",
"frequency_period": 1,
"recurring_amount_cents": 4900,
"currency": "AUD",
"start_date": "2026-05-01",
"until_further_notice": true,
"created_at": "2026-04-01T10:00:00Z",
"updated_at": "2026-04-01T10:00:00Z"
}

Create parameters

ParameterTypeRequiredDescription
customer_idstringYesCustomer (cus_xxx) who will be charged
namestringYesHuman-readable label
frequency_typestringYesweekly or monthly
frequency_periodintegerNoInterval multiplier (default 1). 2 + weekly = fortnightly
recurring_amount_centsintegerYesAmount per scheduled payment in the smallest currency unit
first_amount_centsintegerNoDifferent amount for the first payment only
total_amount_centsintegerNoCap total collections; plan closes when reached
until_further_noticebooleanNotrue for open-ended plans with no total cap
currencystringYesISO 4217 currency code (e.g. AUD, USD)
start_datestringYesISO date (YYYY-MM-DD) of the first payment
first_datestringNoOverride the first payment date (defaults to start_date)
payment_instrument_idstringNoSaved payment method (pm_xxx) to use. Falls back to customer default
failure_behaviourstringNoFailure handling mode (e.g. stop, retry). See Handling Failures

Either total_amount_cents or until_further_notice: true must be set.

Fetch a payment plan

Terminal window
curl https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123def456ghi789jkl012mno \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

List payment plans

Terminal window
curl "https://api.elasticpay.co/api/v1/payment_plans?customer_id=cus_0abc123def456" \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Response shape

{
"data": [],
"has_more": false
}

Supported query parameters:

ParameterDescription
customer_idFilter plans for a specific customer
stateFilter by state (pending, active, suspended, deactivated, closed)
limitNumber of results per page (default 20, max 100)
starting_afterCursor: return results after this plan ID

Update a payment plan

Use PUT to update mutable fields on a plan. Not all fields can be changed after the plan is active (e.g. frequency_type, start_date). The API will return a validation error if a field cannot be changed in the plan’s current state.

Terminal window
curl -X PUT https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123def456ghi789jkl012mno \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"recurring_amount_cents": 5900}'

State transitions

Payment plans move through states via dedicated transition endpoints.

Terminal window
# Activate (pending -> active)
curl -X POST https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123/activate \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Suspend (active -> suspended)
curl -X POST https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123/suspend \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Resume (suspended -> active)
curl -X POST https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123/resume \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Deactivate (active -> deactivated)
curl -X POST https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123/deactivate \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Close (any -> closed)
curl -X POST https://api.elasticpay.co/api/v1/payment_plans/pp_0abc123/close \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Valid transitions

FromToEndpoint
pendingactive/activate
activesuspended/suspend
activedeactivated/deactivate
suspendedactive/resume
active, suspended, pendingclosed/close

Webhook events

Subscribe to these events to monitor plan activity:

EventWhen
payment_plan.activatedPlan transitions to active
payment_plan.suspendedPlan is suspended
payment_plan.deactivatedPlan ends
payment_plan.closedPlan is closed
payment_intent.succeededA scheduled payment is collected
payment_intent.failedA scheduled payment fails

Required permissions

OperationRequired scope
Create / update / state transitionspayment_plans:write
Fetch / listpayment_plans:read

Secret keys (sk_xxx) have both scopes by default.