@openrails/billing-ui 0.237.0 → 0.239.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 +57 -9
- package/README.md +48 -19
- package/dist/account/payment-methods-panel.d.ts +1 -1
- package/dist/authenticate.d.ts +5 -4
- package/dist/buy-button.d.ts +4 -2
- package/dist/client/client.d.ts +47 -13
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/routes.d.ts +64 -32
- package/dist/client/generated/wire.d.ts +29 -15
- package/dist/client/index.d.ts +3 -2
- package/dist/client/token-source.d.ts +60 -0
- package/dist/client/types.d.ts +75 -66
- package/dist/{client-D9G1Tgox.js → client-DgIsTx7x.js} +215 -145
- package/dist/client-DgIsTx7x.js.map +1 -0
- package/dist/client.js +2 -2
- package/dist/{hooks-DYepYVMX.js → hooks-DivfikJv.js} +99 -90
- package/dist/hooks-DivfikJv.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +989 -984
- package/dist/index.js.map +1 -1
- package/dist/offers.d.ts +6 -4
- package/dist/react/config.d.ts +17 -12
- package/dist/react/context.d.ts +3 -1
- package/dist/react/hooks.d.ts +5 -5
- package/dist/react/index.d.ts +1 -1
- package/dist/react.js +2 -2
- package/docs/payment-form-contract.md +1 -1
- package/package.json +1 -1
- package/dist/client-D9G1Tgox.js.map +0 -1
- package/dist/hooks-DYepYVMX.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Public products and staff route groups
|
|
4
|
+
|
|
5
|
+
- Breaking: public `listProducts()` now reads `GET /products`. Catalog
|
|
6
|
+
management uses `/catalog`, merchant configuration `/merchant`, and metrics
|
|
7
|
+
`/metrics`; customer support stays under `/admin`.
|
|
8
|
+
|
|
9
|
+
## Provider operations removed
|
|
10
|
+
|
|
11
|
+
- Breaking: `OpenRailsErrorCode` and `OPENRAILS_ERROR_CODES` lose
|
|
12
|
+
`provider_operation_not_found`, `provider_operation_conflict`,
|
|
13
|
+
`provider_operation_not_open`, `provider_operation_has_billing_evidence`,
|
|
14
|
+
`provider_operation_refused`, `provider_operation_not_refused` and
|
|
15
|
+
`provider_billing_observation_conflict`.
|
|
16
|
+
|
|
17
|
+
## Usage report
|
|
18
|
+
|
|
19
|
+
- `getUsage({ currency, groupBy, from, to, limit, cursor })` reads a page of
|
|
20
|
+
the customer's usage (`GET /me/usage`): `Usage`, its `rows` by total
|
|
21
|
+
amount, largest first, and `next_cursor` (null on the last page). A page
|
|
22
|
+
holds at most 1,000 groups (default 100); a cursor reads only the report it
|
|
23
|
+
came from.
|
|
24
|
+
|
|
25
|
+
## Public reads name their merchant; token source
|
|
26
|
+
|
|
27
|
+
- Breaking: `listProducts({ merchant, keys })`, `useProducts({ merchant, keys
|
|
28
|
+
})` and `<BuyButton merchant>` take the merchant's id, and `<Offers>` takes
|
|
29
|
+
it with `keys`: `GET /catalog/products?merchant=<id>&keys=…`. The read sends
|
|
30
|
+
no bearer, signed in or out.
|
|
31
|
+
- Breaking: `getConfig()` and `useConfig()` are the deployment's part alone
|
|
32
|
+
(`capabilities`, `currencies`, `captcha`, `network`); `PublicConfig` loses
|
|
33
|
+
`payment` and `merchant`. `getCustomerConfig()` and `useCustomerConfig()`
|
|
34
|
+
read the customer's merchant (`GET /me/config`, `CustomerConfig`: `payment`
|
|
35
|
+
and `merchant`); `<OrderCheckout>`, `<AccountBilling>` and
|
|
36
|
+
`<PaymentMethodsPanel>` take their PSPs from it.
|
|
37
|
+
- Breaking: `createConfigStore(read)` takes the read it shares, and
|
|
38
|
+
`ConfigStore` and `ConfigState` name what they hold (`ConfigStore<T>`).
|
|
39
|
+
- `tokenSource({ fetchToken, skew = 60 })` is a `getToken` that keeps the
|
|
40
|
+
customer's access token in memory (never in browser storage), replaces it
|
|
41
|
+
`skew` seconds before it expires with one request in flight, and has
|
|
42
|
+
`invalidate()`. With one, the client sends a call answered 401
|
|
43
|
+
`credential_expired` once more with a new token.
|
|
44
|
+
- `redeemAssertion({ tokenEndpoint, assertion, fetch })` redeems the
|
|
45
|
+
assertion a merchant's backend signed for its customer (RFC 7523,
|
|
46
|
+
`scope=openrails:self`) with the fetch it is given, so a DPoP fetch binds
|
|
47
|
+
the token to the browser's key.
|
|
48
|
+
|
|
49
|
+
## Payment operations removed
|
|
50
|
+
|
|
51
|
+
- Breaking: `getPaymentAuthentication`, `confirmPaymentAuthentication`,
|
|
52
|
+
`authenticatePayment`, `PaymentOperation` and `PaymentAuthentication` are
|
|
53
|
+
removed, with `operation_id` on `SubscriptionChange` and `operation` on
|
|
54
|
+
`PaymentRecovery`. A change the issuer challenges answers an `authenticate`
|
|
55
|
+
`next_action`; `authenticateChange(client, id, change, psp)` completes it
|
|
56
|
+
and confirms the change (`confirmSubscriptionChange`).
|
|
57
|
+
- `NextAction` is one shape for orders, changes and subscriptions (`type`,
|
|
58
|
+
`url`, `psp_id`, `transactions`, `payload`); `OrderNextAction` is gone.
|
|
59
|
+
|
|
3
60
|
## Running charges
|
|
4
61
|
|
|
5
62
|
- `Balance` gains `accrued_amount`, `accrual_rate_per_hour`, `as_of` and
|
|
@@ -235,15 +292,6 @@
|
|
|
235
292
|
product on sale with its current prices. Filter by currency, product or
|
|
236
293
|
renewal in the browser.
|
|
237
294
|
|
|
238
|
-
## Paying on a customer surface
|
|
239
|
-
|
|
240
|
-
- `client.checkoutSource(id, { customerBase })` reads and pays a checkout
|
|
241
|
-
session as its signed-in customer at a customer surface's
|
|
242
|
-
`/checkout-sessions/{id}` (for example a host's
|
|
243
|
-
`/api/v1/merchants/acme/billing/me`), so its saved cards pay. Without
|
|
244
|
-
`customerBase` the session id alone pays at `/checkout-sessions/{id}` as
|
|
245
|
-
before. `<CheckoutPage customerBase>` passes it through.
|
|
246
|
-
|
|
247
295
|
## 1.0.0
|
|
248
296
|
|
|
249
297
|
Ships with OpenRails v1.0.0; use the two at the same version. Everything a host
|
package/README.md
CHANGED
|
@@ -42,11 +42,33 @@ const billing = createBillingClient({ baseUrl: "/billing/v1", fetch: auth.authFe
|
|
|
42
42
|
</BillingProvider>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
Where your backend mints the customer's token, `tokenSource` keeps it: in
|
|
46
|
+
memory only, replaced `skew` seconds (60) before it expires with one request
|
|
47
|
+
however many calls wait, and once more when a call answers 401
|
|
48
|
+
`credential_expired`.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { createBillingClient, redeemAssertion, tokenSource } from "@openrails/billing-ui"
|
|
52
|
+
|
|
53
|
+
const billing = createBillingClient({
|
|
54
|
+
baseUrl: "https://billing.example/v1",
|
|
55
|
+
getToken: tokenSource({
|
|
56
|
+
// { access_token, expires_in } from your backend, or its signed assertion redeemed here.
|
|
57
|
+
fetchToken: async () => {
|
|
58
|
+
const { assertion } = await (await fetch("/api/billing/assertion", { method: "POST" })).json()
|
|
59
|
+
return redeemAssertion({ tokenEndpoint: "https://billing.example/oauth2/token", assertion })
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
45
65
|
`<BuyButton>` buys one price, `<Offers>` the products your server names by
|
|
46
66
|
key (a course, its bundle and the membership that also unlocks it; the Go
|
|
47
67
|
`Client.ListOffers` finds the products granting an entitlement): a
|
|
48
68
|
`BuyButton` per price ("$4.99", "Rent for 3 days, $1.99",
|
|
49
|
-
"$10.00 every 30 days").
|
|
69
|
+
"$10.00 every 30 days"). Both look prices up in the public catalog of the
|
|
70
|
+
merchant whose id you pass as `merchant`, signed in or out. The purchase is
|
|
71
|
+
theirs from start to payment: a
|
|
50
72
|
button creates the customer's order and pays it in a dialog
|
|
51
73
|
(`<OrderCheckout>`); a second click before it is paid opens the same order.
|
|
52
74
|
Signing in is the host's: with `signedIn={false}`, or when OpenRails answers
|
|
@@ -56,6 +78,7 @@ granting anything.
|
|
|
56
78
|
|
|
57
79
|
```tsx
|
|
58
80
|
<BuyButton
|
|
81
|
+
merchant={merchantId} // your merchant's id, from your server
|
|
59
82
|
product="course-101"
|
|
60
83
|
price="rent" // labelled from the catalog unless you pass label
|
|
61
84
|
signedIn={signedIn}
|
|
@@ -64,6 +87,7 @@ granting anything.
|
|
|
64
87
|
/>
|
|
65
88
|
|
|
66
89
|
<Offers
|
|
90
|
+
merchant={merchantId}
|
|
67
91
|
keys={["course-101", "course-bundle", "channel-membership"]} // from your server, or products={...} from its Client.ListOffers
|
|
68
92
|
signedIn={signedIn}
|
|
69
93
|
onSignInRequired={() => openSignIn()}
|
|
@@ -87,7 +111,7 @@ const amount = decimalToAmount(enteredAmount, currency.decimals)
|
|
|
87
111
|
const bounds = depositPrice.customer_amount
|
|
88
112
|
const valid = amount && bounds && BigInt(amount) >= BigInt(bounds.min_amount) && BigInt(amount) <= BigInt(bounds.max_amount)
|
|
89
113
|
|
|
90
|
-
<BuyButton product="api-credits" price="deposit" amount={valid ? amount : undefined} label="Add credits" {...handlers} />
|
|
114
|
+
<BuyButton merchant={merchantId} product="api-credits" price="deposit" amount={valid ? amount : undefined} label="Add credits" {...handlers} />
|
|
91
115
|
```
|
|
92
116
|
|
|
93
117
|
OpenRails validates the bounds and whole currency minor units before accepting
|
|
@@ -140,23 +164,25 @@ const billing = createBillingClient({ baseUrl: "/billing/v1", fetch: auth.authFe
|
|
|
140
164
|
</BillingProvider>
|
|
141
165
|
```
|
|
142
166
|
|
|
143
|
-
The panels read OpenRails'
|
|
144
|
-
|
|
145
|
-
saves a card in the page, and says
|
|
146
|
-
card PSPs are temporarily unavailable;
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
The panels read OpenRails' configuration themselves, once per
|
|
168
|
+
`BillingProvider`: the customer's merchant's (`GET /me/config`), where "Add
|
|
169
|
+
card" offers each PSP of its `payment` that saves a card in the page, and says
|
|
170
|
+
so while the read fails or its card PSPs are temporarily unavailable; and the
|
|
171
|
+
deployment's (`GET /config`), whose currency registry amounts use over the
|
|
172
|
+
pinned copy. `useCustomerConfig()`, `useConfig()` and `useCurrencyScales()`
|
|
173
|
+
read the same copies for host components.
|
|
149
174
|
|
|
150
175
|
## Catalog and plan changes
|
|
151
176
|
|
|
152
177
|
The client also reads the public catalog and changes a subscription's plan.
|
|
153
|
-
The catalog read
|
|
154
|
-
|
|
178
|
+
The catalog read and `GET /config` are public routes: the client sends them
|
|
179
|
+
no bearer.
|
|
155
180
|
|
|
156
181
|
| Call | Route |
|
|
157
182
|
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
158
|
-
| `listProducts({ keys })`: the products on sale named by `keys` (1 to 100 product keys), each with its prices, in one page; `useProducts` reads the same | `GET /
|
|
159
|
-
| `getConfig()` (capabilities, `currencies`, `
|
|
183
|
+
| `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` |
|
|
184
|
+
| `getConfig()` (capabilities, `currencies`, `captcha`; `client.currencies` is the pinned registry) | `GET /config` |
|
|
185
|
+
| `getCustomerConfig()` (the customer's merchant: `payment` with PSPs, `solana.network` and tokens, and `merchant`, its name) | `GET /me/config` |
|
|
160
186
|
| `previewSubscriptionChange(id, { priceId?, quantity? })` | `POST /me/subscriptions/{id}/change/preview` |
|
|
161
187
|
| `changeSubscription(id, { priceId?, quantity?, idempotencyKey, signature? })` | `POST /me/subscriptions/{id}/change` |
|
|
162
188
|
|
|
@@ -173,10 +199,11 @@ const change = await billing.changeSubscription(sub.id, {
|
|
|
173
199
|
charge now; fewer seats and a downgrade apply at the next renewal.
|
|
174
200
|
- `changeSubscription` is a money write. Mint one `idempotencyKey` per attempt and
|
|
175
201
|
reuse it until the change resolves (`status: "processing"`, a
|
|
176
|
-
`subscription_change_in_flight` refusal
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
202
|
+
`subscription_change_in_flight` refusal, a 5xx or a lost response), so
|
|
203
|
+
OpenRails replays the stored result instead of charging twice. A change the
|
|
204
|
+
card issuer challenges answers `requires_action` with an `authenticate`
|
|
205
|
+
`next_action`: `authenticateChange(client, id, change, psp)` runs it in the
|
|
206
|
+
page and confirms the change (`confirmSubscriptionChange`).
|
|
180
207
|
- A rail that needs the customer's own step answers `requires_action` with a
|
|
181
208
|
`next_action`. Solana's is `solana_sign_transactions`:
|
|
182
209
|
`signWalletAction(change.next_action, send)` signs and sends its
|
|
@@ -188,7 +215,7 @@ const change = await billing.changeSubscription(sub.id, {
|
|
|
188
215
|
|
|
189
216
|
## Provider-neutral flows
|
|
190
217
|
|
|
191
|
-
OpenRails's browser PSP configs (`GET /config`'s `payment.psps`) pick the
|
|
218
|
+
OpenRails's browser PSP configs (`GET /me/config`'s `payment.psps`) pick the
|
|
192
219
|
browser flow from each PSP's `flow` and public `config`
|
|
193
220
|
(Collect.js, native card inputs, Stripe Elements, redirect, wallet). Hosts never branch on a
|
|
194
221
|
provider:
|
|
@@ -208,8 +235,6 @@ provider:
|
|
|
208
235
|
page (needs `BillingProvider`); `canSavePaymentMethod(psp)` filters PSPs
|
|
209
236
|
that support it. After an off-page verification the provider returns to
|
|
210
237
|
`returnURL(setupId)`; confirm with `client.confirmCardSetup(id)`.
|
|
211
|
-
- `authenticatePayment(client, operationId, psp)` completes a pending
|
|
212
|
-
payment's 3-D Secure challenge when `canAuthenticatePayment(psp)`.
|
|
213
238
|
- `defaultCountry` (SavePaymentMethod, AccountBilling)
|
|
214
239
|
preselects the billing country, else the browser locale's region.
|
|
215
240
|
|
|
@@ -263,3 +288,7 @@ pnpm contract:check # fail if a generated contract file is stale
|
|
|
263
288
|
`BILLING_UI_SCREENSHOTS=<dir>` to capture light, dark and mobile screenshots.
|
|
264
289
|
Card deletion calls NMI, which the harness has no credentials for; jsdom tests
|
|
265
290
|
cover it.
|
|
291
|
+
|
|
292
|
+
## License
|
|
293
|
+
|
|
294
|
+
MIT; see [LICENSE](LICENSE). Only this package is MIT: the rest of the OpenRails repository is under the Functional Source License (FSL-1.1-ALv2).
|
|
@@ -13,6 +13,6 @@ export interface PaymentMethodsPanelProps {
|
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* The customer's saved cards. "Add card" offers each PSP of the merchant's
|
|
16
|
-
* payment setup (`GET /config`) that saves a card in the page.
|
|
16
|
+
* payment setup (`GET /me/config`) that saves a card in the page.
|
|
17
17
|
*/
|
|
18
18
|
export declare function PaymentMethodsPanel({ defaultCurrency, defaultCountry, appearance, className, }: PaymentMethodsPanelProps): React.JSX.Element;
|
package/dist/authenticate.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { BillingClient } from './client/client';
|
|
2
|
+
import { SubscriptionChange } from './client/types';
|
|
2
3
|
import { PspConfig } from './psp';
|
|
3
4
|
/**
|
|
4
|
-
* Completes the
|
|
5
|
-
* waits on
|
|
6
|
-
*
|
|
5
|
+
* Completes the issuer's authentication (3-D Secure) a subscription change
|
|
6
|
+
* waits on, then confirms the change and answers it. A change with no
|
|
7
|
+
* `authenticate` next action is answered as it is.
|
|
7
8
|
*/
|
|
8
|
-
export declare function
|
|
9
|
+
export declare function authenticateChange(client: BillingClient, subscriptionId: string, change: SubscriptionChange, psp: PspConfig): Promise<SubscriptionChange>;
|
package/dist/buy-button.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { CheckoutAppearance } from './appearance';
|
|
|
2
2
|
import { Order } 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;
|
|
5
7
|
/** The product's catalog key. */
|
|
6
8
|
product: string;
|
|
7
9
|
/** The price's key within the product. */
|
|
@@ -30,8 +32,8 @@ export interface BuyButtonProps {
|
|
|
30
32
|
appearance?: CheckoutAppearance;
|
|
31
33
|
className?: string;
|
|
32
34
|
}
|
|
33
|
-
export declare function BuyButton(props: BuyButtonProps): React.JSX.Element;
|
|
34
|
-
export type PurchaseProps = Omit<BuyButtonProps, "product" | "price"> & {
|
|
35
|
+
export declare function BuyButton({ merchant, product, price: priceKey, ...props }: BuyButtonProps): React.JSX.Element;
|
|
36
|
+
export type PurchaseProps = Omit<BuyButtonProps, "merchant" | "product" | "price"> & {
|
|
35
37
|
/** The price to buy; the button waits while it is unknown. */
|
|
36
38
|
priceId?: string;
|
|
37
39
|
label: string;
|
package/dist/client/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BillingError } from './errors';
|
|
2
|
-
import { Account, CustomerLink, NetworkLinkChallenge, PublicConfig,
|
|
2
|
+
import { Account, CustomerConfig, CustomerLink, NetworkLinkChallenge, PublicConfig, CurrencyScales, ListPage, NewCard, NextAction, Cart, Order, OrderPaymentInput, Page, Payment, PaymentMethod, Product, Subscription, SubscriptionChange, SubscriptionChangePreview, Usage } from './types';
|
|
3
3
|
export interface BillingClientOptions {
|
|
4
4
|
/** OpenRails embedded mount. Default "/billing/v1". */
|
|
5
5
|
baseUrl?: string;
|
|
@@ -8,7 +8,12 @@ export interface BillingClientOptions {
|
|
|
8
8
|
* or combine the default with `getToken`.
|
|
9
9
|
*/
|
|
10
10
|
fetch?: (input: string, init: RequestInit) => Promise<Response>;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* 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
|
|
15
|
+
* `credential_expired` is then retried once with a new token.
|
|
16
|
+
*/
|
|
12
17
|
getToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
13
18
|
/** Sent as Accept-Language. */
|
|
14
19
|
language?: () => string | null | undefined;
|
|
@@ -19,10 +24,11 @@ export interface BillingClientOptions {
|
|
|
19
24
|
currencies?: CurrencyScales;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
|
-
* A public catalog lookup: the products
|
|
23
|
-
* keys), in one page.
|
|
27
|
+
* A public catalog lookup: the products of `merchant` (its id) named by
|
|
28
|
+
* `keys` (at most 100 product keys), in one page.
|
|
24
29
|
*/
|
|
25
30
|
export interface ProductListOptions {
|
|
31
|
+
merchant: string;
|
|
26
32
|
keys: string[];
|
|
27
33
|
signal?: AbortSignal;
|
|
28
34
|
}
|
|
@@ -47,6 +53,18 @@ export interface CursorOptions {
|
|
|
47
53
|
cursor?: string | null;
|
|
48
54
|
signal?: AbortSignal;
|
|
49
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* A page of the customer's usage report in `currency`, grouped by `groupBy`
|
|
58
|
+
* (event type by default). `from` and `to` are RFC 3339 or a date; left out,
|
|
59
|
+
* the month before now, or with `cursor` the window of the page it came from.
|
|
60
|
+
* `limit` is at most 1,000 groups (default 100).
|
|
61
|
+
*/
|
|
62
|
+
export interface UsageOptions extends CursorOptions {
|
|
63
|
+
currency: string;
|
|
64
|
+
groupBy?: "event_type" | "resource" | "invoker";
|
|
65
|
+
from?: string;
|
|
66
|
+
to?: string;
|
|
67
|
+
}
|
|
50
68
|
/**
|
|
51
69
|
* Signs and submits a base64 transaction with the customer's wallet and
|
|
52
70
|
* returns its signature. Throw `WalletRejectedError` when the user declines.
|
|
@@ -99,6 +117,12 @@ export declare function createBillingClient(options?: BillingClientOptions): {
|
|
|
99
117
|
setSubscriptionPaymentMethod(subscriptionId: string, paymentMethodId: string | null): Promise<Subscription>;
|
|
100
118
|
/** What `changeSubscription` would charge now and at the next renewal. */
|
|
101
119
|
previewSubscriptionChange(subscriptionId: string, change: SubscriptionChangeInput, signal?: AbortSignal): Promise<SubscriptionChangePreview>;
|
|
120
|
+
/**
|
|
121
|
+
* Reads the provider for a change awaiting the customer, after they
|
|
122
|
+
* completed its `next_action` (the issuer's authentication), and answers
|
|
123
|
+
* the change as it now stands.
|
|
124
|
+
*/
|
|
125
|
+
confirmSubscriptionChange(subscriptionId: string): Promise<SubscriptionChange>;
|
|
102
126
|
/**
|
|
103
127
|
* Moves the subscription to another price of its tier group, to other
|
|
104
128
|
* seats of a per-seat price, or both. An upgrade and more seats charge
|
|
@@ -106,7 +130,8 @@ export declare function createBillingClient(options?: BillingClientOptions): {
|
|
|
106
130
|
* Reuse `idempotencyKey` until the change resolves (`processing`, a
|
|
107
131
|
* `subscription_change_in_flight` refusal or a lost response) so the
|
|
108
132
|
* stored result replays instead of charging twice. A Solana wallet next
|
|
109
|
-
* action is completed with `signWalletAction`, then repeated with
|
|
133
|
+
* action is completed with `signWalletAction`, then repeated with
|
|
134
|
+
* `signature`; an `authenticate` one with `authenticateChange`.
|
|
110
135
|
*/
|
|
111
136
|
changeSubscription(subscriptionId: string, input: SubscriptionChangeInput & {
|
|
112
137
|
idempotencyKey: string;
|
|
@@ -180,9 +205,6 @@ export declare function createBillingClient(options?: BillingClientOptions): {
|
|
|
180
205
|
* script answered its `next_action`.
|
|
181
206
|
*/
|
|
182
207
|
confirmPaymentMethod(paymentMethodId: string): Promise<PaymentMethod>;
|
|
183
|
-
/** The provider challenge a pending payment operation is waiting on. */
|
|
184
|
-
getPaymentAuthentication(operationId: string): Promise<PaymentAuthentication>;
|
|
185
|
-
confirmPaymentAuthentication(operationId: string): Promise<void>;
|
|
186
208
|
/** `pending` when the provider is still converging (202). */
|
|
187
209
|
removePaymentMethod(paymentMethodId: string): Promise<"removed" | "pending">;
|
|
188
210
|
/**
|
|
@@ -203,8 +225,14 @@ export declare function createBillingClient(options?: BillingClientOptions): {
|
|
|
203
225
|
*/
|
|
204
226
|
getAccount(signal?: AbortSignal): Promise<Account>;
|
|
205
227
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
228
|
+
* A page of the customer's usage: its groups by total amount, largest
|
|
229
|
+
* first. Pass the answer's `next_cursor` as `cursor` for the next page.
|
|
230
|
+
*/
|
|
231
|
+
getUsage(opts: UsageOptions): Promise<Usage>;
|
|
232
|
+
/**
|
|
233
|
+
* The products `merchant` has on sale named by `keys`, each with its
|
|
234
|
+
* current prices: a public read, the same signed in or out. No keys
|
|
235
|
+
* name no products: nothing is fetched.
|
|
208
236
|
*/
|
|
209
237
|
listProducts(opts: ProductListOptions): Promise<Page<Product>>;
|
|
210
238
|
/**
|
|
@@ -221,11 +249,17 @@ export declare function createBillingClient(options?: BillingClientOptions): {
|
|
|
221
249
|
idToken: string;
|
|
222
250
|
}): Promise<CustomerLink>;
|
|
223
251
|
/**
|
|
224
|
-
* The deployment's public
|
|
225
|
-
* currency registry and the
|
|
226
|
-
*
|
|
252
|
+
* The deployment's configuration, a public read: what the mount serves,
|
|
253
|
+
* the currency registry and the captcha. React components share one
|
|
254
|
+
* copy through `useConfig()`.
|
|
227
255
|
*/
|
|
228
256
|
getConfig(signal?: AbortSignal): Promise<PublicConfig>;
|
|
257
|
+
/**
|
|
258
|
+
* The customer's merchant: its payment setup (PSPs, Solana network and
|
|
259
|
+
* tokens) and how it presents itself. React components share one copy
|
|
260
|
+
* through `useCustomerConfig()`.
|
|
261
|
+
*/
|
|
262
|
+
getCustomerConfig(signal?: AbortSignal): Promise<CustomerConfig>;
|
|
229
263
|
/** Currency code (upper case) to native-unit decimals. */
|
|
230
264
|
currencies: Readonly<Record<string, number>>;
|
|
231
265
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type OpenRailsErrorCode = "admission_captured" | "admission_not_found" | "allowance_meter_not_found" | "allowance_source_in_use" | "allowance_source_invalid" | "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_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" | "
|
|
1
|
+
export type OpenRailsErrorCode = "admission_captured" | "admission_not_found" | "allowance_meter_not_found" | "allowance_source_in_use" | "allowance_source_invalid" | "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" | "finding_action_failed" | "finding_not_actionable" | "hold_not_found" | "host_event_not_found" | "host_principal_invalid" | "hosted_checkout_unavailable" | "idempotency_key_in_progress" | "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_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_not_found" | "product_tier_group_conflict" | "product_tier_group_in_use" | "provider_cancel_held" | "provider_outcome_unknown" | "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_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;
|
|
@@ -3,7 +3,10 @@ export type OpenRailsRoute = {
|
|
|
3
3
|
path: string;
|
|
4
4
|
group: string;
|
|
5
5
|
auth: string;
|
|
6
|
-
permission:
|
|
6
|
+
permission: {
|
|
7
|
+
merchant: string | null;
|
|
8
|
+
root: string;
|
|
9
|
+
} | null;
|
|
7
10
|
sensitive: boolean;
|
|
8
11
|
mountedWhen: string | null;
|
|
9
12
|
request: string | null;
|
|
@@ -53,6 +56,20 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
53
56
|
};
|
|
54
57
|
readonly errors: readonly [];
|
|
55
58
|
readonly errorSets: readonly ["tier:public"];
|
|
59
|
+
}, {
|
|
60
|
+
readonly method: "GET";
|
|
61
|
+
readonly path: "/v1/me/config";
|
|
62
|
+
readonly group: "customer";
|
|
63
|
+
readonly auth: "customer";
|
|
64
|
+
readonly permission: null;
|
|
65
|
+
readonly sensitive: false;
|
|
66
|
+
readonly mountedWhen: null;
|
|
67
|
+
readonly request: null;
|
|
68
|
+
readonly responses: {
|
|
69
|
+
readonly 200: "CustomerConfig";
|
|
70
|
+
};
|
|
71
|
+
readonly errors: readonly ["service_unavailable"];
|
|
72
|
+
readonly errorSets: readonly ["tier:customer"];
|
|
56
73
|
}, {
|
|
57
74
|
readonly method: "POST";
|
|
58
75
|
readonly path: "/v1/me/orders/preview";
|
|
@@ -224,7 +241,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
224
241
|
readonly errorSets: readonly ["tier:customer"];
|
|
225
242
|
}, {
|
|
226
243
|
readonly method: "GET";
|
|
227
|
-
readonly path: "/v1/
|
|
244
|
+
readonly path: "/v1/products";
|
|
228
245
|
readonly group: "checkout";
|
|
229
246
|
readonly auth: "public";
|
|
230
247
|
readonly permission: null;
|
|
@@ -234,7 +251,7 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
234
251
|
readonly responses: {
|
|
235
252
|
readonly 200: "ListPage<Product>";
|
|
236
253
|
};
|
|
237
|
-
readonly errors: readonly ["invalid_query"];
|
|
254
|
+
readonly errors: readonly ["invalid_query", "resource_not_found"];
|
|
238
255
|
readonly errorSets: readonly ["tier:public", "request"];
|
|
239
256
|
}, {
|
|
240
257
|
readonly method: "POST";
|
|
@@ -336,6 +353,21 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
336
353
|
};
|
|
337
354
|
readonly errors: readonly ["authentication_required", "card_declined", "customer_action_required", "customer_email_required", "invalid_param", "payment_duplicate_refused", "payment_method_stale", "payment_provider_rejected", "price_change_currency_mismatch", "price_not_found", "product_not_found", "quantity_not_allowed", "rebill_terms_committed", "resource_conflict", "resource_not_found", "scheduled_change_exists", "service_unavailable", "solana_rpc_unavailable", "solana_transaction_refused", "subscription_change_already_scheduled", "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"];
|
|
338
355
|
readonly errorSets: readonly ["tier:customer", "request"];
|
|
356
|
+
}, {
|
|
357
|
+
readonly method: "POST";
|
|
358
|
+
readonly path: "/v1/me/subscriptions/{id}/confirm";
|
|
359
|
+
readonly group: "customer";
|
|
360
|
+
readonly auth: "customer";
|
|
361
|
+
readonly permission: null;
|
|
362
|
+
readonly sensitive: false;
|
|
363
|
+
readonly mountedWhen: null;
|
|
364
|
+
readonly request: null;
|
|
365
|
+
readonly responses: {
|
|
366
|
+
readonly 200: "SubscriptionChange";
|
|
367
|
+
readonly 202: "SubscriptionChange";
|
|
368
|
+
};
|
|
369
|
+
readonly errors: readonly ["authentication_required", "card_declined", "customer_session_required", "invalid_param", "payment_not_found", "payment_provider_rejected", "resource_conflict", "resource_not_found", "service_unavailable", "subscription_change_refused", "subscription_not_found"];
|
|
370
|
+
readonly errorSets: readonly ["tier:customer"];
|
|
339
371
|
}, {
|
|
340
372
|
readonly method: "POST";
|
|
341
373
|
readonly path: "/v1/me/subscriptions/{id}/change/preview";
|
|
@@ -404,36 +436,8 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
404
436
|
readonly responses: {
|
|
405
437
|
readonly 200: "Usage";
|
|
406
438
|
};
|
|
407
|
-
readonly errors: readonly ["currency_unsupported"];
|
|
439
|
+
readonly errors: readonly ["currency_unsupported", "invalid_cursor"];
|
|
408
440
|
readonly errorSets: readonly ["tier:customer", "request"];
|
|
409
|
-
}, {
|
|
410
|
-
readonly method: "GET";
|
|
411
|
-
readonly path: "/v1/me/payment-operations/{id}/authentication";
|
|
412
|
-
readonly group: "customer";
|
|
413
|
-
readonly auth: "customer";
|
|
414
|
-
readonly permission: null;
|
|
415
|
-
readonly sensitive: false;
|
|
416
|
-
readonly mountedWhen: null;
|
|
417
|
-
readonly request: null;
|
|
418
|
-
readonly responses: {
|
|
419
|
-
readonly 200: "StripeEngineAuthentication";
|
|
420
|
-
};
|
|
421
|
-
readonly errors: readonly ["card_attempts_blocked", "card_declined", "card_not_saved", "custodian_capture_unavailable", "customer_session_required", "idempotency_key_reused", "insufficient_funds", "invalid_param", "payment_method_required", "payment_method_stale", "payment_not_found", "payment_provider_rejected", "resource_access_denied", "resource_conflict", "resource_not_found", "service_unavailable"];
|
|
422
|
-
readonly errorSets: readonly ["tier:customer"];
|
|
423
|
-
}, {
|
|
424
|
-
readonly method: "POST";
|
|
425
|
-
readonly path: "/v1/me/payment-operations/{id}/authentication/confirm";
|
|
426
|
-
readonly group: "customer";
|
|
427
|
-
readonly auth: "customer";
|
|
428
|
-
readonly permission: null;
|
|
429
|
-
readonly sensitive: false;
|
|
430
|
-
readonly mountedWhen: null;
|
|
431
|
-
readonly request: null;
|
|
432
|
-
readonly responses: {
|
|
433
|
-
readonly 200: "PaymentOperation";
|
|
434
|
-
};
|
|
435
|
-
readonly errors: readonly ["card_attempts_blocked", "card_declined", "card_not_saved", "custodian_capture_unavailable", "customer_session_required", "idempotency_key_reused", "insufficient_funds", "invalid_param", "payment_method_required", "payment_method_stale", "payment_not_found", "payment_provider_rejected", "resource_access_denied", "resource_conflict", "resource_not_found", "service_unavailable"];
|
|
436
|
-
readonly errorSets: readonly ["tier:customer"];
|
|
437
441
|
}, {
|
|
438
442
|
readonly method: "GET";
|
|
439
443
|
readonly path: "/v1/me/payments";
|
|
@@ -547,6 +551,34 @@ export declare const OPENRAILS_ROUTES: readonly [{
|
|
|
547
551
|
};
|
|
548
552
|
readonly errors: readonly ["invalid_param", "resource_not_found", "route_not_found"];
|
|
549
553
|
readonly errorSets: readonly ["tier:customer"];
|
|
554
|
+
}, {
|
|
555
|
+
readonly method: "GET";
|
|
556
|
+
readonly path: "/v1/me/agreements";
|
|
557
|
+
readonly group: "customer";
|
|
558
|
+
readonly auth: "customer";
|
|
559
|
+
readonly permission: null;
|
|
560
|
+
readonly sensitive: false;
|
|
561
|
+
readonly mountedWhen: null;
|
|
562
|
+
readonly request: null;
|
|
563
|
+
readonly responses: {
|
|
564
|
+
readonly 200: "ListPage<Agreement>";
|
|
565
|
+
};
|
|
566
|
+
readonly errors: readonly ["invalid_cursor"];
|
|
567
|
+
readonly errorSets: readonly ["tier:customer", "request"];
|
|
568
|
+
}, {
|
|
569
|
+
readonly method: "POST";
|
|
570
|
+
readonly path: "/v1/me/agreements/{id}/revoke";
|
|
571
|
+
readonly group: "customer";
|
|
572
|
+
readonly auth: "customer";
|
|
573
|
+
readonly permission: null;
|
|
574
|
+
readonly sensitive: false;
|
|
575
|
+
readonly mountedWhen: null;
|
|
576
|
+
readonly request: null;
|
|
577
|
+
readonly responses: {
|
|
578
|
+
readonly 200: "AgreementRevocation";
|
|
579
|
+
};
|
|
580
|
+
readonly errors: readonly ["cancel_unsupported_on_rail", "customer_action_required", "invalid_param", "payment_in_progress", "provider_cancel_held", "resource_not_found", "service_unavailable", "subscription_not_active"];
|
|
581
|
+
readonly errorSets: readonly ["tier:customer"];
|
|
550
582
|
}, {
|
|
551
583
|
readonly method: "GET";
|
|
552
584
|
readonly path: "/v1/me/notifications";
|