Skip to content

Create a subscription

Assuming you’ve already onboarded a customer and built a catalog, this is one API call.

The minimal call

POST /v1/subscriptions
Idempotency-Key: <uuid>
Content-Type: application/json
{
"customer_id": "cus_…",
"plan_code": "pro-monthly-usd"
}

The customer’s default payment method will be used. The plan’s default trial (if any) will apply. The billing cycle starts now and recurs monthly.

With overrides

{
"customer_id": "cus_…",
"plan_code": "pro-monthly-usd",
"default_payment_method_id": "pm_…",
"trial_days": 30,
"billing_cycle_anchor": "2026-06-01T00:00:00Z",
"quantities": { "active_seats": 7 },
"coupons": ["WELCOME20"],
"metadata": { "team": "alpha" }
}
OverrideEffect
default_payment_method_idUse this method instead of the customer’s default.
trial_daysOverride the plan’s trial; 0 disables.
billing_cycle_anchorPin renewals to a date (e.g. 1st of the month). Proration rules apply.
quantitiesInitial quantities for per_unit / tiered components.
couponsApply discounts at create time.
metadataCarry your application’s foreign keys.

What happens next

The response returns immediately with the subscription in either trialing (if a trial applies) or active. Then asynchronously:

  1. If active, an invoice is generated and finalised.
  2. The invoice is paid using the configured payment method.
  3. On success, subscription.activated and invoice.paid events fire.
  4. On 3DS / SCA, the response carries payment.requires_action with a redirect URL (see Handle 3DS / SCA).
  5. On failure, the subscription transitions to past_due and dunning begins.

Wait for confirmation, or trust the response

For interactive flows (the customer is staring at a “subscribing…” spinner), poll the subscription for up to 10 seconds:

Terminal window
SUB=$(curl -s https://api.paylera.io/v1/subscriptions/$SUB_ID \
-H "Authorization: Bearer $KEY")
echo $SUB | jq -r '.status'

Or — and this is what you should do for non-interactive flows — trust the create response and react to the webhook events.

Mid-period changes

PATCH /v1/subscriptions/{id}
{
"plan_code": "business-monthly-usd",
"proration_behavior": "create_prorations"
}
proration_behaviorBehaviour
create_prorations (default)Credit unused, charge prorated; appears on the next invoice.
noneChange at next period; no prorations.
always_invoiceBill the proration immediately.

Quantities (per-unit components):

POST /v1/subscriptions/{id}/quantities
{ "meter": "active_seats", "quantity": 12 }

Pause

POST /v1/subscriptions/{id}/pause
{ "until": "2026-08-01T00:00:00Z", "behavior": "void_invoices" }

The subscription will auto-resume on until. Set until: null to pause indefinitely; you’ll need to resume manually.

Cancel

POST /v1/subscriptions/{id}/cancel
{ "at": "period_end", "reason": "customer_request" }

at: now cancels immediately (with proration credit if the plan prorates). at: period_end lets the period finish, then transitions to canceled.

Idempotency on subscribes

The most common bug in subscription flows: two subscribes hit your backend (double-click, retry, idempotent client middleware) and both make the same POST /v1/subscriptions with different keys. Result: two subscriptions, two charges.

Fix: derive the idempotency key from a value unique to the intent, not the call. A good key:

sub-create:{your_user_id}:{plan_code}:{your_request_id}

The first two pin the intent; the third lets you legitimately re-issue across days.

Webhook events to watch

EventWhat to do
subscription.activatedProvision access in your application.
subscription.trial_will_endEmail the customer (T-3 days).
subscription.past_dueShow a banner; pause non-essential features.
subscription.canceledDeprovision; tag for win-back.
invoice.paidUpdate last-paid timestamp; reset alerts.
invoice.payment_failedDon’t deprovision yet — let dunning try.