Create a subscription
Assuming you’ve already onboarded a customer and built a catalog, this is one API call.
The minimal call
POST /v1/subscriptionsIdempotency-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" }}| Override | Effect |
|---|---|
default_payment_method_id | Use this method instead of the customer’s default. |
trial_days | Override the plan’s trial; 0 disables. |
billing_cycle_anchor | Pin renewals to a date (e.g. 1st of the month). Proration rules apply. |
quantities | Initial quantities for per_unit / tiered components. |
coupons | Apply discounts at create time. |
metadata | Carry 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:
- If
active, an invoice is generated and finalised. - The invoice is paid using the configured payment method.
- On success,
subscription.activatedandinvoice.paidevents fire. - On 3DS / SCA, the response carries
payment.requires_actionwith a redirect URL (see Handle 3DS / SCA). - On failure, the subscription transitions to
past_dueand 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:
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_behavior | Behaviour |
|---|---|
create_prorations (default) | Credit unused, charge prorated; appears on the next invoice. |
none | Change at next period; no prorations. |
always_invoice | Bill 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
| Event | What to do |
|---|---|
subscription.activated | Provision access in your application. |
subscription.trial_will_end | Email the customer (T-3 days). |
subscription.past_due | Show a banner; pause non-essential features. |
subscription.canceled | Deprovision; tag for win-back. |
invoice.paid | Update last-paid timestamp; reset alerts. |
invoice.payment_failed | Don’t deprovision yet — let dunning try. |