--- url: https://docs.youcan.shop/apps/billing/overview.md --- # Apps Billing Apps Billing lets Partners with approved applications charge sellers directly through YouCan. YouCan collects payments from the seller'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 seller 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](/apps/billing/plans) from your app's catalog so the listing and the charge never drift apart. ## How billing works ```mermaid sequenceDiagram actor seller participant App as Your App participant API as YouCan API participant SA as Seller Area seller->>App: Initiates a purchase or plan change App->>API: POST /billing/apps/charges/onetime (or /recurring) API-->>App: { status: "pending", confirmation_url: "..." } App->>seller: Redirect to confirmation_url seller->>SA: Reviews and approves the charge SA->>App: Redirect to return_url with result App->>API: GET /billing/apps/charges (verify status) ``` 1. A seller takes an action in your app that involves a charge (e.g. purchasing a feature or upgrading a plan). 2. Your app creates a charge via the StoreAdmin API. 3. YouCan verifies the charge and returns a `confirmation_url`. Redirect the seller to it. 4. The seller approves (or declines) the charge on the YouCan-hosted page. 5. YouCan redirects back to the `return_url` you specified on the charge. 6. 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 seller. | | `active` | Charge approved by the seller and currently active. | | `deferred` | Charge deferred to the next billing cycle (e.g. a plan downgrade). | | `frozen` | Charge frozen due to non-payment. | | `declined` | Seller declined the charge. Terminal state. | | `expired` | Charge was not approved before it expired. Terminal state. | | `canceled` | Charge was canceled. See [Cancellation](#cancellation). Terminal state. | ## Plan upgrades and downgrades Recurring charge plan changes go through the same approval flow. The proration strategy applies when both the old and new plan share the same billing interval (`30_days`). Otherwise the new plan is deferred until the end of the current billing period. ## Cancellation Your app can cancel an active recurring charge on demand with [Cancel a recurring charge](/apps/billing/charges/cancel) (`DELETE /billing/apps/charges/recurring/{id}`). Cancellation is at period end. 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 too long without payment. Stale frozen charges are canceled after an extended grace period. ::: warning Cancellation happens immediately or at the end of the current billing period: * Immediate: `status` becomes `canceled` right away. * At period end (app uninstallation triggers this): `status` stays `active` and `period_ends_at` does not change until the period elapses. Then `status` becomes `canceled`. Right after a seller uninstalls your app, `GET /billing/apps/charges` still shows `status: "active"`. The seller is not billed for a renewal. ::: If you need to know sooner whether a seller 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](/apps/developer-tools/dev-store/development-store) 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](/store-admin/resthooks/subscribe) or declare it in `youcan.app.json`, see [Webhooks](/apps/webhooks). The payload follows the standard [format](/store-admin/resthooks/overview#payload-format), with the charge under `data.charge`: ```json { "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](/apps/billing/charges/listing) | Retrieve all charges for the current store. | | [Create a one-time charge](/apps/billing/charges/onetime) | Issue a single payment request to a seller. | | [Create a recurring charge](/apps/billing/charges/recurring) | Issue a subscription charge with optional trial. | | [Cancel a recurring charge](/apps/billing/charges/cancel) | Cancel an active recurring charge at period end. |