Payments
Subscriptions
Charge a customer every month or year from a recurring price. Start subscriptions from a payment link or the API, and follow renewals, failures, pauses and cancellations through events.
On this page
A subscription ties a customer to a recurring price. Each period, KrokoPay creates a charge for the price amount; when it is paid, the subscription moves to the next period. Everything you sell, recurring or not, starts in the catalog: products and their prices.
Products and prices
A product is what you sell (a course, a plan, a service). A price is how much and how often: a product can have several prices, such as a monthly and a yearly plan.
type | interval | Use it for |
|---|---|---|
one_time | null | Single payments: a course, a template pack, a one-off service. Charged once through a charge or payment link. |
recurring | month or year | Subscriptions. Paying it starts a subscription that renews every interval. |
/v1/productsBody parameters
namestringRequired- Product name, shown on the checkout.
descriptionstringOptional- Short description.
activebooleanOptional- Defaults to
true. Inactive products cannot be bought.
curl -X POST https://api.krokopay.app/v1/products \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Content-Type: application/json" \ -d '{ "name": "Curso Identidade Visual do Zero", "description": "Curso online em 32 aulas, com exercícios práticos e arquivos de apoio." }'/v1/pricesBody parameters
product_idstringRequired- The product this price belongs to (
prod_…). nicknamestringRequired- Label of the plan or variant, e.g.
MonthlyorLifetime access. amountintegerRequired- Amount per payment, in centavos.
currencystringRequiredBRL.typestringRequiredone_timeorrecurring.intervalstringOptional- Required for
recurring:monthoryear.
curl -X POST https://api.krokopay.app/v1/prices \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_3Vb7QpK9sWd2Ee", "nickname": "Acesso vitalício", "amount": 49700, "currency": "BRL", "type": "one_time" }'curl -X POST https://api.krokopay.app/v1/prices \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_6Rj8YdF3nQs5Kv", "nickname": "Mensal", "amount": 4900, "currency": "BRL", "type": "recurring", "interval": "month" }'Information: Archive instead of editing amounts
active: false on the old one with POST /v1/prices/{id}. Payment links that use an archived price show the unavailable state on the checkout.How a subscription starts
Step 1: From a payment link
Create a payment link for a recurring price and share it. When the buyer pays, KrokoPay creates the customer (if needed), the first charge and the subscription. You receive
charge.paidandsubscription.created.Step 2: From the API
Call
POST /v1/subscriptionsfor an existing customer and recurring price. The subscription starts now and its first period is charged right away.
curl -X POST https://api.krokopay.app/v1/payment_links \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Content-Type: application/json" \ -d '{ "name": "Clube Jacarandá — Mensal", "price_id": "price_9Tm4BxW2gLp7Zc", "methods": [ "card" ] }'Create a subscription
/v1/subscriptionsBody parameters
customer_idstringRequired- The customer who pays.
price_idstringRequired- A
recurringprice. One-time prices are rejected. methodstringRequiredcardorpix, used for every renewal.
curl -X POST https://api.krokopay.app/v1/subscriptions \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Idempotency-Key: signup_ana_souza_club" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_8Hq2LmZr4TxN1a", "price_id": "price_9Tm4BxW2gLp7Zc", "method": "card" }'Warning: Collecting payment details
The subscription object
Attributes
idstring- Unique identifier, prefixed with
sub_. objectstring- Always
subscription. customer_idstring- Who pays.
product_idstring- The product subscribed to.
price_idstring- The recurring price charged each period.
statusstringtrialing,active,past_due,pausedorcanceled.methodstringcardorpix.started_atstring- When the subscription began.
current_period_startstring- Start of the period already paid.
current_period_endstring- End of that period; the next renewal happens here.
canceled_atstring | null- When it ended, or when it will end if
cancel_at_period_endistrue. cancel_at_period_endbooleantruewhen the subscription stops atcurrent_period_endinstead of renewing.
{ "id": "sub_5Hn2RtK8wPz4Bq", "object": "subscription", "customer_id": "cus_8Hq2LmZr4TxN1a", "product_id": "prod_6Rj8YdF3nQs5Kv", "price_id": "price_9Tm4BxW2gLp7Zc", "status": "active", "method": "card", "started_at": "2026-09-03T12:00:00.000Z", "current_period_start": "2026-11-03T12:00:00.000Z", "current_period_end": "2026-12-03T12:00:00.000Z", "canceled_at": null, "cancel_at_period_end": false}/v1/subscriptions/{id}curl https://api.krokopay.app/v1/subscriptions/sub_5Hn2RtK8wPz4Bq \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"Statuses and transitions
| Status | Meaning |
|---|---|
trialing | In a trial period before the first paid period. How trials are configured is to be defined. |
active | The current period is paid. Renews at current_period_end. |
past_due | The latest renewal charge failed. Access decisions are yours. |
paused | No renewals are charged until it is resumed. |
canceled | Ended. A canceled subscription cannot be resumed; start a new one. |
| From | To | Trigger | Events |
|---|---|---|---|
| — | active | First period paid (link) or subscription created (API). | subscription.created, charge.created, charge.paid |
active | active | A renewal charge is paid; a new period starts. | charge.created, charge.paid, subscription.renewed |
active | past_due | A renewal charge fails. | charge.failed, subscription.past_due |
trialing / active / past_due | paused | POST /v1/subscriptions/{id}/pause | subscription.paused |
paused | active | POST /v1/subscriptions/{id}/resume | subscription.resumed (plus a renewal if the period already ended) |
any except canceled | canceled | DELETE /v1/subscriptions/{id}, or the period ends with cancel_at_period_end | subscription.canceled |
Information: Still to be defined
past_due subscription is charged again) and the move from trialing to active are not defined yet. Handle subscription.past_due by asking the customer to update their payment.Pause and resume
/v1/subscriptions/{id}/pauseStops renewals. Allowed from trialing, active and past_due.
curl -X POST https://api.krokopay.app/v1/subscriptions/sub_5Hn2RtK8wPz4Bq/pause \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"/v1/subscriptions/{id}/resumeOnly for paused subscriptions. If the paid period has not ended yet, the subscription simply becomes active again. If it has ended, a new period starts now and is charged immediately, emitting subscription.renewed after subscription.resumed.
curl -X POST https://api.krokopay.app/v1/subscriptions/sub_5Hn2RtK8wPz4Bq/resume \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"Cancel
At the end of the period
/v1/subscriptions/{id}Set cancel_at_period_end: true. The customer keeps what they already paid for, canceled_at shows when it ends, and the subscription does not renew. No event is sent at request time; subscription.canceled follows when the period ends.
curl -X POST https://api.krokopay.app/v1/subscriptions/sub_5Hn2RtK8wPz4Bq \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Content-Type: application/json" \ -d '{ "cancel_at_period_end": true }'Immediately
/v1/subscriptions/{id}Ends the subscription now and emits subscription.canceled. Charges already paid are not refunded automatically: refund the last charge yourself if your policy says so.
curl -X DELETE https://api.krokopay.app/v1/subscriptions/sub_5Hn2RtK8wPz4Bq \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"Events
Subscribe your webhook endpoint to the subscription events and to charge.* (each period is a charge). The event's data.object is the subscription as returned by the API.
{ "id": "evt_5Ee6Ff7Gg8Hh9I", "object": "event", "type": "subscription.renewed", "api_version": "2026-11-01", "created_at": "2026-11-03T12:00:09.000Z", "data": { "object": { "id": "sub_5Hn2RtK8wPz4Bq", "object": "subscription", "customer_id": "cus_8Hq2LmZr4TxN1a", "product_id": "prod_6Rj8YdF3nQs5Kv", "price_id": "price_9Tm4BxW2gLp7Zc", "status": "active", "method": "card", "started_at": "2026-09-03T12:00:00.000Z", "current_period_start": "2026-11-03T12:00:00.000Z", "current_period_end": "2026-12-03T12:00:00.000Z", "canceled_at": null, "cancel_at_period_end": false } }}subscription.created: grant access.subscription.renewed: extend access to the newcurrent_period_end.subscription.past_due: warn the customer; decide how long to keep access.subscription.paused/subscription.resumed: suspend and restore access.subscription.canceled: remove access.