@checkoutpage/sdk 0.1.31 → 0.1.32

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/README.md CHANGED
@@ -241,6 +241,67 @@ const pageBookings = await checkoutpage.bookings.list({
241
241
  });
242
242
  ```
243
243
 
244
+ #### Create a booking
245
+
246
+ `bookings.create` issues a real booking without collecting card payment: tickets
247
+ are issued, the customer gets a confirmation email with the ticket PDF, and
248
+ booking webhooks fire. Field values are addressed by `fieldId`, and every field
249
+ the event marks as required must be supplied.
250
+
251
+ ```typescript
252
+ const { data: booking } = await checkoutpage.bookings.create({
253
+ eventId: '67fcbdac6a91c25ef2d3534a',
254
+ tickets: { '65f4a1c2e4a9f3d2b1c0a9e8': 2 },
255
+ fields: [
256
+ { fieldId: '507f1f77bcf86cd799439030', value: 'ada@example.com' },
257
+ { fieldId: '507f1f77bcf86cd799439031', value: 'Ada Lovelace' },
258
+ ],
259
+ paymentOption: { manualType: 'invoice' },
260
+ });
261
+
262
+ console.log(booking.status); // 'unpaid'
263
+ console.log(booking.amountDue); // 5000, settled outside checkout
264
+ ```
265
+
266
+ #### Create a complimentary booking
267
+
268
+ There are two ways to settle a booking, and exactly one of them is required.
269
+ Pass `paymentOption`, as above, and the booking is recorded as `unpaid` with the
270
+ amount as its balance due, settled outside checkout. Pass `complimentary: true`
271
+ instead and the tickets are issued at no charge: the booking is recorded as
272
+ `paid` with `amount`, `amountPaid` and `amountDue` of 0 and
273
+ `isComplimentary: true`, while the ticket lines keep their face value and
274
+ `complimentaryDiscountAmount` records what they would have cost. `complimentary`
275
+ cannot be combined with `paymentOption` or `couponId`.
276
+
277
+ ```typescript
278
+ const { data: booking } = await checkoutpage.bookings.create({
279
+ eventId: '67fcbdac6a91c25ef2d3534a',
280
+ tickets: { '65f4a1c2e4a9f3d2b1c0a9e8': 2 },
281
+ fields: [
282
+ { fieldId: '507f1f77bcf86cd799439030', value: 'ada@example.com' },
283
+ { fieldId: '507f1f77bcf86cd799439031', value: 'Ada Lovelace' },
284
+ ],
285
+ complimentary: true,
286
+ });
287
+
288
+ console.log(booking.status); // 'paid'
289
+ console.log(booking.amount); // 0
290
+ console.log(booking.complimentaryDiscountAmount); // 5000 (2 x 2500 face value)
291
+ ```
292
+
293
+ #### Filter complimentary bookings
294
+
295
+ ```typescript
296
+ const complimentary = await checkoutpage.bookings.list({
297
+ isComplimentary: 'true',
298
+ });
299
+
300
+ const paidFor = await checkoutpage.bookings.list({
301
+ isComplimentary: 'false',
302
+ });
303
+ ```
304
+
244
305
  ### Products
245
306
 
246
307
  #### Get a product
@@ -249,6 +310,15 @@ const pageBookings = await checkoutpage.bookings.list({
249
310
  const product = await checkoutpage.products.get('product_id');
250
311
  ```
251
312
 
313
+ #### List products
314
+
315
+ ```typescript
316
+ const products = await checkoutpage.products.list({
317
+ search: 'shirt',
318
+ limit: 20,
319
+ });
320
+ ```
321
+
252
322
  #### Update a product
253
323
 
254
324
  ```typescript
@@ -327,6 +397,69 @@ const result = await checkoutpage.files.upload({
327
397
  console.log('File uploaded:', result.data.id);
328
398
  ```
329
399
 
400
+ ### Themes
401
+
402
+ A theme is a page design you can reuse across checkout pages, events and forms. `list()` returns
403
+ your own themes (`scope: 'seller'`) and the built-in ones (`scope: 'global'`), which are read-only.
404
+
405
+ #### List themes
406
+
407
+ ```typescript
408
+ const { data: themes, has_more } = await checkoutpage.themes.list();
409
+
410
+ const builtIn = await checkoutpage.themes.list({ scope: 'global' });
411
+ ```
412
+
413
+ #### Create a theme
414
+
415
+ ```typescript
416
+ const { data: theme } = await checkoutpage.themes.create({
417
+ name: 'Brand',
418
+ // Optional: start from a copy of a built-in theme or one of yours
419
+ baseThemeId: builtIn.data[0].id,
420
+ variables: { tokens: { colorPrimary: { light: '#4f46e5' } } },
421
+ });
422
+ ```
423
+
424
+ `variables` takes the same shape as a page's `themeOverrides`. A copy of a built-in theme does not
425
+ follow your store's brand colour, so set `tokens.colorPrimary` if you want it. A name another of
426
+ your themes already uses is rejected with a `ConflictError`.
427
+
428
+ #### Get and update a theme
429
+
430
+ ```typescript
431
+ const { data: theme } = await checkoutpage.themes.get(themeId);
432
+
433
+ const { data: updated } = await checkoutpage.themes.update(themeId, {
434
+ name: 'Brand v2',
435
+ variables: { tokens: { colorPrimary: { light: '#0f766e' }, radius: null } },
436
+ });
437
+ ```
438
+
439
+ Every page that uses the theme changes too. Keys you leave out keep their value, and `null` resets a
440
+ property, or everything under a key. Built-in themes can't be changed: copy one with `baseThemeId`.
441
+
442
+ #### Use a theme on a page
443
+
444
+ ```typescript
445
+ await checkoutpage.checkoutPages.update(pageId, { themeId: theme.id });
446
+ ```
447
+
448
+ `events` and `forms` take `themeId` on `create` and `update` too, and page responses include it.
449
+ Changing a page's theme replaces the page's own theme settings, including ones set in the
450
+ dashboard such as custom CSS, so the page looks like the theme. `themeOverrides` sent in the same
451
+ request apply on top, and the page's locale is kept.
452
+
453
+ #### Delete a theme
454
+
455
+ ```typescript
456
+ const { data: deleted } = await checkoutpage.themes.delete(themeId);
457
+ ```
458
+
459
+ A theme that any of your pages uses, archived ones included, or that is your store's default theme,
460
+ can't be deleted and throws a `ConflictError`. Move those pages to another theme with `themeId`
461
+ first.
462
+
330
463
  ### Webhooks
