@openrails/billing-ui 0.248.0 → 0.249.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## Hosts sell the products their pages carry
4
+
5
+ - Breaking: the browser never reads the catalog. `listProducts`, `useProducts`,
6
+ `ProductListOptions` and `ProductsState` are removed with OpenRails' public
7
+ `GET /products`; your server reads the catalog with the Go client and puts the
8
+ products in its page (`billing.BuyerPrices`).
9
+ - Breaking: `<ProductList products>` takes the host's products (no `merchant`
10
+ or `keys`); `<BuyButton price>` takes one of their prices (no `merchant`,
11
+ `product` or price key). `Purchase` is folded into `BuyButton`.
12
+ - `createOrder({ checkout: { ui_mode: "embedded" } })` creates the order with
13
+ its embedded checkout in one call: `order.checkout.url` on the checkout host,
14
+ as long as the order is open, returning nowhere (`success_url` null), for the
15
+ merchant's own signed-in person. Without `payment` it
16
+ answers the customer's open order of the same lines when there is one (with
17
+ a fresh URL); `idempotencyKey` is needed only with `payment`.
18
+ - On a site the merchant registered to frame its checkout, `BuyButton` creates
19
+ the order that way and frames it (`<EmbeddedCheckout>`); elsewhere it pays on
20
+ the page as before. It stores nothing and sends no key: a reload or a
21
+ reopened dialog answers the same open order.
22
+
3
23
  ## Entitlements read
4
24
 
5
25
  - `getEntitlements()` lists the entitlement keys the customer holds
package/README.md CHANGED
@@ -64,33 +64,41 @@ const billing = createBillingClient({
64
64
  })
65
65
  ```
66
66
 
67
- `<BuyButton>` buys one price, `<ProductList>` the products your server names by
68
- key (a course, its bundle and the membership that also unlocks it; the Go
69
- `Client.ListProducts` finds the products granting an entitlement): a
70
- `BuyButton` per price ("$4.99", "Rent for 3 days, $1.99",
71
- "$10.00 every 30 days"). Both look prices up in the public catalog of the
72
- merchant whose id you pass as `merchant`, signed in or out. The purchase is
73
- theirs from start to payment: a
74
- button creates the customer's order and pays it in a dialog
75
- (`<OrderCheckout>`); a second click before it is paid opens the same order.
76
- Signing in is the host's: with `signedIn={false}`, or when OpenRails answers
77
- 401, they call `onSignInRequired` instead. `onPaid` receives the completed
78
- order; it is a hint, so confirm access from your own API (your gate) before
79
- granting anything.
67
+ The browser never reads the catalog (Stripe's and Paddle's model): your
68
+ server reads the products it sells with the Go `Client.ListProducts` (by key,
69
+ or those granting an entitlement) and puts them in its own page's response,
70
+ their prices as a buyer sees them (`billing.BuyerPrices`). `<BuyButton price>`
71
+ buys one of those prices, `<ProductList products>` sells those products (a
72
+ course, its bundle and the membership that also unlocks it): a `BuyButton` per
73
+ price ("$4.99", "Rent for 3 days, $1.99", "$10.00 every 30 days").
74
+
75
+ The purchase is theirs from start to payment: a button creates the customer's
76
+ order (`POST /me/orders`) and pays it in a dialog. On a page of a site the
77
+ merchant registered to frame its checkout (`merchant.embed_origins` in
78
+ `GET /me/config`), it creates the order with its embedded checkout in the same
79
+ call (`createOrder({ lines, checkout: { ui_mode: "embedded" } })`) and frames
80
+ `order.checkout.url` from the checkout host (`<EmbeddedCheckout>`); anywhere
81
+ else it pays on the page (`<OrderCheckout>`). The embedded checkout returns
82
+ nowhere: the frame says it is paid and tells the page (`onPaid`), and a
83
+ redirect PSP comes back inside it. Nothing is stored: OpenRails answers the
84
+ customer's open order of the same lines, so a second click, a reopened dialog
85
+ or a reload pays the same order (with a fresh URL), and a paid or expired one
86
+ is bought again as a new order. Signing in is the
87
+ host's: with `signedIn={false}`, or when OpenRails answers 401, they call
88
+ `onSignInRequired` instead. `onPaid` receives the completed order; it is a
89
+ hint, so confirm access from your own API (your gate) before granting
90
+ anything.
80
91
 
81
92
  ```tsx
82
93
  <BuyButton
83
- merchant={merchantId} // your merchant's id, from your server
84
- product="course-101"
85
- price="rent" // labelled from the catalog unless you pass label
94
+ price={course.prices[0]} // from your server's page response
86
95
  signedIn={signedIn}
87
96
  onSignInRequired={() => openSignIn()}
88
97
  onPaid={() => navigate("/courses/css-101")} // your gate now admits them
89
98
  />
90
99
 
91
100
  <ProductList
92
- merchant={merchantId}
93
- keys={["course-101", "course-bundle", "channel-membership"]} // from your server, or products={...} from its Client.ListProducts
101
+ products={products} // from your server's page response
94
102
  signedIn={signedIn}
95
103
  onSignInRequired={() => openSignIn()}
96
104
  onPaid={() => navigate("/courses/css-101")}
