mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 17:25:19 +03:00
feat(core,api): take payment, and let the provider decide who is paid up
Checkout, the customer portal, and the webhook that moves a team's plan. Nothing money-shaped is stored. No price, no currency, no card detail — a subscription's existence and its state are the whole of what crosses back, because they are the only two facts the product needs and anything more would be a second copy of a record somebody else is authoritative for. Currency is deliberately not ours to hold. A product carries a price per currency on their side and the customer's location picks one at checkout, so there is no figure in this API that could drift from the one somebody is charged. The team id travels as the customer's external id, which keeps the mapping on their side rather than putting a foreign primary key in our schema. Access follows their state, and the interesting cases are where that is not the same as "paying right now". Cancelling keeps the plan: they paid to the end of the period and turning them off when they click it takes something they bought. A failed card keeps it too, because a retry that ends in payment should not have cost them access in the middle. Only a revoked subscription takes it away, which is the one moment nothing is left that was paid for. An event we do not recognise changes nothing at all — new types are added by people who do not know what we do with them, and a default that moved a plan would eventually cancel an account nobody cancelled. The webhook is the only route here no session protects, because its caller has no account and never will. A signature over the raw body stands in for one, and it is checked before the body is looked at — a body that has been parsed and re-serialized is not the body that was signed. With no secret configured it refuses everything rather than accepting anything, since otherwise knowing the URL would be enough to set somebody's plan. Note also what is absent: no route sets a plan, so there is no endpoint for granting yourself a subscription. The product is written down as a definition with a script rather than clicked into a dashboard, because the two environments are separate servers and nothing made in one can be moved to the other. Promoting it is running the same script with the other token, which is the only version of that which cannot drift. It writes nothing without --apply and refuses to add a second product with a name already taken.
This commit is contained in:
@@ -10,6 +10,7 @@ import { type ContentfulStatusCode } from 'hono/utils/http-status';
|
||||
|
||||
import { auth } from './middleware/auth.js';
|
||||
import { AccessTokenApi } from './routes/access-token.js';
|
||||
import { BillingApi } from './routes/billing.js';
|
||||
import { EnrolmentApi } from './routes/enrolment.js';
|
||||
import { GameApi } from './routes/game.js';
|
||||
import { IndexApi } from './routes/index.js';
|
||||
@@ -43,6 +44,7 @@ const routes = app
|
||||
.route('/steam', SteamApi.route)
|
||||
.route('/library', LibraryApi.route)
|
||||
.route('/games', GameApi.route)
|
||||
.route('/billing', BillingApi.route)
|
||||
.route('/organisation', OrganisationApi.route)
|
||||
.route('/machine', MachineApi.route)
|
||||
.route('/machine', SessionApi.machineRoute)
|
||||
|
||||
Reference in New Issue
Block a user