@endorr/core-sdk 0.1.0 → 0.2.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 ADDED
@@ -0,0 +1,27 @@
1
+ # @endorr/core-sdk
2
+
3
+ ## 0.2.0 — 2026-09-11
4
+
5
+ - Billing: `client.billing.{catalogue, plans, entitlements, overview, checkout, payments, subscription, changePlan, cancel, resume, refresh, claimable, claim}` (needs the new `billing` scope; managing needs organisation owner/admin). `checkout` takes a plan (`studio`, `studio_plus`) or the `printreadysheets` add-on.
6
+ - Tokens: `client.billing.{wallet, spend, refund, buyTokens, refreshPayment}`. Denied spends throw `EndorrEntitlementError` (402 `not_entitled` / `insufficient_tokens`) carrying the access check.
7
+ - Access checks: `client.billing.check` (product, feature or action), `canUse`, `require`; offline `hasProduct`, `hasFeature`, `describeDenial`, `assertAllowed`.
8
+ - `EndorrBillingSync`: a product's server-side client — check, spend and refund for a connected user with client credentials, and report subscriptions the product still bills itself.
9
+ - `EndorrBillingSync.payments({ since, limit })`: paid charges of the add-ons that unlock your product, oldest first (for dealer commission and revenue reports once your billing runs through Endorr).
10
+ - `spend` (both clients) takes `product` when your app runs another product's tools (PrintReadySheets hosting FileFixer), so Core checks that product's entitlement.
11
+ - Next.js: `requireEntitlement`, `withEntitlement`, `entitlementErrorResponse`. React: `useEntitlements`, `useAccess`, `useWallet`, `<Entitled>`.
12
+ - `EndorrApiError.isPaymentRequired`; `StorageUsage` gains `permanent_quota_bytes` and `plan`.
13
+ - Types: `Catalogue`, `Plan`, `Addon`, `TokenPack`, `Entitlements`, `AccessCheck`, `Wallet`, `TokenTransaction`, `TokenSpend`, `Subscription`, `BillingOverview`, `BillingPayment`, `CheckoutSession`, `TokenCheckout`, `PlanChange`, `ExternalSubscriptionInput`, `Money`, `ProductKey`, `FeatureKey`, `TokenAction`.
14
+
15
+ ## 0.1.1 — 2026-09-10
16
+
17
+ - Fix: token-endpoint failures that carry Core's generic API error envelope (`{ error: { code, message } }`, e.g. rate limits) now produce a readable `EndorrOAuthError` with `error = code` instead of the message `[object Object]`. RFC 6749 `{ error, error_description }` bodies are unchanged.
18
+ - Fix: non-JSON or empty error bodies map to `server_error` with the HTTP status.
19
+ - Added since 0.1.0: `files.trash`, `files.restore`, paginated `files.recent` and `folders.children` (`{ items | folders/files, next_cursor }`), `organizations.audit`, `organizations.delete`, `organizations.resendInvite`, `teams.rename`, `me.requestEmailChange`, `me.deleteAccount`, `oauth.endSessionUrl`.
20
+
21
+ ### Breaking versus 0.1.0
22
+ - `files.recent()` returns `{ items, next_cursor }` instead of an array. Use `(await core.files.recent()).items`.
23
+ - `folders.children()` response gains `next_cursor`; existing fields are unchanged.
24
+
25
+ ## 0.1.0 — 2026-09-09
26
+
27
+ Initial release: OAuth/PKCE + token endpoints + ID-token verification, typed `/v1` client, browser uploads, Next.js login/callback handlers, React provider and hooks.
package/README.md CHANGED
@@ -77,3 +77,79 @@ await sessions.update({ accessToken: next.access_token, refreshToken: next.refre
77
77
 
78
78
  A `401` from the API or `invalid_grant` on refresh means the user disconnected your product in
79
79
  Endorr or reuse detection fired: drop your session and send them through login again.
80
+
81
+ ## Billing
82
+
83
+ Request the `billing` scope. Any member can read entitlements and check access; owners and admins manage subscriptions.
84
+ Every organisation is on Studio Free unless it pays for Studio or Studio+; PrintReadySheets is an add-on (included in Studio+).
85
+
86
+ ```ts
87
+ import { EndorrEntitlementError, hasProduct, hasFeature } from '@endorr/core-sdk';
88
+
89
+ const ent = await core.billing.entitlements(); // token's organisation
90
+ ent.plan.key; // 'free' | 'studio' | 'studio_plus'
91
+ hasProduct(ent, 'printreadysheets'); hasFeature(ent, 'batch_workflows'); // offline, for rendering
92
+
93
+ // Live check: a denial is an answer, with what fixes it.
94
+ const access = await core.billing.check({ product: 'printreadysheets' }); // or { feature } or { action, quantity }
95
+ if (!access.allowed) showUpgrade(access.addon ?? access.upgrade); // reason: not_in_plan | addon_required | insufficient_tokens
96
+ await core.billing.canUse('pixlpilot'); // boolean
97
+ await core.billing.require({ feature: 'permissions' }); // throws EndorrEntitlementError (402)
98
+
99
+ const { checkout_url, subscription } = await core.billing.checkout(orgId, { plan: 'studio', redirect_url: 'https://endorr.com/studio/settings/billing' });
100
+ // …redirect to checkout_url; on return:
101
+ await core.billing.refresh(subscription.id);
102
+ await core.billing.checkout(orgId, { plan: 'printreadysheets' }); // the add-on
103
+ await core.billing.buyTokens(orgId, { pack: 'tokens_250' });
104
+ ```
105
+
106
+ ### Tokens
107
+
108
+ ```ts
109
+ // Pay before doing the work (the wallet is locked, so jobs never overdraw it); refund if the work fails.
110
+ const { transaction } = await core.billing.spend({ action: 'upscale', idempotency_key: job.id });
111
+ try { await runUpscale(job); } catch (e) { await core.billing.refund(transaction.id); throw e; }
112
+
113
+ try { await core.billing.spend({ action: 'repair' }); }
114
+ catch (e) { if (e instanceof EndorrEntitlementError) return showTopUp(e.check.top_up, e.message); throw e; }
115
+
116
+ await core.billing.wallet(); // { balance, free_balance, paid_balance, free_resets_at, transactions }
117
+ ```
118
+
119
+ Core owns the prices (`upscale` 2, `repair` 1, `vectorize` 1; see `core.billing.catalogue()`). Only Endorr apps spend,
120
+ and only for organisations that may use them. From a back end without a user token, use the same calls on
121
+ `EndorrBillingSync` with the user's Endorr id: `sync.canUse(userId, 'filefixer')`, `sync.spend(userId, { action })`,
122
+ `sync.refund(userId, transactionId)`.
123
+
124
+ ### Subscriptions your product still bills
125
+
126
+ ```ts
127
+ import { EndorrBillingSync } from '@endorr/core-sdk';
128
+ const sync = new EndorrBillingSync({ baseUrl: 'https://auth.endorr.com', clientId: 'printreadysheets', clientSecret: process.env.ENDORR_CLIENT_SECRET! });
129
+
130
+ await sync.upsert(local.id, {
131
+ user_id: local.endorrUserId ?? null, // Endorr `sub` if the customer connected Endorr…
132
+ customer_email: local.endorrUserId ? null : user.email, // …otherwise their email; they claim it in Endorr
133
+ plan_key: 'prs_shopify', plan_name: 'PrintReadySheets via Shopify', status: 'active',
134
+ provider: 'shopify', amount: { value: '79.00', currency: 'USD' }, current_period_end: local.currentPeriodEnd.toISOString(),
135
+ manage_url: 'https://printreadysheets.com/en/dashboard/billing',
136
+ });
137
+ ```
138
+
139
+ Send the full state after every change (paid, renewed, failed, cancelled). Core never charges or cancels these.
140
+
141
+ ### Next.js and React
142
+
143
+ ```ts
144
+ import { withEntitlement, requireEntitlement, entitlementErrorResponse } from '@endorr/core-sdk/nextjs';
145
+ export const POST = withEntitlement((req) => coreFor(req), { product: 'printreadysheets' }, async (req, access) => Response.json({ ok: true }));
146
+ ```
147
+
148
+ ```tsx
149
+ import { Entitled, useAccess, useEntitlements, useWallet } from '@endorr/core-sdk/react';
150
+ <Entitled product="printreadysheets" fallback={(c) => <UpgradeCard addon={c.addon} plan={c.upgrade} />}>
151
+ <SheetBuilder />
152
+ </Entitled>
153
+ ```
154
+
155
+ `<Entitled>` only hides UI; the server-side check or `spend` is what enforces.
@@ -0,0 +1,74 @@
1
+ import type { AccessCheck, Entitlements, ExternalSubscriptionInput, ExternalSubscriptionResult, FeatureKey, ProductKey, ProductPaymentsPage, TokenAction, TokenSpend, Wallet } from './types';
2
+ export interface BillingSyncConfig {
3
+ /** Core origin, e.g. https://auth.endorr.com */
4
+ baseUrl: string;
5
+ /** Your OAuth client id, e.g. "printreadysheets". */
6
+ clientId: string;
7
+ clientSecret: string;
8
+ fetch?: typeof fetch;
9
+ }
10
+ type Check = {
11
+ product?: ProductKey;
12
+ feature?: FeatureKey;
13
+ action?: TokenAction;
14
+ quantity?: number;
15
+ organizationId?: string;
16
+ };
17
+ /**
18
+ * An app's server-side billing client. Authenticates as your OAuth client (never as a user), so keep
19
+ * it on the server. Every call about a person takes their Endorr user id (`sub`) and is accepted only
20
+ * for people who connected your app.
21
+ *
22
+ * 1. Check access and pay for work in tokens from a back-end job with no user token at hand:
23
+ *
24
+ * if (!(await sync.canUse(userId, 'printreadysheets'))) …
25
+ * const { transaction } = await sync.spend(userId, { action: 'upscale', idempotency_key: job.id });
26
+ *
27
+ * 2. Report subscriptions you still bill yourself (Shopify merchants, for example), so they appear in
28
+ * the customer's Endorr account. Needs a client enabled for billing sync. Send the complete current
29
+ * state whenever it changes; omitted fields are cleared, except the organisation link, which sticks.
30
+ */
31
+ export declare class EndorrBillingSync {
32
+ private readonly base;
33
+ private readonly f;
34
+ private readonly authorization;
35
+ constructor(cfg: BillingSyncConfig);
36
+ entitlements(userId: string, opts?: {
37
+ organizationId?: string;
38
+ }): Promise<Entitlements>;
39
+ check(userId: string, q: Check): Promise<AccessCheck>;
40
+ canUse(userId: string, product: ProductKey, q?: Omit<Check, 'product'>): Promise<boolean>;
41
+ /** Throws EndorrEntitlementError (402) when denied. */
42
+ require(userId: string, q: Check): Promise<AccessCheck>;
43
+ wallet(userId: string, opts?: {
44
+ organizationId?: string;
45
+ }): Promise<Wallet>;
46
+ /**
47
+ * Pay for work in tokens; throws EndorrEntitlementError (402 not_entitled / insufficient_tokens) when
48
+ * it may not. `product` names the product the work belongs to when your app runs another product's
49
+ * tools (PrintReadySheets hosts FileFixer): Core then checks that product instead of your own.
50
+ */
51
+ spend(userId: string, input: {
52
+ action: TokenAction;
53
+ quantity?: number;
54
+ idempotency_key?: string;
55
+ organization_id?: string;
56
+ product?: ProductKey;
57
+ }): Promise<TokenSpend>;
58
+ refund(userId: string, transactionId: string): Promise<TokenSpend>;
59
+ /**
60
+ * Paid charges of the add-ons that unlock your product, oldest first — for your own books once your
61
+ * billing runs through Endorr (dealer commission, revenue reports). Pass `next_since` back as
62
+ * `since` to page; replays are safe to skip by `id`.
63
+ */
64
+ payments(opts?: {
65
+ since?: string | Date;
66
+ limit?: number;
67
+ }): Promise<ProductPaymentsPage>;
68
+ /** Create or replace the subscription Core holds under your id. */
69
+ upsert(externalId: string, input: ExternalSubscriptionInput): Promise<ExternalSubscriptionResult>;
70
+ get(externalId: string): Promise<ExternalSubscriptionResult>;
71
+ private request;
72
+ }
73
+ export {};
74
+ //# sourceMappingURL=billing-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-sync.d.ts","sourceRoot":"","sources":["../src/billing-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAAE,YAAY,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,UAAU,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAC/J,MAAM,SAAS,CAAC;AAIjB,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAGD,KAAK,KAAK,GAAG;IAAE,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9H;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAe;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,GAAG,EAAE,iBAAiB;IAMlC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAK3F,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;IAM/C,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,GAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInG,uDAAuD;IACjD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;IAI7D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/E;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvK,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAIlE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAK5F,mEAAmE;IACnE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAIjG,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;YAI9C,OAAO;CAStB"}
@@ -0,0 +1,86 @@
1
+ import { throwForResponse } from './errors';
2
+ import { assertAllowed } from './entitlements';
3
+ /**
4
+ * An app's server-side billing client. Authenticates as your OAuth client (never as a user), so keep
5
+ * it on the server. Every call about a person takes their Endorr user id (`sub`) and is accepted only
6
+ * for people who connected your app.
7
+ *
8
+ * 1. Check access and pay for work in tokens from a back-end job with no user token at hand:
9
+ *
10
+ * if (!(await sync.canUse(userId, 'printreadysheets'))) …
11
+ * const { transaction } = await sync.spend(userId, { action: 'upscale', idempotency_key: job.id });
12
+ *
13
+ * 2. Report subscriptions you still bill yourself (Shopify merchants, for example), so they appear in
14
+ * the customer's Endorr account. Needs a client enabled for billing sync. Send the complete current
15
+ * state whenever it changes; omitted fields are cleared, except the organisation link, which sticks.
16
+ */
17
+ export class EndorrBillingSync {
18
+ base;
19
+ f;
20
+ authorization;
21
+ constructor(cfg) {
22
+ this.base = cfg.baseUrl.replace(/\/$/, '');
23
+ this.f = cfg.fetch ?? ((input, init) => fetch(input, init));
24
+ this.authorization = 'Basic ' + btoa(`${encodeURIComponent(cfg.clientId)}:${encodeURIComponent(cfg.clientSecret)}`);
25
+ }
26
+ entitlements(userId, opts = {}) {
27
+ return this.request('GET', '/v1/billing/entitlements', { user_id: userId, organization_id: opts.organizationId })
28
+ .then((r) => r.entitlements);
29
+ }
30
+ check(userId, q) {
31
+ return this.request('GET', '/v1/billing/entitlements/check', {
32
+ user_id: userId, product: q.product, feature: q.feature, action: q.action, quantity: q.quantity, organization_id: q.organizationId,
33
+ }).then((r) => r.access);
34
+ }
35
+ async canUse(userId, product, q = {}) {
36
+ return (await this.check(userId, { ...q, product })).allowed;
37
+ }
38
+ /** Throws EndorrEntitlementError (402) when denied. */
39
+ async require(userId, q) {
40
+ return assertAllowed(await this.check(userId, q));
41
+ }
42
+ wallet(userId, opts = {}) {
43
+ return this.request('GET', '/v1/billing/tokens', { user_id: userId, organization_id: opts.organizationId }).then((r) => r.wallet);
44
+ }
45
+ /**
46
+ * Pay for work in tokens; throws EndorrEntitlementError (402 not_entitled / insufficient_tokens) when
47
+ * it may not. `product` names the product the work belongs to when your app runs another product's
48
+ * tools (PrintReadySheets hosts FileFixer): Core then checks that product instead of your own.
49
+ */
50
+ spend(userId, input) {
51
+ return this.request('POST', '/v1/billing/tokens/spend', {}, { ...input, user_id: userId });
52
+ }
53
+ refund(userId, transactionId) {
54
+ return this.request('DELETE', `/v1/billing/tokens/spend/${encodeURIComponent(transactionId)}`, { user_id: userId });
55
+ }
56
+ /**
57
+ * Paid charges of the add-ons that unlock your product, oldest first — for your own books once your
58
+ * billing runs through Endorr (dealer commission, revenue reports). Pass `next_since` back as
59
+ * `since` to page; replays are safe to skip by `id`.
60
+ */
61
+ payments(opts = {}) {
62
+ const since = opts.since instanceof Date ? opts.since.toISOString() : opts.since;
63
+ return this.request('GET', '/v1/billing/product-payments', { since, limit: opts.limit });
64
+ }
65
+ /** Create or replace the subscription Core holds under your id. */
66
+ upsert(externalId, input) {
67
+ return this.request('PUT', `/v1/billing/external-subscriptions/${encodeURIComponent(externalId)}`, {}, input);
68
+ }
69
+ get(externalId) {
70
+ return this.request('GET', `/v1/billing/external-subscriptions/${encodeURIComponent(externalId)}`);
71
+ }
72
+ async request(method, path, query = {}, body) {
73
+ const url = new URL(this.base + path);
74
+ for (const [k, v] of Object.entries(query))
75
+ if (v !== undefined && v !== null)
76
+ url.searchParams.set(k, String(v));
77
+ const headers = { accept: 'application/json', authorization: this.authorization };
78
+ if (body !== undefined)
79
+ headers['content-type'] = 'application/json';
80
+ const res = await this.f(url.toString(), { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined });
81
+ if (!res.ok)
82
+ await throwForResponse(res);
83
+ return (await res.json());
84
+ }
85
+ }
86
+ //# sourceMappingURL=billing-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-sync.js","sourceRoot":"","sources":["../src/billing-sync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAc/C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,iBAAiB;IACX,IAAI,CAAS;IACb,CAAC,CAAe;IAChB,aAAa,CAAS;IAEvC,YAAY,GAAsB;QAChC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5D,IAAI,CAAC,aAAa,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACtH,CAAC;IAED,YAAY,CAAC,MAAc,EAAE,OAAoC,EAAE;QACjE,OAAO,IAAI,CAAC,OAAO,CAAiC,KAAK,EAAE,0BAA0B,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;aAC9I,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,MAAc,EAAE,CAAQ;QAC5B,OAAO,IAAI,CAAC,OAAO,CAA0B,KAAK,EAAE,gCAAgC,EAAE;YACpF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC,cAAc;SACnI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,OAAmB,EAAE,IAA4B,EAAE;QAC9E,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,CAAQ;QACpC,OAAO,aAAa,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,MAAc,EAAE,OAAoC,EAAE;QAC3D,OAAO,IAAI,CAAC,OAAO,CAAqB,KAAK,EAAE,oBAAoB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACxJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAc,EAAE,KAA2H;QAC/I,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,0BAA0B,EAAE,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,CAAC,MAAc,EAAE,aAAqB;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,4BAA4B,kBAAkB,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACtH,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,OAAkD,EAAE;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACjF,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,8BAA8B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,mEAAmE;IACnE,MAAM,CAAC,UAAkB,EAAE,KAAgC;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,sCAAsC,kBAAkB,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAChH,CAAC;IAED,GAAG,CAAC,UAAkB;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,sCAAsC,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACrG,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,QAAe,EAAE,EAAE,IAAc;QACtF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACtC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;gBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAClH,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,kBAAkB,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1G,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QACrE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3H,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;IACjC,CAAC;CACF"}
package/dist/client.d.ts CHANGED
@@ -1,4 +1,14 @@
1
- import type { Me, EndorrUser, OrganizationSummary, SessionInfo, ConnectedApp, Member, Invite, Team, EndorrFile, EndorrFolder, UploadTicket, DownloadTicket, Grant, ShareLink, StorageUsage, OrgRole, ResourceRole, PrincipalType, StorageClass, ResourceType } from './types';
1
+ import type { Me, EndorrUser, OrganizationSummary, SessionInfo, ConnectedApp, Member, Invite, Team, EndorrFile, EndorrFolder, UploadTicket, DownloadTicket, Grant, ShareLink, StorageUsage, OrgRole, ResourceRole, PrincipalType, StorageClass, ResourceType, AuditEvent, Page, Plan, PlanKey, Entitlements, BillingOverview, BillingPayment, CheckoutSession, PlanChange, Subscription, AccessCheck, AddonKey, Catalogue, FeatureKey, ProductKey, TokenAction, TokenCheckout, TokenSpend, Wallet } from './types';
2
+ /** What to check: a product, a plan feature, or whether the wallet affords `quantity` × `action`. */
3
+ export interface AccessQuery {
4
+ product?: ProductKey;
5
+ feature?: FeatureKey;
6
+ action?: TokenAction;
7
+ /** Units of `action`; default 1. */
8
+ quantity?: number;
9
+ /** Defaults to the token's organisation. */
10
+ organizationId?: string;
11
+ }
2
12
  export interface ClientConfig {
3
13
  /** Core origin, e.g. https://auth.endorr.com */
4
14
  baseUrl: string;
@@ -42,6 +52,20 @@ export declare class EndorrClient {
42
52
  resendVerification: () => Promise<{
43
53
  ok: true;
44
54
  }>;
55
+ /** Starts an email change; the new address must open the verification link. */
56
+ requestEmailChange: (input: {
57
+ email: string;
58
+ current_password: string;
59
+ }) => Promise<{
60
+ ok: true;
61
+ pending_email: string;
62
+ }>;
63
+ /** Deletes the account (password confirmation). Refused while sole owner of a shared organisation. */
64
+ deleteAccount: (input: {
65
+ current_password: string;
66
+ }) => Promise<{
67
+ ok: true;
68
+ }>;
45
69
  organizations: () => Promise<OrganizationSummary[]>;
46
70
  createOrganization: (input: {
47
71
  name: string;
@@ -71,6 +95,16 @@ export declare class EndorrClient {
71
95
  update: (id: string, input: {
72
96
  name?: string;
73
97
  }) => Promise<OrganizationSummary>;
98
+ /** Owner only. Soft-deletes the organisation and its files. */
99
+ delete: (id: string) => Promise<{
100
+ ok: true;
101
+ }>;
102
+ /** Admin: privileged-activity log, newest first. */
103
+ audit: (id: string, opts?: {
104
+ limit?: number;
105
+ cursor?: string | null;
106
+ types?: string[];
107
+ }) => Promise<Page<AuditEvent>>;
74
108
  members: (id: string) => Promise<Member[]>;
75
109
  setMemberRole: (id: string, userId: string, role: OrgRole) => Promise<{
76
110
  ok: true;
@@ -86,12 +120,19 @@ export declare class EndorrClient {
86
120
  revokeInvite: (id: string, inviteId: string) => Promise<{
87
121
  ok: true;
88
122
  }>;
123
+ resendInvite: (id: string, inviteId: string) => Promise<{
124
+ ok: true;
125
+ }>;
89
126
  teams: (id: string) => Promise<Team[]>;
90
127
  createTeam: (id: string, input: {
91
128
  name: string;
92
129
  }) => Promise<Team>;
93
130
  };
94
131
  teams: {
132
+ rename: (teamId: string, name: string) => Promise<{
133
+ id: string;
134
+ name: string;
135
+ }>;
95
136
  delete: (teamId: string) => Promise<{
96
137
  ok: true;
97
138
  }>;
@@ -126,7 +167,16 @@ export declare class EndorrClient {
126
167
  delete: (fileId: string) => Promise<{
127
168
  ok: true;
128
169
  }>;
129
- recent: (limit?: number) => Promise<EndorrFile[]>;
170
+ recent: (opts?: {
171
+ limit?: number;
172
+ cursor?: string | null;
173
+ }) => Promise<Page<EndorrFile>>;
174
+ /** Soft-deleted files still recoverable. */
175
+ trash: (opts?: {
176
+ limit?: number;
177
+ cursor?: string | null;
178
+ }) => Promise<Page<EndorrFile>>;
179
+ restore: (fileId: string) => Promise<EndorrFile>;
130
180
  addRelationship: (sourceFileId: string, input: {
131
181
  derived_file_id: string;
132
182
  relationship_type: string;
@@ -145,10 +195,14 @@ export declare class EndorrClient {
145
195
  }) => Promise<EndorrFolder>;
146
196
  get: (folderId: string) => Promise<EndorrFolder>;
147
197
  /** `null` lists the organisation root. */
148
- children: (folderId: string | null) => Promise<{
198
+ children: (folderId: string | null, opts?: {
199
+ limit?: number;
200
+ cursor?: string | null;
201
+ }) => Promise<{
149
202
  folder_id: string | null;
150
203
  folders: EndorrFolder[];
151
204
  files: EndorrFile[];
205
+ next_cursor: string | null;
152
206
  }>;
153
207
  update: (folderId: string, input: {
154
208
  name?: string;
@@ -197,6 +251,60 @@ export declare class EndorrClient {
197
251
  storage: {
198
252
  usage: () => Promise<StorageUsage>;
199
253
  };
254
+ billing: {
255
+ /** Public catalogue: plans, add-ons, token packs and what each action costs. */
256
+ catalogue: () => Promise<Catalogue>;
257
+ plans: () => Promise<Plan[]>;
258
+ /** Plan, add-ons, products, features, storage and monthly tokens. Defaults to the token's organisation. */
259
+ entitlements: (organizationId?: string) => Promise<Entitlements>;
260
+ /** Entitlements, subscriptions, wallet and storage in one call, for an account page. */
261
+ overview: (organizationId: string) => Promise<BillingOverview>;
262
+ /** Subscribe to a plan (studio, studio_plus) or add an add-on (printreadysheets). Send the browser to `checkout_url`. */
263
+ checkout: (organizationId: string, input: {
264
+ plan: Exclude<PlanKey, "free"> | AddonKey;
265
+ redirect_url?: string | null;
266
+ }) => Promise<CheckoutSession>;
267
+ payments: (organizationId: string) => Promise<BillingPayment[]>;
268
+ subscription: (id: string) => Promise<Subscription>;
269
+ /** Studio ↔ Studio+. Upgrades apply once the prorated charge is paid; downgrades at the next renewal. */
270
+ changePlan: (id: string, plan: Exclude<PlanKey, "free">) => Promise<PlanChange>;
271
+ cancel: (id: string) => Promise<Subscription>;
272
+ resume: (id: string) => Promise<Subscription>;
273
+ /** Reconcile with Mollie, e.g. on the checkout return page. */
274
+ refresh: (id: string) => Promise<Subscription>;
275
+ /** Product subscriptions reported for the caller's verified email, waiting to be attached. */
276
+ claimable: () => Promise<Subscription[]>;
277
+ claim: (id: string, organizationId: string) => Promise<Subscription>;
278
+ /** Live access check. A denial is an answer, not an error: read `allowed`, `reason`, and `addon` / `upgrade` / `top_up`. */
279
+ check: (q: AccessQuery) => Promise<AccessCheck>;
280
+ /** `true` when the organisation may use the product (and afford `quantity` × `action`, if given). */
281
+ canUse: (product: ProductKey, q?: Omit<AccessQuery, "product">) => Promise<boolean>;
282
+ /** Like `check`, but throws EndorrEntitlementError (402) when denied. Use it to gate a handler. */
283
+ require: (q: AccessQuery) => Promise<AccessCheck>;
284
+ /** The token wallet: balances and the latest movements. */
285
+ wallet: (organizationId?: string) => Promise<Wallet>;
286
+ /**
287
+ * Pay for metered work in tokens (Endorr apps only). Spend before the work and `refund` if it fails;
288
+ * an idempotency key makes retries count once. Throws EndorrEntitlementError (402 not_entitled /
289
+ * insufficient_tokens) when it may not. `product` names the product the work belongs to when your
290
+ * app runs another product's tools.
291
+ */
292
+ spend: (input: {
293
+ action: TokenAction;
294
+ quantity?: number;
295
+ idempotency_key?: string;
296
+ organization_id?: string;
297
+ product?: ProductKey;
298
+ }) => Promise<TokenSpend>;
299
+ refund: (transactionId: string) => Promise<TokenSpend>;
300
+ /** Admin: buy a token pack; the tokens land once Mollie reports it paid. */
301
+ buyTokens: (organizationId: string, input: {
302
+ pack: string;
303
+ redirect_url?: string | null;
304
+ }) => Promise<TokenCheckout>;
305
+ /** Reconcile one payment with Mollie (a token pack's return page). */
306
+ refreshPayment: (paymentId: string) => Promise<BillingPayment>;
307
+ };
200
308
  }
201
309
  export {};
202
310
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { throwForResponse } from './errors';
2
+ import { assertAllowed } from './entitlements';
2
3
  /**
3
4
  * Typed client for the Endorr Core /v1 API. Every method throws EndorrApiError with the server's
4
5
  * stable `code`, so callers can branch on 403 (needs a role) vs 404 (not yours / gone).
@@ -39,6 +40,10 @@ export class EndorrClient {
39
40
  updateProfile: (input) => this.request('PATCH', '/v1/me', { body: input }),
40
41
  changePassword: (input) => this.request('POST', '/v1/me/password', { body: input }),
41
42
  resendVerification: () => this.request('POST', '/v1/me/verification/resend', { body: {} }),
43
+ /** Starts an email change; the new address must open the verification link. */
44
+ requestEmailChange: (input) => this.request('POST', '/v1/me/email', { body: input }),
45
+ /** Deletes the account (password confirmation). Refused while sole owner of a shared organisation. */
46
+ deleteAccount: (input) => this.request('DELETE', '/v1/me', { body: input }),
42
47
  organizations: () => this.request('GET', '/v1/me/organizations').then((r) => r.organizations),
43
48
  createOrganization: (input) => this.request('POST', '/v1/me/organizations', { body: input }).then((r) => r.organization),
44
49
  sessions: {
@@ -55,16 +60,22 @@ export class EndorrClient {
55
60
  organizations = {
56
61
  get: (id) => this.request('GET', `/v1/organizations/${enc(id)}`).then((r) => r.organization),
57
62
  update: (id, input) => this.request('PATCH', `/v1/organizations/${enc(id)}`, { body: input }).then((r) => r.organization),
63
+ /** Owner only. Soft-deletes the organisation and its files. */
64
+ delete: (id) => this.request('DELETE', `/v1/organizations/${enc(id)}`),
65
+ /** Admin: privileged-activity log, newest first. */
66
+ audit: (id, opts = {}) => this.request('GET', `/v1/organizations/${enc(id)}/audit`, { query: { limit: opts.limit, cursor: opts.cursor, types: opts.types?.join(',') } }).then((r) => ({ items: r.events, next_cursor: r.next_cursor })),
58
67
  members: (id) => this.request('GET', `/v1/organizations/${enc(id)}/members`).then((r) => r.members),
59
68
  setMemberRole: (id, userId, role) => this.request('PATCH', `/v1/organizations/${enc(id)}/members/${enc(userId)}`, { body: { role } }),
60
69
  removeMember: (id, userId) => this.request('DELETE', `/v1/organizations/${enc(id)}/members/${enc(userId)}`),
61
70
  invites: (id) => this.request('GET', `/v1/organizations/${enc(id)}/invites`).then((r) => r.invites),
62
71
  invite: (id, input) => this.request('POST', `/v1/organizations/${enc(id)}/invites`, { body: input }).then((r) => r.invite),
63
72
  revokeInvite: (id, inviteId) => this.request('DELETE', `/v1/organizations/${enc(id)}/invites/${enc(inviteId)}`),
73
+ resendInvite: (id, inviteId) => this.request('POST', `/v1/organizations/${enc(id)}/invites/${enc(inviteId)}/resend`, { body: {} }),
64
74
  teams: (id) => this.request('GET', `/v1/organizations/${enc(id)}/teams`).then((r) => r.teams),
65
75
  createTeam: (id, input) => this.request('POST', `/v1/organizations/${enc(id)}/teams`, { body: input }).then((r) => r.team),
66
76
  };
67
77
  teams = {
78
+ rename: (teamId, name) => this.request('PATCH', `/v1/teams/${enc(teamId)}`, { body: { name } }).then((r) => r.team),
68
79
  delete: (teamId) => this.request('DELETE', `/v1/teams/${enc(teamId)}`),
69
80
  addMember: (teamId, userId) => this.request('PUT', `/v1/teams/${enc(teamId)}/members/${enc(userId)}`, { body: {} }),
70
81
  removeMember: (teamId, userId) => this.request('DELETE', `/v1/teams/${enc(teamId)}/members/${enc(userId)}`),
@@ -78,14 +89,17 @@ export class EndorrClient {
78
89
  update: (fileId, input) => this.request('PATCH', `/v1/files/${enc(fileId)}`, { body: input }).then((r) => r.file),
79
90
  keepPermanently: (fileId) => this.files.update(fileId, { storage_class: 'permanent' }),
80
91
  delete: (fileId) => this.request('DELETE', `/v1/files/${enc(fileId)}`),
81
- recent: (limit = 20) => this.request('GET', '/v1/files/recent', { query: { limit } }).then((r) => r.files),
92
+ recent: (opts = {}) => this.request('GET', '/v1/files/recent', { query: { limit: opts.limit, cursor: opts.cursor } }).then((r) => ({ items: r.files, next_cursor: r.next_cursor })),
93
+ /** Soft-deleted files still recoverable. */
94
+ trash: (opts = {}) => this.request('GET', '/v1/files/trash', { query: { limit: opts.limit, cursor: opts.cursor } }).then((r) => ({ items: r.files, next_cursor: r.next_cursor })),
95
+ restore: (fileId) => this.request('POST', `/v1/files/${enc(fileId)}/restore`, { body: {} }).then((r) => r.file),
82
96
  addRelationship: (sourceFileId, input) => this.request('POST', `/v1/files/${enc(sourceFileId)}/relationships`, { body: input }).then((r) => r.relationship),
83
97
  };
84
98
  folders = {
85
99
  create: (input) => this.request('POST', '/v1/folders', { body: input }).then((r) => r.folder),
86
100
  get: (folderId) => this.request('GET', `/v1/folders/${enc(folderId)}`).then((r) => r.folder),
87
101
  /** `null` lists the organisation root. */
88
- children: (folderId) => this.request('GET', `/v1/folders/${folderId ? enc(folderId) : 'root'}/children`),
102
+ children: (folderId, opts = {}) => this.request('GET', `/v1/folders/${folderId ? enc(folderId) : 'root'}/children`, { query: { limit: opts.limit, cursor: opts.cursor } }),
89
103
  update: (folderId, input) => this.request('PATCH', `/v1/folders/${enc(folderId)}`, { body: input }).then((r) => r.folder),
90
104
  delete: (folderId) => this.request('DELETE', `/v1/folders/${enc(folderId)}`),
91
105
  };
@@ -103,6 +117,51 @@ export class EndorrClient {
103
117
  storage = {
104
118
  usage: () => this.request('GET', '/v1/storage/usage'),
105
119
  };
120
+ /* ── Billing (billing scope; managing needs organisation owner/admin) ───────────── */
121
+ billing = {
122
+ /** Public catalogue: plans, add-ons, token packs and what each action costs. */
123
+ catalogue: () => this.request('GET', '/v1/billing/plans'),
124
+ plans: () => this.billing.catalogue().then((c) => c.plans),
125
+ /** Plan, add-ons, products, features, storage and monthly tokens. Defaults to the token's organisation. */
126
+ entitlements: (organizationId) => this.request('GET', '/v1/billing/entitlements', { query: { organization_id: organizationId } }).then((r) => r.entitlements),
127
+ /** Entitlements, subscriptions, wallet and storage in one call, for an account page. */
128
+ overview: (organizationId) => this.request('GET', `/v1/organizations/${enc(organizationId)}/billing`),
129
+ /** Subscribe to a plan (studio, studio_plus) or add an add-on (printreadysheets). Send the browser to `checkout_url`. */
130
+ checkout: (organizationId, input) => this.request('POST', `/v1/organizations/${enc(organizationId)}/billing/checkout`, { body: input }),
131
+ payments: (organizationId) => this.request('GET', `/v1/organizations/${enc(organizationId)}/billing/payments`).then((r) => r.payments),
132
+ subscription: (id) => this.request('GET', `/v1/billing/subscriptions/${enc(id)}`).then((r) => r.subscription),
133
+ /** Studio ↔ Studio+. Upgrades apply once the prorated charge is paid; downgrades at the next renewal. */
134
+ changePlan: (id, plan) => this.request('POST', `/v1/billing/subscriptions/${enc(id)}/change-plan`, { body: { plan } }),
135
+ cancel: (id) => this.request('POST', `/v1/billing/subscriptions/${enc(id)}/cancel`, { body: {} }).then((r) => r.subscription),
136
+ resume: (id) => this.request('POST', `/v1/billing/subscriptions/${enc(id)}/resume`, { body: {} }).then((r) => r.subscription),
137
+ /** Reconcile with Mollie, e.g. on the checkout return page. */
138
+ refresh: (id) => this.request('POST', `/v1/billing/subscriptions/${enc(id)}/refresh`, { body: {} }).then((r) => r.subscription),
139
+ /** Product subscriptions reported for the caller's verified email, waiting to be attached. */
140
+ claimable: () => this.request('GET', '/v1/billing/claimable').then((r) => r.subscriptions),
141
+ claim: (id, organizationId) => this.request('POST', `/v1/billing/subscriptions/${enc(id)}/claim`, { body: { organization_id: organizationId } }).then((r) => r.subscription),
142
+ /** Live access check. A denial is an answer, not an error: read `allowed`, `reason`, and `addon` / `upgrade` / `top_up`. */
143
+ check: (q) => this.request('GET', '/v1/billing/entitlements/check', {
144
+ query: { product: q.product, feature: q.feature, action: q.action, quantity: q.quantity, organization_id: q.organizationId },
145
+ }).then((r) => r.access),
146
+ /** `true` when the organisation may use the product (and afford `quantity` × `action`, if given). */
147
+ canUse: async (product, q = {}) => (await this.billing.check({ ...q, product })).allowed,
148
+ /** Like `check`, but throws EndorrEntitlementError (402) when denied. Use it to gate a handler. */
149
+ require: async (q) => assertAllowed(await this.billing.check(q)),
150
+ /** The token wallet: balances and the latest movements. */
151
+ wallet: (organizationId) => this.request('GET', '/v1/billing/tokens', { query: { organization_id: organizationId } }).then((r) => r.wallet),
152
+ /**
153
+ * Pay for metered work in tokens (Endorr apps only). Spend before the work and `refund` if it fails;
154
+ * an idempotency key makes retries count once. Throws EndorrEntitlementError (402 not_entitled /
155
+ * insufficient_tokens) when it may not. `product` names the product the work belongs to when your
156
+ * app runs another product's tools.
157
+ */
158
+ spend: (input) => this.request('POST', '/v1/billing/tokens/spend', { body: input }),
159
+ refund: (transactionId) => this.request('DELETE', `/v1/billing/tokens/spend/${enc(transactionId)}`),
160
+ /** Admin: buy a token pack; the tokens land once Mollie reports it paid. */
161
+ buyTokens: (organizationId, input) => this.request('POST', `/v1/organizations/${enc(organizationId)}/billing/tokens/checkout`, { body: input }),
162
+ /** Reconcile one payment with Mollie (a token pack's return page). */
163
+ refreshPayment: (paymentId) => this.request('POST', `/v1/billing/payments/${enc(paymentId)}/refresh`, { body: {} }).then((r) => r.payment),
164
+ };
106
165
  }
107
166
  function enc(s) { return encodeURIComponent(s); }
108
167
  //# sourceMappingURL=client.js.map