@@ -107,13 +115,13 @@ page, and the checkout charges exactly that:
107
115
  ```tsx
108
116
  import { decimalToAmount } from "@openrails/billing-ui/client"
109
117
 
110
- // `depositPrice` is in a product from listProducts; `currency` from getConfig().currencies.
118
+ // `depositPrice` is in a product your server sent; `currency` from getConfig().currencies.
111
119
  // `enteredAmount` is the text from an <input inputMode="decimal">, e.g. "100".
112
120
  const amount = decimalToAmount(enteredAmount, currency.decimals)
113
121
  const bounds = depositPrice.customer_amount
114
122
  const valid = amount && bounds && BigInt(amount) >= BigInt(bounds.min_amount) && BigInt(amount) <= BigInt(bounds.max_amount)
115
123
 
116
- <BuyButton merchant={merchantId} product="api-credits" price="deposit" amount={valid ? amount : undefined} label="Add credits" {...handlers} />
124
+ <BuyButton price={depositPrice} amount={valid ? amount : undefined} label="Add credits" {...handlers} />
117
125
  ```
118
126
 
119
127
  OpenRails validates the bounds and whole currency minor units before accepting
@@ -205,15 +213,13 @@ host content and links. The customer imports above do not load admin code or
205
213
  styles. See the [BillingAdmin integration guide](https://github.com/open-rails/openrails/blob/master/docs/billing-admin.md)
206
214
  for merchant selection, permissions, localization, and standalone console setup.
207
215
 
208
- ## Catalog and plan changes
216
+ ## Configuration and plan changes
209
217
 
210
- The client also reads the public catalog and changes a subscription's plan.
211
- The catalog read and `GET /config` are public routes: the client sends them
212
- no bearer.
218
+ The client also reads the configuration and changes a subscription's plan.
219
+ `GET /config` is a public route: the client sends it no bearer.
213
220
 
214
221
  | Call | Route |
215
222
  | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
216
- | `listProducts({ merchant, keys })`: the products `merchant` (its id) has on sale named by `keys` (1 to 100 product keys), each with its prices, in one page; `useProducts` reads the same | `GET /products` |
217
223
  | `getConfig()` (capabilities, `currencies`, `captcha`; `client.currencies` is the pinned registry) | `GET /config` |
218
224
  | `getCustomerConfig()` (the customer's merchant: `payment` with PSPs, `solana.network` and tokens, and `merchant`, its name) | `GET /me/config` |
219
225
  | `previewSubscriptionChange(id, { priceId?, quantity? })` | `POST /me/subscriptions/{id}/change/preview` |
@@ -278,8 +284,7 @@ provider:
278
284
  subscription row; `useBillingRefresh()` refetches after host-side changes.
279
285
  - Hooks: `useSubscriptions` (`cancel`, `resume`, `setPaymentMethod`,
280
286
  `changeSubscription`, per-row `pending`, `nextCursor`), `usePaymentMethods` (`add`,
281
- `remove`, `setDefault`), `usePayments` (cursor pages), `useProducts` (a
282
- catalog lookup by product key).
287
+ `remove`, `setDefault`), `usePayments` (cursor pages).
283
288
  Actions resolve to `null` or a `BillingError`; they never throw.
284
289
  `changeSubscription` resolves to the `SubscriptionChange` instead of `null`. Cancel, resume
285
290
  and the card change answer the subscription, which replaces the row.
@@ -1,14 +1,14 @@
1
1
  import { CheckoutAppearance } from './appearance';
2
- import { Order } from './client/types';
2
+ import { Order, Price } from './client/types';
3
3
  import * as React from "react";
4
4
  export interface BuyButtonProps {
5
- /** The id of the merchant that sells the product. */
6
- merchant: string;
7
- /** The product's catalog key. */
8
- product: string;
9
- /** The price's key within the product. */
10
- price: string;
11
- /** The button's text; by default the price's amount and terms, from the catalog. */
5
+ /**
6
+ * The price to buy, from a product the host's server put in its page (the
7
+ * Go Client's ListProducts, its prices as a buyer sees them:
8
+ * `billing.BuyerPrices`). The browser never reads the catalog.
9
+ */
10
+ price: Price;
11
+ /** The button's text; by default the price's amount and terms. */
12
12
  label?: string;
13
13
  /**
14
14
  * A customer-chosen deposit, in the price currency's native units, for a
@@ -32,11 +32,5 @@ export interface BuyButtonProps {
32
32
  appearance?: CheckoutAppearance;
33
33
  className?: string;
34
34
  }
35
- export declare function BuyButton({ merchant, product, price: priceKey, ...props }: BuyButtonProps): React.JSX.Element;
36
- export type PurchaseProps = Omit<BuyButtonProps, "merchant" | "product" | "price"> & {
37
- /** The price to buy; the button waits while it is unknown. */
38
- priceId?: string;
39
- label: string;
40
- };
41
35
  /** One price's button and its order. Requires `BillingProvider`. */
42
- export declare function Purchase({ priceId, label, amount, returnUrl, onPaid, onSignInRequired, signedIn, appearance, className, }: PurchaseProps): React.JSX.Element;
36
+ export declare function BuyButton({ price, label, amount, returnUrl, onPaid, onSignInRequired, signedIn, appearance, className, }: BuyButtonProps): React.JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { BillingError } from './errors';
2
- import { Account, CustomerConfig, CustomerEntitlement, CustomerLink, LowBalanceLine, NetworkLinkChallenge, PublicConfig, CurrencyScales, ListPage, NewCard, CardCaptureReference, NextAction, Cart, Order, OrderPaymentInput, Page, Payment, PaymentMethod, Product, Subscription, SubscriptionChange, SubscriptionChangePreview, Usage } from './types';
2
+ import { Account, CustomerConfig, CustomerEntitlement, CustomerLink, LowBalanceLine, NetworkLinkChallenge, PublicConfig, CurrencyScales, ListPage, NewCard, CardCaptureReference, NextAction, Cart, Order, OrderPaymentInput, Payment, PaymentMethod, Subscription, SubscriptionChange, SubscriptionChangePreview, Usage } from './types';
3
+ import type * as wire from "./generated/wire";
3
4
  export interface BillingClientOptions {
4
5
  /** OpenRails embedded mount. Default "/billing/v1". */
5
6
  baseUrl?: string;
@@ -10,8 +11,8 @@ export interface BillingClientOptions {
10
11
  fetch?: (input: string, init: RequestInit) => Promise<Response>;
11
12
  /**
12
13
  * The customer's access token, sent as the bearer of every request but
13
- * the two public reads (`getConfig`, `listProducts`); omit when `fetch`
14
- * authenticates. A `tokenSource` keeps it fresh: a call answered 401
14
+ * the public read (`getConfig`); omit when `fetch` authenticates. A
15
+ * `tokenSource` keeps it fresh: a call answered 401
15
16
  * `credential_expired` is then retried once with a new token.
16
17
  */
17
18
  getToken?: () => string | null | undefined | Promise<string | null | undefined>;
@@ -23,15 +24,6 @@ export interface BillingClientOptions {
23
24
  */
24
25
  currencies?: CurrencyScales;
25
26
  }
26
- /**
27
- * A public catalog lookup: the products of `merchant` (its id) named by
28
- * `keys` (at most 100 product keys), in one page.
29
- */
30
- export interface ProductListOptions {
31
- merchant: string;
32
- keys: string[];
33
- signal?: AbortSignal;
34
- }
35
27
  export interface ListOptions {
36
28
  limit?: number;
37
29
  offset?: number;
@@ -161,7 +153,12 @@ export declare function createBillingClient(options?: BillingClientOptions): {
161
153
  /**
162
154
  * Creates an order from `lines` or the cart (`cart: true`), and with
163
155
  * `payment` pays it in the same call; `expectedTotal` is the total the
164
- * customer saw. A failed payment resolves as payOrder's does.
156
+ * customer saw; `idempotencyKey`, required with `payment`, names the
157
+ * payment attempt. A failed payment resolves as payOrder's does. Without
158
+ * `payment` the customer's open order of the same lines is answered when
159
+ * there is one. With `checkout` the order answers its embedded checkout,
160
+ * `order.checkout.url` on the checkout host, for `<EmbeddedCheckout>`,
161
+ * fresh on every answer: the merchant's own signed-in person only.
165
162
  */
166
163
  createOrder(input: {
167
164
  lines?: {
@@ -173,7 +170,8 @@ export declare function createBillingClient(options?: BillingClientOptions): {
173
170
  expectedTotal?: string;
174
171
  payment?: OrderPaymentInput;
175
172
  reusable?: boolean;
176
- idempotencyKey: string;
173
+ checkout?: wire.MyOrderCheckoutParams;
174
+ idempotencyKey?: string;
177
175
  }): Promise<OrderResult>;
178
176
  /**
179
177
  * The customer's orders, newest first: `origin: "usage"` their usage
@@ -257,12 +255,6 @@ export declare function createBillingClient(options?: BillingClientOptions): {
257
255
  * first. Pass the answer's `next_cursor` as `cursor` for the next page.
258
256
  */
259
257
  getUsage(opts: UsageOptions): Promise<Usage>;
260
- /**
261
- * The products `merchant` has on sale named by `keys`, each with its
262
- * current prices: a public read, the same signed in or out. No keys
263
- * name no products: nothing is fetched.
264
- */
265
- listProducts(opts: ProductListOptions): Promise<Page<Product>>;
266
258
  /**
267
259
  * A challenge to link the customer to an openrails.dev account: its
268
260
  * `nonce` goes in the network sign-in's authorization request.
@@ -1,4 +1,4 @@
1
- export type OpenRailsErrorCode = "admission_captured" | "admission_not_found" | "already_owned" | "application_required" | "as_of_required" | "authentication_required" | "authentication_unavailable" | "authorization_unavailable" | "billing_archive_integrity" | "billing_archive_invalid_artifact" | "billing_archive_merchant_mismatch" | "billing_archive_not_empty" | "billing_archive_unavailable" | "billing_archive_unsupported_state" | "billing_policy_not_found" | "cancel_unsupported_on_rail" | "captcha_invalid" | "captcha_required" | "card_attempts_blocked" | "card_declined" | "card_not_saved" | "card_requires_https" | "catalog_benefit_overlap" | "catalog_revision_conflict" | "checkout_attempt_closed" | "checkout_attempt_expired" | "checkout_attempts_exhausted" | "checkout_embed_origins_required" | "checkout_expired" | "checkout_not_found" | "credential_expired" | "credential_revoked" | "credit_grant_held" | "credit_grant_not_found" | "credit_grant_unavailable" | "csrf_origin_denied" | "currency_unsupported" | "custodian_capture_unavailable" | "customer_action_required" | "customer_email_required" | "customer_issuer_mismatch" | "customer_not_found" | "customer_payment_unsupported" | "customer_session_required" | "dashboard_invalid" | "database_busy" | "default_payment_method_invalid" | "default_payment_method_required" | "default_rate_card_not_found" | "destructive_actions_held" | "finding_action_failed" | "finding_not_actionable" | "finding_requires_merchant_config" | "hold_not_found" | "host_event_not_found" | "host_principal_invalid" | "hosted_checkout_unavailable" | "idempotency_key_in_use" | "idempotency_key_required" | "idempotency_key_reused" | "insufficient_credits" | "insufficient_funds" | "internal_error" | "invalid_cursor" | "invalid_customer_id" | "invalid_host_event_request" | "invalid_param" | "invalid_payment_method" | "invalid_psp_reference" | "invalid_query" | "invalid_request_body" | "invalid_settlement_status_request" | "invoker_scoped_principal" | "merchant_config_read_only" | "merchant_mismatch" | "merchant_unresolved" | "meter_in_use" | "meter_rate_card_conflict" | "method_not_allowed" | "metrics_query_invalid" | "model_unavailable" | "network_account_linked" | "network_link_challenge_invalid" | "network_link_conflict" | "network_link_in_use" | "network_terms_required" | "order_action_not_allowed" | "order_has_recurring_line" | "order_line_unavailable" | "order_not_cancelable" | "order_not_payable" | "order_payment_in_progress" | "order_total_changed" | "payment_duplicate_refused" | "payment_exceeds_due" | "payment_failed" | "payment_idempotency_conflict" | "payment_in_progress" | "payment_method_delete_failed" | "payment_method_delete_unsupported" | "payment_method_not_psp_vaulted" | "payment_method_not_usable" | "payment_method_psp_mismatch" | "payment_method_required" | "payment_method_same_vault" | "payment_method_stale" | "payment_method_update_failed" | "payment_method_update_unsupported" | "payment_not_found" | "payment_not_refundable" | "payment_not_retryable" | "payment_option_unavailable" | "payment_provider_rejected" | "permission_required" | "price_change_currency_mismatch" | "price_change_target_archived" | "price_increase_notice_too_short" | "price_key_cadence_conflict" | "price_key_not_found" | "price_migration_not_found" | "price_not_found" | "price_not_sellable" | "product_in_use" | "product_not_found" | "product_tier_group_conflict" | "product_tier_group_in_use" | "provider_cancel_held" | "provider_outcome_unknown" | "provider_writes_held" | "psp_claim_requires_proof" | "psp_credentials_rejected" | "psp_exists" | "psp_key_taken" | "psp_last_active" | "psp_not_found" | "purchase_review_resolved" | "quantity_not_allowed" | "rate_card_product_not_found" | "rate_limit_exceeded" | "rebill_terms_committed" | "refund_failed" | "refund_rail_unavailable" | "refund_unsupported" | "request_body_too_large" | "resource_access_denied" | "resource_conflict" | "resource_not_found" | "revision_mismatch" | "route_not_found" | "running_charge_not_found" | "scheduled_change_exists" | "service_credential_customer_scope_denied" | "service_unavailable" | "solana_rpc_unavailable" | "solana_transaction_refused" | "step_up_required" | "step_up_unavailable" | "stored_credential_required" | "subscription_change_already_scheduled" | "subscription_change_cadence_unsupported" | "subscription_change_credit_exceeds_price" | "subscription_change_cycle_unknown" | "subscription_change_idempotency_conflict" | "subscription_change_idempotency_key_required" | "subscription_change_in_flight" | "subscription_change_period_unknown" | "subscription_change_provider_conflict" | "subscription_change_refused" | "subscription_change_renewal_due" | "subscription_change_requires_linked_plan" | "subscription_change_target_inactive" | "subscription_change_unsupported_on_rail" | "subscription_not_active" | "subscription_not_found" | "subscription_paid_through" | "subscription_resumable" | "trial_unsupported_on_rail" | "unknown_field" | "unsupported_media_type" | "usage_meter_invalid" | "usage_meter_not_found" | "usage_not_priced" | "usage_rate_card_invalid" | "webhook_account_mismatch" | "webhook_invalid";
1
+ export type OpenRailsErrorCode = "admission_captured" | "admission_not_found" | "already_owned" | "application_required" | "as_of_required" | "authentication_required" | "authentication_unavailable" | "authorization_unavailable" | "billing_archive_integrity" | "billing_archive_invalid_artifact" | "billing_archive_merchant_mismatch" | "billing_archive_not_empty" | "billing_archive_platform_cards" | "billing_archive_unavailable" | "billing_archive_unsupported_state" | "billing_policy_not_found" | "cancel_unsupported_on_rail" | "captcha_invalid" | "captcha_required" | "card_attempts_blocked" | "card_custody_reserved" | "card_declined" | "card_not_saved" | "card_requires_https" | "catalog_benefit_overlap" | "catalog_revision_conflict" | "checkout_attempt_closed" | "checkout_attempt_expired" | "checkout_attempts_exhausted" | "checkout_embed_origins_required" | "checkout_expired" | "checkout_not_found" | "credential_expired" | "credential_revoked" | "credit_grant_held" | "credit_grant_not_found" | "credit_grant_unavailable" | "csrf_origin_denied" | "currency_unsupported" | "custodian_capture_unavailable" | "customer_action_required" | "customer_email_required" | "customer_issuer_mismatch" | "customer_not_found" | "customer_payment_unsupported" | "customer_session_required" | "dashboard_invalid" | "database_busy" | "default_payment_method_invalid" | "default_payment_method_required" | "default_rate_card_not_found" | "destructive_actions_held" | "entitlement_required" | "finding_action_failed" | "finding_not_actionable" | "finding_requires_merchant_config" | "hold_not_found" | "host_event_not_found" | "host_principal_invalid" | "hosted_checkout_unavailable" | "idempotency_key_in_use" | "idempotency_key_required" | "idempotency_key_reused" | "insufficient_credits" | "insufficient_funds" | "internal_error" | "invalid_cursor" | "invalid_customer_id" | "invalid_host_event_request" | "invalid_param" | "invalid_payment_method" | "invalid_psp_reference" | "invalid_query" | "invalid_request_body" | "invalid_settlement_status_request" | "invoker_scoped_principal" | "merchant_config_read_only" | "merchant_mismatch" | "merchant_unresolved" | "meter_in_use" | "meter_rate_card_conflict" | "method_not_allowed" | "metrics_query_invalid" | "model_unavailable" | "network_account_linked" | "network_link_challenge_invalid" | "network_link_conflict" | "network_link_in_use" | "network_terms_required" | "order_action_not_allowed" | "order_has_recurring_line" | "order_line_unavailable" | "order_not_cancelable" | "order_not_payable" | "order_payment_in_progress" | "order_total_changed" | "payment_duplicate_refused" | "payment_exceeds_due" | "payment_failed" | "payment_idempotency_conflict" | "payment_in_progress" | "payment_method_delete_failed" | "payment_method_delete_unsupported" | "payment_method_not_psp_vaulted" | "payment_method_not_usable" | "payment_method_psp_mismatch" | "payment_method_required" | "payment_method_same_vault" | "payment_method_stale" | "payment_method_update_failed" | "payment_method_update_unsupported" | "payment_not_found" | "payment_not_refundable" | "payment_not_retryable" | "payment_option_unavailable" | "payment_provider_rejected" | "permission_required" | "platform_vault_unavailable" | "platform_vault_unreachable" | "price_change_currency_mismatch" | "price_change_target_archived" | "price_increase_notice_too_short" | "price_key_cadence_conflict" | "price_key_not_found" | "price_migration_not_found" | "price_not_found" | "price_not_sellable" | "product_in_use" | "product_not_found" | "product_tier_group_conflict" | "product_tier_group_in_use" | "provider_cancel_held" | "provider_outcome_unknown" | "provider_writes_held" | "psp_claim_requires_proof" | "psp_credentials_rejected" | "psp_exists" | "psp_key_taken" | "psp_last_active" | "psp_not_found" | "purchase_review_resolved" | "quantity_not_allowed" | "rate_card_product_not_found" | "rate_limit_exceeded" | "rebill_terms_committed" | "refund_failed" | "refund_rail_unavailable" | "refund_unsupported" | "request_body_too_large" | "resource_access_denied" | "resource_conflict" | "resource_not_found" | "revision_mismatch" | "route_not_found" | "running_charge_not_found" | "scheduled_change_exists" | "service_credential_customer_scope_denied" | "service_unavailable" | "solana_rpc_unavailable" | "solana_transaction_refused" | "step_up_required" | "step_up_unavailable" | "stored_credential_required" | "subscription_change_already_scheduled" | "subscription_change_cadence_unsupported" | "subscription_change_credit_exceeds_price" | "subscription_change_cycle_unknown" | "subscription_change_idempotency_conflict" | "subscription_change_idempotency_key_required" | "subscription_change_in_flight" | "subscription_change_period_unknown" | "subscription_change_provider_conflict" | "subscription_change_refused" | "subscription_change_renewal_due" | "subscription_change_requires_linked_plan" | "subscription_change_target_inactive" | "subscription_change_unsupported_on_rail" | "subscription_not_active" | "subscription_not_found" | "subscription_paid_through" | "subscription_resumable" | "trial_unsupported_on_rail" | "unknown_field" | "unsupported_media_type" | "usage_meter_invalid" | "usage_meter_not_found" | "usage_not_priced" | "usage_rate_card_invalid" | "webhook_account_mismatch" | "webhook_invalid";
2
2
  export type OpenRailsErrorType = "api_error" | "authentication_error" | "authorization_error" | "card_error" | "invalid_request_error" | "rate_limit_error";
3
3
  export declare const OPENRAILS_ERROR_CODES: Readonly<Record<OpenRailsErrorCode, {
4
4
  status: number;
@@ -98,7 +98,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
98
98
  readonly 200: "Order";
99
99
  readonly 201: "Order";
100
100
  };
101
- readonly errors: readonly ["already_owned", "card_attempts_blocked", "card_declined", "customer_action_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_line_unavailable", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "quantity_not_allowed", "resource_conflict", "resource_not_found", "service_unavailable"];
101
+ readonly errors: readonly ["already_owned", "card_attempts_blocked", "card_declined", "checkout_embed_origins_required", "customer_action_required", "customer_session_required", "entitlement_required", "hosted_checkout_unavailable", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_line_unavailable", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "quantity_not_allowed", "resource_conflict", "resource_not_found", "service_unavailable"];
102
102
  readonly errorSets: readonly ["tier:customer", "request"];
103
103
  }, {
104
104
  readonly method: "GET";
@@ -140,7 +140,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
140
140
  readonly responses: {
141
141
  readonly 200: "Order";
142
142
  };
143
- readonly errors: readonly ["card_attempts_blocked", "card_declined", "customer_action_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "resource_conflict", "resource_not_found", "service_unavailable"];
143
+ readonly errors: readonly ["card_attempts_blocked", "card_declined", "customer_action_required", "entitlement_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "resource_conflict", "resource_not_found", "service_unavailable"];
144
144
  readonly errorSets: readonly ["tier:customer", "request"];
145
145
  }, {
146
146
  readonly method: "POST";
@@ -231,7 +231,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
231
231
  readonly 200: "Order";
232
232
  readonly 201: "Order";
233
233
  };
234
- readonly errors: readonly ["already_owned", "checkout_embed_origins_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_line_unavailable", "quantity_not_allowed", "resource_not_found", "service_unavailable"];
234
+ readonly errors: readonly ["already_owned", "checkout_embed_origins_required", "entitlement_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_line_unavailable", "quantity_not_allowed", "resource_not_found", "service_unavailable"];
235
235
  readonly errorSets: readonly ["tier:application", "request"];
236
236
  }, {
237
237
  readonly method: "POST";
@@ -360,20 +360,6 @@ export declare const OPENRAILS_ROUTES: readonly [{
360
360
  };
361
361
  readonly errors: readonly ["service_unavailable"];
362
362
  readonly errorSets: readonly ["tier:customer"];
363
- }, {
364
- readonly method: "GET";
365
- readonly path: "/v1/products";
366
- readonly group: "checkout";
367
- readonly auth: "public";
368
- readonly permission: null;
369
- readonly sensitive: false;
370
- readonly mountedWhen: null;
371
- readonly request: null;
372
- readonly responses: {
373
- readonly 200: "ListPage<Product>";
374
- };
375
- readonly errors: readonly ["invalid_query", "resource_not_found"];
376
- readonly errorSets: readonly ["tier:public", "request"];
377
363
  }, {
378
364
  readonly method: "POST";
379
365
  readonly path: "/v1/catalog/apply";
@@ -1823,7 +1809,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
1823
1809
  readonly responses: {
1824
1810
  readonly 201: "PSP";
1825
1811
  };
1826
- readonly errors: readonly ["invalid_param", "psp_claim_requires_proof", "psp_credentials_rejected", "psp_exists", "psp_key_taken", "revision_mismatch", "service_unavailable"];
1812
+ readonly errors: readonly ["invalid_param", "platform_vault_unreachable", "psp_claim_requires_proof", "psp_credentials_rejected", "psp_exists", "psp_key_taken", "revision_mismatch", "service_unavailable"];
1827
1813
  readonly errorSets: readonly ["tier:merchant", "request"];
1828
1814
  }, {
1829
1815
  readonly method: "GET";
@@ -1939,7 +1925,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
1939
1925
  readonly responses: {
1940
1926
  readonly 200: "MerchantConfigurationState";
1941
1927
  };
1942
- readonly errors: readonly ["invalid_param", "revision_mismatch", "service_unavailable"];
1928
+ readonly errors: readonly ["card_custody_reserved", "invalid_param", "platform_vault_unavailable", "platform_vault_unreachable", "resource_conflict", "revision_mismatch", "service_unavailable"];
1943
1929
  readonly errorSets: readonly ["tier:merchant", "request"];
1944
1930
  }, {
1945
1931
  readonly method: "GET";
@@ -2024,7 +2010,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
2024
2010
  readonly responses: {
2025
2011
  readonly 200: "application/x-ndjson";
2026
2012
  };
2027
- readonly errors: readonly ["billing_archive_unavailable", "billing_archive_unsupported_state"];
2013
+ readonly errors: readonly ["billing_archive_platform_cards", "billing_archive_unavailable", "billing_archive_unsupported_state"];
2028
2014
  readonly errorSets: readonly ["tier:merchant"];
2029
2015
  }, {
2030
2016
  readonly method: "POST";
@@ -2041,7 +2027,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
2041
2027
  readonly responses: {
2042
2028
  readonly 200: "BillingArchiveImport";
2043
2029
  };
2044
- readonly errors: readonly ["billing_archive_integrity", "billing_archive_invalid_artifact", "billing_archive_merchant_mismatch", "billing_archive_not_empty", "billing_archive_unavailable", "billing_archive_unsupported_state", "request_body_too_large"];
2030
+ readonly errors: readonly ["billing_archive_integrity", "billing_archive_invalid_artifact", "billing_archive_merchant_mismatch", "billing_archive_not_empty", "billing_archive_platform_cards", "billing_archive_unavailable", "billing_archive_unsupported_state", "request_body_too_large"];
2045
2031
  readonly errorSets: readonly ["tier:merchant", "request"];
2046
2032
  }, {
2047
2033
  readonly method: "POST";
@@ -2607,7 +2593,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
2607
2593
  readonly responses: {
2608
2594
  readonly 200: "Order";
2609
2595
  };
2610
- readonly errors: readonly ["card_attempts_blocked", "card_declined", "customer_action_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "resource_conflict", "resource_not_found", "service_unavailable"];
2596
+ readonly errors: readonly ["card_attempts_blocked", "card_declined", "customer_action_required", "entitlement_required", "idempotency_key_in_use", "idempotency_key_required", "idempotency_key_reused", "invalid_param", "order_not_payable", "order_payment_in_progress", "order_total_changed", "payment_failed", "payment_method_stale", "payment_option_unavailable", "payment_provider_rejected", "resource_conflict", "resource_not_found", "service_unavailable"];
2611
2597
  readonly errorSets: readonly ["tier:network", "request"];
2612
2598
  }, {
2613
2599
  readonly method: "POST";
@@ -145,6 +145,7 @@ export type ApplyProduct = {
145
145
  archived?: boolean | null;
146
146
  ownership?: "consumable" | "extend" | "unique" | null;
147
147
  entitlements?: string[];
148
+ required_entitlements?: string[];
148
149
  credit_grant?: CreditGrantSpec | null;
149
150
  prices?: Record<string, ApplyPrice>;
150
151
  rate_cards?: RateCard[] | null;
@@ -455,6 +456,7 @@ export type CreateMyOrderParams = {
455
456
  expected_total?: string;
456
457
  payment?: OrderPaymentParams;
457
458
  reusable?: boolean;
459
+ checkout?: MyOrderCheckoutParams;
458
460
  };
459
461
  export type CreateNetworkLinkParams = {
460
462
  challenge_id?: string;
@@ -531,6 +533,7 @@ export type CreateProductParams = {
531
533
  display_name?: string;
532
534
  description?: string;
533
535
  entitlements?: string[];
536
+ required_entitlements?: string[];
534
537
  credit_grant?: CreditGrantSpec;
535
538
  tier_group?: string;
536
539
  tier_rank?: number;
@@ -699,10 +702,18 @@ export type DeclaredBilling = {
699
702
  subscriptions?: DeclaredSubscription[];
700
703
  transactions?: DeclaredTransaction[];
701
704
  admin_grants?: DeclaredAdminGrant[];
705
+ purchases?: DeclaredPurchase[];
702
706
  };
703
707
  export type DeclaredCustomer = {
704
708
  customer?: string;
705
709
  };
710
+ export type DeclaredOrderLine = {
711
+ price?: string;
712
+ quantity?: number;
713
+ unit_amount?: string;
714
+ description?: string;
715
+ access_ends_at?: string;
716
+ };
706
717
  export type DeclaredPaymentMethod = {
707
718
  customer?: string;
708
719
  rail?: string;
@@ -722,6 +733,25 @@ export type DeclaredProviderSchedule = {
722
733
  interval_months?: number;
723
734
  first_due_at?: string;
724
735
  };
736
+ export type DeclaredPurchase = {
737
+ source_id?: string;
738
+ customer?: string;
739
+ rail?: string;
740
+ psp?: PSPRef;
741
+ transaction_id?: string;
742
+ currency?: string;
743
+ amount?: string;
744
+ paid_at?: string;
745
+ lines?: DeclaredOrderLine[];
746
+ settlement?: DeclaredSettlement;
747
+ evidence?: unknown;
748
+ };
749
+ export type DeclaredSettlement = {
750
+ asset?: string;
751
+ quantity?: string;
752
+ payer?: string;
753
+ recipient?: string;
754
+ };
725
755
  export type DeclaredStripeInvoice = {
726
756
  id?: string;
727
757
  customer_reference?: string;
@@ -1006,6 +1036,7 @@ export type MerchantConfigurationState = {
1006
1036
  revision: number;
1007
1037
  display_name: string;
1008
1038
  settings: MerchantSettings;
1039
+ platform_vault: PlatformVaultState;
1009
1040
  };
1010
1041
  export type MerchantProfile = {
1011
1042
  logo_url?: string;
@@ -1028,6 +1059,7 @@ export type MerchantSettings = {
1028
1059
  dunning_policy?: DunningPolicy;
1029
1060
  checkout?: MerchantCheckoutSettings;
1030
1061
  balance_notices?: BalanceNoticeSettings;
1062
+ card_custody?: "hosted" | "merchant" | "platform";
1031
1063
  billing_policies?: BillingPolicy[];
1032
1064
  billing_policy_bindings?: BillingPolicyBinding[];
1033
1065
  delegated_invoker_wasted_spend_limits?: BudgetWindow[];
@@ -1131,6 +1163,9 @@ export type MetricsSchema = {
1131
1163
  limits: MetricsLimits;
1132
1164
  query_shape: string;
1133
1165
  };
1166
+ export type MyOrderCheckoutParams = {
1167
+ ui_mode?: "embedded" | "hosted";
1168
+ };
1134
1169
  export type NetworkLink = {
1135
1170
  link: CustomerLink;
1136
1171
  merchant: PublicMerchant;
@@ -1204,7 +1239,7 @@ export type OrderCheckout = {
1204
1239
  url: string | null;
1205
1240
  ui_mode: "embedded" | "hosted";
1206
1241
  expires_at: string;
1207
- success_url: string;
1242
+ success_url: string | null;
1208
1243
  cancel_url: string | null;
1209
1244
  saved_payment_methods: boolean;
1210
1245
  };
@@ -1250,6 +1285,7 @@ export type OrderLineRefusal = {
1250
1285
  message: string;
1251
1286
  owned_by: string | null;
1252
1287
  hint: string | null;
1288
+ missing?: string[];
1253
1289
  };
1254
1290
  export type OrderPayment = {
1255
1291
  status: "processing" | "requires_action" | "requires_payment_method" | "succeeded";
@@ -1513,6 +1549,9 @@ export type PerUnitPrice = {
1513
1549
  maximum_amount?: string;
1514
1550
  matrix?: Matrix;
1515
1551
  };
1552
+ export type PlatformVaultState = {
1553
+ available: boolean;
1554
+ };
1516
1555
  export type PreviewMyOrderParams = {
1517
1556
  lines?: OrderLineParams[];
1518
1557
  cart?: boolean;
@@ -1616,6 +1655,7 @@ export type Product = {
1616
1655
  display_name: string;
1617
1656
  description: string;
1618
1657
  entitlements: string[];
1658
+ required_entitlements: string[];
1619
1659
  credit_grant?: CreditGrantSpec;
1620
1660
  tier_group: string | null;
1621
1661
  tier_rank: number;
@@ -2016,6 +2056,7 @@ export type UpdateProductParams = {
2016
2056
  display_name?: string | null;
2017
2057
  description?: string | null;
2018
2058
  entitlements?: string[];
2059
+ required_entitlements?: string[];
2019
2060
  credit_grant?: CreditGrantSpec | null;
2020
2061
  tier_group?: string | null;
2021
2062
  tier_rank?: number | null;
@@ -1,4 +1,4 @@
1
- export { CANCEL_REASON_MAX, CANCEL_REASON_MIN, createBillingClient, isWalletAction, isWalletRejection, RETRY_BUDGET_MS, signWalletAction, WalletRejectedError, type BillingClient, type BillingClientOptions, type ListOptions, type OrderResult, type ProductListOptions, type SendSolanaTransaction, type SubscriptionChangeInput, type UsageOptions, } from './client';
1
+ export { CANCEL_REASON_MAX, CANCEL_REASON_MIN, createBillingClient, isWalletAction, isWalletRejection, RETRY_BUDGET_MS, signWalletAction, WalletRejectedError, type BillingClient, type BillingClientOptions, type ListOptions, type OrderResult, type SendSolanaTransaction, type SubscriptionChangeInput, type UsageOptions, } from './client';
2
2
  export { redeemAssertion, tokenSource, type RedeemAssertionOptions, type TokenResponse, type TokenSource, type TokenSourceOptions, } from './token-source';
3
3
  export { BillingError, isBillingError, isServerError, readBillingError, toBillingError, type BillingErrorBody, } from './errors';
4
4
  export type { Account, Balance, CaptchaConfig, CardSummary, Cart, Currency, CurrencyScales, CustomerConfig, CustomerEntitlement, CustomerLink, PaymentConfig, PaymentFailure, PublicConfig, PublicMerchant, ListPage, LowBalanceLine, NetworkLinkChallenge, NewCard, CardCaptureReference, NextAction, Order, OrderLine, OrderLineRefusal, OrderPaymentInput, OrderPreviewLine, Page, Payment, PaymentMethod, PaymentRecovery, Price, Product, Subscription, SubscriptionDunning, SubscriptionProduct, SubscriptionStatus, SubscriptionChange, SubscriptionChangePreview, Usage, UsageRow, } from './types';
@@ -425,11 +425,11 @@ export declare const orderSchema: z.ZodObject<{
425
425
  checkout: z.ZodOptional<z.ZodNullable<z.ZodObject<{
426
426
  url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
427
427
  ui_mode: z.ZodCatch<z.ZodEnum<{
428
- embedded: "embedded";
429
428
  hosted: "hosted";
429
+ embedded: "embedded";
430
430
  }>>;
431
431
  expires_at: z.ZodString;
432
- success_url: z.ZodString;
432
+ success_url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
433
433
  cancel_url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
434
434
  saved_payment_methods: z.ZodBoolean;
435
435
  }, z.core.$strip>>>;
@@ -460,12 +460,13 @@ export declare const orderSchema: z.ZodObject<{
460
460
  created_at: z.ZodString;
461
461
  }, z.core.$strip>;
462
462
  export type Order = z.infer<typeof orderSchema>;
463
- /** Why a line cannot be bought: `already_owned`, `unavailable`, ... */
463
+ /** Why a line cannot be bought: `already_owned`, `entitlement_required`, `unavailable`, ... */
464
464
  export declare const orderLineRefusalSchema: z.ZodObject<{
465
465
  code: z.ZodString;
466
466
  message: z.ZodString;
467
467
  owned_by: z.ZodOptional<z.ZodNullable<z.ZodString>>;
468
468
  hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
469
+ missing: z.ZodOptional<z.ZodArray<z.ZodString>>;
469
470
  }, z.core.$strip>;
470
471
  export type OrderLineRefusal = z.infer<typeof orderLineRefusalSchema>;
471
472
  /** One line priced as an order would freeze it, or why it cannot be bought. */
@@ -484,6 +485,7 @@ export declare const orderPreviewLineSchema: z.ZodObject<{
484
485
  message: z.ZodString;
485
486
  owned_by: z.ZodOptional<z.ZodNullable<z.ZodString>>;
486
487
  hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
488
+ missing: z.ZodOptional<z.ZodArray<z.ZodString>>;
487
489
  }, z.core.$strip>>>;
488
490
  }, z.core.$strip>;
489
491
  export type OrderPreviewLine = z.infer<typeof orderPreviewLineSchema>;
@@ -510,6 +512,7 @@ export declare const cartSchema: z.ZodObject<{
510
512
  message: z.ZodString;
511
513
  owned_by: z.ZodOptional<z.ZodNullable<z.ZodString>>;
512
514
  hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
515
+ missing: z.ZodOptional<z.ZodArray<z.ZodString>>;
513
516
  }, z.core.$strip>>>;
514
517
  }, z.core.$strip>>;
515
518
  payment_options: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
@@ -555,6 +558,7 @@ export declare const productSchema: z.ZodObject<{
555
558
  display_name: z.ZodString;
556
559
  description: z.ZodString;
557
560
  entitlements: z.ZodArray<z.ZodString>;
561
+ required_entitlements: z.ZodOptional<z.ZodArray<z.ZodString>>;
558
562
  credit_grant: z.ZodOptional<z.ZodNullable<z.ZodObject<{
559
563
  currency: z.ZodString;
560
564
  amount: z.ZodOptional<z.ZodNullable<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>>>;