@tuppence/node 0.0.0-stage → 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,2719 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AGENT_PROOF_HEADER: () => AGENT_PROOF_HEADER,
24
+ ApiError: () => ApiError,
25
+ AuthenticationError: () => AuthenticationError,
26
+ CardError: () => CardError,
27
+ ConnectionError: () => ConnectionError,
28
+ DEFAULT_API_VERSION: () => DEFAULT_API_VERSION,
29
+ DEFAULT_TOLERANCE_SECONDS: () => DEFAULT_TOLERANCE_SECONDS,
30
+ IdempotencyError: () => IdempotencyError,
31
+ InvalidRequestError: () => InvalidRequestError,
32
+ PermissionError: () => PermissionError,
33
+ RateLimitError: () => RateLimitError,
34
+ SIGNATURE_HEADER: () => SIGNATURE_HEADER,
35
+ SignatureVerificationError: () => SignatureVerificationError,
36
+ Tuppence: () => Tuppence,
37
+ TuppenceError: () => TuppenceError,
38
+ VERSION: () => VERSION,
39
+ constructEvent: () => constructEvent,
40
+ default: () => index_default,
41
+ signAgentProof: () => signAgentProof
42
+ });
43
+ module.exports = __toCommonJS(index_exports);
44
+
45
+ // src/errors.ts
46
+ var TuppenceError = class extends Error {
47
+ type;
48
+ code;
49
+ status;
50
+ param;
51
+ declineCode;
52
+ requestId;
53
+ /**
54
+ * The whole error object — e.g. `balance` and `topup_url` on `insufficient_credits`; `limit`,
55
+ * `used`, `max`, `resets_at` and `increase_url` on `issuing_card_limit`; `missing_evidence` on
56
+ * `dispute_evidence_incomplete`; `country`, `country_label`, `coming_soon` and `waitlist_url` on
57
+ * `country_not_supported` and `region_unavailable`.
58
+ */
59
+ raw;
60
+ constructor(body, status) {
61
+ super(body.message ?? "The Tuppence API returned an error.");
62
+ this.name = new.target.name;
63
+ this.type = body.type ?? "api_error";
64
+ this.code = body.code ?? "unknown_error";
65
+ this.status = status;
66
+ this.param = body.param;
67
+ this.declineCode = body.decline_code;
68
+ this.requestId = body.request_id;
69
+ this.raw = body;
70
+ }
71
+ /** The right subclass for an error envelope. */
72
+ static from(body, status) {
73
+ const Kind = {
74
+ invalid_request_error: InvalidRequestError,
75
+ authentication_error: AuthenticationError,
76
+ permission_error: PermissionError,
77
+ rate_limit_error: RateLimitError,
78
+ idempotency_error: IdempotencyError,
79
+ card_error: CardError
80
+ }[body.type ?? ""] ?? ApiError;
81
+ return new Kind(body, status);
82
+ }
83
+ };
84
+ var InvalidRequestError = class extends TuppenceError {
85
+ };
86
+ var AuthenticationError = class extends TuppenceError {
87
+ };
88
+ var PermissionError = class extends TuppenceError {
89
+ };
90
+ var RateLimitError = class extends TuppenceError {
91
+ };
92
+ var IdempotencyError = class extends TuppenceError {
93
+ };
94
+ var CardError = class extends TuppenceError {
95
+ };
96
+ var ApiError = class extends TuppenceError {
97
+ };
98
+ var ConnectionError = class extends TuppenceError {
99
+ constructor(message, cause) {
100
+ super({ type: "connection_error", code: "connection_failed", message });
101
+ if (cause !== void 0) this.cause = cause;
102
+ }
103
+ };
104
+ var SignatureVerificationError = class extends TuppenceError {
105
+ constructor(code, message) {
106
+ super({ type: "signature_verification_error", code, message });
107
+ }
108
+ };
109
+
110
+ // src/http.ts
111
+ var VERSION = "0.1.0";
112
+ var DEFAULT_API_VERSION = "2026-09-20";
113
+ var EncodedBody = class {
114
+ constructor(bytes, contentType) {
115
+ this.bytes = bytes;
116
+ this.contentType = contentType;
117
+ }
118
+ };
119
+ var RETRY_BASE_MS = 500;
120
+ var RETRY_MAX_MS = 8e3;
121
+ var backoff = (attempt) => Math.random() * Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** attempt);
122
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
123
+ var HttpClient = class {
124
+ constructor(apiKey, options = {}) {
125
+ this.apiKey = apiKey;
126
+ this.options = options;
127
+ if (!apiKey || typeof apiKey !== "string") {
128
+ throw new TypeError("new Tuppence(apiKey): an API key (sk_test_\u2026 or sk_live_\u2026) is required.");
129
+ }
130
+ this.baseUrl = (options.baseUrl ?? globalThis.process?.env?.TUPPENCE_API_URL ?? "https://api.tuppence.ai").replace(/\/+$/, "");
131
+ const fetcher = options.fetch ?? globalThis.fetch;
132
+ if (!fetcher)
133
+ throw new TypeError("fetch is not available: use Node 18+ or pass options.fetch.");
134
+ this.fetch = fetcher;
135
+ }
136
+ baseUrl;
137
+ fetch;
138
+ async request(method, path, { body, query, ...options } = {}) {
139
+ const url = new URL(`${this.baseUrl}${path}`);
140
+ for (const [key, value] of Object.entries(query ?? {})) {
141
+ if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
142
+ }
143
+ const headers = {
144
+ Authorization: `Bearer ${this.apiKey}`,
145
+ Accept: "application/json",
146
+ "User-Agent": `tuppence-node/${VERSION}`
147
+ };
148
+ const version = options.apiVersion ?? this.options.apiVersion;
149
+ if (version) headers["Tuppence-Version"] = version;
150
+ const account = options.tuppenceAccount ?? this.options.tuppenceAccount;
151
+ if (account) headers["Tuppence-Account"] = account;
152
+ const encoded = body instanceof EncodedBody ? body : void 0;
153
+ if (encoded) headers["Content-Type"] = encoded.contentType;
154
+ else if (body !== void 0) headers["Content-Type"] = "application/json";
155
+ if (method === "POST")
156
+ headers["Idempotency-Key"] = options.idempotencyKey ?? crypto.randomUUID();
157
+ const retries = options.maxRetries ?? this.options.maxRetries ?? 2;
158
+ const timeoutMs = options.timeoutMs ?? this.options.timeoutMs ?? 3e4;
159
+ for (let attempt = 0; ; attempt += 1) {
160
+ let response;
161
+ try {
162
+ response = await this.fetch(url, {
163
+ method,
164
+ headers,
165
+ body: encoded ? encoded.bytes : body === void 0 ? void 0 : JSON.stringify(body),
166
+ signal: AbortSignal.timeout(timeoutMs)
167
+ });
168
+ } catch (error2) {
169
+ if (attempt < retries) {
170
+ await sleep(backoff(attempt));
171
+ continue;
172
+ }
173
+ const timedOut = error2.name === "TimeoutError";
174
+ throw new ConnectionError(
175
+ timedOut ? `No answer from Tuppence within ${timeoutMs} ms (${retries + 1} attempts).` : `Could not reach Tuppence (${retries + 1} attempts): ${error2.message}`,
176
+ error2
177
+ );
178
+ }
179
+ if (response.ok) {
180
+ this.notice(response.headers.get("tuppence-notice"));
181
+ return response.status === 204 ? void 0 : await response.json();
182
+ }
183
+ const text = await response.text();
184
+ let error;
185
+ try {
186
+ error = JSON.parse(text).error ?? { message: text };
187
+ } catch {
188
+ error = { message: text || `HTTP ${response.status}` };
189
+ }
190
+ error.request_id ??= response.headers.get("request-id") ?? void 0;
191
+ if (attempt < retries && retryable(response.status, error)) {
192
+ const after = Number(response.headers.get("retry-after"));
193
+ await sleep(
194
+ Number.isFinite(after) && after > 0 ? Math.min(after * 1e3, RETRY_MAX_MS) : backoff(attempt)
195
+ );
196
+ continue;
197
+ }
198
+ throw TuppenceError.from(error, response.status);
199
+ }
200
+ }
201
+ noticed = /* @__PURE__ */ new Set();
202
+ /** `code; message` — said once per code, and never twice for the same kind of request. */
203
+ notice(header) {
204
+ if (!header) return;
205
+ const [code = "", ...rest] = header.split(";");
206
+ const message = rest.join(";").trim();
207
+ if (!code || this.noticed.has(code)) return;
208
+ this.noticed.add(code);
209
+ const handler = this.options.onNotice;
210
+ if (handler) handler({ code, message });
211
+ else console.warn(`Tuppence: ${message || code}`);
212
+ }
213
+ };
214
+ function retryable(status, error) {
215
+ return status >= 500 || status === 429 || status === 409 && error.code === "idempotency_in_progress";
216
+ }
217
+
218
+ // src/resources.ts
219
+ var id = (value) => encodeURIComponent(value);
220
+ async function* paginate(fetchPage, params = {}) {
221
+ let cursor = params.starting_after;
222
+ for (; ; ) {
223
+ const page = await fetchPage({ ...params, ...cursor ? { starting_after: cursor } : {} });
224
+ for (const item of page.data) yield item;
225
+ const last = page.data[page.data.length - 1];
226
+ if (!page.has_more || !last) return;
227
+ cursor = last.id;
228
+ }
229
+ }
230
+ function lister(http, path) {
231
+ const list = (params = {}, options) => http.request("GET", path, { query: params, ...options });
232
+ return {
233
+ list,
234
+ /** `for await (const item of listAll())` — every item, page by page. */
235
+ listAll: (params = {}, options) => paginate((p) => list({ ...params, ...p }, options))
236
+ };
237
+ }
238
+ function childLister(http, path) {
239
+ return {
240
+ list: (parentId, params = {}, options) => lister(http, path(parentId)).list(params, options),
241
+ listAll: (parentId, params = {}, options) => lister(http, path(parentId)).listAll(params, options)
242
+ };
243
+ }
244
+ async function multipart(fields, { file, filename }) {
245
+ const own = (view) => new Uint8Array(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
246
+ let blob;
247
+ if (file instanceof Blob) blob = file;
248
+ else if (file instanceof ArrayBuffer) blob = new Blob([file]);
249
+ else if (ArrayBuffer.isView(file)) blob = new Blob([own(file)]);
250
+ else {
251
+ const chunks = [];
252
+ for await (const chunk of file) chunks.push(typeof chunk === "string" ? chunk : own(chunk));
253
+ blob = new Blob(chunks);
254
+ }
255
+ const form = new FormData();
256
+ for (const [name, value] of Object.entries(fields)) form.append(name, value);
257
+ form.append(
258
+ "file",
259
+ blob,
260
+ filename ?? (typeof File !== "undefined" && file instanceof File ? file.name : "upload")
261
+ );
262
+ const encoded = new Response(form);
263
+ return new EncodedBody(
264
+ new Uint8Array(await encoded.arrayBuffer()),
265
+ encoded.headers.get("content-type") ?? "multipart/form-data"
266
+ );
267
+ }
268
+ function resources(http) {
269
+ const crud = (path) => ({
270
+ create: (body, options) => http.request("POST", path, { body, ...options }),
271
+ retrieve: (objectId, options) => http.request("GET", `${path}/${id(objectId)}`, options),
272
+ update: (objectId, body, options) => http.request("POST", `${path}/${id(objectId)}`, { body, ...options }),
273
+ ...lister(http, path)
274
+ });
275
+ return {
276
+ /** The AI agents a business runs — what its cards belong to (14-03). */
277
+ agents: {
278
+ ...crud("/v1/agents"),
279
+ /** What's normal for this agent's spending, and its latest unusual purchases (19-07). */
280
+ profile: (agentId, options) => http.request("GET", `/v1/agents/${id(agentId)}/profile`, options),
281
+ /**
282
+ * Funding mandates (54-15, E13): what a person lets an agent top the cards up with. Only a
283
+ * person signed in to the dashboard gives one (fresh second factor); a key lists and revokes.
284
+ */
285
+ fundingMandates: {
286
+ list: (agentId, params = {}, options) => http.request(
287
+ "GET",
288
+ `/v1/agents/${id(agentId)}/funding_mandates`,
289
+ { query: params, ...options }
290
+ ),
291
+ retrieve: (agentId, mandateId, options) => http.request(
292
+ "GET",
293
+ `/v1/agents/${id(agentId)}/funding_mandates/${id(mandateId)}`,
294
+ options
295
+ ),
296
+ /** Revoked at once: the agent's next top-up asks a person. */
297
+ revoke: (agentId, mandateId, options) => http.request(
298
+ "DELETE",
299
+ `/v1/agents/${id(agentId)}/funding_mandates/${id(mandateId)}`,
300
+ options
301
+ )
302
+ }
303
+ },
304
+ /** Who cards are issued to. Secret keys only (14-03). */
305
+ cardholders: crud("/v1/cardholders"),
306
+ /** The rules cards spend under: on a card, or an agent's default. Secret keys only (14-04). */
307
+ spendPolicies: crud("/v1/spend_policies"),
308
+ /**
309
+ * Cards (14-05): virtual — the business's own, or an agent's (`agent`) — or physical, a
310
+ * person's. A person sees a card's number in Stripe's own fields, in the dashboard or the app
311
+ * (14-12, 16-07); the SDK never has a method for that.
312
+ */
313
+ cards: {
314
+ create: (body, options) => http.request("POST", "/v1/cards", { body, ...options }),
315
+ retrieve: (cardId, options) => http.request("GET", `/v1/cards/${id(cardId)}`, options),
316
+ update: (cardId, body, options) => http.request("POST", `/v1/cards/${id(cardId)}`, { body, ...options }),
317
+ /** `null` removes a limit; a card always keeps at least one. */
318
+ setLimits: (cardId, body, options) => http.request("POST", `/v1/cards/${id(cardId)}/limits`, { body, ...options }),
319
+ activate: (cardId, options) => http.request("POST", `/v1/cards/${id(cardId)}/activate`, options),
320
+ freeze: (cardId, options) => http.request("POST", `/v1/cards/${id(cardId)}/freeze`, options),
321
+ unfreeze: (cardId, options) => http.request("POST", `/v1/cards/${id(cardId)}/unfreeze`, options),
322
+ cancel: (cardId, options) => http.request("POST", `/v1/cards/${id(cardId)}/cancel`, options),
323
+ /**
324
+ * An active virtual card's number, CVC and expiry — the business's own or an agent's — to
325
+ * fill in a merchant's checkout (14-22). Only a restricted key made with `card_details:read`, on an account whose
326
+ * owner has allowed it; ten a minute per key; every read is audited and sent as
327
+ * `card.details_retrieved`. The SDK keeps nothing: never store, print or log the answer.
328
+ */
329
+ retrieveDetails: (cardId, options) => http.request("GET", `/v1/cards/${id(cardId)}/details`, options),
330
+ ...lister(http, "/v1/cards")
331
+ },
332
+ /** Every purchase a card attempted, and what was decided (14-07). */
333
+ cardAuthorizations: {
334
+ retrieve: (authorizationId, options) => http.request(
335
+ "GET",
336
+ `/v1/card_authorizations/${id(authorizationId)}`,
337
+ options
338
+ ),
339
+ ...lister(http, "/v1/card_authorizations")
340
+ },
341
+ /** What settled on the cards — captures and refunds (14-08) — and each purchase's story (14-10). */
342
+ cardTransactions: {
343
+ /** With `timeline`: asked, approved, authorised, captured, refunded — oldest first. */
344
+ retrieve: (transactionId, options) => http.request("GET", `/v1/card_transactions/${id(transactionId)}`, options),
345
+ ...lister(http, "/v1/card_transactions")
346
+ },
347
+ /**
348
+ * Disputing a card purchase (53-05): a draft until submitted. Fill in the evidence, attach
349
+ * files, then submit — once; a person's act (an agent's key gets
350
+ * `dispute_submission_needs_person`, or an approval of `kind: "card_dispute_submission"`).
351
+ * Refusals: `dispute_evidence_incomplete` (`missing_evidence` in the error's `raw`),
352
+ * `dispute_window_closed` (`dispute_by`), `dispute_not_allowed` (`available_at`).
353
+ */
354
+ cardDisputes: {
355
+ /** `submit: true` sends it at once; `prefill: true` fills the evidence from what we know. */
356
+ create: (cardTransactionId, body = {}, options) => http.request(
357
+ "POST",
358
+ `/v1/card_transactions/${id(cardTransactionId)}/disputes`,
359
+ { body, ...options }
360
+ ),
361
+ retrieve: (disputeId, options) => http.request("GET", `/v1/card_disputes/${id(disputeId)}`, options),
362
+ /** A draft's evidence: fields you send replace what is saved; `null` clears one. */
363
+ update: (disputeId, body, options) => http.request("POST", `/v1/card_disputes/${id(disputeId)}`, {
364
+ body,
365
+ ...options
366
+ }),
367
+ /** Attaches a PDF or JPEG (up to 5 MB) to a draft's evidence, as multipart. */
368
+ uploadFile: async (disputeId, params, options) => http.request("POST", `/v1/card_disputes/${id(disputeId)}/files`, {
369
+ body: await multipart(params.field ? { field: params.field } : {}, params),
370
+ ...options
371
+ }),
372
+ /** Sends it to the card network. Nothing can be added after. */
373
+ submit: (disputeId, options) => http.request(
374
+ "POST",
375
+ `/v1/card_disputes/${id(disputeId)}/submit`,
376
+ options
377
+ ),
378
+ ...lister(http, "/v1/card_disputes")
379
+ },
380
+ /** The cards' own balance, its top-ups (M54) and Issuing's limits (53-03). */
381
+ issuing: {
382
+ /**
383
+ * Each card limit: its value, what is used, when it resets and where it comes from. Over
384
+ * one, a request fails with `issuing_card_limit` / `issuing_cardholder_limit` (`limit`,
385
+ * `used`, `max`, `resets_at`, `increase_url` in the error's `raw`).
386
+ */
387
+ limits: {
388
+ retrieve: (options) => http.request("GET", "/v1/issuing/limits", options)
389
+ },
390
+ /**
391
+ * What the cards can spend right now (`spendable`) — read it before buying. `spends_from`:
392
+ * `issuing_balance` (UK, topped up) or `payments_balance` (US, the earnings directly).
393
+ */
394
+ balance: {
395
+ retrieve: (options) => http.request("GET", "/v1/issuing/balance", options)
396
+ },
397
+ /** The card balance's own bank details (UK: sort code and account number). */
398
+ fundingInstructions: {
399
+ retrieve: (options) => http.request("GET", "/v1/issuing/funding_instructions", options)
400
+ },
401
+ /**
402
+ * Money on its way to the card balance, whatever the method. Until it is `available` a
403
+ * top-up says what it waits on (`delay`) and when it should be spendable
404
+ * (`expected_available_at`); `issuing_topup.*` webhooks carry every change.
405
+ */
406
+ topups: {
407
+ /**
408
+ * `{ method: "bank_transfer", amount }` (UK, free): `requires_action`, with your card
409
+ * balance's bank details and a reference in `next_action.bank_transfer`; nothing moves
410
+ * until you send it. `{ method: "balance", speed: "instant" }`: pending money onto the
411
+ * cards now, for 0.99%. Every call carries an `Idempotency-Key` (pass `idempotencyKey`
412
+ * to choose it), reused by its retries, so a retry never makes a second top-up.
413
+ */
414
+ /**
415
+ * Every way to top up that can be made now (54-07): for each `method` and `speed`,
416
+ * `available` — or `reason`, `message` and a `fix_url` — the `fee`, the `total` you pay for
417
+ * `amount` to arrive, `expected_available_at`, the `delay` it would wait on, and for
418
+ * `bank_transfer` the bank details. Leave `amount` out for rates and timings only.
419
+ */
420
+ options: (params = {}, options) => http.request("GET", "/v1/issuing/topups/options", {
421
+ query: Object.fromEntries(
422
+ Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => [k, String(v)])
423
+ ),
424
+ ...options
425
+ }),
426
+ create: (body, options) => http.request("POST", "/v1/issuing/topups", { body, ...options }),
427
+ retrieve: (topupId, options) => http.request("GET", `/v1/issuing/topups/${id(topupId)}`, options),
428
+ /** Calls off one still `requires_action` — before any money moves. */
429
+ cancel: (topupId, options) => http.request("POST", `/v1/issuing/topups/${id(topupId)}/cancel`, options),
430
+ /** Newest first; `status` and `method` filter. */
431
+ ...lister(http, "/v1/issuing/topups")
432
+ },
433
+ /**
434
+ * Hosted top-up pages (54-18): a person tops up the card balance by card, or sees its bank
435
+ * details. Single use, good for 24 hours; a connected account's page wears its platform's
436
+ * branding. In a browser, `@tuppence/js`'s `tuppence.topups.redirect({ url })` sends them.
437
+ */
438
+ topupLinks: {
439
+ /** `{ return_url, amount? }`: the answer's `url` is shown only now — send it on. */
440
+ create: (body, options) => http.request("POST", "/v1/issuing/topup_links", { body, ...options }),
441
+ /** `open`, `used` (with the `topup` made on it) or `expired`. */
442
+ retrieve: (linkId, options) => http.request("GET", `/v1/issuing/topup_links/${id(linkId)}`, options)
443
+ },
444
+ /**
445
+ * The auto top-up rule (54-15): when Spendable, plus top-ups on their way, falls below
446
+ * `threshold`, top up by `amount` — `card` (a saved top-up card) or `balance` (UK). Paused
447
+ * after a failure (`status: paused`, `fix_url`). `update` changes only what it is sent.
448
+ */
449
+ autoTopup: {
450
+ retrieve: (options) => http.request("GET", "/v1/issuing/auto_topup", options),
451
+ update: (body, options) => http.request("POST", "/v1/issuing/auto_topup", { body, ...options })
452
+ },
453
+ /**
454
+ * Your own cards saved for top-ups (54-15) — saved by a card top-up with
455
+ * `save_payment_method: true`, charged later with `{ method: "card", payment_method }`.
456
+ */
457
+ topupPaymentMethods: {
458
+ retrieve: (methodId, options) => http.request(
459
+ "GET",
460
+ `/v1/issuing/topup_payment_methods/${id(methodId)}`,
461
+ options
462
+ ),
463
+ /** Removed at Stripe too: it can't be charged again. */
464
+ remove: (methodId, options) => http.request(
465
+ "DELETE",
466
+ `/v1/issuing/topup_payment_methods/${id(methodId)}`,
467
+ options
468
+ ),
469
+ ...lister(
470
+ http,
471
+ "/v1/issuing/topup_payment_methods"
472
+ )
473
+ }
474
+ },
475
+ /** TEST MODE: make things happen that a person, a bank or a card network would. */
476
+ testHelpers: {
477
+ issuing: {
478
+ topups: {
479
+ /**
480
+ * The bank transfer for a `requires_action` bank-transfer top-up arrives — Stripe's
481
+ * test transfer, through the real arrival path. It is usually `available` in the answer;
482
+ * on a slow sandbox, retrieve it again a few seconds later.
483
+ */
484
+ arrive: (topupId, options) => http.request(
485
+ "POST",
486
+ `/v1/test_helpers/issuing/topups/${id(topupId)}/arrive`,
487
+ options
488
+ )
489
+ }
490
+ }
491
+ },
492
+ /** A person's say over a purchase at or over the threshold (14-09). Ask; poll; buy. */
493
+ approvals: {
494
+ /** Ask BEFORE buying — the merchant never sees a decline. */
495
+ create: (body, options) => http.request("POST", "/v1/approvals", { body, ...options }),
496
+ retrieve: (approvalId, options) => http.request("GET", `/v1/approvals/${id(approvalId)}`, options),
497
+ ...lister(http, "/v1/approvals")
498
+ },
499
+ account: {
500
+ retrieve: (options) => http.request("GET", "/v1/account", options),
501
+ update: (body, options) => http.request("POST", "/v1/account", { body, ...options }),
502
+ /**
503
+ * Every price the account pays now (61-12): the card rate, surcharges, next-day and instant
504
+ * payouts, the dispute fee — each the list price or one agreed with Tuppence, with its dates.
505
+ */
506
+ retrievePricing: (params = {}, options) => http.request("GET", "/v1/account/pricing", {
507
+ query: params.currency ? { currency: params.currency } : {},
508
+ ...options
509
+ })
510
+ },
511
+ /**
512
+ * Bacs Direct Debit, by application (59-11): where the business is (`status`, its limits and
513
+ * usage, the price, and `fix_url` when something stops it), applying with a reason, answering
514
+ * what we asked, withdrawing, and asking for higher limits. Tuppence staff decide; a Connect
515
+ * platform may apply for one of its connected accounts with `{ tuppenceAccount }`.
516
+ */
517
+ directDebit: {
518
+ retrieve: (options) => http.request("GET", "/v1/direct_debit", options),
519
+ apply: (body, options) => http.request("POST", "/v1/direct_debit/application", {
520
+ body,
521
+ ...options
522
+ }),
523
+ respond: (body, options) => http.request("POST", "/v1/direct_debit/application/respond", {
524
+ body,
525
+ ...options
526
+ }),
527
+ withdraw: (options) => http.request(
528
+ "POST",
529
+ "/v1/direct_debit/application/withdraw",
530
+ options
531
+ ),
532
+ requestLimitIncrease: (body, options) => http.request("POST", "/v1/direct_debit/limit_increase", {
533
+ body,
534
+ ...options
535
+ })
536
+ },
537
+ /**
538
+ * Tuppence Connect: your connected accounts (M40) — each a full Tuppence account, which you
539
+ * act as with `{ tuppenceAccount }` on any request, or through `tuppence.as("acct_…")`.
540
+ */
541
+ accounts: {
542
+ /** Made in your key's mode, with Stripe's requirements for it in `requirements`. */
543
+ create: (body, options) => http.request("POST", "/v1/accounts", { body, ...options }),
544
+ retrieve: (accountId, options) => http.request("GET", `/v1/accounts/${id(accountId)}`, options),
545
+ update: (accountId, body, options) => http.request("POST", `/v1/accounts/${id(accountId)}`, {
546
+ body,
547
+ ...options
548
+ }),
549
+ /** Closes it. In live mode, only once it holds no money. */
550
+ del: (accountId, options) => http.request("DELETE", `/v1/accounts/${id(accountId)}`, options),
551
+ /** Its store as you see it (94-09): address, status, and this month's orders, revenue and your fees. */
552
+ retrieveStore: (accountId, options) => http.request("GET", `/v1/accounts/${id(accountId)}/store`, options),
553
+ /** Stops it for good: `fraud`, `terms_of_service` or `other`. */
554
+ reject: (accountId, body, options) => http.request("POST", `/v1/accounts/${id(accountId)}/reject`, {
555
+ body,
556
+ ...options
557
+ }),
558
+ ...lister(
559
+ http,
560
+ "/v1/accounts"
561
+ ),
562
+ /** The people behind a connected account (41-04): their names and roles come back, never the details. */
563
+ persons: {
564
+ create: (accountId, body, options) => http.request("POST", `/v1/accounts/${id(accountId)}/persons`, {
565
+ body,
566
+ ...options
567
+ }),
568
+ retrieve: (accountId, personId, options) => http.request(
569
+ "GET",
570
+ `/v1/accounts/${id(accountId)}/persons/${id(personId)}`,
571
+ options
572
+ ),
573
+ update: (accountId, personId, body, options) => http.request("POST", `/v1/accounts/${id(accountId)}/persons/${id(personId)}`, {
574
+ body,
575
+ ...options
576
+ }),
577
+ del: (accountId, personId, options) => http.request(
578
+ "DELETE",
579
+ `/v1/accounts/${id(accountId)}/persons/${id(personId)}`,
580
+ options
581
+ ),
582
+ /** Their identity check: a Stripe Identity session to send them to. */
583
+ createIdentitySession: (accountId, personId, options) => http.request(
584
+ "POST",
585
+ `/v1/accounts/${id(accountId)}/persons/${id(personId)}/identity_sessions`,
586
+ options
587
+ ),
588
+ /** Filter by role: `{ "relationship[owner]": true }`. */
589
+ ...childLister(http, (accountId) => `/v1/accounts/${id(accountId)}/persons`)
590
+ },
591
+ /**
592
+ * Where a connected account is paid out (41-05, 52-09, 52-17): the details, as
593
+ * `@tuppence/js` `bankAccountDetails` shapes them — kept encrypted by Tuppence, never
594
+ * returned or logged. A bank account token (`btok_…`) is refused.
595
+ */
596
+ externalAccounts: {
597
+ create: (accountId, body, options) => http.request("POST", `/v1/accounts/${id(accountId)}/external_accounts`, {
598
+ body,
599
+ ...options
600
+ }),
601
+ retrieve: (accountId, bankId, options) => http.request(
602
+ "GET",
603
+ `/v1/accounts/${id(accountId)}/external_accounts/${id(bankId)}`,
604
+ options
605
+ ),
606
+ /** `default_for_currency: true` — another becomes the default by being chosen. */
607
+ update: (accountId, bankId, body, options) => http.request(
608
+ "POST",
609
+ `/v1/accounts/${id(accountId)}/external_accounts/${id(bankId)}`,
610
+ { body, ...options }
611
+ ),
612
+ /** Never the only default for its currency. */
613
+ del: (accountId, bankId, options) => http.request(
614
+ "DELETE",
615
+ `/v1/accounts/${id(accountId)}/external_accounts/${id(bankId)}`,
616
+ options
617
+ ),
618
+ ...childLister(
619
+ http,
620
+ (accountId) => `/v1/accounts/${id(accountId)}/external_accounts`
621
+ )
622
+ },
623
+ /** What a connected account may do — `card_payments`, `transfers` — and what each needs. */
624
+ capabilities: {
625
+ list: (accountId, options) => http.request(
626
+ "GET",
627
+ `/v1/accounts/${id(accountId)}/capabilities`,
628
+ options
629
+ ),
630
+ retrieve: (accountId, capability, options) => http.request(
631
+ "GET",
632
+ `/v1/accounts/${id(accountId)}/capabilities/${id(capability)}`,
633
+ options
634
+ ),
635
+ update: (accountId, capability, body, options) => http.request(
636
+ "POST",
637
+ `/v1/accounts/${id(accountId)}/capabilities/${id(capability)}`,
638
+ { body, ...options }
639
+ )
640
+ }
641
+ },
642
+ /** Onboarding a connected account (41-01): hand the link's `url` to the account's owner. */
643
+ accountLinks: {
644
+ /** Good once and for five minutes — make it when they click, not before. */
645
+ create: (body, options) => http.request("POST", "/v1/account_links", { body, ...options })
646
+ },
647
+ /** Files for a connected account's verification (41-06), uploaded as that account. */
648
+ files: {
649
+ /** Send it as the account: `{ tuppenceAccount }`, or through `tuppence.as("acct_…")`. */
650
+ create: async (params, options) => http.request("POST", "/v1/files", {
651
+ body: await multipart({ purpose: params.purpose }, params),
652
+ ...options
653
+ }),
654
+ retrieve: (fileId, options) => http.request("GET", `/v1/files/${id(fileId)}`, options)
655
+ },
656
+ /** Your fees on your connected accounts' payments (42-01), and any you gave back. */
657
+ applicationFees: {
658
+ retrieve: (feeId, options) => http.request("GET", `/v1/application_fees/${id(feeId)}`, options),
659
+ ...lister(
660
+ http,
661
+ "/v1/application_fees"
662
+ ),
663
+ refunds: {
664
+ /** All of what is left of the fee, or `amount` of it — from your Connect balance. */
665
+ create: (feeId, body = {}, options) => http.request("POST", `/v1/application_fees/${id(feeId)}/refunds`, {
666
+ body,
667
+ ...options
668
+ }),
669
+ retrieve: (feeId, refundId, options) => http.request(
670
+ "GET",
671
+ `/v1/application_fees/${id(feeId)}/refunds/${id(refundId)}`,
672
+ options
673
+ ),
674
+ ...childLister(http, (feeId) => `/v1/application_fees/${id(feeId)}/refunds`)
675
+ }
676
+ },
677
+ /** Money from your Connect balance to a connected account (42-03), and back. */
678
+ transfers: {
679
+ create: (body, options) => http.request("POST", "/v1/transfers", { body, ...options }),
680
+ retrieve: (transferId, options) => http.request("GET", `/v1/transfers/${id(transferId)}`, options),
681
+ ...lister(http, "/v1/transfers"),
682
+ reversals: {
683
+ /** All of what is left of the transfer, or `amount` of it. */
684
+ create: (transferId, body = {}, options) => http.request("POST", `/v1/transfers/${id(transferId)}/reversals`, {
685
+ body,
686
+ ...options
687
+ }),
688
+ retrieve: (transferId, reversalId, options) => http.request(
689
+ "GET",
690
+ `/v1/transfers/${id(transferId)}/reversals/${id(reversalId)}`,
691
+ options
692
+ ),
693
+ ...childLister(
694
+ http,
695
+ (transferId) => `/v1/transfers/${id(transferId)}/reversals`
696
+ )
697
+ }
698
+ },
699
+ paymentLinks: {
700
+ create: (body, options) => http.request("POST", "/v1/payment_links", { body, ...options }),
701
+ retrieve: (linkId, options) => http.request("GET", `/v1/payment_links/${id(linkId)}`, options),
702
+ update: (linkId, body, options) => http.request("POST", `/v1/payment_links/${id(linkId)}`, { body, ...options }),
703
+ expire: (linkId, options) => http.request("POST", `/v1/payment_links/${id(linkId)}/expire`, options),
704
+ /** Takes payments again on a link the card-testing check paused (13-03), once you have looked. */
705
+ unpause: (linkId, options) => http.request("POST", `/v1/payment_links/${id(linkId)}/unpause`, options),
706
+ ...lister(http, "/v1/payment_links")
707
+ },
708
+ /** What a business sells on repeat. A plan's price never changes: a new price is a new plan. */
709
+ plans: {
710
+ create: (body, options) => http.request("POST", "/v1/plans", { body, ...options }),
711
+ retrieve: (planId, options) => http.request("GET", `/v1/plans/${id(planId)}`, options),
712
+ /** Renaming and metadata only — the price, interval and trial cannot be changed. */
713
+ update: (planId, body, options) => http.request("POST", `/v1/plans/${id(planId)}`, { body, ...options }),
714
+ /** Stops new subscriptions; the ones already on it carry on. */
715
+ archive: (planId, options) => http.request("POST", `/v1/plans/${id(planId)}/archive`, options),
716
+ ...lister(http, "/v1/plans")
717
+ },
718
+ /** Discounts on subscriptions: a percentage or an amount off, for some charges or for ever. */
719
+ coupons: {
720
+ create: (body, options) => http.request("POST", "/v1/coupons", { body, ...options }),
721
+ retrieve: (couponId, options) => http.request("GET", `/v1/coupons/${id(couponId)}`, options),
722
+ /** Stops new redemptions; subscriptions already carrying it keep it. */
723
+ archive: (couponId, options) => http.request("POST", `/v1/coupons/${id(couponId)}/archive`, options),
724
+ ...lister(http, "/v1/coupons")
725
+ },
726
+ /** What each subscription charge was for, numbered without gaps. No tax is calculated. */
727
+ invoices: {
728
+ retrieve: (invoiceId, options) => http.request("GET", `/v1/invoices/${id(invoiceId)}`, options),
729
+ ...lister(http, "/v1/invoices")
730
+ },
731
+ /** The customer portal: a one-hour link for one customer, doing only what you allow. */
732
+ portalSessions: {
733
+ create: (body, options) => http.request("POST", "/v1/portal_sessions", { body, ...options })
734
+ },
735
+ /** Codes a customer types for a coupon, matched in any case. */
736
+ promoCodes: {
737
+ create: (body, options) => http.request("POST", "/v1/promo_codes", { body, ...options }),
738
+ retrieve: (promoCodeId, options) => http.request("GET", `/v1/promo_codes/${id(promoCodeId)}`, options),
739
+ deactivate: (promoCodeId, options) => http.request("POST", `/v1/promo_codes/${id(promoCodeId)}/deactivate`, options),
740
+ ...lister(http, "/v1/promo_codes")
741
+ },
742
+ /** Someone paying for a plan, over and over, on a card they saved. */
743
+ subscriptions: {
744
+ /** Charges the first period now, unless the plan has a trial. */
745
+ create: (body, options) => http.request("POST", "/v1/subscriptions", { body, ...options }),
746
+ retrieve: (subscriptionId, options) => http.request("GET", `/v1/subscriptions/${id(subscriptionId)}`, options),
747
+ /**
748
+ * What moving to another plan would cost — the unused time credited, the remaining time
749
+ * charged. Pass the `proration_at` it returns back to `change` and the charge is this
750
+ * number to the penny.
751
+ */
752
+ preview: (subscriptionId, body, options) => http.request("POST", `/v1/subscriptions/${id(subscriptionId)}/preview`, {
753
+ body,
754
+ ...options
755
+ }),
756
+ /** A dearer plan is charged and takes effect now; a cheaper one waits for the period. */
757
+ change: (subscriptionId, body, options) => http.request("POST", `/v1/subscriptions/${id(subscriptionId)}/change`, {
758
+ body,
759
+ ...options
760
+ }),
761
+ /** Ends it — now, or with `at_period_end: true` when the period they have paid for ends. */
762
+ cancel: (subscriptionId, body, options) => http.request("POST", `/v1/subscriptions/${id(subscriptionId)}/cancel`, {
763
+ ...body ? { body } : {},
764
+ ...options
765
+ }),
766
+ /** Nothing is charged until it resumes — on `resumes_at`, or when `resume` is called. */
767
+ pause: (subscriptionId, body, options) => http.request("POST", `/v1/subscriptions/${id(subscriptionId)}/pause`, {
768
+ ...body ? { body } : {},
769
+ ...options
770
+ }),
771
+ /** Charged now if the period it had paid for is over; otherwise it simply carries on. */
772
+ resume: (subscriptionId, options) => http.request(
773
+ "POST",
774
+ `/v1/subscriptions/${id(subscriptionId)}/resume`,
775
+ options
776
+ ),
777
+ /** Takes back a cancellation set for the end of the period, before it lands. */
778
+ reactivate: (subscriptionId, options) => http.request(
779
+ "POST",
780
+ `/v1/subscriptions/${id(subscriptionId)}/reactivate`,
781
+ options
782
+ ),
783
+ ...lister(http, "/v1/subscriptions")
784
+ },
785
+ payments: {
786
+ /** Creates the payment; the payer pays at its `approval_url` (or your page, with the JS SDK). */
787
+ create: (body, options) => http.request("POST", "/v1/payments", { body, ...options }),
788
+ /** Charges a card the customer saved for off-session use, under its mandate. */
789
+ chargeSaved: (body, options) => http.request("POST", "/v1/payments/charge_saved", { body, ...options }),
790
+ retrieve: (paymentId, options) => http.request("GET", `/v1/payments/${id(paymentId)}`, options),
791
+ /** Presents a card — in test mode, one of Stripe's test cards by name (`pm_card_gb`). */
792
+ confirm: (paymentId, body, options) => http.request("POST", `/v1/payments/${id(paymentId)}/confirm`, {
793
+ body,
794
+ ...options
795
+ }),
796
+ /** Takes a held (`requires_capture`) payment — all of it, or `amount_to_capture`. */
797
+ capture: (paymentId, body = {}, options) => http.request("POST", `/v1/payments/${id(paymentId)}/capture`, {
798
+ body,
799
+ ...options
800
+ }),
801
+ cancel: (paymentId, options) => http.request("POST", `/v1/payments/${id(paymentId)}/cancel`, options),
802
+ ...lister(http, "/v1/payments")
803
+ },
804
+ refunds: {
805
+ create: (body, options) => http.request("POST", "/v1/refunds", { body, ...options }),
806
+ retrieve: (refundId, options) => http.request("GET", `/v1/refunds/${id(refundId)}`, options),
807
+ ...lister(http, "/v1/refunds")
808
+ },
809
+ customers: {
810
+ create: (body, options) => http.request("POST", "/v1/customers", { body, ...options }),
811
+ retrieve: (customerId, options) => http.request("GET", `/v1/customers/${id(customerId)}`, options),
812
+ update: (customerId, body, options) => http.request("POST", `/v1/customers/${id(customerId)}`, { body, ...options }),
813
+ ...lister(http, "/v1/customers"),
814
+ /**
815
+ * What the customer told your store's quiz they like (91-07), kept only when they ticked
816
+ * *Remember my answers*: all of it, by attribute. It orders their search, never their prices.
817
+ */
818
+ preferences: (customerId, options) => http.request(
819
+ "GET",
820
+ `/v1/customers/${id(customerId)}/preferences`,
821
+ options
822
+ )
823
+ },
824
+ balance: {
825
+ retrieve: (options) => http.request("GET", "/v1/balance", options),
826
+ /**
827
+ * Everything that moved the balance, newest first. Filters: `type` (comma-separated),
828
+ * `payout` (what that payout covered); a platform's Connect balance with `balance: "connect"`.
829
+ */
830
+ listTransactions: (params = {}, options) => http.request("GET", "/v1/balance/transactions", {
831
+ query: params,
832
+ ...options
833
+ }),
834
+ listAllTransactions: (params = {}, options) => lister(
835
+ http,
836
+ "/v1/balance/transactions"
837
+ ).listAll(params, options)
838
+ },
839
+ payouts: {
840
+ create: (body, options) => http.request("POST", "/v1/payouts", { body, ...options }),
841
+ retrieve: (payoutId, options) => http.request("GET", `/v1/payouts/${id(payoutId)}`, options),
842
+ ...lister(http, "/v1/payouts"),
843
+ /** What the payout covered, from the books: the balance before, its activity, after. */
844
+ reconciliation: (payoutId, options) => http.request(
845
+ "GET",
846
+ `/v1/payouts/${id(payoutId)}/reconciliation`,
847
+ options
848
+ ),
849
+ /**
850
+ * What an instant move would cost (0.99%, taken out of it) and what arrives — at the bank
851
+ * (the default) or, with `destination: "card_balance"`, on the card balance — and when.
852
+ * Omit `amount` for the most that could go now. A destination that can't be used still
853
+ * answers, `available: false`, with the `reason`, `message` and `fix_url`.
854
+ */
855
+ instantQuote: (params = {}, options) => http.request("GET", "/v1/payouts/instant/quote", {
856
+ query: {
857
+ ...params.amount !== void 0 ? { amount: String(params.amount) } : {},
858
+ ...params.destination ? { destination: params.destination } : {}
859
+ },
860
+ ...options
861
+ }),
862
+ /** The schedule, the bank, the limits, and instant access per destination. */
863
+ settings: (options) => http.request("GET", "/v1/payout_settings", options),
864
+ /**
865
+ * Next-day payouts (UK) on or off: 0.2% on each payment from then on, paid out the day after
866
+ * it's taken. Refused with `next_day_unavailable` (and its `reason`) until
867
+ * `settings().next_day.available` says so.
868
+ */
869
+ setNextDay: (body, options) => http.request("POST", "/v1/payout_settings/next_day", { body, ...options })
870
+ },
871
+ disputes: {
872
+ retrieve: (disputeId, options) => http.request("GET", `/v1/disputes/${id(disputeId)}`, options),
873
+ update: (disputeId, body, options) => http.request("POST", `/v1/disputes/${id(disputeId)}`, { body, ...options }),
874
+ submit: (disputeId, options) => http.request("POST", `/v1/disputes/${id(disputeId)}/submit`, options),
875
+ ...lister(http, "/v1/disputes")
876
+ },
877
+ events: {
878
+ retrieve: (eventId, options) => http.request("GET", `/v1/events/${id(eventId)}`, options),
879
+ ...lister(http, "/v1/events")
880
+ },
881
+ webhookEndpoints: {
882
+ /** The response carries the endpoint's signing `secret` — once. Store it. */
883
+ create: (body, options) => http.request("POST", "/v1/webhook_endpoints", {
884
+ body,
885
+ ...options
886
+ }),
887
+ retrieve: (endpointId, options) => http.request("GET", `/v1/webhook_endpoints/${id(endpointId)}`, options),
888
+ update: (endpointId, body, options) => http.request("POST", `/v1/webhook_endpoints/${id(endpointId)}`, {
889
+ body,
890
+ ...options
891
+ }),
892
+ del: (endpointId, options) => http.request("DELETE", `/v1/webhook_endpoints/${id(endpointId)}`, options),
893
+ ...lister(http, "/v1/webhook_endpoints")
894
+ },
895
+ /** The domains your own checkout runs on, so Apple Pay and Google Pay show there (09-13). */
896
+ paymentMethodDomains: {
897
+ create: (body, options) => http.request("POST", "/v1/payment_method_domains", {
898
+ body,
899
+ ...options
900
+ }),
901
+ retrieve: (domainId, options) => http.request(
902
+ "GET",
903
+ `/v1/payment_method_domains/${id(domainId)}`,
904
+ options
905
+ ),
906
+ /** Asks Stripe to check the domain's wallets again now. */
907
+ validate: (domainId, options) => http.request(
908
+ "POST",
909
+ `/v1/payment_method_domains/${id(domainId)}/validate`,
910
+ options
911
+ ),
912
+ del: (domainId, options) => http.request("DELETE", `/v1/payment_method_domains/${id(domainId)}`, options),
913
+ ...lister(http, "/v1/payment_method_domains")
914
+ },
915
+ meters: {
916
+ create: (body, options) => http.request("POST", "/v1/meters", { body, ...options }),
917
+ list: (options) => http.request("GET", "/v1/meters", options)
918
+ },
919
+ credits: {
920
+ /** Every customer holding credit, with the totals topped up and used. */
921
+ ...lister(http, "/v1/credits"),
922
+ retrieve: (customerId, options) => http.request("GET", `/v1/credits/${id(customerId)}`, options),
923
+ /** Sells credit: returns the top-up payment to be paid. */
924
+ topup: (customerId, body, options) => http.request("POST", `/v1/credits/${id(customerId)}/topups`, {
925
+ body,
926
+ ...options
927
+ }),
928
+ /** A customer's top-ups, newest first. */
929
+ listTopups: (customerId, params = {}, options) => http.request("GET", `/v1/credits/${id(customerId)}/topups`, {
930
+ query: params,
931
+ ...options
932
+ })
933
+ },
934
+ meterEvents: {
935
+ /**
936
+ * Records usage and draws the customer's credit down. Naturally idempotent on
937
+ * `identifier` — the same event twice is one charge, and says `replayed`.
938
+ */
939
+ create: (body, options) => http.request("POST", "/v1/meter_events", { body, ...options }),
940
+ /** Recorded usage, newest first — one `customer`'s, or one `meter`'s (name or id). */
941
+ ...lister(http, "/v1/meter_events"),
942
+ /**
943
+ * Usage per meter and per UTC day, `from`–`to` (YYYY-MM-DD, inclusive; default the last
944
+ * 30 days) — summed from the events themselves.
945
+ */
946
+ summary: (params = {}, options) => http.request("GET", "/v1/meter_events/summary", {
947
+ query: params,
948
+ ...options
949
+ })
950
+ },
951
+ // ---- Tuppence Events (M114): ticketed events, their ticket types, orders and tickets. ----
952
+ // `/v1/events` is the webhook event log, so the events themselves live under `ticketing`.
953
+ ticketing: {
954
+ /** Events: a draft from a title and `starts_at`, then on sale, off sale or cancelled. */
955
+ events: {
956
+ create: (body, options) => http.request("POST", "/v1/ticketing/events", { body, ...options }),
957
+ retrieve: (eventId, options) => http.request("GET", `/v1/ticketing/events/${id(eventId)}`, options),
958
+ update: (eventId, body, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}`, {
959
+ body,
960
+ ...options
961
+ }),
962
+ /** On sale: its page opens and `event.published` is sent. */
963
+ publish: (eventId, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}/publish`, {
964
+ body: {},
965
+ ...options
966
+ }),
967
+ /** Off sale, back to a draft. Tickets already sold stay valid. */
968
+ unpublish: (eventId, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}/unpublish`, {
969
+ body: {},
970
+ ...options
971
+ }),
972
+ /** For good: every ticket voided, every buyer refunded in full, once. */
973
+ cancel: (eventId, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}/cancel`, {
974
+ body: {},
975
+ ...options
976
+ }),
977
+ /** The guest list a door device checks guests in from, with the key to verify codes. */
978
+ checkInManifest: (eventId, options) => http.request(
979
+ "GET",
980
+ `/v1/ticketing/events/${id(eventId)}/check_in_manifest`,
981
+ options
982
+ ),
983
+ /** Gross, refunds, fees, held and released for one event. */
984
+ settlement: (eventId, options) => http.request(
985
+ "GET",
986
+ `/v1/ticketing/events/${id(eventId)}/settlement`,
987
+ options
988
+ ),
989
+ /** More dates (118-01): one (`starts_at`), a list (`dates`), or a series (`repeat`). */
990
+ addDates: (eventId, body, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}/dates`, {
991
+ body,
992
+ ...options
993
+ }),
994
+ /** Moves one date or changes its capacity; its funds hold's release follows. */
995
+ updateDate: (eventId, dateId, body, options) => http.request(
996
+ "POST",
997
+ `/v1/ticketing/events/${id(eventId)}/dates/${id(dateId)}`,
998
+ { body, ...options }
999
+ ),
1000
+ /** Removes a date nobody has ordered for; an event keeps one date at least. */
1001
+ removeDate: (eventId, dateId, options) => http.request(
1002
+ "DELETE",
1003
+ `/v1/ticketing/events/${id(eventId)}/dates/${id(dateId)}`,
1004
+ options
1005
+ ),
1006
+ /** The door, live: tickets in by gate and by type (116-07). */
1007
+ checkInCounts: (eventId, options) => http.request(
1008
+ "GET",
1009
+ `/v1/ticketing/events/${id(eventId)}/check_in_counts`,
1010
+ options
1011
+ ),
1012
+ ...lister(http, "/v1/ticketing/events")
1013
+ },
1014
+ /** Events a door can check guests in for, soonest first (116-05). */
1015
+ checkInEvents: {
1016
+ list: (options) => http.request(
1017
+ "GET",
1018
+ "/v1/ticketing/check_in_events",
1019
+ options
1020
+ )
1021
+ },
1022
+ /** Messages to an event's attendees by email, text or WhatsApp, now or scheduled (118-04). */
1023
+ messages: {
1024
+ create: (eventId, body, options) => http.request("POST", `/v1/ticketing/events/${id(eventId)}/messages`, {
1025
+ body,
1026
+ ...options
1027
+ }),
1028
+ retrieve: (messageId, options) => http.request("GET", `/v1/ticketing/messages/${id(messageId)}`, options),
1029
+ /** A scheduled message that has not gone yet. */
1030
+ cancel: (messageId, options) => http.request("POST", `/v1/ticketing/messages/${id(messageId)}/cancel`, {
1031
+ body: {},
1032
+ ...options
1033
+ }),
1034
+ ...childLister(
1035
+ http,
1036
+ (eventId) => `/v1/ticketing/events/${id(eventId)}/messages`
1037
+ )
1038
+ },
1039
+ /** Places on sold-out ticket types' waitlists, in turn (117-07). */
1040
+ waitlist: lister(http, "/v1/ticketing/waitlist"),
1041
+ /** Partners' commissions on orders made with affiliate codes (118-03). */
1042
+ commissions: lister(http, "/v1/ticketing/commissions"),
1043
+ /** The account's settings for every event: its ad pixels (118-06). */
1044
+ settings: {
1045
+ retrieve: (options) => http.request("GET", "/v1/ticketing/settings", options),
1046
+ update: (body, options) => http.request("POST", "/v1/ticketing/settings", { body, ...options })
1047
+ },
1048
+ /** Promo and access codes, typed by the buyer at checkout (114-07). */
1049
+ promoCodes: {
1050
+ create: (body, options) => http.request("POST", "/v1/ticketing/promo_codes", { body, ...options }),
1051
+ retrieve: (codeId, options) => http.request("GET", `/v1/ticketing/promo_codes/${id(codeId)}`, options),
1052
+ update: (codeId, body, options) => http.request("POST", `/v1/ticketing/promo_codes/${id(codeId)}`, {
1053
+ body,
1054
+ ...options
1055
+ }),
1056
+ del: (codeId, options) => http.request(
1057
+ "DELETE",
1058
+ `/v1/ticketing/promo_codes/${id(codeId)}`,
1059
+ options
1060
+ ),
1061
+ ...lister(http, "/v1/ticketing/promo_codes")
1062
+ },
1063
+ /** Scans at the door: a `code`, a `short_code` or a `ticket`; the first scan admits. */
1064
+ checkIns: {
1065
+ create: (body, options) => http.request("POST", "/v1/ticketing/check_ins", { body, ...options }),
1066
+ /** A device's offline scans, applied in the order they were made. */
1067
+ sync: (body, options) => http.request("POST", "/v1/ticketing/check_ins/sync", { body, ...options }),
1068
+ /** Newest first; `event` or `ticket` for one's. A refused scan has no id, so no `listAll`. */
1069
+ list: (params = {}, options) => http.request("GET", "/v1/ticketing/check_ins", {
1070
+ query: params,
1071
+ ...options
1072
+ })
1073
+ },
1074
+ /** Ticket money held until after each date, and when it is released (114-05). */
1075
+ fundsHolds: lister(http, "/v1/ticketing/funds_holds"),
1076
+ reports: {
1077
+ /** Sales by event, ticket type and source; `from` and `to` are `YYYY-MM-DD`. */
1078
+ sales: (params = {}, options) => http.request("GET", "/v1/ticketing/reports/sales", {
1079
+ query: params,
1080
+ ...options
1081
+ })
1082
+ }
1083
+ },
1084
+ /** What an event sells: free or paid, with up to five price phases before the base price. */
1085
+ ticketTypes: {
1086
+ create: (body, options) => http.request("POST", "/v1/ticket_types", { body, ...options }),
1087
+ retrieve: (typeId, options) => http.request("GET", `/v1/ticket_types/${id(typeId)}`, options),
1088
+ update: (typeId, body, options) => http.request("POST", `/v1/ticket_types/${id(typeId)}`, { body, ...options }),
1089
+ /** Off sale for good; tickets already sold stay valid. */
1090
+ archive: (typeId, options) => http.request("DELETE", `/v1/ticket_types/${id(typeId)}`, options),
1091
+ ...lister(http, "/v1/ticket_types")
1092
+ },
1093
+ /** Buyers' orders, placed on the event page; a key reads and refunds them. */
1094
+ ticketOrders: {
1095
+ retrieve: (orderId, options) => http.request("GET", `/v1/ticket_orders/${id(orderId)}`, options),
1096
+ /** In full, or `tickets` by id: they are voided and their seats go back on sale. */
1097
+ refund: (orderId, body = {}, options) => http.request("POST", `/v1/ticket_orders/${id(orderId)}/refund`, {
1098
+ body,
1099
+ ...options
1100
+ }),
1101
+ /** An approval-only event's request (118-02): approve it, and the buyer is asked to pay. */
1102
+ approve: (orderId, options) => http.request("POST", `/v1/ticket_orders/${id(orderId)}/approve`, {
1103
+ body: {},
1104
+ ...options
1105
+ }),
1106
+ /** Decline a request; its seats go back on sale. */
1107
+ decline: (orderId, options) => http.request("POST", `/v1/ticket_orders/${id(orderId)}/decline`, {
1108
+ body: {},
1109
+ ...options
1110
+ }),
1111
+ ...lister(http, "/v1/ticket_orders")
1112
+ },
1113
+ /** One admission each: its holder, status and short code. */
1114
+ tickets: {
1115
+ retrieve: (ticketId, options) => http.request("GET", `/v1/tickets/${id(ticketId)}`, options),
1116
+ /** Give it to someone else (117-06): it is voided and a new ticket issued to them. */
1117
+ transfer: (ticketId, body, options) => http.request("POST", `/v1/tickets/${id(ticketId)}/transfer`, {
1118
+ body,
1119
+ ...options
1120
+ }),
1121
+ /** Back to a sold-out type's waitlist to sell at face value (117-08). */
1122
+ return: (ticketId, options) => http.request("POST", `/v1/tickets/${id(ticketId)}/return`, {
1123
+ body: {},
1124
+ ...options
1125
+ }),
1126
+ ...lister(http, "/v1/tickets")
1127
+ },
1128
+ // ---- Bookings (M23) ----
1129
+ /** Where services happen (23-03). Every account has one from the first look. */
1130
+ locations: {
1131
+ create: (body, options) => http.request("POST", "/v1/locations", { body, ...options }),
1132
+ retrieve: (locationId, options) => http.request("GET", `/v1/locations/${id(locationId)}`, options),
1133
+ update: (locationId, body, options) => http.request("POST", `/v1/locations/${id(locationId)}`, { body, ...options }),
1134
+ archive: (locationId, options) => http.request("POST", `/v1/locations/${id(locationId)}/archive`, options),
1135
+ /** Does a mobile location cover a client — by `postcode`, or `lat` and `lng`? */
1136
+ coverage: (locationId, params, options) => http.request("GET", `/v1/locations/${id(locationId)}/coverage`, {
1137
+ query: params,
1138
+ ...options
1139
+ }),
1140
+ ...lister(http, "/v1/locations")
1141
+ },
1142
+ /**
1143
+ * The country packs (31-19): a country's tax components and classes, location tax defaults,
1144
+ * receipt rules, rounding and conventions, as data. Reference data — the same for every account,
1145
+ * readable with any key.
1146
+ */
1147
+ countryPacks: {
1148
+ /** A country's pack (`GB`, `CA`, `US`…) — or a province's or state's with `region` (`QC`, `TX`). */
1149
+ retrieve: (country, params = {}, options) => http.request("GET", `/v1/country_packs/${id(country)}`, {
1150
+ query: params,
1151
+ ...options
1152
+ })
1153
+ },
1154
+ /** Headings services are grouped under (23-04). */
1155
+ serviceCategories: {
1156
+ create: (body, options) => http.request("POST", "/v1/service_categories", { body, ...options }),
1157
+ retrieve: (categoryId, options) => http.request("GET", `/v1/service_categories/${id(categoryId)}`, options),
1158
+ update: (categoryId, body, options) => http.request("POST", `/v1/service_categories/${id(categoryId)}`, {
1159
+ body,
1160
+ ...options
1161
+ }),
1162
+ archive: (categoryId, options) => http.request(
1163
+ "POST",
1164
+ `/v1/service_categories/${id(categoryId)}/archive`,
1165
+ options
1166
+ ),
1167
+ ...lister(http, "/v1/service_categories")
1168
+ },
1169
+ /** What a business offers (23-04): duration, price, options, add-ons, what it needs, who does it. */
1170
+ services: {
1171
+ create: (body, options) => http.request("POST", "/v1/services", { body, ...options }),
1172
+ retrieve: (serviceId, options) => http.request("GET", `/v1/services/${id(serviceId)}`, options),
1173
+ update: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}`, { body, ...options }),
1174
+ archive: (serviceId, options) => http.request("POST", `/v1/services/${id(serviceId)}/archive`, options),
1175
+ createVariant: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/variants`, {
1176
+ body,
1177
+ ...options
1178
+ }),
1179
+ updateVariant: (serviceId, variantId, body, options) => http.request(
1180
+ "POST",
1181
+ `/v1/services/${id(serviceId)}/variants/${id(variantId)}`,
1182
+ { body, ...options }
1183
+ ),
1184
+ createAddon: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/addons`, {
1185
+ body,
1186
+ ...options
1187
+ }),
1188
+ updateAddon: (serviceId, addonId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/addons/${id(addonId)}`, {
1189
+ body,
1190
+ ...options
1191
+ }),
1192
+ /** The whole list of what it needs — `[{kind, count}]`; what is not here is no longer needed. */
1193
+ setResources: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/resources`, {
1194
+ body,
1195
+ ...options
1196
+ }),
1197
+ /** The whole list of who performs it; empty means everyone active does. */
1198
+ setStaff: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/staff`, {
1199
+ body,
1200
+ ...options
1201
+ }),
1202
+ setImage: (serviceId, body, options) => http.request("POST", `/v1/services/${id(serviceId)}/image`, {
1203
+ body,
1204
+ ...options
1205
+ }),
1206
+ removeImage: (serviceId, options) => http.request("DELETE", `/v1/services/${id(serviceId)}/image`, options),
1207
+ /** What it would take and cost as chosen — an option, add-ons, a person, a group. */
1208
+ quote: (serviceId, body = {}, options) => http.request("POST", `/v1/services/${id(serviceId)}/quote`, {
1209
+ body,
1210
+ ...options
1211
+ }),
1212
+ ...lister(
1213
+ http,
1214
+ "/v1/services"
1215
+ )
1216
+ },
1217
+ /** The people who perform services (23-05), and their hours. */
1218
+ staff: {
1219
+ create: (body, options) => http.request("POST", "/v1/staff", { body, ...options }),
1220
+ retrieve: (staffId, options) => http.request("GET", `/v1/staff/${id(staffId)}`, options),
1221
+ update: (staffId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}`, { body, ...options }),
1222
+ archive: (staffId, options) => http.request("POST", `/v1/staff/${id(staffId)}/archive`, options),
1223
+ setLocations: (staffId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}/locations`, {
1224
+ body,
1225
+ ...options
1226
+ }),
1227
+ setServices: (staffId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}/services`, {
1228
+ body,
1229
+ ...options
1230
+ }),
1231
+ setImage: (staffId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}/image`, { body, ...options }),
1232
+ removeImage: (staffId, options) => http.request("DELETE", `/v1/staff/${id(staffId)}/image`, options),
1233
+ /** Hours: a weekly pattern or a two-week rotation at a location, from a date. */
1234
+ createSchedule: (staffId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}/schedules`, {
1235
+ body,
1236
+ ...options
1237
+ }),
1238
+ updateSchedule: (staffId, scheduleId, body, options) => http.request("POST", `/v1/staff/${id(staffId)}/schedules/${id(scheduleId)}`, {
1239
+ body,
1240
+ ...options
1241
+ }),
1242
+ listSchedules: (staffId, options) => http.request("GET", `/v1/staff/${id(staffId)}/schedules`, options),
1243
+ /** When they actually work between two dates: hours, less time off, plus extra hours. */
1244
+ workingHours: (staffId, params, options) => http.request("GET", `/v1/staff/${id(staffId)}/working_hours`, {
1245
+ query: params,
1246
+ ...options
1247
+ }),
1248
+ ...lister(
1249
+ http,
1250
+ "/v1/staff"
1251
+ )
1252
+ },
1253
+ /** Time off, breaks, blocked time and extra hours (23-05). */
1254
+ scheduleExceptions: {
1255
+ create: (body, options) => http.request("POST", "/v1/schedule_exceptions", { body, ...options }),
1256
+ retrieve: (exceptionId, options) => http.request(
1257
+ "GET",
1258
+ `/v1/schedule_exceptions/${id(exceptionId)}`,
1259
+ options
1260
+ ),
1261
+ del: (exceptionId, options) => http.request(
1262
+ "DELETE",
1263
+ `/v1/schedule_exceptions/${id(exceptionId)}`,
1264
+ options
1265
+ ),
1266
+ ...lister(
1267
+ http,
1268
+ "/v1/schedule_exceptions"
1269
+ )
1270
+ },
1271
+ /** Rooms, chairs, baths — what a service needs besides a person (23-06). */
1272
+ resources: {
1273
+ create: (body, options) => http.request("POST", "/v1/resources", { body, ...options }),
1274
+ retrieve: (resourceId, options) => http.request("GET", `/v1/resources/${id(resourceId)}`, options),
1275
+ update: (resourceId, body, options) => http.request("POST", `/v1/resources/${id(resourceId)}`, { body, ...options }),
1276
+ archive: (resourceId, options) => http.request("POST", `/v1/resources/${id(resourceId)}/archive`, options),
1277
+ /** Could these requirements be met at a location — and if not, what is short? */
1278
+ check: (body, options) => http.request("POST", "/v1/resources/check", { body, ...options }),
1279
+ ...lister(
1280
+ http,
1281
+ "/v1/resources"
1282
+ )
1283
+ },
1284
+ /** The account's booking policy (23-07): deposits, cancellation, notice, approval, holds. */
1285
+ bookingPolicy: {
1286
+ retrieve: (options) => http.request("GET", "/v1/booking_policy", options),
1287
+ /** Every change is a new version; bookings keep the one their client accepted. */
1288
+ update: (body, options) => http.request("POST", "/v1/booking_policy", { body, ...options }),
1289
+ listVersions: (params = {}, options) => http.request("GET", "/v1/booking_policy/versions", {
1290
+ query: params,
1291
+ ...options
1292
+ }),
1293
+ /** The policy's words as a client sees them — for a service, an amount, or a draft. */
1294
+ render: (body = {}, options) => http.request("POST", "/v1/booking_policy/render", { body, ...options })
1295
+ },
1296
+ /** The business's public booking page (24-01): its address, look, content, flow — and whether it is published. */
1297
+ bookingPage: {
1298
+ retrieve: (options) => http.request("GET", "/v1/booking_page", options),
1299
+ /** Each of `theme`, `content`, `flow` and `seo` is a patch; a new `slug` keeps the old one redirecting for 90 days. */
1300
+ update: (body, options) => http.request("POST", "/v1/booking_page", { body, ...options }),
1301
+ publish: (options) => http.request("POST", "/v1/booking_page/publish", { body: {}, ...options }),
1302
+ unpublish: (options) => http.request("POST", "/v1/booking_page/unpublish", { body: {}, ...options }),
1303
+ /** Shown once; minting another retires the last. */
1304
+ createPreviewToken: (options) => http.request("POST", "/v1/booking_page/preview_token", {
1305
+ body: {},
1306
+ ...options
1307
+ }),
1308
+ /** A picture (base64 PNG or JPEG), re-encoded and shown last; at most 20. */
1309
+ addGalleryImage: (body, options) => http.request("POST", "/v1/booking_page/gallery", { body, ...options }),
1310
+ setCover: (body, options) => http.request("POST", "/v1/booking_page/cover", { body, ...options })
1311
+ },
1312
+ /** When a client could book (23-10). */
1313
+ availability: {
1314
+ /**
1315
+ * The starts between `from` and `to` (`YYYY-MM-DD`, up to 62 days) for a `service` (with
1316
+ * `variant` and `addons`) or `items` (`svc_…` or `svc_…:svar_…`, a visit of several), at a
1317
+ * `location`, with a `staff_member` or anyone.
1318
+ */
1319
+ query: (params, options) => {
1320
+ const { addons, items, ...rest } = params;
1321
+ return http.request("GET", "/v1/availability", {
1322
+ query: {
1323
+ ...rest,
1324
+ ...addons ? { addons: addons.join(",") } : {},
1325
+ ...items ? { items: items.join(",") } : {}
1326
+ },
1327
+ ...options
1328
+ });
1329
+ },
1330
+ /** The first start a client could book, on or after `from` (today by default). */
1331
+ next: (params, options) => {
1332
+ const { addons, items, ...rest } = params;
1333
+ return http.request("GET", "/v1/availability/next", {
1334
+ query: {
1335
+ ...rest,
1336
+ ...addons ? { addons: addons.join(",") } : {},
1337
+ ...items ? { items: items.join(",") } : {}
1338
+ },
1339
+ ...options
1340
+ });
1341
+ }
1342
+ },
1343
+ /** Bookings (23-11, 23-12): made from what availability offered, then their whole life. */
1344
+ bookings: {
1345
+ /** Needs an idempotency key — the SDK always sends one. `409 slot_unavailable` names other starts. */
1346
+ create: (body, options) => http.request("POST", "/v1/bookings", { body, ...options }),
1347
+ retrieve: (bookingId, options) => http.request("GET", `/v1/bookings/${id(bookingId)}`, options),
1348
+ /** Notes and metadata. When, and with whom, is `reschedule`. */
1349
+ update: (bookingId, body, options) => http.request("POST", `/v1/bookings/${id(bookingId)}`, { body, ...options }),
1350
+ /** Takes the slot for the policy's `hold_minutes` with no client yet; confirm it to book. */
1351
+ hold: (body, options) => http.request("POST", "/v1/bookings/holds", { body, ...options }),
1352
+ extendHold: (bookingId, options) => http.request("POST", `/v1/bookings/holds/${id(bookingId)}/extend`, options),
1353
+ releaseHold: (bookingId, options) => http.request("POST", `/v1/bookings/holds/${id(bookingId)}/release`, options),
1354
+ confirm: (bookingId, body = {}, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/confirm`, {
1355
+ body,
1356
+ ...options
1357
+ }),
1358
+ reschedule: (bookingId, body, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/reschedule`, {
1359
+ body,
1360
+ ...options
1361
+ }),
1362
+ /** `by: "client"` applies the policy's outcome; the business owes nothing and returns everything. */
1363
+ cancel: (bookingId, body = {}, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/cancel`, {
1364
+ body,
1365
+ ...options
1366
+ }),
1367
+ checkIn: (bookingId, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/check_in`, options),
1368
+ start: (bookingId, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/start`, options),
1369
+ complete: (bookingId, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/complete`, options),
1370
+ noShow: (bookingId, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/no_show`, options),
1371
+ approve: (bookingId, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/approve`, options),
1372
+ decline: (bookingId, body = {}, options) => http.request("POST", `/v1/bookings/${id(bookingId)}/decline`, {
1373
+ body,
1374
+ ...options
1375
+ }),
1376
+ ...lister(http, "/v1/bookings")
1377
+ },
1378
+ /** A class's sessions (23-13): scheduled, with seats. */
1379
+ classSessions: {
1380
+ create: (body, options) => http.request("POST", "/v1/class_sessions", { body, ...options }),
1381
+ retrieve: (sessionId, options) => http.request("GET", `/v1/class_sessions/${id(sessionId)}`, options),
1382
+ update: (sessionId, body, options) => http.request("POST", `/v1/class_sessions/${id(sessionId)}`, {
1383
+ body,
1384
+ ...options
1385
+ }),
1386
+ cancel: (sessionId, body = {}, options) => http.request("POST", `/v1/class_sessions/${id(sessionId)}/cancel`, {
1387
+ body,
1388
+ ...options
1389
+ }),
1390
+ ...lister(http, "/v1/class_sessions")
1391
+ },
1392
+ /** "Every Monday at 10:00 with Ana" (23-14): a rule, kept as bookings eight weeks ahead. */
1393
+ bookingSeries: {
1394
+ create: (body, options) => http.request("POST", "/v1/booking_series", { body, ...options }),
1395
+ retrieve: (seriesId, options) => http.request("GET", `/v1/booking_series/${id(seriesId)}`, options),
1396
+ /** "This and following": a new time or person from a date. */
1397
+ update: (seriesId, body, options) => http.request("POST", `/v1/booking_series/${id(seriesId)}`, {
1398
+ body,
1399
+ ...options
1400
+ }),
1401
+ skip: (seriesId, body, options) => http.request("POST", `/v1/booking_series/${id(seriesId)}/skip`, {
1402
+ body,
1403
+ ...options
1404
+ }),
1405
+ end: (seriesId, body = {}, options) => http.request("POST", `/v1/booking_series/${id(seriesId)}/end`, {
1406
+ body,
1407
+ ...options
1408
+ }),
1409
+ ...lister(http, "/v1/booking_series")
1410
+ },
1411
+ /** Wishes for a slot that is not there yet (23-15), offered the moment one frees up. */
1412
+ waitlist: {
1413
+ create: (body, options) => http.request("POST", "/v1/waitlist", { body, ...options }),
1414
+ retrieve: (entryId, options) => http.request("GET", `/v1/waitlist/${id(entryId)}`, options),
1415
+ update: (entryId, body, options) => http.request("POST", `/v1/waitlist/${id(entryId)}`, { body, ...options }),
1416
+ cancel: (entryId, options) => http.request("POST", `/v1/waitlist/${id(entryId)}/cancel`, options),
1417
+ /** Takes up the open offer: the held slot becomes the client's booking. */
1418
+ accept: (entryId, options) => http.request("POST", `/v1/waitlist/${id(entryId)}/accept`, options),
1419
+ ...lister(http, "/v1/waitlist")
1420
+ },
1421
+ // ---- The store (94-02): every store operation has a method here and in Python, which
1422
+ // `scripts/check-sdk-coverage.mjs` holds to as each store resource ships. ----
1423
+ /** Customers' reviews (M91): read them, reply, hide one, publish one. */
1424
+ reviews: {
1425
+ retrieve: (reviewId, options) => http.request("GET", `/v1/reviews/${id(reviewId)}`, options),
1426
+ /** The average and the count, as the store shows them. */
1427
+ summary: (options) => http.request("GET", "/v1/reviews/summary", options),
1428
+ reply: (reviewId, body, options) => http.request("POST", `/v1/reviews/${id(reviewId)}/reply`, { body, ...options }),
1429
+ hide: (reviewId, options) => http.request("POST", `/v1/reviews/${id(reviewId)}/hide`, { body: {}, ...options }),
1430
+ publish: (reviewId, options) => http.request("POST", `/v1/reviews/${id(reviewId)}/publish`, {
1431
+ body: {},
1432
+ ...options
1433
+ }),
1434
+ ...lister(http, "/v1/reviews")
1435
+ },
1436
+ /** What changed in the store and who changed it, each with its undo (92-01). */
1437
+ changeSets: {
1438
+ retrieve: (changeSetId, options) => http.request("GET", `/v1/change_sets/${id(changeSetId)}`, options),
1439
+ /** Undoes the change, if nothing since depends on it. */
1440
+ revert: (changeSetId, options) => http.request("POST", `/v1/change_sets/${id(changeSetId)}/revert`, {
1441
+ body: {},
1442
+ ...options
1443
+ }),
1444
+ ...lister(http, "/v1/change_sets")
1445
+ },
1446
+ /** Moving a store from another platform (93-01): files, a preview, then the run. */
1447
+ storeImports: {
1448
+ create: (body, options) => http.request("POST", "/v1/store_imports", { body, ...options }),
1449
+ retrieve: (importId, options) => http.request("GET", `/v1/store_imports/${id(importId)}`, options),
1450
+ /**
1451
+ * What a completed import's last 12 months of orders would have cost on Tuppence, beside the
1452
+ * plan you paid: a confirmed `plan`, or your own `monthly_fee`, `card_bps` and `card_fixed`.
1453
+ */
1454
+ savings: (importId, params = {}, options) => http.request("GET", `/v1/store_imports/${id(importId)}/savings`, {
1455
+ query: Object.fromEntries(
1456
+ Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => [k, String(v)])
1457
+ ),
1458
+ ...options
1459
+ }),
1460
+ update: (importId, body, options) => http.request("POST", `/v1/store_imports/${id(importId)}`, {
1461
+ body,
1462
+ ...options
1463
+ }),
1464
+ /** An export file, in parts of up to 800,000 characters. */
1465
+ addFile: (importId, body, options) => http.request("POST", `/v1/store_imports/${id(importId)}/files`, {
1466
+ body,
1467
+ ...options
1468
+ }),
1469
+ /** What would come across, writing nothing. */
1470
+ preview: (importId, options) => http.request("POST", `/v1/store_imports/${id(importId)}/preview`, {
1471
+ body: {},
1472
+ ...options
1473
+ }),
1474
+ run: (importId, options) => http.request("POST", `/v1/store_imports/${id(importId)}/run`, {
1475
+ body: {},
1476
+ ...options
1477
+ }),
1478
+ /** The stock mirror that keeps the old store and this one level while you move (live mode). */
1479
+ retrieveStockMirror: (importId, options) => http.request("GET", `/v1/store_imports/${id(importId)}/stock_mirror`, options),
1480
+ /** Turn the stock mirror on (with `credentials` after it was off) or off. */
1481
+ setStockMirror: (importId, body, options) => http.request("POST", `/v1/store_imports/${id(importId)}/stock_mirror`, {
1482
+ body,
1483
+ ...options
1484
+ }),
1485
+ ...lister(http, "/v1/store_imports")
1486
+ },
1487
+ /** The store's operator jobs (M92): what each does, its runs, briefs and examples. */
1488
+ assistantJobs: {
1489
+ list: (options) => http.request("GET", "/v1/assistant_jobs", options),
1490
+ retrieve: (jobId, options) => http.request("GET", `/v1/assistant_jobs/${id(jobId)}`, options),
1491
+ runs: childLister(http, (jobId) => `/v1/assistant_jobs/${id(jobId)}/runs`),
1492
+ listBriefs: (jobId, options) => http.request(
1493
+ "GET",
1494
+ `/v1/assistant_jobs/${id(jobId)}/briefs`,
1495
+ options
1496
+ ),
1497
+ listExamples: (jobId, options) => http.request(
1498
+ "GET",
1499
+ `/v1/assistant_jobs/${id(jobId)}/examples`,
1500
+ options
1501
+ )
1502
+ },
1503
+ /**
1504
+ * Sales per channel (90-17): orders, units, gross, discounts, refunds, the channel's own
1505
+ * fees (estimated and final apart, never Tuppence's) and net; `from`/`to` are business days.
1506
+ */
1507
+ channelReports: {
1508
+ retrieve: (params = {}, options) => http.request("GET", "/v1/reports/channels", {
1509
+ query: params,
1510
+ ...options
1511
+ })
1512
+ },
1513
+ /** The store's daily briefs (M92). */
1514
+ storeBriefs: {
1515
+ retrieve: (briefId, options) => http.request("GET", `/v1/store_briefs/${id(briefId)}`, options),
1516
+ ...lister(http, "/v1/store_briefs")
1517
+ },
1518
+ /**
1519
+ * The business's one store site (85-02): settings, domains, fonts, pages, publishing and
1520
+ * its versions. `list` answers the one site, so `data[0].id` is the site to work on.
1521
+ */
1522
+ sites: {
1523
+ list: (options) => http.request("GET", "/v1/sites", options),
1524
+ retrieve: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}`, options),
1525
+ update: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}`, { body, ...options }),
1526
+ /** Takes checkouts again after the store paused them. */
1527
+ resumeCheckouts: (siteId, options) => http.request("POST", `/v1/sites/${id(siteId)}/resume_checkouts`, {
1528
+ body: {},
1529
+ ...options
1530
+ }),
1531
+ /** A new free address; the old one redirects to it. */
1532
+ changeSlug: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/slug`, { body, ...options }),
1533
+ /** Publishes the draft as a new version, live at once. */
1534
+ publish: (siteId, body = {}, options) => http.request("POST", `/v1/sites/${id(siteId)}/publish`, { body, ...options }),
1535
+ /** Publishes the draft at `at` (Unix seconds). */
1536
+ schedule: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/schedule`, {
1537
+ body,
1538
+ ...options
1539
+ }),
1540
+ cancelSchedule: (siteId, options) => http.request("DELETE", `/v1/sites/${id(siteId)}/schedule`, options),
1541
+ /** A short-lived link to the draft, for someone without a dashboard login. */
1542
+ createPreviewToken: (siteId, options) => http.request("POST", `/v1/sites/${id(siteId)}/preview_token`, {
1543
+ body: {},
1544
+ ...options
1545
+ }),
1546
+ /** What a page would render with: the site's data for blocks you send, saving nothing. */
1547
+ renderContext: (siteId, body = {}, options) => http.request("POST", `/v1/sites/${id(siteId)}/render_context`, {
1548
+ body,
1549
+ ...options
1550
+ }),
1551
+ /** What stands between the store and taking orders, each with its fix. */
1552
+ readiness: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/readiness`, options),
1553
+ sellingAbroad: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/selling_abroad`, options),
1554
+ checklist: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/checklist`, options),
1555
+ retrieveReturnPolicy: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/return_policy`, options),
1556
+ updateReturnPolicy: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/return_policy`, {
1557
+ body,
1558
+ ...options
1559
+ }),
1560
+ /** Your own domains: add one, check its DNS records, remove it. */
1561
+ domains: {
1562
+ list: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/domains`, options),
1563
+ add: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/domains`, {
1564
+ body,
1565
+ ...options
1566
+ }),
1567
+ check: (siteId, hostname, options) => http.request(
1568
+ "POST",
1569
+ `/v1/sites/${id(siteId)}/domains/${id(hostname)}/check`,
1570
+ { body: {}, ...options }
1571
+ ),
1572
+ remove: (siteId, hostname, options) => http.request(
1573
+ "DELETE",
1574
+ `/v1/sites/${id(siteId)}/domains/${id(hostname)}`,
1575
+ options
1576
+ )
1577
+ },
1578
+ /** Moving the old store's domain here, the certificate first and the email records kept (live mode). */
1579
+ domainSwitch: {
1580
+ retrieve: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/domain_switch`, options),
1581
+ start: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/domain_switch`, {
1582
+ body,
1583
+ ...options
1584
+ }),
1585
+ check: (siteId, options) => http.request("POST", `/v1/sites/${id(siteId)}/domain_switch/check`, {
1586
+ body: {},
1587
+ ...options
1588
+ }),
1589
+ switch: (siteId, options) => http.request("POST", `/v1/sites/${id(siteId)}/domain_switch/switch`, {
1590
+ body: {},
1591
+ ...options
1592
+ }),
1593
+ rollBack: (siteId, options) => http.request("POST", `/v1/sites/${id(siteId)}/domain_switch/roll_back`, {
1594
+ body: {},
1595
+ ...options
1596
+ })
1597
+ },
1598
+ /** The site's fonts: a Google font by name, or your own file with its licence confirmed. */
1599
+ fonts: {
1600
+ list: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/fonts`, options),
1601
+ add: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/fonts`, { body, ...options }),
1602
+ remove: (siteId, family, options) => http.request("DELETE", `/v1/sites/${id(siteId)}/fonts/${id(family)}`, options)
1603
+ },
1604
+ /** The draft's pages; a change shows on the store once the site is published. */
1605
+ pages: {
1606
+ list: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/pages`, options),
1607
+ create: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/pages`, { body, ...options }),
1608
+ retrieve: (siteId, pageId, options) => http.request("GET", `/v1/sites/${id(siteId)}/pages/${id(pageId)}`, options),
1609
+ update: (siteId, pageId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/pages/${id(pageId)}`, {
1610
+ body,
1611
+ ...options
1612
+ }),
1613
+ /** Archives the page; the home page cannot be archived. */
1614
+ archive: (siteId, pageId, options) => http.request("DELETE", `/v1/sites/${id(siteId)}/pages/${id(pageId)}`, options)
1615
+ },
1616
+ /** Every published version; reverting makes an old one the draft and publishes it. */
1617
+ versions: {
1618
+ list: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/versions`, options),
1619
+ retrieve: (siteId, versionId, options) => http.request(
1620
+ "GET",
1621
+ `/v1/sites/${id(siteId)}/versions/${id(versionId)}`,
1622
+ options
1623
+ ),
1624
+ revert: (siteId, versionId, options) => http.request(
1625
+ "POST",
1626
+ `/v1/sites/${id(siteId)}/versions/${id(versionId)}/revert`,
1627
+ { body: {}, ...options }
1628
+ )
1629
+ },
1630
+ /** The design file: export the look, sections and layouts; import one into the draft. */
1631
+ exportDesign: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/design`, options),
1632
+ importDesign: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/design/import`, {
1633
+ body,
1634
+ ...options
1635
+ }),
1636
+ /** Runs a section's source through the checks, saving nothing. */
1637
+ checkSection: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/section_checks`, {
1638
+ body,
1639
+ ...options
1640
+ }),
1641
+ retrieveSectionVersion: (siteId, versionId, options) => http.request(
1642
+ "GET",
1643
+ `/v1/sites/${id(siteId)}/section_versions/${id(versionId)}`,
1644
+ options
1645
+ ),
1646
+ /** Paths shoppers asked for three or more times in a day that had no page, with suggestions. */
1647
+ listNotFound: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/not_found`, options),
1648
+ /** The site's translations in one of the business's languages (91-15): draft, approved or stale. */
1649
+ listTranslations: (siteId, params = {}, options) => http.request("GET", `/v1/sites/${id(siteId)}/translations`, {
1650
+ query: params,
1651
+ ...options
1652
+ }),
1653
+ /** Drafts the site's products in a language, in the brand voice; a person approves them. */
1654
+ draftTranslations: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/translations/draft`, {
1655
+ body,
1656
+ ...options
1657
+ }),
1658
+ /** The site's redirects (93-06), newest first, each with how often it was answered. */
1659
+ listRedirects: (siteId, params = {}, options) => http.request("GET", `/v1/sites/${id(siteId)}/redirects`, {
1660
+ query: params,
1661
+ ...options
1662
+ }),
1663
+ /** Redirect an old path (301): a chain is flattened to one hop, a loop is refused. */
1664
+ createRedirect: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/redirects`, {
1665
+ body,
1666
+ ...options
1667
+ }),
1668
+ /** Remove a redirect: the old path answers 404 again. */
1669
+ deleteRedirect: (siteId, redirectId, options) => http.request(
1670
+ "DELETE",
1671
+ `/v1/sites/${id(siteId)}/redirects/${id(redirectId)}`,
1672
+ options
1673
+ ),
1674
+ /** The design agent: a change to how the store looks, proposed for a person to approve. */
1675
+ designRuns: {
1676
+ create: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/design_runs`, {
1677
+ body,
1678
+ ...options
1679
+ }),
1680
+ retrieve: (siteId, runId, options) => http.request(
1681
+ "GET",
1682
+ `/v1/sites/${id(siteId)}/design_runs/${id(runId)}`,
1683
+ options
1684
+ )
1685
+ },
1686
+ /** The site's custom sections, each through the same checks as the agent's. */
1687
+ sections: {
1688
+ list: (siteId, options) => http.request("GET", `/v1/sites/${id(siteId)}/sections`, options),
1689
+ create: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/sections`, {
1690
+ body,
1691
+ ...options
1692
+ }),
1693
+ retrieve: (siteId, sectionId, options) => http.request(
1694
+ "GET",
1695
+ `/v1/sites/${id(siteId)}/sections/${id(sectionId)}`,
1696
+ options
1697
+ ),
1698
+ rename: (siteId, sectionId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/sections/${id(sectionId)}`, {
1699
+ body,
1700
+ ...options
1701
+ }),
1702
+ /** Takes it off every draft page; the live site keeps it until the next publish. */
1703
+ del: (siteId, sectionId, options) => http.request(
1704
+ "DELETE",
1705
+ `/v1/sites/${id(siteId)}/sections/${id(sectionId)}`,
1706
+ options
1707
+ ),
1708
+ duplicate: (siteId, sectionId, options) => http.request(
1709
+ "POST",
1710
+ `/v1/sites/${id(siteId)}/sections/${id(sectionId)}/duplicate`,
1711
+ { body: {}, ...options }
1712
+ ),
1713
+ /** An earlier version's source becomes the next version. */
1714
+ restore: (siteId, sectionId, body, options) => http.request(
1715
+ "POST",
1716
+ `/v1/sites/${id(siteId)}/sections/${id(sectionId)}/restore`,
1717
+ { body, ...options }
1718
+ ),
1719
+ /** The next version from source edited by hand; it becomes the current one. */
1720
+ edit: (siteId, sectionId, body, options) => http.request(
1721
+ "POST",
1722
+ `/v1/sites/${id(siteId)}/sections/${id(sectionId)}/versions`,
1723
+ { body, ...options }
1724
+ )
1725
+ },
1726
+ /** Code sections, only with them switched on for the site (S25). */
1727
+ codeSections: {
1728
+ list: (siteId, options) => http.request(
1729
+ "GET",
1730
+ `/v1/sites/${id(siteId)}/code_sections`,
1731
+ options
1732
+ ),
1733
+ create: (siteId, body, options) => http.request("POST", `/v1/sites/${id(siteId)}/code_sections`, {
1734
+ body,
1735
+ ...options
1736
+ }),
1737
+ retrieve: (siteId, codeId, options) => http.request(
1738
+ "GET",
1739
+ `/v1/sites/${id(siteId)}/code_sections/${id(codeId)}`,
1740
+ options
1741
+ )
1742
+ }
1743
+ },
1744
+ /**
1745
+ * The store builder and its helpers (M86): a change from a sentence, the builder's proposals,
1746
+ * a product from a photo, and the store's settings. A proposal or a snap also streams its
1747
+ * progress as Server-Sent Events for a browser; from a server, `retrieve` answers the same.
1748
+ */
1749
+ store: {
1750
+ /** A change from a sentence, proposed as a change set; nothing changes until approved. */
1751
+ proposeChange: (body, options) => http.request("POST", "/v1/store/changes", { body, ...options }),
1752
+ retrieveSettings: (options) => http.request("GET", "/v1/store/settings", options),
1753
+ /** `po_limit`: the most a restock drafts on its own; `null` restores the default. */
1754
+ updateSettings: (body, options) => http.request("POST", "/v1/store/settings", { body, ...options }),
1755
+ proposals: {
1756
+ /** Newest first, without items; `{ status: "open" }` answers the one still open. */
1757
+ list: (params = {}, options) => http.request("GET", "/v1/store/proposals", {
1758
+ query: params,
1759
+ ...options
1760
+ }),
1761
+ /** Starts the builder from any mix of a sentence, the till, a website, socials and files. */
1762
+ create: (body = {}, options) => http.request("POST", "/v1/store/proposals", { body, ...options }),
1763
+ /** The proposal with a page of its items (`group`, `limit` up to 200, `starting_after`). */
1764
+ retrieve: (proposalId, params = {}, options) => http.request("GET", `/v1/store/proposals/${id(proposalId)}`, {
1765
+ query: params,
1766
+ ...options
1767
+ }),
1768
+ /** Discards it; nothing it proposed is kept. */
1769
+ discard: (proposalId, options) => http.request("DELETE", `/v1/store/proposals/${id(proposalId)}`, options),
1770
+ /** `accept`, `reject` or `edit` (with `payload`) one item. */
1771
+ decideItem: (proposalId, itemId, body, options) => http.request(
1772
+ "POST",
1773
+ `/v1/store/proposals/${id(proposalId)}/items/${id(itemId)}`,
1774
+ { body, ...options }
1775
+ ),
1776
+ /** Redoes one item on your words, at most 3 times an item. */
1777
+ redoItem: (proposalId, itemId, body, options) => http.request(
1778
+ "POST",
1779
+ `/v1/store/proposals/${id(proposalId)}/items/${id(itemId)}/redo`,
1780
+ { body, ...options }
1781
+ ),
1782
+ /** A link to the store as the proposal would make it, never written or cached. */
1783
+ preview: (proposalId, options) => http.request("POST", `/v1/store/proposals/${id(proposalId)}/preview`, {
1784
+ body: {},
1785
+ ...options
1786
+ }),
1787
+ acceptAll: (proposalId, options) => http.request(
1788
+ "POST",
1789
+ `/v1/store/proposals/${id(proposalId)}/accept_all`,
1790
+ { body: {}, ...options }
1791
+ ),
1792
+ /** Applies every accepted item with no guess left. */
1793
+ publish: (proposalId, body = {}, options) => http.request("POST", `/v1/store/proposals/${id(proposalId)}/publish`, {
1794
+ body,
1795
+ ...options
1796
+ })
1797
+ },
1798
+ /** A product from 1 to 5 photos: a draft to price, count and publish. */
1799
+ snaps: {
1800
+ create: (body, options) => http.request("POST", "/v1/store/snaps", { body, ...options }),
1801
+ retrieve: (snapId, options) => http.request("GET", `/v1/store/snaps/${id(snapId)}`, options),
1802
+ /** Prices a ready snap's draft, counts its stock in and puts it on its channels. */
1803
+ publish: (snapId, body, options) => http.request("POST", `/v1/store/snaps/${id(snapId)}/publish`, {
1804
+ body,
1805
+ ...options
1806
+ }),
1807
+ /** A studio or lifestyle shot of the main photo, added to the draft. */
1808
+ addPhoto: (snapId, body, options) => http.request("POST", `/v1/store/snaps/${id(snapId)}/photos`, {
1809
+ body,
1810
+ ...options
1811
+ })
1812
+ }
1813
+ },
1814
+ /**
1815
+ * Fulfilment (M87): the pick list, packing, labels from the balance or your own carrier
1816
+ * account, shipping, local delivery and collection.
1817
+ */
1818
+ fulfilments: {
1819
+ /** The pick list: what is still to leave, oldest promise first. */
1820
+ ...lister(http, "/v1/fulfilments"),
1821
+ retrieve: (fulfilmentId, options) => http.request("GET", `/v1/fulfilments/${id(fulfilmentId)}`, options),
1822
+ /** Packs it by scans, with the package and weight. */
1823
+ pack: (fulfilmentId, body, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/pack`, {
1824
+ body,
1825
+ ...options
1826
+ }),
1827
+ /** The packing slip: where it goes and what is in the box, no prices. */
1828
+ packingSlip: (fulfilmentId, options) => http.request(
1829
+ "GET",
1830
+ `/v1/fulfilments/${id(fulfilmentId)}/packing_slip`,
1831
+ options
1832
+ ),
1833
+ /** What a label costs for the packed parcel, by service. */
1834
+ rates: (fulfilmentId, options) => http.request("GET", `/v1/fulfilments/${id(fulfilmentId)}/rates`, options),
1835
+ /** Buys a label; `confirm_amount` must equal the quoted price. */
1836
+ buyLabel: (fulfilmentId, body, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/label`, {
1837
+ body,
1838
+ ...options
1839
+ }),
1840
+ voidLabel: (fulfilmentId, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/label/void`, {
1841
+ body: {},
1842
+ ...options
1843
+ }),
1844
+ /** Labels for many packed parcels at once. */
1845
+ buyLabels: (body, options) => http.request("POST", "/v1/fulfilments/labels", { body, ...options }),
1846
+ /** Marks it shipped, with your own tracking number when the label was not ours. */
1847
+ ship: (fulfilmentId, body = {}, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/ship`, {
1848
+ body,
1849
+ ...options
1850
+ }),
1851
+ /** Ready to collect: the shopper is told. */
1852
+ ready: (fulfilmentId, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/ready`, {
1853
+ body: {},
1854
+ ...options
1855
+ }),
1856
+ /** Hands over a collection by the shopper's code. */
1857
+ collect: (body, options) => http.request("POST", "/v1/fulfilments/collect", { body, ...options }),
1858
+ /** A local delivery leaves. */
1859
+ outForDelivery: (fulfilmentId, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/out_for_delivery`, {
1860
+ body: {},
1861
+ ...options
1862
+ }),
1863
+ delivered: (fulfilmentId, options) => http.request("POST", `/v1/fulfilments/${id(fulfilmentId)}/delivered`, {
1864
+ body: {},
1865
+ ...options
1866
+ })
1867
+ },
1868
+ /** Returns and exchanges (87-09): requested, approved, on their way back, received, closed. */
1869
+ returns: {
1870
+ ...lister(http, "/v1/returns"),
1871
+ create: (body, options) => http.request("POST", "/v1/returns", { body, ...options }),
1872
+ retrieve: (returnId, options) => http.request("GET", `/v1/returns/${id(returnId)}`, options),
1873
+ /** Finds the order a parcel or a receipt's code belongs to, at the counter. */
1874
+ scan: (body, options) => http.request("POST", "/v1/returns/scan", { body, ...options }),
1875
+ approve: (returnId, body = {}, options) => http.request("POST", `/v1/returns/${id(returnId)}/approve`, { body, ...options }),
1876
+ reject: (returnId, body = {}, options) => http.request("POST", `/v1/returns/${id(returnId)}/reject`, { body, ...options }),
1877
+ /** Received back; the refund or exchange follows the return's terms. */
1878
+ receive: (returnId, body = {}, options) => http.request("POST", `/v1/returns/${id(returnId)}/receive`, { body, ...options }),
1879
+ /** How the parcel can come back: a label, a drop-off, a shop. */
1880
+ waysBack: (returnId, options) => http.request("GET", `/v1/returns/${id(returnId)}/ways_back`, options),
1881
+ chooseWayBack: (returnId, body, options) => http.request("POST", `/v1/returns/${id(returnId)}/way_back`, { body, ...options }),
1882
+ close: (returnId, options) => http.request("POST", `/v1/returns/${id(returnId)}/close`, {
1883
+ body: {},
1884
+ ...options
1885
+ })
1886
+ },
1887
+ /** Closing the shipping day (87-10): the manifest for the carrier. */
1888
+ shippingManifests: {
1889
+ ...lister(http, "/v1/shipping_manifests"),
1890
+ retrieve: (manifestId, options) => http.request("GET", `/v1/shipping_manifests/${id(manifestId)}`, options),
1891
+ closeDay: (body = {}, options) => http.request("POST", "/v1/shipping_manifests", { body, ...options })
1892
+ },
1893
+ /** A carrier collecting from a location (87-10). */
1894
+ carrierPickups: {
1895
+ ...lister(http, "/v1/carrier_pickups"),
1896
+ retrieve: (pickupId, options) => http.request("GET", `/v1/carrier_pickups/${id(pickupId)}`, options),
1897
+ book: (body, options) => http.request("POST", "/v1/carrier_pickups", { body, ...options })
1898
+ },
1899
+ /** Postage owed for labels bought from the balance, and the credit limit (87-03). */
1900
+ postage: {
1901
+ retrieve: (options) => http.request("GET", "/v1/postage", options)
1902
+ },
1903
+ /** Your own carrier accounts for labels (87-03b); the balance is the fallback if allowed. */
1904
+ carrierAccounts: {
1905
+ /** The connected accounts, with every carrier and the fields each needs. */
1906
+ list: (options) => http.request("GET", "/v1/carrier_accounts", options),
1907
+ connect: (body, options) => http.request("POST", "/v1/carrier_accounts", { body, ...options }),
1908
+ update: (accountId, body, options) => http.request("POST", `/v1/carrier_accounts/${id(accountId)}`, {
1909
+ body,
1910
+ ...options
1911
+ }),
1912
+ disconnect: (accountId, options) => http.request("DELETE", `/v1/carrier_accounts/${id(accountId)}`, options)
1913
+ },
1914
+ /** What delivery costs where (87-01): profiles of zones, each with its rates. */
1915
+ shippingProfiles: {
1916
+ ...lister(http, "/v1/shipping_profiles"),
1917
+ create: (body = {}, options) => http.request("POST", "/v1/shipping_profiles", { body, ...options }),
1918
+ retrieve: (profileId, options) => http.request("GET", `/v1/shipping_profiles/${id(profileId)}`, options),
1919
+ update: (profileId, body, options) => http.request("POST", `/v1/shipping_profiles/${id(profileId)}`, {
1920
+ body,
1921
+ ...options
1922
+ }),
1923
+ del: (profileId, options) => http.request("DELETE", `/v1/shipping_profiles/${id(profileId)}`, options),
1924
+ /** Moves these products onto the profile. */
1925
+ assignProducts: (profileId, body, options) => http.request("POST", `/v1/shipping_profiles/${id(profileId)}/products`, {
1926
+ body,
1927
+ ...options
1928
+ }),
1929
+ /** Products' weights where none was given, as delivery estimates them. */
1930
+ estimatedWeights: (params = {}, options) => http.request("GET", "/v1/shipping_profiles/weights", {
1931
+ query: params,
1932
+ ...options
1933
+ }),
1934
+ /** The delivery options a shopper would see for an address and basket. */
1935
+ preview: (params, options) => http.request("GET", "/v1/shipping_profiles/preview", {
1936
+ query: params,
1937
+ ...options
1938
+ }),
1939
+ createZone: (profileId, body, options) => http.request("POST", `/v1/shipping_profiles/${id(profileId)}/zones`, {
1940
+ body,
1941
+ ...options
1942
+ }),
1943
+ updateZone: (profileId, zoneId, body, options) => http.request(
1944
+ "POST",
1945
+ `/v1/shipping_profiles/${id(profileId)}/zones/${id(zoneId)}`,
1946
+ { body, ...options }
1947
+ ),
1948
+ deleteZone: (profileId, zoneId, options) => http.request(
1949
+ "DELETE",
1950
+ `/v1/shipping_profiles/${id(profileId)}/zones/${id(zoneId)}`,
1951
+ options
1952
+ ),
1953
+ createRate: (profileId, zoneId, body, options) => http.request(
1954
+ "POST",
1955
+ `/v1/shipping_profiles/${id(profileId)}/zones/${id(zoneId)}/rates`,
1956
+ { body, ...options }
1957
+ ),
1958
+ updateRate: (profileId, zoneId, rateId, body, options) => http.request(
1959
+ "POST",
1960
+ `/v1/shipping_profiles/${id(profileId)}/zones/${id(zoneId)}/rates/${id(rateId)}`,
1961
+ { body, ...options }
1962
+ ),
1963
+ deleteRate: (profileId, zoneId, rateId, options) => http.request(
1964
+ "DELETE",
1965
+ `/v1/shipping_profiles/${id(profileId)}/zones/${id(zoneId)}/rates/${id(rateId)}`,
1966
+ options
1967
+ )
1968
+ },
1969
+ /** The boxes you pack in, for label rates (87-02). */
1970
+ shippingPackages: {
1971
+ ...lister(http, "/v1/shipping_packages"),
1972
+ create: (body, options) => http.request("POST", "/v1/shipping_packages", { body, ...options }),
1973
+ update: (packageId, body, options) => http.request("POST", `/v1/shipping_packages/${id(packageId)}`, {
1974
+ body,
1975
+ ...options
1976
+ }),
1977
+ del: (packageId, options) => http.request("DELETE", `/v1/shipping_packages/${id(packageId)}`, options)
1978
+ },
1979
+ /** The carriers' services a rate or a label can use. */
1980
+ shippingServices: {
1981
+ list: (params = {}, options) => http.request("GET", "/v1/shipping_services", {
1982
+ query: params,
1983
+ ...options
1984
+ })
1985
+ },
1986
+ /** The media library (85-04): photos and videos for products and pages. */
1987
+ media: {
1988
+ ...lister(http, "/v1/media"),
1989
+ /** A photo (base64 `data`), or a video from a finished upload; same bytes, same asset. */
1990
+ create: (body, options) => http.request("POST", "/v1/media", { body, ...options }),
1991
+ /** A resumable upload for a video up to 50 MB: send the bytes to `upload_url`. */
1992
+ createUpload: (body, options) => http.request("POST", "/v1/media/uploads", { body, ...options }),
1993
+ retrieve: (assetId, options) => http.request("GET", `/v1/media/${id(assetId)}`, options),
1994
+ update: (assetId, body, options) => http.request("POST", `/v1/media/${id(assetId)}`, { body, ...options }),
1995
+ /** 90-11: the products a video shows, proposed from up to six frames; they wait for you. */
1996
+ proposeVideoTags: (assetId, body, options) => http.request("POST", `/v1/media/${id(assetId)}/video_tags/propose`, {
1997
+ body,
1998
+ ...options
1999
+ }),
2000
+ /** 90-11: a video's product tags, confirmed: only these show on the store. */
2001
+ setVideoTags: (assetId, body, options) => http.request("POST", `/v1/media/${id(assetId)}/video_tags`, {
2002
+ body,
2003
+ ...options
2004
+ }),
2005
+ del: (assetId, options) => http.request("DELETE", `/v1/media/${id(assetId)}`, options)
2006
+ },
2007
+ /** The files digital products deliver to buyers (88-12). */
2008
+ digitalAssets: {
2009
+ ...lister(http, "/v1/digital_assets"),
2010
+ create: (body, options) => http.request("POST", "/v1/digital_assets", { body, ...options }),
2011
+ retrieve: (assetId, options) => http.request("GET", `/v1/digital_assets/${id(assetId)}`, options),
2012
+ del: (assetId, options) => http.request("DELETE", `/v1/digital_assets/${id(assetId)}`, options)
2013
+ },
2014
+ /** Product photo edits (86-13): clean, studio, relight or scene, each a new asset. */
2015
+ imageStudio: {
2016
+ retrieve: (params = {}, options) => http.request("GET", "/v1/image_studio", { query: params, ...options }),
2017
+ createEdit: (body, options) => http.request("POST", "/v1/image_studio/edits", { body, ...options })
2018
+ },
2019
+ /** Store collections (85-05): chosen products, or rules that pick them. */
2020
+ collections: {
2021
+ ...lister(
2022
+ http,
2023
+ "/v1/collections"
2024
+ ),
2025
+ create: (body = {}, options) => http.request("POST", "/v1/collections", { body, ...options }),
2026
+ retrieve: (collectionId, options) => http.request("GET", `/v1/collections/${id(collectionId)}`, options),
2027
+ update: (collectionId, body, options) => http.request("POST", `/v1/collections/${id(collectionId)}`, {
2028
+ body,
2029
+ ...options
2030
+ }),
2031
+ del: (collectionId, options) => http.request("DELETE", `/v1/collections/${id(collectionId)}`, options),
2032
+ /** The collection's products in its order. */
2033
+ products: childLister(
2034
+ http,
2035
+ (collectionId) => `/v1/collections/${id(collectionId)}/products`
2036
+ )
2037
+ },
2038
+ /** Drops (85-12): a limited release at a set time, sold through a fair queue. */
2039
+ drops: {
2040
+ ...lister(http, "/v1/drops"),
2041
+ create: (body, options) => http.request("POST", "/v1/drops", { body, ...options }),
2042
+ retrieve: (dropId, options) => http.request("GET", `/v1/drops/${id(dropId)}`, options),
2043
+ update: (dropId, body, options) => http.request("POST", `/v1/drops/${id(dropId)}`, { body, ...options }),
2044
+ /** The queue as counts: joined, drawing, waiting, checking out, done, and the waitlist. */
2045
+ queue: (dropId, options) => http.request("GET", `/v1/drops/${id(dropId)}/queue`, options)
2046
+ },
2047
+ /**
2048
+ * Products, one catalogue for the till and the store: their web fields (85-03), going
2049
+ * online, variants, the image, licence keys for digital products and return insights.
2050
+ */
2051
+ products: {
2052
+ ...lister(http, "/v1/products"),
2053
+ create: (body, options) => http.request("POST", "/v1/products", { body, ...options }),
2054
+ retrieve: (productId, options) => http.request("GET", `/v1/products/${id(productId)}`, options),
2055
+ /** Web fields too: `web_title`, `web_description`, `web_path`, `seo`, `media`, `channels`. */
2056
+ update: (productId, body, options) => http.request("POST", `/v1/products/${id(productId)}`, { body, ...options }),
2057
+ /** The product with this barcode or SKU. */
2058
+ lookup: (params, options) => http.request("GET", "/v1/products/lookup", { query: params, ...options }),
2059
+ bulkUpdate: (body, options) => http.request("POST", "/v1/products/bulk", { body, ...options }),
2060
+ archive: (productId, options) => http.request("POST", `/v1/products/${id(productId)}/archive`, {
2061
+ body: {},
2062
+ ...options
2063
+ }),
2064
+ /** Sold out or back, on every channel at once. */
2065
+ setAvailable: (productId, body, options) => http.request("POST", `/v1/products/${id(productId)}/available`, {
2066
+ body,
2067
+ ...options
2068
+ }),
2069
+ /** What it still needs to go online, each with its fix. */
2070
+ onlineChecklist: (productId, options) => http.request(
2071
+ "GET",
2072
+ `/v1/products/${id(productId)}/online_checklist`,
2073
+ options
2074
+ ),
2075
+ publishOnline: (productId, options) => http.request("POST", `/v1/products/${id(productId)}/publish_online`, {
2076
+ body: {},
2077
+ ...options
2078
+ }),
2079
+ unpublishOnline: (productId, options) => http.request("POST", `/v1/products/${id(productId)}/unpublish_online`, {
2080
+ body: {},
2081
+ ...options
2082
+ }),
2083
+ variants: childLister(
2084
+ http,
2085
+ (productId) => `/v1/products/${id(productId)}/variants`
2086
+ ),
2087
+ updateVariant: (productId, variantId, body, options) => http.request(
2088
+ "POST",
2089
+ `/v1/products/${id(productId)}/variants/${id(variantId)}`,
2090
+ { body, ...options }
2091
+ ),
2092
+ setImage: (productId, body, options) => http.request("POST", `/v1/products/${id(productId)}/image`, { body, ...options }),
2093
+ removeImage: (productId, options) => http.request("DELETE", `/v1/products/${id(productId)}/image`, options),
2094
+ /** A digital product's licence keys: how many are left. */
2095
+ retrieveLicenceKeys: (productId, options) => http.request("GET", `/v1/products/${id(productId)}/licence_keys`, options),
2096
+ addLicenceKeys: (productId, body, options) => http.request("POST", `/v1/products/${id(productId)}/licence_keys`, {
2097
+ body,
2098
+ ...options
2099
+ }),
2100
+ /** Why it comes back, from its returns (87-09). */
2101
+ returnInsights: (productId, options) => http.request(
2102
+ "GET",
2103
+ `/v1/products/${id(productId)}/return_insights`,
2104
+ options
2105
+ )
2106
+ },
2107
+ /**
2108
+ * Orders, one list for the till, the store and every channel (`source`): find them,
2109
+ * change them, take tenders, return lines and send receipts.
2110
+ */
2111
+ orders: {
2112
+ ...lister(http, "/v1/orders"),
2113
+ create: (body, options) => http.request("POST", "/v1/orders", { body, ...options }),
2114
+ retrieve: (orderId, options) => http.request("GET", `/v1/orders/${id(orderId)}`, options),
2115
+ /** The order's lines, totals, fulfilment, payments and contact details. */
2116
+ details: (orderId, options) => http.request("GET", `/v1/orders/${id(orderId)}/details`, options),
2117
+ /** The order found by a receipt's number or code. */
2118
+ findByReceipt: (body, options) => http.request("POST", "/v1/orders/by_receipt", { body, ...options }),
2119
+ events: childLister(http, (orderId) => `/v1/orders/${id(orderId)}/events`),
2120
+ /** A till's offline events, applied in order; replays are ignored. */
2121
+ appendEvents: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/events`, { body, ...options }),
2122
+ hold: (orderId, body = {}, options) => http.request("POST", `/v1/orders/${id(orderId)}/hold`, { body, ...options }),
2123
+ resume: (orderId, body = {}, options) => http.request("POST", `/v1/orders/${id(orderId)}/resume`, { body, ...options }),
2124
+ void: (orderId, body = {}, options) => http.request("POST", `/v1/orders/${id(orderId)}/void`, { body, ...options }),
2125
+ setOrderType: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/order_type`, { body, ...options }),
2126
+ applyDiscount: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/discounts`, { body, ...options }),
2127
+ setTaxExemption: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/tax_exemption`, {
2128
+ body,
2129
+ ...options
2130
+ }),
2131
+ setCustomer: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/customer`, { body, ...options }),
2132
+ tenders: childLister(http, (orderId) => `/v1/orders/${id(orderId)}/tenders`),
2133
+ createTender: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/tenders`, {
2134
+ body,
2135
+ ...options
2136
+ }),
2137
+ complete: (orderId, body = {}, options) => http.request("POST", `/v1/orders/${id(orderId)}/complete`, { body, ...options }),
2138
+ /** Lines back from a completed order, refunded to their tenders. */
2139
+ createReturn: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/returns`, {
2140
+ body,
2141
+ ...options
2142
+ }),
2143
+ /** What a return of these lines would refund, writing nothing. */
2144
+ previewReturn: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/returns/preview`, {
2145
+ body,
2146
+ ...options
2147
+ }),
2148
+ /** A store order's delivery address, while it has not shipped. */
2149
+ changeDeliveryAddress: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/delivery_address`, {
2150
+ body,
2151
+ ...options
2152
+ }),
2153
+ /** Release the hold on a store order's sending, so it can be packed and sent (92-11b). */
2154
+ releaseHold: (orderId, options) => http.request("POST", `/v1/orders/${id(orderId)}/release_hold`, {
2155
+ body: {},
2156
+ ...options
2157
+ }),
2158
+ resendConfirmation: (orderId, options) => http.request(
2159
+ "POST",
2160
+ `/v1/orders/${id(orderId)}/resend_confirmation`,
2161
+ { body: {}, ...options }
2162
+ ),
2163
+ setEReceipt: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/e_receipt`, {
2164
+ body,
2165
+ ...options
2166
+ }),
2167
+ retrieveReceipt: (orderId, params = {}, options) => http.request("GET", `/v1/orders/${id(orderId)}/receipt`, {
2168
+ query: params,
2169
+ ...options
2170
+ }),
2171
+ sendReceipt: (orderId, body, options) => http.request("POST", `/v1/orders/${id(orderId)}/receipts`, {
2172
+ body,
2173
+ ...options
2174
+ }),
2175
+ reprint: (orderId, options) => http.request("POST", `/v1/orders/${id(orderId)}/reprint`, {
2176
+ body: {},
2177
+ ...options
2178
+ })
2179
+ },
2180
+ /** The store's policy pages: generated, put in your own words, approved by a person. */
2181
+ sitePolicies: {
2182
+ list: (params = {}, options) => http.request("GET", "/v1/site_policies", { query: params, ...options }),
2183
+ /** Drafts every policy the site needs from what it sells and where; nothing goes live. */
2184
+ generate: (body, options) => http.request("POST", "/v1/site_policies/generate", { body, ...options }),
2185
+ retrieve: (policyId, options) => http.request("GET", `/v1/site_policies/${id(policyId)}`, options),
2186
+ versions: (policyId, options) => http.request(
2187
+ "GET",
2188
+ `/v1/site_policies/${id(policyId)}/versions`,
2189
+ options
2190
+ ),
2191
+ /** A new version in your own words, to approve. */
2192
+ setOwnWords: (policyId, body, options) => http.request("POST", `/v1/site_policies/${id(policyId)}/own_words`, {
2193
+ body,
2194
+ ...options
2195
+ }),
2196
+ retrieveVersion: (versionId, options) => http.request(
2197
+ "GET",
2198
+ `/v1/site_policy_versions/${id(versionId)}`,
2199
+ options
2200
+ ),
2201
+ /** A person approves the version; it goes live on the store. */
2202
+ approveVersion: (versionId, options) => http.request("POST", `/v1/site_policy_versions/${id(versionId)}/approve`, {
2203
+ body: {},
2204
+ ...options
2205
+ })
2206
+ },
2207
+ /** Shoppers' requests to see or erase their data, to complete within the legal time. */
2208
+ storePrivacyRequests: {
2209
+ ...lister(
2210
+ http,
2211
+ "/v1/store_privacy_requests"
2212
+ ),
2213
+ retrieve: (requestId, options) => http.request(
2214
+ "GET",
2215
+ `/v1/store_privacy_requests/${id(requestId)}`,
2216
+ options
2217
+ ),
2218
+ complete: (requestId, options) => http.request(
2219
+ "POST",
2220
+ `/v1/store_privacy_requests/${id(requestId)}/complete`,
2221
+ { body: {}, ...options }
2222
+ )
2223
+ },
2224
+ /** Your own say over "you might also like": products pinned first, or never shown (91-03). */
2225
+ recommendationRules: {
2226
+ ...lister(
2227
+ http,
2228
+ "/v1/recommendation_rules"
2229
+ ),
2230
+ create: (body, options) => http.request("POST", "/v1/recommendation_rules", { body, ...options }),
2231
+ retrieve: (ruleId, options) => http.request("GET", `/v1/recommendation_rules/${id(ruleId)}`, options),
2232
+ update: (ruleId, body, options) => http.request("POST", `/v1/recommendation_rules/${id(ruleId)}`, {
2233
+ body,
2234
+ ...options
2235
+ }),
2236
+ /** Takes the rule away: recommendations go back to the store's own. */
2237
+ del: (ruleId, options) => http.request(
2238
+ "DELETE",
2239
+ `/v1/recommendation_rules/${id(ruleId)}`,
2240
+ options
2241
+ )
2242
+ },
2243
+ /** Subscribe and save: a product on repeat for less, priced at each order (91-08). */
2244
+ subscriptionOffers: {
2245
+ ...lister(
2246
+ http,
2247
+ "/v1/subscription_offers"
2248
+ ),
2249
+ create: (body, options) => http.request("POST", "/v1/subscription_offers", { body, ...options }),
2250
+ retrieve: (offerId, options) => http.request("GET", `/v1/subscription_offers/${id(offerId)}`, options),
2251
+ /** Turn it off with `active: false`: offers are never deleted. */
2252
+ update: (offerId, body, options) => http.request("POST", `/v1/subscription_offers/${id(offerId)}`, {
2253
+ body,
2254
+ ...options
2255
+ })
2256
+ },
2257
+ /**
2258
+ * Store campaigns (91-09b): a one-off email to a segment of the customers who said yes.
2259
+ * Who it goes to is worked out when it sends; no method takes a list of people.
2260
+ */
2261
+ storeCampaigns: {
2262
+ ...lister(http, "/v1/store_campaigns"),
2263
+ create: (body, options) => http.request("POST", "/v1/store_campaigns", { body, ...options }),
2264
+ retrieve: (campaignId, options) => http.request("GET", `/v1/store_campaigns/${id(campaignId)}`, options),
2265
+ /** A draft only: only what is sent changes. */
2266
+ update: (campaignId, body, options) => http.request("POST", `/v1/store_campaigns/${id(campaignId)}`, {
2267
+ body,
2268
+ ...options
2269
+ }),
2270
+ /** How many it would reach now, a few first names, and the words. */
2271
+ preview: (campaignId, options) => http.request(
2272
+ "GET",
2273
+ `/v1/store_campaigns/${id(campaignId)}/preview`,
2274
+ options
2275
+ ),
2276
+ /** To the signed-in person's own email only (a dashboard session, not an API key). */
2277
+ test: (campaignId, options) => http.request("POST", `/v1/store_campaigns/${id(campaignId)}/test`, options),
2278
+ /** `send_at` on the business's clock, `YYYY-MM-DDTHH:MM`, or null for now. */
2279
+ schedule: (campaignId, body = {}, options) => http.request("POST", `/v1/store_campaigns/${id(campaignId)}/schedule`, {
2280
+ body,
2281
+ ...options
2282
+ }),
2283
+ unschedule: (campaignId, options) => http.request(
2284
+ "POST",
2285
+ `/v1/store_campaigns/${id(campaignId)}/unschedule`,
2286
+ options
2287
+ ),
2288
+ results: (campaignId, options) => http.request(
2289
+ "GET",
2290
+ `/v1/store_campaigns/${id(campaignId)}/results`,
2291
+ options
2292
+ )
2293
+ },
2294
+ /**
2295
+ * Store flows (91-17): the six emails that go on their own to customers who said yes. Turn one
2296
+ * off, change its words, or turn it back on after the guardrail paused it.
2297
+ */
2298
+ storeFlows: {
2299
+ list: (options) => http.request("GET", "/v1/store_flows", options),
2300
+ retrieve: (flowId, options) => http.request("GET", `/v1/store_flows/${id(flowId)}`, options),
2301
+ /** `enabled`, `copy` (one for each message) or `use_default_copy`. */
2302
+ update: (flowId, body, options) => http.request("POST", `/v1/store_flows/${id(flowId)}`, { body, ...options }),
2303
+ /** After reviewing its email: only sends from now count towards the next pause. */
2304
+ resume: (flowId, options) => http.request("POST", `/v1/store_flows/${id(flowId)}/resume`, options)
2305
+ },
2306
+ /** The store's connections to other places it sells: marketplaces, social shops, feeds (M90). */
2307
+ salesChannels: {
2308
+ ...lister(http, "/v1/sales_channels"),
2309
+ retrieve: (channelId, options) => http.request("GET", `/v1/sales_channels/${id(channelId)}`, options),
2310
+ /** Nothing is sent to the channel until it resumes. */
2311
+ pause: (channelId, options) => http.request("POST", `/v1/sales_channels/${id(channelId)}/pause`, {
2312
+ body: {},
2313
+ ...options
2314
+ }),
2315
+ /** What changed while paused is sent. */
2316
+ resume: (channelId, options) => http.request("POST", `/v1/sales_channels/${id(channelId)}/resume`, {
2317
+ body: {},
2318
+ ...options
2319
+ })
2320
+ },
2321
+ /** Each variant's place on a channel, with its state and the channel's issues (M90). */
2322
+ listings: {
2323
+ ...lister(
2324
+ http,
2325
+ "/v1/listings"
2326
+ ),
2327
+ retrieve: (listingId, options) => http.request("GET", `/v1/listings/${id(listingId)}`, options),
2328
+ /** Keeps this variant off the channel; it stays on the store. */
2329
+ exclude: (listingId, options) => http.request("POST", `/v1/listings/${id(listingId)}/exclude`, {
2330
+ body: {},
2331
+ ...options
2332
+ }),
2333
+ /** Lists this variant on the channel again. */
2334
+ include: (listingId, options) => http.request("POST", `/v1/listings/${id(listingId)}/include`, {
2335
+ body: {},
2336
+ ...options
2337
+ })
2338
+ },
2339
+ /** The store inbox: shoppers' conversations with the store, by chat and email (91-10). */
2340
+ storeThreads: {
2341
+ ...lister(
2342
+ http,
2343
+ "/v1/store_threads"
2344
+ ),
2345
+ /** With its messages. */
2346
+ retrieve: (threadId, options) => http.request("GET", `/v1/store_threads/${id(threadId)}`, options),
2347
+ /** `status` and `assignee` (a team member's `usr_` id, or null). */
2348
+ update: (threadId, body, options) => http.request("POST", `/v1/store_threads/${id(threadId)}`, {
2349
+ body,
2350
+ ...options
2351
+ }),
2352
+ /** By email from the store's sender when the shopper left an address. */
2353
+ reply: (threadId, body, options) => http.request("POST", `/v1/store_threads/${id(threadId)}/messages`, {
2354
+ body,
2355
+ ...options
2356
+ }),
2357
+ /** A WhatsApp conversation's approved templates (91-11). */
2358
+ templates: (threadId, options) => http.request(
2359
+ "GET",
2360
+ `/v1/store_threads/${id(threadId)}/templates`,
2361
+ options
2362
+ ),
2363
+ /** An approved WhatsApp template: the only reply WhatsApp takes after 24 hours (91-11). */
2364
+ sendTemplate: (threadId, body, options) => http.request("POST", `/v1/store_threads/${id(threadId)}/templates`, {
2365
+ body,
2366
+ ...options
2367
+ })
2368
+ },
2369
+ /** Your store's own sending domain: store emails go from it once it verifies (91-13). */
2370
+ merchantSendingDomains: {
2371
+ ...lister(http, "/v1/merchant_sending_domains"),
2372
+ /** `mail.` on your store's own domain, or null. */
2373
+ suggestion: (options) => http.request(
2374
+ "GET",
2375
+ "/v1/merchant_sending_domains/suggestion",
2376
+ options
2377
+ ),
2378
+ /** The suggestion when `domain` is left out. Answers the records to add. */
2379
+ create: (body = {}, options) => http.request("POST", "/v1/merchant_sending_domains", {
2380
+ body,
2381
+ ...options
2382
+ }),
2383
+ retrieve: (domainId, options) => http.request(
2384
+ "GET",
2385
+ `/v1/merchant_sending_domains/${id(domainId)}`,
2386
+ options
2387
+ ),
2388
+ /** Checks the records now. */
2389
+ check: (domainId, options) => http.request(
2390
+ "POST",
2391
+ `/v1/merchant_sending_domains/${id(domainId)}/check`,
2392
+ options
2393
+ ),
2394
+ /** Store emails go from Tuppence in your name again. */
2395
+ remove: (domainId, options) => http.request(
2396
+ "DELETE",
2397
+ `/v1/merchant_sending_domains/${id(domainId)}`,
2398
+ options
2399
+ )
2400
+ }
2401
+ };
2402
+ }
2403
+
2404
+ // src/webhooks.ts
2405
+ var import_node_crypto = require("node:crypto");
2406
+ var SIGNATURE_HEADER = "Tuppence-Signature";
2407
+ var DEFAULT_TOLERANCE_SECONDS = 300;
2408
+ var hmac = (secret, timestamp, payload) => (0, import_node_crypto.createHmac)("sha256", secret).update(`${timestamp}.${payload}`, "utf8").digest("hex");
2409
+ function constructEvent(payload, header, secret, options = {}) {
2410
+ const body = typeof payload === "string" ? payload : payload.toString("utf8");
2411
+ const value = Array.isArray(header) ? header[0] : header;
2412
+ if (!value) {
2413
+ throw new SignatureVerificationError("malformed_header", `No ${SIGNATURE_HEADER} header.`);
2414
+ }
2415
+ let timestamp;
2416
+ const signatures = [];
2417
+ for (const part of value.split(",")) {
2418
+ const index = part.indexOf("=");
2419
+ if (index < 1)
2420
+ throw new SignatureVerificationError(
2421
+ "malformed_header",
2422
+ "The signature header is malformed."
2423
+ );
2424
+ const key = part.slice(0, index).trim();
2425
+ const v = part.slice(index + 1).trim();
2426
+ if (key === "t" && /^\d{1,12}$/.test(v)) timestamp = Number(v);
2427
+ else if (key === "v1") signatures.push(v);
2428
+ }
2429
+ if (timestamp === void 0 || signatures.length === 0) {
2430
+ throw new SignatureVerificationError("malformed_header", "The signature header is malformed.");
2431
+ }
2432
+ const expected = Buffer.from(hmac(secret, timestamp, body), "hex");
2433
+ const matched = signatures.some(
2434
+ (candidate) => /^[0-9a-f]{64}$/i.test(candidate) && (0, import_node_crypto.timingSafeEqual)(Buffer.from(candidate, "hex"), expected)
2435
+ );
2436
+ if (!matched) {
2437
+ throw new SignatureVerificationError(
2438
+ "no_matching_signature",
2439
+ "The signature does not match: check the endpoint's signing secret, and that you passed the raw body."
2440
+ );
2441
+ }
2442
+ const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
2443
+ if (Math.abs(now - timestamp) > (options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS)) {
2444
+ throw new SignatureVerificationError(
2445
+ "timestamp_out_of_tolerance",
2446
+ "The webhook's timestamp is too old (or your clock is wrong): refusing a possible replay."
2447
+ );
2448
+ }
2449
+ return JSON.parse(body);
2450
+ }
2451
+ function generateTestHeader(payload, secret, timestamp = Math.floor(Date.now() / 1e3)) {
2452
+ return `t=${timestamp},v1=${hmac(secret, timestamp, payload)}`;
2453
+ }
2454
+
2455
+ // src/agent-proof.ts
2456
+ var import_node_crypto2 = require("node:crypto");
2457
+ var b64url = (value) => (Buffer.isBuffer(value) ? value : Buffer.from(JSON.stringify(value))).toString("base64url");
2458
+ function keyOf(key) {
2459
+ if (typeof key === "string") return (0, import_node_crypto2.createPrivateKey)(key);
2460
+ if (typeof key === "object" && "d" in key) return (0, import_node_crypto2.createPrivateKey)({ key, format: "jwk" });
2461
+ return key;
2462
+ }
2463
+ function canonical(url) {
2464
+ const parsed = new URL(url);
2465
+ parsed.hash = "";
2466
+ return parsed.search === "?" ? parsed.toString().replace(/\?$/, "") : parsed.toString();
2467
+ }
2468
+ function signAgentProof(input) {
2469
+ const now = input.nowSeconds ?? Math.floor(Date.now() / 1e3);
2470
+ const header = { alg: "EdDSA", typ: "agent-proof+jwt", kid: input.kid };
2471
+ const claims = {
2472
+ iss: input.agent,
2473
+ htm: input.method.toUpperCase(),
2474
+ htu: canonical(input.url),
2475
+ iat: now,
2476
+ exp: now + (input.lifetimeSeconds ?? 60),
2477
+ jti: (0, import_node_crypto2.randomUUID)(),
2478
+ ...input.body === void 0 ? {} : { bh: (0, import_node_crypto2.createHash)("sha256").update(input.body).digest("base64url") },
2479
+ ...input.audience === void 0 ? {} : { aud: input.audience }
2480
+ };
2481
+ const signed = `${b64url(header)}.${b64url(claims)}`;
2482
+ return `${signed}.${b64url((0, import_node_crypto2.sign)(null, Buffer.from(signed), keyOf(input.privateKey)))}`;
2483
+ }
2484
+ var AGENT_PROOF_HEADER = "Tuppence-Agent-Proof";
2485
+
2486
+ // src/index.ts
2487
+ var Tuppence = class _Tuppence {
2488
+ http;
2489
+ // Kept for `as()`, out of sight: never enumerable, printed or serialised.
2490
+ #apiKey;
2491
+ #options;
2492
+ account;
2493
+ /** Bacs Direct Debit by application: its status, applying, and asking for higher limits. */
2494
+ directDebit;
2495
+ /** Tuppence Connect: your connected accounts, and their people, banks and capabilities. */
2496
+ accounts;
2497
+ accountLinks;
2498
+ files;
2499
+ /** Your fees on your connected accounts' payments, and the refunds of them. */
2500
+ applicationFees;
2501
+ /** Money from your Connect balance to your connected accounts, and its reversals. */
2502
+ transfers;
2503
+ plans;
2504
+ subscriptions;
2505
+ paymentLinks;
2506
+ payments;
2507
+ refunds;
2508
+ customers;
2509
+ balance;
2510
+ payouts;
2511
+ disputes;
2512
+ events;
2513
+ /** Tuppence Events: `ticketing.events`, `.promoCodes`, `.fundsHolds`, `.reports`. */
2514
+ ticketing;
2515
+ ticketTypes;
2516
+ ticketOrders;
2517
+ tickets;
2518
+ webhookEndpoints;
2519
+ paymentMethodDomains;
2520
+ meters;
2521
+ credits;
2522
+ meterEvents;
2523
+ agents;
2524
+ cardholders;
2525
+ spendPolicies;
2526
+ cards;
2527
+ cardAuthorizations;
2528
+ cardTransactions;
2529
+ /** Disputing a card purchase: a draft, its evidence and files, then submitted by a person. */
2530
+ cardDisputes;
2531
+ /**
2532
+ * The cards' own balance and its top-ups — `issuing.balance`, `issuing.topups`,
2533
+ * `issuing.fundingInstructions` — and Issuing's limits for the account's tier (`issuing.limits`).
2534
+ */
2535
+ issuing;
2536
+ /** TEST MODE only: `testHelpers.issuing.topups.arrive(id)`. */
2537
+ testHelpers;
2538
+ approvals;
2539
+ locations;
2540
+ countryPacks;
2541
+ serviceCategories;
2542
+ services;
2543
+ staff;
2544
+ scheduleExceptions;
2545
+ resources;
2546
+ bookingPolicy;
2547
+ bookingPage;
2548
+ availability;
2549
+ bookings;
2550
+ classSessions;
2551
+ bookingSeries;
2552
+ waitlist;
2553
+ // The store (94-02).
2554
+ reviews;
2555
+ changeSets;
2556
+ storeImports;
2557
+ assistantJobs;
2558
+ channelReports;
2559
+ storeBriefs;
2560
+ sites;
2561
+ store;
2562
+ fulfilments;
2563
+ returns;
2564
+ shippingManifests;
2565
+ carrierPickups;
2566
+ postage;
2567
+ carrierAccounts;
2568
+ shippingProfiles;
2569
+ shippingPackages;
2570
+ shippingServices;
2571
+ media;
2572
+ digitalAssets;
2573
+ imageStudio;
2574
+ collections;
2575
+ drops;
2576
+ products;
2577
+ orders;
2578
+ sitePolicies;
2579
+ storePrivacyRequests;
2580
+ recommendationRules;
2581
+ subscriptionOffers;
2582
+ storeCampaigns;
2583
+ storeFlows;
2584
+ salesChannels;
2585
+ listings;
2586
+ storeThreads;
2587
+ merchantSendingDomains;
2588
+ webhooks = { constructEvent, generateTestHeader };
2589
+ constructor(apiKey, options = {}) {
2590
+ this.http = new HttpClient(apiKey, options);
2591
+ this.#apiKey = apiKey;
2592
+ this.#options = options;
2593
+ const r = resources(this.http);
2594
+ this.account = r.account;
2595
+ this.directDebit = r.directDebit;
2596
+ this.accounts = r.accounts;
2597
+ this.accountLinks = r.accountLinks;
2598
+ this.files = r.files;
2599
+ this.applicationFees = r.applicationFees;
2600
+ this.transfers = r.transfers;
2601
+ this.plans = r.plans;
2602
+ this.subscriptions = r.subscriptions;
2603
+ this.paymentLinks = r.paymentLinks;
2604
+ this.payments = r.payments;
2605
+ this.refunds = r.refunds;
2606
+ this.customers = r.customers;
2607
+ this.balance = r.balance;
2608
+ this.payouts = r.payouts;
2609
+ this.disputes = r.disputes;
2610
+ this.events = r.events;
2611
+ this.ticketing = r.ticketing;
2612
+ this.ticketTypes = r.ticketTypes;
2613
+ this.ticketOrders = r.ticketOrders;
2614
+ this.tickets = r.tickets;
2615
+ this.webhookEndpoints = r.webhookEndpoints;
2616
+ this.paymentMethodDomains = r.paymentMethodDomains;
2617
+ this.meters = r.meters;
2618
+ this.credits = r.credits;
2619
+ this.meterEvents = r.meterEvents;
2620
+ this.agents = r.agents;
2621
+ this.cardholders = r.cardholders;
2622
+ this.spendPolicies = r.spendPolicies;
2623
+ this.cards = r.cards;
2624
+ this.cardAuthorizations = r.cardAuthorizations;
2625
+ this.cardTransactions = r.cardTransactions;
2626
+ this.cardDisputes = r.cardDisputes;
2627
+ this.issuing = r.issuing;
2628
+ this.testHelpers = r.testHelpers;
2629
+ this.approvals = r.approvals;
2630
+ this.locations = r.locations;
2631
+ this.countryPacks = r.countryPacks;
2632
+ this.serviceCategories = r.serviceCategories;
2633
+ this.services = r.services;
2634
+ this.staff = r.staff;
2635
+ this.scheduleExceptions = r.scheduleExceptions;
2636
+ this.resources = r.resources;
2637
+ this.bookingPolicy = r.bookingPolicy;
2638
+ this.bookingPage = r.bookingPage;
2639
+ this.availability = r.availability;
2640
+ this.bookings = r.bookings;
2641
+ this.classSessions = r.classSessions;
2642
+ this.bookingSeries = r.bookingSeries;
2643
+ this.waitlist = r.waitlist;
2644
+ this.reviews = r.reviews;
2645
+ this.changeSets = r.changeSets;
2646
+ this.storeImports = r.storeImports;
2647
+ this.assistantJobs = r.assistantJobs;
2648
+ this.channelReports = r.channelReports;
2649
+ this.storeBriefs = r.storeBriefs;
2650
+ this.sites = r.sites;
2651
+ this.store = r.store;
2652
+ this.fulfilments = r.fulfilments;
2653
+ this.returns = r.returns;
2654
+ this.shippingManifests = r.shippingManifests;
2655
+ this.carrierPickups = r.carrierPickups;
2656
+ this.postage = r.postage;
2657
+ this.carrierAccounts = r.carrierAccounts;
2658
+ this.shippingProfiles = r.shippingProfiles;
2659
+ this.shippingPackages = r.shippingPackages;
2660
+ this.shippingServices = r.shippingServices;
2661
+ this.media = r.media;
2662
+ this.digitalAssets = r.digitalAssets;
2663
+ this.imageStudio = r.imageStudio;
2664
+ this.collections = r.collections;
2665
+ this.drops = r.drops;
2666
+ this.products = r.products;
2667
+ this.orders = r.orders;
2668
+ this.sitePolicies = r.sitePolicies;
2669
+ this.storePrivacyRequests = r.storePrivacyRequests;
2670
+ this.recommendationRules = r.recommendationRules;
2671
+ this.subscriptionOffers = r.subscriptionOffers;
2672
+ this.storeCampaigns = r.storeCampaigns;
2673
+ this.storeFlows = r.storeFlows;
2674
+ this.salesChannels = r.salesChannels;
2675
+ this.listings = r.listings;
2676
+ this.storeThreads = r.storeThreads;
2677
+ this.merchantSendingDomains = r.merchantSendingDomains;
2678
+ }
2679
+ /**
2680
+ * Tuppence Connect: a client that acts as one of your connected accounts on every request —
2681
+ * the `Tuppence-Account` header, with your key. A NEW client: this one is unchanged, so one
2682
+ * shared client can serve every account. A request's own `tuppenceAccount` still wins.
2683
+ *
2684
+ * const bella = tuppence.as("acct_…");
2685
+ * await bella.bookings.create({ … });
2686
+ */
2687
+ as(accountId) {
2688
+ if (!accountId || typeof accountId !== "string") {
2689
+ throw new TypeError('tuppence.as(accountId): a connected account id ("acct_\u2026") is required.');
2690
+ }
2691
+ return new _Tuppence(this.#apiKey, { ...this.#options, tuppenceAccount: accountId });
2692
+ }
2693
+ /** Any endpoint the SDK has no method for yet — same auth, retries and idempotency. */
2694
+ request(method, path, options = {}) {
2695
+ return this.http.request(method, path, options);
2696
+ }
2697
+ };
2698
+ var index_default = Tuppence;
2699
+ // Annotate the CommonJS export names for ESM import in node:
2700
+ 0 && (module.exports = {
2701
+ AGENT_PROOF_HEADER,
2702
+ ApiError,
2703
+ AuthenticationError,
2704
+ CardError,
2705
+ ConnectionError,
2706
+ DEFAULT_API_VERSION,
2707
+ DEFAULT_TOLERANCE_SECONDS,
2708
+ IdempotencyError,
2709
+ InvalidRequestError,
2710
+ PermissionError,
2711
+ RateLimitError,
2712
+ SIGNATURE_HEADER,
2713
+ SignatureVerificationError,
2714
+ Tuppence,
2715
+ TuppenceError,
2716
+ VERSION,
2717
+ constructEvent,
2718
+ signAgentProof
2719
+ });