For SaaS
Recurring billing your backend can follow
The hard part of charging for software is not the first payment. It is knowing, every month, who renewed, whose card failed and who canceled. KrokoPay turns each of those moments into a subscription status and a webhook event.
Pick a plan on the right: the request changes with it.
Rota Certa · choose your plan
Interactive democurl -X POST https://api.krokopay.app/v1/subscriptions \ -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \ -H "Idempotency-Key: signup_cus_7Hq2LmN4pZx8Wd_starter" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_7Hq2LmN4pZx8Wd", "price_id": "price_2Rc8StMnTh4Qa1", "method": "card" }'Monthly or yearly is just a different price_id. Fictional prices set by the example business.
The month after the signup
Every billing moment has a name
No more guessing from bank statements. Each situation below changes the subscription status and sends one event; your app decides what that means for access.
- What happened
- A customer subscribes
- Event and status
subscription.createdActive- What your app usually does
- Create the account and unlock the plan's features.
- What happened
- The period renews and is paid
- Event and status
subscription.renewedActive- What your app usually does
- Extend access until the new period end.
- What happened
- A renewal payment fails
- Event and status
subscription.past_duePast due- What your app usually does
- Show a banner asking to update the payment method.
- What happened
- You pause the subscription
- Event and status
subscription.pausedPaused- What your app usually does
- Keep the data, limit access while paused.
- What happened
- You resume it
- Event and status
subscription.resumedActive- What your app usually does
- Unlock the plan again from the next period.
- What happened
- The subscription is canceled
- Event and status
subscription.canceledCanceled- What your app usually does
- Limit access at the end of the paid period.
See it happen
Play a subscription from signup to recovery
Pick a scenario and watch the status, the charges and the events of a fictional subscription move. It is the same model your backend receives.
- Statuses: trialing, active, past_due, paused, canceled.
- Pause and resume without losing the customer.
- Everything also shows in your dashboard, no code needed to check.
Members club
Monthly plan · R$49.00/month
sub_5Hn2RtK8wPz4Bq- Current status
- Active
- Next charge
- Dec 3, 2026
Subscription history
Trial started
Aug 20, 2026The customer subscribed with a card. No charge during the trial.subscription.createdFirst charge paid
Sep 3, 2026Trial over: R$49.00 charged and the subscription is active.charge.paidRenewed
Oct 3, 2026R$49.00 charged for the new period.subscription.renewedRenewal declined
Nov 3, 2026The card had insufficient funds. The subscription is past due.subscription.past_duePayment recovered
Nov 5, 2026The customer updated the card and the renewal was paid.subscription.renewed
Integration
Three steps, one webhook
Create the subscription when the customer picks a plan, let the hosted checkout collect the card, and keep access in sync from a single endpoint.
Create prices
One price per plan and period, in the dashboard or via the API.
Create the subscription
POST /subscriptions with the customer and the chosen price.
Listen to events
Grant, warn or limit access from the subscription.* events.
export async function POST(request) { const payload = await request.text(); const signature = request.headers.get("KrokoPay-Signature"); if (!verifySignature(payload, signature, process.env.KROKOPAY_WEBHOOK_SECRET)) { return new Response(null, { status: 400 }); } const event = JSON.parse(payload); const subscription = event.data.object; switch (event.type) { case "subscription.created": case "subscription.renewed": case "subscription.resumed": await accounts.grantAccess(subscription.customer_id, subscription.current_period_end); break; case "subscription.past_due": await accounts.showPaymentBanner(subscription.customer_id); break; case "subscription.paused": case "subscription.canceled": await accounts.limitAccess(subscription.customer_id); break; } return new Response(null, { status: 200 });}verifySignature stands for the signature check described in the webhooks docs. Contract proposal, subject to change.
Transparency
What is ready and what is not yet
We prefer to show the gaps than to promise them away. If one of these blocks your launch, tell us.
Already in the product
- Monthly and yearly prices per plan.
- Statuses and webhook events for every lifecycle change.
- Pause, resume and cancel from the dashboard or the API.
- Test mode with test keys and fictional data.
Still being defined
- Upgrades and downgrades with proration.To be announced
- Automatic retry schedule after a failed renewal.To be announced
- Renewal by Pix.To be announced
- Fees and payout times.To be announced
Questions from SaaS teams
Short answers, including the ones that are still "not yet".
Keep exploring
The products behind this page, the docs to integrate them and the other segments.
Start billing your first plan
Create your account, set up a test price and watch the events arrive.
No real payment is made.
