Apps Billing
Apps Billing lets Partners with approved applications charge merchants directly through YouCan. YouCan collects payments from the store's balance or attached payment method, then passes revenue to Partners via Payouts. YouCan handles chargebacks. You define your own pricing.
Payouts
Your share of collected revenue accumulates in your Partner balance. Once your balance reaches $100, you can request a payout from the Partners dashboard at /dashboard/apps/:id/insights.
Charge types
| Type | Description |
|---|---|
| One-time | A single payment that requires merchant approval each time. |
| Recurring (time-based) | A subscription billed monthly (30_days) or yearly (365_days). Supports a trial period. After the first approval, YouCan handles renewals automatically. |
Charges can carry raw amounts, or reference a pricing plan from your app's catalog so the listing and the charge never drift apart.
How billing works
- A merchant takes an action in your app that involves a charge (e.g. purchasing a feature or upgrading a plan).
- Your app creates a charge via the StoreAdmin API.
- YouCan verifies the charge and returns a
confirmation_url. Redirect the merchant to it. - The merchant approves (or declines) the charge on the YouCan-hosted page.
- YouCan redirects back to the
return_urlyou specified on the charge. - Your app reads the charge status to confirm and unlock the feature.
Charge statuses
| Status | Description |
|---|---|
pending | Charge created but not yet reviewed by the merchant. |
active | Charge approved by the merchant and currently active. |
deferred | Charge deferred to the end of the current billing period (e.g. a change from yearly to monthly). |
frozen | Charge frozen due to non-payment. |
declined | Merchant declined the charge. Terminal state. |
expired | Charge was not approved before it expired. Terminal state. |
canceled | Charge was canceled. See Cancellation. Terminal state. |
Plan upgrades and downgrades
Recurring charge plan changes go through the same approval flow. When the merchant approves the new charge:
- Yearly to monthly, or yearly to a cheaper yearly plan: the new plan is deferred to the end of the current billing period. The current plan is kept until then.
- Monthly to yearly: the new plan is applied at once. The store is billed for the full year and credited for the unused days of the month.
- Any other change is applied at once. On an upgrade, the store is billed for the price difference over the days left in the period. On a downgrade, the store is credited for the price difference over the days left. On a change to the same price, the current period end is kept.
Cancellation
Your app can cancel an active recurring charge on demand with Cancel a recurring charge (DELETE /billing/apps/charges/recurring/{id}). Cancellation is at period end, or at once with a prorated credit when you send prorate: true.
A recurring charge is also canceled automatically in these cases:
- The app is uninstalled. Any active recurring charge for that store is scheduled for cancellation at period end.
- A plan change replaces it. Upgrading or downgrading creates a new charge and cancels the one it replaces.
- It stays frozen for 30 days without payment. A frozen charge is not active, and it is renewed if the store adds credit within those 30 days.
Warning
Cancellation happens immediately or at the end of the current billing period:
- Immediate:
statusbecomescanceledright away. - At period end (app uninstallation triggers this):
statusstaysactiveandperiod_ends_atdoes not change until the period elapses. Thenstatusbecomescanceled. Right after a merchant uninstalls your app,GET /billing/apps/chargesstill showsstatus: "active". The store is not billed for a renewal.
If you need to know sooner whether a merchant has uninstalled your app, treat the app.uninstalled webhook itself as your signal, rather than polling the charge's status.
Requirements
- Your application must be approved to create real charges.
- Charges created for non-approved apps or development stores must set
"test": true.
Webhooks
YouCan emits the following webhook topic for billing events:
| Topic | Triggered when |
|---|---|
app.charge_updated | The status of a one-time or recurring charge changes. |
Subscribe via the REST Hooks API or declare it in youcan.app.json, see Webhooks.
The payload follows the standard format, with the charge under data.charge:
{
"event_name": "app.charge_updated",
"event_happened_at": "2026-08-08T21:30:00.000000Z",
"data": {
"charge": {
"type": "recurring",
"id": "arch_xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"store_id": "00000000-0000-0000-0000-000000000000",
"name": "Pro plan",
"status": "active",
"plans": [{ "interval": 30, "price": { "amount": 9.99, "currency": "USD" } }],
"test": false,
"trial_days": 7,
"created_at": 1791234567,
"period_ends_at": 1793826567,
"canceled_at": null
}
}
}Tip
The payload always includes both status and period_ends_at, whatever triggered the event. For an at-period-end cancellation (e.g. from app uninstallation), the first webhook fires immediately with status: "active" and a future period_ends_at. A second webhook fires when the period ends, with status: "canceled".
API reference
| Page | Description |
|---|---|
| List charges | Retrieve all charges for the current store. |
| Create a one-time charge | Issue a single payment request to a merchant. |
| Create a recurring charge | Issue a subscription charge with optional trial. |
| Cancel a recurring charge | Cancel an active recurring charge at period end. |