
Keep billing logic separate from the vendor
Application billing speaks one shared contract for customers, purchases and subscription changes. A provider adapter translates that contract into the vendor’s API, keeping vendor-specific request shapes out of everyday application code.
Example — Change a plan through one contract
The application requests a subscription change with its items and proration policy. The selected adapter translates that request into the provider’s update call.
For engineers
StandardBilling_Interface is the backend adapter contract. The runtime resolves the billing provider from the authored backend scope and gives billing services that interface. Stripe is the shipped implementation; a different vendor needs a complete adapter, an SDK-package entry in the engine billing adapter registry and provider registration, not just a different providerRef string.
The Stripe implementation’s update path shows the boundary. The complete method below maps metadata, proration and subscription items:
The following selected excerpt is from stripe-standard-billing-provider.backend.service.ts; the surrounding module and explanatory source comments are omitted.
async updateSubscription(providerSubscriptionId: string, request: StandardBilling_UpdateSubscriptionRequest): Promise<void> {
await this.getStripe().subscriptions.update(providerSubscriptionId, {
metadata: request.metadata,
...(request.prorationBehavior && { proration_behavior: request.prorationBehavior }),
...(request.providerPromotionCodeId && { promotion_code: request.providerPromotionCodeId }),
...(request.items && {
items: request.items.map((item) => ({
...(item.providerSubscriptionItemId ? { id: item.providerSubscriptionItemId } : {}),
price: item.providerPriceId,
quantity: item.quantity,
})),
}),
});
}
The application chooses the product and policy. The billing operation constructs StandardBilling_UpdateSubscriptionRequest; the adapter names the provider’s fields. A contract field only has an effect when that adapter implements its meaning.
What a new provider must connect
| Responsibility | Integration required |
|---|---|
| Outgoing operations | Customer, product, price, subscription, checkout and portal methods used by billing |
| Incoming state | Signature verification, provider-event normalization and customer-to-account scope resolution |
| Discovery | Provider capability, protocol and runtime module available to the backend |
| Deployment | SDK dependencies, secrets and reachable webhook delivery |
Use the mock billing provider for application tests that need deterministic billing responses. Such tests exercise application behavior; they do not establish that a live vendor accepts every translated request. Switching an existing deployment also requires deciding how its provider customer, price and subscription identifiers migrate.