---
title: Payments
description: Sell subscriptions and one-time purchases through your own Stripe account, with one price catalog, hosted checkout, and one entitlement check for access.
type: tutorial
product: payments
summary: What Payments owns, the order of work, and where to go next.
updated: 2026-10-07
order: 0
---

Payments charges your customers through your own Stripe account. You connect
the account once, declare your prices in one
[price catalog](/docs/api/price_catalogs), send buyers to a hosted
[checkout](/docs/api/checkout_sessions), and ask
[`entitlement_grants:check`](/docs/api/entitlement_grants) whether someone has
access. Your app holds no Stripe key, no webhook route and no billing table;
there is nothing to deploy, and one key in your project is enough.

## What Payments gives you

- **You stay merchant of record.** Money is paid into your own Stripe account;
  Sylphx keeps the connected account id. Connect with OAuth, or with a
  restricted key (`rk_test_…`, `rk_live_…`), never a secret key.
- **One catalog.** Products, prices in several currencies, trials and the
  features each product grants live in one catalog, pushed to Stripe by
  `:sync`. A changed amount makes a new Stripe price, so existing subscribers
  keep the price they signed up at. A pricing page reads the catalog; it never
  hard-codes an amount.
- **Hosted checkout and portal.** A checkout session returns Stripe's hosted
  page; a portal session lets a customer update a card, read invoices or cancel.
  Subscriptions and one-time purchases both work.
- **One answer for access.** `entitlement_grants:check` answers whether a
  subject holds a feature now, and until when, whether they paid on the web,
  in the App Store or on Google Play.
- **Webhooks handled for you.** Money creates its own webhook endpoint on your
  Stripe account and applies every event once, so a repeated or late event
  changes nothing. A renewal whose webhook lags keeps access for a 3-day grace.
- **Subscriptions you can manage.** Cancel now or at period end, resume, change
  plan, or change the seat count, all through the API.

## Names and ids

<KeyValue
	items={[
		{ key: 'Seller', value: 'orgs/{org}/projects/{project}/envs/{env}/merchant_accounts/default', mono: true },
		{ key: 'Catalog', value: 'orgs/{org}/projects/{project}/envs/{env}/price_catalogs/default', mono: true },
		{ key: 'Checkout', value: '…/envs/{env}/checkout_sessions/{checkout_session}', mono: true },
		{ key: 'Subscription', value: '…/envs/{env}/customer_subscriptions/{customer_subscription}', mono: true },
		{ key: 'Subject', value: '{"end_user": "<your account id>"} or {"customer_organization": "<id>"}', mono: true },
	]}
/>

The subject is any stable id your app already has for a person or a customer
organization, 1 to 255 characters; it does not have to be a Sylphx Auth id.

## The scopes

- `billing:write` — connecting the seller, writing and syncing the catalog,
  creating checkout and portal sessions, and changing subscriptions. Call
  these from your server.
- `billing:read` — reading the catalog, subscriptions and checkouts, and
  `entitlement_grants:check`.

[Keys and scopes](/docs/platform/keys-and-scopes) covers the two kinds of key.

<RelatedDocs
	links={[
		{
			href: '/docs/payments/quickstart',
			label: 'Quickstart',
			description: 'Connect a test-mode Stripe account, declare a plan, check out, and check access.',
		},
		{
			href: '/docs/api/price_catalogs',
			label: 'The price_catalogs collection',
			description: 'Products, prices, features and trials.',
		},
		{
			href: '/docs/api/checkout_sessions',
			label: 'The checkout_sessions collection',
			description: 'Hosted checkout for subscriptions and one-time purchases.',
		},
		{
			href: '/docs/api/customer_subscriptions',
			label: 'The customer_subscriptions collection',
			description: 'Cancel, resume, change plan and change seats.',
		},
		{
			href: '/docs/api/entitlement_grants',
			label: 'The entitlement_grants collection',
			description: 'Who holds which feature, and until when.',
		},
	]}
/>
