Providers
The Payments port, the capabilities a provider declares, and what the deploy validates.
A provider is the part of the system that moves money. It implements the
Payments port: it opens a purchase path, takes the payment, and answers a
refund. Paykit records the result and decides no entitlement from it.
import { Paykit } from "@potion.run/paykit";
export const Provider = Paykit.Manual();
providers is an array on the billing stack. The stack validates each mapping
against the catalog at deploy, so a plan with no path to pay fails there rather
than at a customer’s checkout.
The required surface and the declared capabilities
Every provider can sell and refund. The rest is optional, and a provider
declares what it supports: checkout, invoice, charge, refund, portal,
usage, setup and quantity.
Asking a provider for a capability it does not declare fails with
ProviderCapabilityMissing. It never silently does nothing.
That is why Manual can serve a test and a real invoice. It declares invoice
and refund, so asking it for a hosted checkout is a typed refusal rather than
a page that cannot take a card.
What each provider package owns
| Package | Deploy | Runtime |
|---|---|---|
@potion.run/paykit |
Manual, Memory, the port |
The Payments service a world provides |
@potion.run/paykit-stripe |
StripeBilling: products, prices, meters |
Stripe: checkout, portal, refunds, webhooks |
@potion.run/paykit-polar |
PolarBilling: products, meters |
Polar: checkout, customer session, webhooks |
The deploy half creates the vendor objects the catalog states and returns their ids or lookup keys. The runtime half reads those ids from the Worker’s environment, so the catalog carries no vendor id and the vendor mapping is stated once.
What the deploy checks
Paykit.BillingStack runs validateProviderMappings before it records
anything:
- every plan with a price has a provider mapping, or
NoPurchasePathfails - two providers cannot claim the same plan, which is
ProviderDuplicate - the provider’s price must match the catalog’s, which is
CatalogPriceMismatch
Pick one
- Manual sells by invoice. It needs no key, which makes it the provider for tests and a first deploy.
- Stripe hosts checkout and the billing portal, calculates tax and retries failed payments.
- Polar sells the same catalog as merchant of record, so it calculates and collects tax for you.
The same catalog runs on all three. Moving from Manual to Stripe changes the
provider array and the environment, not the catalog.