331
464
 
332
465
  #### List webhook endpoints
@@ -362,8 +495,36 @@ saveSecret(webhook.secret);
362
495
  > and a URL already registered on the account is rejected with a `ConflictError`.
363
496
 
364
497
  > The create response is the **only** place the signing `secret` is ever returned.
365
- > It is not included in `list()` responses and cannot be retrieved later — store it
366
- > when you create the endpoint. Omit `secret` to have one generated for you.
498
+ > It is not included in `list()` or `get()` responses and cannot be retrieved later, so store
499
+ > it when you create the endpoint. Omit `secret` to have one generated for you.
500
+
501
+ #### Get a webhook endpoint
502
+
503
+ ```typescript
504
+ const { data: webhook } = await checkoutpage.webhooks.get(webhookId);
505
+
506
+ console.log(webhook.status, webhook.deliveryCount, webhook.lastFailureAt);
507
+ ```
508
+
509
+ The signing `secret` is not included.
510
+
511
+ #### Update a webhook endpoint
512
+
513
+ ```typescript
514
+ const { data: updated } = await checkoutpage.webhooks.update(webhookId, {
515
+ url: 'https://example.com/hooks/checkoutpage-v2',
516
+ events: ['payment.paid', 'checkout_page.updated', 'product.updated'],
517
+ });
518
+
519
+ // Pause deliveries without deleting the endpoint, then resume them
520
+ await checkoutpage.webhooks.update(webhookId, { status: 'inactive' });
521
+ await checkoutpage.webhooks.update(webhookId, { status: 'active' });
522
+ ```
523
+
524
+ Only the fields you send change. `events` and `customHeaders` replace the existing values rather
525
+ than merging with them. A new `url` must use https and must not already be registered on another of
526
+ your webhooks (`ValidationError` / `ConflictError`). The signing secret cannot be changed through
527
+ the API.
367
528
 
368
529
  #### Delete a webhook endpoint
369
530
 
@@ -373,6 +534,39 @@ const { data: deleted } = await checkoutpage.webhooks.delete(webhook.id);
373
534
 
374
535
  Deliveries stop immediately and the endpoint no longer appears in `list()`.
375
536
 
537
+ ### Test mode
538
+
539
+ Switch a checkout page, event or form into test mode with `testmode: true`. While it is on, every
540
+ purchase on that page is a test purchase: no money is taken, the buyer gets the product for free,
541
+ and the records are created with `livemode: false`.
542
+
543
+ ```typescript
544
+ await checkoutpage.checkoutPages.update(pageId, { testmode: true });
545
+
546
+ const { data: pagesInTestMode } = await checkoutpage.checkoutPages.list({ testmode: true });
547
+
548
+ // Turn it off to take real payments again
549
+ await checkoutpage.checkoutPages.update(pageId, { testmode: false });
550
+ ```
551
+
552
+ `events` and `forms` take the same field on `create`, `update` and `list`. Page responses carry
553
+ `testmode` and `testmodeEnabledAt` (when test mode was switched on, `null` while it is off).
554
+
555
+ #### Read test records
556
+
557
+ Pass `livemode: false` to read test records from payments, bookings, subscriptions, subscription
558
+ payments, invoices, submissions and tickets:
559
+
560
+ ```typescript
561
+ const { data: testPayments } = await checkoutpage.payments.list({ pageId, livemode: false });
562
+ const { data: testPayment } = await checkoutpage.payments.get(paymentId, { livemode: false });
563
+ const pdf = await checkoutpage.bookings.downloadTicketPdf(bookingId, { livemode: false });
564
+ ```
565
+
566
+ Without `livemode`, reads return records in the mode of your API key. A live key (`sk_live_`)
567
+ reads live data by default and test data with `livemode: false`. A test key (`sk_test_`) only
568
+ reads test data: `livemode: true` with a test key throws an `AuthenticationError` (403).
569
+
376
570
  ## Error Handling
377
571
 
378
572
  The SDK provides typed error classes for different error scenarios: