@resira/sdk 0.4.5 → 0.4.7

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.d.cts CHANGED
@@ -1,901 +1,901 @@
1
- /**
2
- * POST body for creating a reservation.
3
- *
4
- * Use date fields (`startDate`/`endDate`) for property bookings and
5
- * datetime fields (`startTime`/`endTime`) for restaurant/experience
6
- * reservations. Both can be provided simultaneously.
7
- */
8
- interface CreateReservationRequest {
9
- /** The resource to book. Sent in the request body. */
10
- resourceId: string;
11
- /** Guest's full name. */
12
- guestName: string;
13
- /** Guest's email address. Optional for restaurant reservations. */
14
- guestEmail?: string;
15
- /** Guest's phone number. Required for restaurant if email not provided. */
16
- guestPhone?: string;
17
- /** Start date in `YYYY-MM-DD` format (date-based resources). Optional for time-based resources. */
18
- startDate?: string;
19
- /** End date in `YYYY-MM-DD` format (date-based resources). Optional for time-based resources. */
20
- endDate?: string;
21
- /** Start datetime in ISO 8601 / RFC 3339 (time-based resources). */
22
- startTime?: string;
23
- /** End datetime in ISO 8601 / RFC 3339 (time-based resources). */
24
- endTime?: string;
25
- /** Number of guests / party size. Defaults to 2 on the server. */
26
- partySize?: number;
27
- /** Free-form notes from the guest. */
28
- notes?: string;
29
- }
30
- /** Query parameters for listing reservations. */
31
- interface ListReservationsParams {
32
- /** Filter by status (e.g. `"pending"`, `"confirmed"`). Omit for all non-archived. */
33
- status?: string;
34
- /** Page number (1-indexed). Defaults to 1. */
35
- page?: number;
36
- /** Items per page (1–100). Defaults to 25. */
37
- limit?: number;
38
- }
39
- /**
40
- * Query parameters for the availability endpoint.
41
- *
42
- * For **properties**: pass `startDate` + `endDate` to check a range,
43
- * or omit both to get all blocked dates for calendar rendering.
44
- *
45
- * For **restaurants**: pass `date` (and optionally `partySize`) to
46
- * get time-slot availability for a specific day.
47
- */
48
- interface AvailabilityParams {
49
- /** Start date `YYYY-MM-DD` (property: range start). */
50
- startDate?: string;
51
- /** End date `YYYY-MM-DD` (property: range end). */
52
- endDate?: string;
53
- /** Date `YYYY-MM-DD` (restaurant: day to query slots for). */
54
- date?: string;
55
- /** Party size (restaurant: filter by capacity). */
56
- partySize?: number;
57
- /** Session duration in minutes (watersport/service: controls slot intervals). */
58
- durationMinutes?: number;
59
- }
60
- /**
61
- * A reservation as returned by the public API.
62
- *
63
- * Intentionally minimal — no Stripe internals, no per-night
64
- * breakdown, no audit metadata.
65
- */
66
- interface Reservation {
67
- /** Unique reservation identifier. */
68
- id: string;
69
- /** The resource this reservation belongs to. */
70
- resourceId: string;
71
- /** Reservation status: `pending`, `confirmed`, `cancelled`, etc. */
72
- status: string;
73
- /** Start date (`YYYY-MM-DD`) for date-based reservations. */
74
- startDate?: string;
75
- /** End date (`YYYY-MM-DD`) for date-based reservations. */
76
- endDate?: string;
77
- /** Start datetime (ISO 8601) for time-based reservations. */
78
- startTime?: string;
79
- /** End datetime (ISO 8601) for time-based reservations. */
80
- endTime?: string;
81
- /** Start datetime (ISO 8601) — returned by v2 API for datetime-range reservations. */
82
- startDatetime?: string;
83
- /** End datetime (ISO 8601) — returned by v2 API for datetime-range reservations. */
84
- endDatetime?: string;
85
- /** Guest's name. */
86
- guestName: string;
87
- /** Party size. */
88
- partySize: number;
89
- /** Total price in the smallest currency unit (cents). */
90
- totalPrice: number;
91
- /** ISO 4217 currency code (e.g. `"EUR"`). */
92
- currency: string;
93
- /** When the reservation was created (ISO 8601). */
94
- createdAt: string;
95
- }
96
- /** Response wrapper for a single reservation. */
97
- interface ReservationResponse {
98
- reservation: Reservation;
99
- }
100
- /** Paginated list of reservations. */
101
- interface PaginatedReservations {
102
- data: Reservation[];
103
- total: number;
104
- page: number;
105
- limit: number;
106
- totalPages: number;
107
- }
108
- /** Date-level availability for property-like resources. */
109
- interface DateAvailability {
110
- /** Whether the requested date range is fully available. */
111
- available?: boolean;
112
- /** Sorted list of unavailable dates (`YYYY-MM-DD`). */
113
- blockedDates: string[];
114
- /** Total price for the requested range (cents). */
115
- totalPrice?: number;
116
- /** Minimum stay in nights. */
117
- minStay?: number;
118
- }
119
- /** A single time-slot with remaining capacity (restaurants). */
120
- interface TimeSlotAvailability {
121
- /** Slot start time (ISO 8601). */
122
- start: string;
123
- /** Slot end time (ISO 8601). */
124
- end: string;
125
- /** Total capacity. */
126
- capacity: number;
127
- /** Number of confirmed/pending reservations in this slot. */
128
- reserved: number;
129
- /** Remaining seats (`capacity - reserved`). */
130
- remaining: number;
131
- /** Whether the slot has any remaining capacity. */
132
- available: boolean;
133
- }
134
- /**
135
- * Availability response — domain-agnostic.
136
- *
137
- * For properties, `dates` is populated.
138
- * For restaurants, `timeSlots` is populated.
139
- * Both are never present simultaneously.
140
- */
141
- interface Availability {
142
- /** The resource being queried. */
143
- resourceId: string;
144
- /** ISO 4217 currency code. */
145
- currency: string;
146
- /** Date-level availability (properties). */
147
- dates?: DateAvailability;
148
- /** Time-slot availability (restaurants). */
149
- timeSlots?: TimeSlotAvailability[];
150
- }
151
- /** Configuration for the Resira SDK client. */
152
- interface WeightedBaseUrl {
153
- /** Base URL for an API origin. */
154
- url: string;
155
- /** Legacy weight field. Ignored by the SDK in deterministic routing mode. */
156
- weight?: number;
157
- }
158
- interface ResiraConfig {
159
- /** API key (format: `resira_live_<hex>`). */
160
- apiKey: string;
161
- /**
162
- * Base URL of the API.
163
- * Overrides default endpoint resolution when set.
164
- */
165
- baseUrl?: string;
166
- /**
167
- * Ordered fallback API origins.
168
- * The SDK uses the first valid entry deterministically and does not persist routing state in browser storage.
169
- */
170
- baseUrls?: Array<string | WeightedBaseUrl>;
171
- /**
172
- * Maximum number of retry attempts for retryable errors (429, 5xx).
173
- * @default 3
174
- */
175
- maxRetries?: number;
176
- /**
177
- * Base delay in milliseconds for exponential backoff.
178
- * @default 500
179
- */
180
- retryBaseDelay?: number;
181
- /**
182
- * Custom `fetch` implementation (for testing or Node 16 polyfills).
183
- * Defaults to the global `fetch`.
184
- */
185
- fetch?: typeof globalThis.fetch;
186
- }
187
- /** Display settings for a resource image (CSS-level transform hints). */
188
- interface ResourceImageDisplaySettings {
189
- /** How the image fits the container. */
190
- objectFit?: "cover" | "contain" | "fill" | "none";
191
- /** CSS object-position value (e.g. "center center", "top left"). */
192
- objectPosition?: string;
193
- /** Zoom level (1.0 = no zoom, 2.0 = 200%). */
194
- zoom?: number;
195
- }
196
- /** A single image entry for a resource (multi-image support). */
197
- interface ResourceImage {
198
- /** CDN URL of the image. */
199
- url: string;
200
- /** Per-image display preferences. */
201
- displaySettings?: ResourceImageDisplaySettings;
202
- }
203
- /** A bookable resource as returned by the public API. */
204
- interface PublicResource {
205
- /** Unique resource identifier. */
206
- id: string;
207
- /** Human-readable name. */
208
- name: string;
209
- /** URL-friendly slug. */
210
- slug: string;
211
- /** Resource type (e.g. "boat", "property", "vehicle"). */
212
- resourceType: string;
213
- /** Max capacity / seats. */
214
- capacity: number | null;
215
- /** Whether the resource is active. */
216
- active: boolean;
217
- /** Optional description. */
218
- description?: string;
219
- /** Optional primary image URL (first image). */
220
- imageUrl?: string;
221
- /** All images for this resource (ordered). The first is the primary/cover image. */
222
- images?: ResourceImage[];
223
- /** Price per session in cents (watersport/service). */
224
- pricePerSession?: number;
225
- /** Session duration in minutes (watersport/service). */
226
- durationMinutes?: number;
227
- /** Currency code (e.g. "EUR"). */
228
- currency?: string;
229
- /** Subtype (e.g. "jet_ski", "kayak"). */
230
- boatType?: string;
231
- }
232
- /** Response wrapper for resource listing. */
233
- interface ResourceListResponse {
234
- resources: PublicResource[];
235
- count: number;
236
- }
237
- /** Raw error body returned by the API (`{ "error": "..." }`). */
238
- interface ApiErrorBody {
239
- error: string;
240
- retryAfter?: number;
241
- }
242
- /** Pricing model for a product/service. */
243
- type PricingModel = "per_session" | "per_person" | "per_rider";
244
- /** A duration-price pair for multi-duration services. */
245
- interface DurationPrice {
246
- /** Duration in minutes. */
247
- durationMinutes: number;
248
- /** Price in the smallest currency unit (cents). */
249
- priceCents: number;
250
- }
251
- /** A rider-tier with its own set of duration-price pairs. */
252
- interface RiderTierPrice {
253
- /** Number of riders this tier applies to. */
254
- riders: number;
255
- /** Duration-price options for this rider count. */
256
- durationPricing: DurationPrice[];
257
- }
258
- /** A bookable product/service as returned by the public API. */
259
- interface Product {
260
- /** Unique product identifier. */
261
- id: string;
262
- /** Human-readable name. */
263
- name: string;
264
- /** Optional description. */
265
- description?: string;
266
- /** Default duration in minutes (first/shortest option). */
267
- durationMinutes: number;
268
- /** Default price in the smallest currency unit (cents). */
269
- priceCents: number;
270
- /** ISO 4217 currency code (e.g. `"EUR"`). */
271
- currency: string;
272
- /** Optional image URL. */
273
- imageUrl?: string;
274
- /** Optional calendar/display color for this service, usually configured in admin settings. */
275
- serviceColor?: string;
276
- /** Whether the product is active. */
277
- active: boolean;
278
- /** Sort order. */
279
- sortOrder?: number;
280
- /** Pricing model: flat rate per session or per person. */
281
- pricingModel: PricingModel;
282
- /** IDs of linked equipment/resources. */
283
- equipmentIds: string[];
284
- /** Equipment names (resolved by the server). */
285
- equipmentNames?: string[];
286
- /** Maximum party size for this service (derived from linked equipment's maxPeople). */
287
- maxPartySize?: number;
288
- /** Available duration options with per-duration pricing. If absent, single duration. */
289
- durationPricing?: DurationPrice[];
290
- /** Rider-tier pricing (per_rider model). Each tier has a rider count and its own duration-price set. */
291
- riderTierPricing?: RiderTierPrice[];
292
- /** Normalized product variants with duration and price (returned by v2 API). */
293
- variants?: ProductVariant[];
294
- /** Available slot durations in minutes (returned by v2 API). */
295
- slotDurations?: number[];
296
- }
297
- /** Response wrapper for product listing. */
298
- interface ProductListResponse {
299
- products: Product[];
300
- count: number;
301
- }
302
- /** Request body for creating a payment intent. */
303
- interface CreatePaymentIntentRequest {
304
- /** Product ID being booked. */
305
- productId?: string;
306
- /** Resource/equipment ID. */
307
- resourceId?: string;
308
- /** Party size. */
309
- partySize?: number;
310
- /** Selected duration in minutes (for multi-duration products). */
311
- durationMinutes?: number;
312
- /** Start date (YYYY-MM-DD). */
313
- startDate?: string;
314
- /** Start time (ISO 8601, optional). */
315
- startTime?: string;
316
- /** End time (ISO 8601, optional). */
317
- endTime?: string;
318
- /** Guest name. */
319
- guestName: string;
320
- /** Guest email. Optional for restaurant reservations. */
321
- guestEmail?: string;
322
- /** Guest phone. Required for restaurant if email not provided. */
323
- guestPhone?: string;
324
- /** Notes (optional). */
325
- notes?: string;
326
- /** Promo/discount code (optional). Validated server-side. */
327
- promoCode?: string;
328
- /** Whether the guest accepted terms & conditions. Required when property has termsRequired=true. */
329
- termsAccepted?: boolean;
330
- /** Checkout session token. When provided, session data is merged with the payload. */
331
- checkoutSessionToken?: string;
332
- }
333
- /** Response from creating a payment intent. */
334
- interface PaymentIntentResponse {
335
- /** Stripe client secret for confirming payment. */
336
- clientSecret: string;
337
- /** Payment intent ID. */
338
- paymentIntentId: string;
339
- /** Amount due now (cents) — maps from backend `amountDue`. */
340
- amountNow: number;
341
- /** Amount to charge at venue (cents) — computed: totalAmount - amountNow. */
342
- amountAtVenue: number;
343
- /** Total amount (cents) — maps from backend `totalPrice`. */
344
- totalAmount: number;
345
- /** Currency code. */
346
- currency: string;
347
- /** Payment option: "full" or "deposit". */
348
- paymentOption?: string;
349
- /** The reservation created in pending state (may not be returned). */
350
- reservationId?: string;
351
- /** Discount amount in cents (if a promo code was applied). */
352
- discountAmount?: number;
353
- /** Original price before discount (cents). */
354
- originalPrice?: number;
355
- /** The promo code that was applied (echoed back by server). */
356
- promoCodeApplied?: string;
357
- }
358
- /** Request to confirm payment was successful. */
359
- interface ConfirmPaymentRequest {
360
- /** The payment intent ID from Stripe. */
361
- paymentIntentId: string;
362
- /** The reservation ID to confirm. */
363
- reservationId: string;
364
- }
365
- /** Response after confirming payment. */
366
- interface ConfirmPaymentResponse {
367
- /** The confirmed reservation. */
368
- reservation: Reservation;
369
- /** Whether payment was successfully captured. */
370
- paymentStatus: "succeeded" | "requires_action" | "failed";
371
- }
372
- /** Public-safe property configuration returned by GET /v1/public/config. */
373
- interface PropertyConfig {
374
- /** Property name. */
375
- name?: string;
376
- /** ISO 4217 currency code. */
377
- currency?: string;
378
- /** Whether online bookings are enabled. */
379
- bookingsEnabled?: boolean;
380
- /** Deposit percentage (0–100). */
381
- depositPercent?: number;
382
- /** Primary brand color. */
383
- primaryColor?: string;
384
- /** Stripe publishable key (pk_test_… or pk_live_…). */
385
- stripePublishableKey?: string | null;
386
- /** Whether multi-resource selection is allowed. */
387
- allowMultiResourceSelect?: boolean;
388
- /** Whether guests must accept terms & conditions before booking. */
389
- termsRequired?: boolean;
390
- /** Custom terms & conditions text shown to guests. */
391
- termsText?: string;
392
- /** Refund policy rules (sorted by hoursBeforeStart descending). */
393
- refundPolicy?: RefundRule[];
394
- }
395
- /** A single refund policy rule: if cancellation is >= hoursBeforeStart hours before the booking, refund refundPercent%. */
396
- interface RefundRule {
397
- /** Minimum hours before the booking start time for this tier to apply. */
398
- hoursBeforeStart: number;
399
- /** Percentage of the payment to refund (0–100). */
400
- refundPercent: number;
401
- }
402
- /** Response from validating a promo code. */
403
- interface ValidatePromoCodeResponse {
404
- /** Whether the code is valid. */
405
- valid: boolean;
406
- /** Discount type: "percent" or "fixed". */
407
- discountType?: "percent" | "fixed";
408
- /** Discount value (percentage 0-100 or fixed amount in cents). */
409
- discountValue?: number;
410
- /** Currency for fixed discounts. */
411
- currency?: string;
412
- /** Minimum order amount in cents (if applicable). */
413
- minOrderCents?: number;
414
- /** Error message if invalid. */
415
- error?: string;
416
- }
417
- /** A promo code as returned by the admin API. */
418
- interface PromoCode {
419
- id: string;
420
- propertyId: string;
421
- code: string;
422
- discountType: "percent" | "fixed";
423
- discountValue: number;
424
- currency: string;
425
- maxUses: number | null;
426
- timesUsed: number;
427
- minOrderCents: number;
428
- expiresAt: string | null;
429
- active: boolean;
430
- createdAt: string;
431
- updatedAt: string;
432
- }
433
- /** A 3D model asset attached to a dish. */
434
- interface DishModel {
435
- /** URL to the GLB/glTF model file. */
436
- glbUrl: string;
437
- /** URL to the USDZ model file (iOS AR Quick Look). */
438
- usdzUrl?: string;
439
- /** Optional poster/thumbnail shown while the model loads. */
440
- posterUrl?: string;
441
- /** Alt text for accessibility. */
442
- alt?: string;
443
- }
444
- /** A dish as returned by the public API. */
445
- interface Dish {
446
- /** Unique dish identifier (shown in admin for easy copy). */
447
- id: string;
448
- /** Human-readable dish name. */
449
- name: string;
450
- /** Optional description. */
451
- description?: string;
452
- /** Price in the smallest currency unit (cents). */
453
- priceCents?: number;
454
- /** ISO 4217 currency code (e.g. `"EUR"`). */
455
- currency?: string;
456
- /** Category or tag (e.g. "Starter", "Main", "Dessert"). */
457
- category?: string;
458
- /** Optional flat image URL (fallback when 3D is unavailable). */
459
- imageUrl?: string;
460
- /** 3D model data for AR/preview. */
461
- model?: DishModel;
462
- /** Whether the dish is currently available. */
463
- available?: boolean;
464
- /** Allergen tags (e.g. ["gluten", "dairy"]). */
465
- allergens?: string[];
466
- /** Sort order. */
467
- sortOrder?: number;
468
- }
469
- /** Response wrapper for a single dish. */
470
- interface DishResponse {
471
- dish: Dish;
472
- }
473
- /** Response wrapper for dish listing. */
474
- interface DishListResponse {
475
- dishes: Dish[];
476
- count: number;
477
- }
478
- /** Checkout configuration embedded in a checkout session. */
479
- interface CheckoutConfig {
480
- /** Stripe publishable key. */
481
- stripePublishableKey: string;
482
- /** Deposit percentage (0–100). */
483
- depositPercent: number;
484
- /** Whether terms acceptance is required. */
485
- termsRequired: boolean;
486
- /** Terms text to display. */
487
- termsText?: string;
488
- }
489
- /** A checkout session as returned by the API. */
490
- interface CheckoutSession {
491
- /** Unique session token. */
492
- sessionToken: string;
493
- /** Session status. */
494
- status: "pending" | "consumed" | "expired";
495
- /** When the session expires (ISO 8601). */
496
- expiresAt: string;
497
- /** Product ID. */
498
- productId: string;
499
- /** Product display name. */
500
- productName: string;
501
- /** Duration in minutes. */
502
- durationMinutes: number;
503
- /** Price in smallest currency unit (cents). */
504
- priceCents: number;
505
- /** ISO 4217 currency code. */
506
- currency: string;
507
- /** Party size / number of riders. */
508
- partySize: number;
509
- /** Pricing model. */
510
- pricingModel: PricingModel;
511
- /** Booking date (YYYY-MM-DD). */
512
- date: string;
513
- /** Start time (ISO 8601). */
514
- startTime: string;
515
- /** End time (ISO 8601). */
516
- endTime: string;
517
- /** Service display color. */
518
- serviceColor?: string;
519
- /** Product image URL. */
520
- imageUrl?: string;
521
- /** Pre-filled guest name. */
522
- guestName?: string;
523
- /** Pre-filled guest email. */
524
- guestEmail?: string;
525
- /** Pre-applied promo code. */
526
- promoCode?: string;
527
- /** Checkout-specific configuration. */
528
- checkoutConfig: CheckoutConfig;
529
- }
530
- /** Response wrapper for a checkout session. */
531
- interface CheckoutSessionResponse {
532
- session: CheckoutSession;
533
- }
534
- /** Request body for creating a checkout session. */
535
- interface CreateCheckoutSessionRequest {
536
- /** Product ID. */
537
- productId: string;
538
- /** Duration in minutes. */
539
- durationMinutes: number;
540
- /** Party size. */
541
- partySize: number;
542
- /** Booking date (YYYY-MM-DD). */
543
- date: string;
544
- /** Start time (ISO 8601). */
545
- startTime: string;
546
- /** End time (ISO 8601). */
547
- endTime: string;
548
- /** Guest name (optional). */
549
- guestName?: string;
550
- /** Guest email (optional). */
551
- guestEmail?: string;
552
- /** Promo code (optional). */
553
- promoCode?: string;
554
- }
555
- /** Response from creating a checkout session. */
556
- interface CreateCheckoutSessionResponse {
557
- sessionToken: string;
558
- expiresAt: string;
559
- }
560
- /** A normalized product variant with duration and price. */
561
- interface ProductVariant {
562
- /** Duration in minutes. */
563
- durationMinutes: number;
564
- /** Price in smallest currency unit (cents). */
565
- priceCents: number;
566
- /** Optional display label (e.g. "Full Hour"). */
567
- label?: string;
568
- }
569
-
570
- /**
571
- * Resira SDK client.
572
- *
573
- * ```ts
574
- * const resira = new Resira({
575
- * apiKey: "resira_live_abc123…",
576
- * baseUrl: "https://api.example.com", // optional
577
- * });
578
- *
579
- * const availability = await resira.getAvailability("prop-1", {
580
- * startDate: "2026-07-01",
581
- * endDate: "2026-07-07",
582
- * });
583
- * ```
584
- */
585
- declare class Resira {
586
- private readonly apiKey;
587
- private readonly baseUrls;
588
- private readonly maxRetries;
589
- private readonly retryBaseDelay;
590
- private readonly _fetch;
591
- constructor(config: ResiraConfig);
592
- /** The resolved API origin used by this client instance. */
593
- getBaseUrl(): string;
594
- /**
595
- * Fetch the public property configuration.
596
- *
597
- * Returns non-sensitive settings such as the Stripe publishable
598
- * key, deposit percentage, currency, and branding info.
599
- *
600
- * ```ts
601
- * const config = await resira.getConfig();
602
- * console.log(config.stripePublishableKey); // "pk_test_…"
603
- * ```
604
- */
605
- getConfig(): Promise<PropertyConfig>;
606
- /**
607
- * Validate a promo/discount code.
608
- *
609
- * Returns discount details if valid, or an error message if not.
610
- *
611
- * ```ts
612
- * const result = await resira.validatePromoCode("SUMMER20");
613
- * if (result.valid) {
614
- * console.log(result.discountType, result.discountValue);
615
- * }
616
- * ```
617
- */
618
- validatePromoCode(code: string): Promise<ValidatePromoCodeResponse>;
619
- /**
620
- * List all active resources for the organization.
621
- *
622
- * Returns resource cards with name, description, price, duration,
623
- * image, and type — suitable for building a resource picker.
624
- *
625
- * ```ts
626
- * const { resources } = await resira.listResources();
627
- * ```
628
- */
629
- listResources(): Promise<ResourceListResponse>;
630
- /**
631
- * Query availability for a resource.
632
- *
633
- * **Properties** (date-based):
634
- * ```ts
635
- * await resira.getAvailability("prop-1", {
636
- * startDate: "2026-07-01",
637
- * endDate: "2026-07-07",
638
- * });
639
- * ```
640
- *
641
- * **Restaurants** (time-slot):
642
- * ```ts
643
- * await resira.getAvailability("table-5", {
644
- * date: "2026-07-01",
645
- * partySize: 4,
646
- * });
647
- * ```
648
- *
649
- * Omit params to get all blocked dates (for calendar rendering).
650
- */
651
- getAvailability(resourceId: string, params?: AvailabilityParams): Promise<Availability>;
652
- /**
653
- * Query availability for a product/service.
654
- *
655
- * Aggregates capacity across all linked equipment. If a product
656
- * has 2 jet skis (each capacity=1), slots show capacity: 2.
657
- * Both pending and confirmed reservations count as occupied.
658
- *
659
- * ```ts
660
- * await resira.getProductAvailability("prod-123", {
661
- * date: "2026-07-01",
662
- * durationMinutes: 30,
663
- * });
664
- * ```
665
- */
666
- getProductAvailability(productId: string, params?: AvailabilityParams): Promise<Availability>;
667
- /**
668
- * Create a reservation.
669
- *
670
- * Uses `POST /v2/api/reservations` — the `resourceId` is sent in
671
- * the request body, **not** in the URL path.
672
- *
673
- * An `Idempotency-Key` header is automatically attached so that
674
- * retries (including those from exponential backoff) are safe.
675
- *
676
- * ```ts
677
- * const { reservation } = await resira.createReservation({
678
- * resourceId: "prop-1",
679
- * guestName: "Jane Doe",
680
- * guestEmail: "jane@example.com",
681
- * startDate: "2026-07-01",
682
- * endDate: "2026-07-07",
683
- * partySize: 3,
684
- * });
685
- * ```
686
- */
687
- createReservation(payload: CreateReservationRequest, options?: {
688
- idempotencyKey?: string;
689
- }): Promise<ReservationResponse>;
690
- /**
691
- * List reservations for a resource (paginated).
692
- *
693
- * ```ts
694
- * const page = await resira.listReservations("prop-1", {
695
- * status: "confirmed",
696
- * page: 1,
697
- * limit: 50,
698
- * });
699
- * console.log(page.data); // Reservation[]
700
- * console.log(page.totalPages); // number
701
- * ```
702
- */
703
- listReservations(resourceId: string, params?: ListReservationsParams): Promise<PaginatedReservations>;
704
- /**
705
- * Get a single reservation by ID.
706
- *
707
- * ```ts
708
- * const { reservation } = await resira.getReservation("prop-1", "res-uuid");
709
- * ```
710
- */
711
- getReservation(resourceId: string, reservationId: string): Promise<ReservationResponse>;
712
- /**
713
- * List all active products/services for the organisation.
714
- *
715
- * Calls `GET /v1/public/products` which returns products with
716
- * pricing, duration, and linked equipment.
717
- *
718
- * Falls back to mapping resources → products if the endpoint
719
- * returns 404 (backend hasn't been updated yet).
720
- *
721
- * ```ts
722
- * const { products } = await resira.listProducts();
723
- * ```
724
- */
725
- listProducts(): Promise<ProductListResponse>;
726
- /**
727
- * List all dishes with 3D model data for the organisation.
728
- *
729
- * Returns dishes with name, description, price, image, and
730
- * 3D model URLs for AR/preview rendering.
731
- *
732
- * ```ts
733
- * const { dishes } = await resira.listDishes();
734
- * ```
735
- */
736
- listDishes(): Promise<DishListResponse>;
737
- /**
738
- * Get a single dish by ID.
739
- *
740
- * ```ts
741
- * const { dish } = await resira.getDish("dish-uuid");
742
- * console.log(dish.name, dish.model?.glbUrl);
743
- * ```
744
- */
745
- getDish(dishId: string): Promise<DishResponse>;
746
- /**
747
- * Retrieve a checkout session by its token.
748
- *
749
- * Used to hydrate the checkout screen when opening the widget
750
- * with a pre-created session token (skip service selection).
751
- *
752
- * ```ts
753
- * const { session } = await resira.getCheckoutSession("cs_ab12cd34ef56");
754
- * console.log(session.productName, session.priceCents);
755
- * ```
756
- */
757
- getCheckoutSession(token: string): Promise<CheckoutSessionResponse>;
758
- /**
759
- * Create a new checkout session.
760
- *
761
- * External sites can create a session with product, slot, and guest
762
- * details, then pass the returned token to the widget to skip
763
- * directly to checkout.
764
- *
765
- * ```ts
766
- * const { sessionToken } = await resira.createCheckoutSession({
767
- * productId: "prod-123",
768
- * durationMinutes: 30,
769
- * partySize: 2,
770
- * date: "2026-07-01",
771
- * startTime: "2026-07-01T10:00:00Z",
772
- * endTime: "2026-07-01T10:30:00Z",
773
- * });
774
- * ```
775
- */
776
- createCheckoutSession(payload: CreateCheckoutSessionRequest, options?: {
777
- idempotencyKey?: string;
778
- }): Promise<CreateCheckoutSessionResponse>;
779
- /**
780
- * Create a Stripe payment intent for a booking.
781
- *
782
- * The server creates the payment intent, calculates the amount,
783
- * and returns a `clientSecret` to confirm payment on the frontend
784
- * using Stripe Elements.
785
- *
786
- * ```ts
787
- * const { clientSecret, amountNow, amountAtVenue } =
788
- * await resira.createPaymentIntent({
789
- * productId: "prod-123",
790
- * resourceId: "res-456",
791
- * partySize: 2,
792
- * startDate: "2026-07-01",
793
- * startTime: "2026-07-01T10:00:00Z",
794
- * endTime: "2026-07-01T11:00:00Z",
795
- * guestName: "Jane Doe",
796
- * guestEmail: "jane@example.com",
797
- * });
798
- * ```
799
- */
800
- createPaymentIntent(payload: CreatePaymentIntentRequest, options?: {
801
- idempotencyKey?: string;
802
- }): Promise<PaymentIntentResponse>;
803
- /**
804
- * Confirm that a payment was successful after the guest
805
- * completes the Stripe payment flow.
806
- *
807
- * This transitions the reservation from `pending` to `confirmed`.
808
- *
809
- * ```ts
810
- * const { reservation, paymentStatus } =
811
- * await resira.confirmPayment({
812
- * paymentIntentId: "pi_xxx",
813
- * reservationId: "res-uuid",
814
- * });
815
- * ```
816
- */
817
- confirmPayment(payload: ConfirmPaymentRequest): Promise<ConfirmPaymentResponse>;
818
- /**
819
- * Execute an HTTP request with retry logic and error normalization.
820
- *
821
- * - Attaches `Authorization: Bearer <apiKey>` on every request.
822
- * - Retries on 429 and 5xx with exponential backoff + jitter.
823
- * - Parses error bodies and throws typed error classes.
824
- */
825
- private request;
826
- /**
827
- * Calculate backoff delay in milliseconds for a given retry attempt.
828
- *
829
- * Uses exponential backoff with full jitter:
830
- * delay = random(0, base * 2^attempt)
831
- *
832
- * For 429 responses, respects the `Retry-After` header as a minimum.
833
- */
834
- private calculateBackoff;
835
- }
836
-
837
- declare function getRoutingStats(): Record<string, never>;
838
-
839
- /**
840
- * Base error class for all SDK errors.
841
- *
842
- * Use `instanceof` checks to distinguish error types:
843
- *
844
- * ```ts
845
- * try { … } catch (e) {
846
- * if (e instanceof ResiraRateLimitError) { … }
847
- * if (e instanceof ResiraApiError) { … }
848
- * if (e instanceof ResiraNetworkError) { … }
849
- * }
850
- * ```
851
- */
852
- declare class ResiraError extends Error {
853
- constructor(message: string);
854
- }
855
- /**
856
- * Thrown when the API returns a non-2xx response with a JSON body.
857
- *
858
- * ```ts
859
- * err.status // 400, 404, 409, 422, 500, …
860
- * err.code // HTTP status text (e.g. "Not Found")
861
- * err.body // Parsed `{ error: "…" }` from the server
862
- * ```
863
- */
864
- declare class ResiraApiError extends ResiraError {
865
- /** HTTP status code. */
866
- readonly status: number;
867
- /** HTTP status text (e.g. `"Bad Request"`). */
868
- readonly code: string;
869
- /** Parsed error body from the API. */
870
- readonly body: ApiErrorBody;
871
- /** The full `Response` object (headers are still accessible). */
872
- readonly response: Response;
873
- constructor(status: number, code: string, body: ApiErrorBody, response: Response);
874
- /** Whether this error is retryable (5xx or 429). */
875
- get retryable(): boolean;
876
- }
877
- /**
878
- * Thrown when the API returns 429 Too Many Requests.
879
- *
880
- * ```ts
881
- * err.retryAfter // Seconds until the client should retry
882
- * ```
883
- */
884
- declare class ResiraRateLimitError extends ResiraApiError {
885
- /** Seconds to wait before retrying (from `Retry-After` header). */
886
- readonly retryAfter: number;
887
- constructor(body: ApiErrorBody, response: Response);
888
- }
889
- /**
890
- * Thrown when the request never reached the server.
891
- *
892
- * This wraps the underlying `TypeError` or `DOMException` from
893
- * `fetch()` failures (DNS resolution, TLS, network offline, etc.).
894
- */
895
- declare class ResiraNetworkError extends ResiraError {
896
- /** The original error thrown by `fetch`. */
897
- readonly cause: unknown;
898
- constructor(message: string, cause: unknown);
899
- }
900
-
901
- export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };
1
+ /**
2
+ * POST body for creating a reservation.
3
+ *
4
+ * Use date fields (`startDate`/`endDate`) for property bookings and
5
+ * datetime fields (`startTime`/`endTime`) for restaurant/experience
6
+ * reservations. Both can be provided simultaneously.
7
+ */
8
+ interface CreateReservationRequest {
9
+ /** The resource to book. Sent in the request body. */
10
+ resourceId: string;
11
+ /** Guest's full name. */
12
+ guestName: string;
13
+ /** Guest's email address. Optional for restaurant reservations. */
14
+ guestEmail?: string;
15
+ /** Guest's phone number. Required for restaurant if email not provided. */
16
+ guestPhone?: string;
17
+ /** Start date in `YYYY-MM-DD` format (date-based resources). Optional for time-based resources. */
18
+ startDate?: string;
19
+ /** End date in `YYYY-MM-DD` format (date-based resources). Optional for time-based resources. */
20
+ endDate?: string;
21
+ /** Start datetime in ISO 8601 / RFC 3339 (time-based resources). */
22
+ startTime?: string;
23
+ /** End datetime in ISO 8601 / RFC 3339 (time-based resources). */
24
+ endTime?: string;
25
+ /** Number of guests / party size. Defaults to 2 on the server. */
26
+ partySize?: number;
27
+ /** Free-form notes from the guest. */
28
+ notes?: string;
29
+ }
30
+ /** Query parameters for listing reservations. */
31
+ interface ListReservationsParams {
32
+ /** Filter by status (e.g. `"pending"`, `"confirmed"`). Omit for all non-archived. */
33
+ status?: string;
34
+ /** Page number (1-indexed). Defaults to 1. */
35
+ page?: number;
36
+ /** Items per page (1–100). Defaults to 25. */
37
+ limit?: number;
38
+ }
39
+ /**
40
+ * Query parameters for the availability endpoint.
41
+ *
42
+ * For **properties**: pass `startDate` + `endDate` to check a range,
43
+ * or omit both to get all blocked dates for calendar rendering.
44
+ *
45
+ * For **restaurants**: pass `date` (and optionally `partySize`) to
46
+ * get time-slot availability for a specific day.
47
+ */
48
+ interface AvailabilityParams {
49
+ /** Start date `YYYY-MM-DD` (property: range start). */
50
+ startDate?: string;
51
+ /** End date `YYYY-MM-DD` (property: range end). */
52
+ endDate?: string;
53
+ /** Date `YYYY-MM-DD` (restaurant: day to query slots for). */
54
+ date?: string;
55
+ /** Party size (restaurant: filter by capacity). */
56
+ partySize?: number;
57
+ /** Session duration in minutes (watersport/service: controls slot intervals). */
58
+ durationMinutes?: number;
59
+ }
60
+ /**
61
+ * A reservation as returned by the public API.
62
+ *
63
+ * Intentionally minimal — no Stripe internals, no per-night
64
+ * breakdown, no audit metadata.
65
+ */
66
+ interface Reservation {
67
+ /** Unique reservation identifier. */
68
+ id: string;
69
+ /** The resource this reservation belongs to. */
70
+ resourceId: string;
71
+ /** Reservation status: `pending`, `confirmed`, `cancelled`, etc. */
72
+ status: string;
73
+ /** Start date (`YYYY-MM-DD`) for date-based reservations. */
74
+ startDate?: string;
75
+ /** End date (`YYYY-MM-DD`) for date-based reservations. */
76
+ endDate?: string;
77
+ /** Start datetime (ISO 8601) for time-based reservations. */
78
+ startTime?: string;
79
+ /** End datetime (ISO 8601) for time-based reservations. */
80
+ endTime?: string;
81
+ /** Start datetime (ISO 8601) — returned by v2 API for datetime-range reservations. */
82
+ startDatetime?: string;
83
+ /** End datetime (ISO 8601) — returned by v2 API for datetime-range reservations. */
84
+ endDatetime?: string;
85
+ /** Guest's name. */
86
+ guestName: string;
87
+ /** Party size. */
88
+ partySize: number;
89
+ /** Total price in the smallest currency unit (cents). */
90
+ totalPrice: number;
91
+ /** ISO 4217 currency code (e.g. `"EUR"`). */
92
+ currency: string;
93
+ /** When the reservation was created (ISO 8601). */
94
+ createdAt: string;
95
+ }
96
+ /** Response wrapper for a single reservation. */
97
+ interface ReservationResponse {
98
+ reservation: Reservation;
99
+ }
100
+ /** Paginated list of reservations. */
101
+ interface PaginatedReservations {
102
+ data: Reservation[];
103
+ total: number;
104
+ page: number;
105
+ limit: number;
106
+ totalPages: number;
107
+ }
108
+ /** Date-level availability for property-like resources. */
109
+ interface DateAvailability {
110
+ /** Whether the requested date range is fully available. */
111
+ available?: boolean;
112
+ /** Sorted list of unavailable dates (`YYYY-MM-DD`). */
113
+ blockedDates: string[];
114
+ /** Total price for the requested range (cents). */
115
+ totalPrice?: number;
116
+ /** Minimum stay in nights. */
117
+ minStay?: number;
118
+ }
119
+ /** A single time-slot with remaining capacity (restaurants). */
120
+ interface TimeSlotAvailability {
121
+ /** Slot start time (ISO 8601). */
122
+ start: string;
123
+ /** Slot end time (ISO 8601). */
124
+ end: string;
125
+ /** Total capacity. */
126
+ capacity: number;
127
+ /** Number of confirmed/pending reservations in this slot. */
128
+ reserved: number;
129
+ /** Remaining seats (`capacity - reserved`). */
130
+ remaining: number;
131
+ /** Whether the slot has any remaining capacity. */
132
+ available: boolean;
133
+ }
134
+ /**
135
+ * Availability response — domain-agnostic.
136
+ *
137
+ * For properties, `dates` is populated.
138
+ * For restaurants, `timeSlots` is populated.
139
+ * Both are never present simultaneously.
140
+ */
141
+ interface Availability {
142
+ /** The resource being queried. */
143
+ resourceId: string;
144
+ /** ISO 4217 currency code. */
145
+ currency: string;
146
+ /** Date-level availability (properties). */
147
+ dates?: DateAvailability;
148
+ /** Time-slot availability (restaurants). */
149
+ timeSlots?: TimeSlotAvailability[];
150
+ }
151
+ /** Configuration for the Resira SDK client. */
152
+ interface WeightedBaseUrl {
153
+ /** Base URL for an API origin. */
154
+ url: string;
155
+ /** Legacy weight field. Ignored by the SDK in deterministic routing mode. */
156
+ weight?: number;
157
+ }
158
+ interface ResiraConfig {
159
+ /** API key (format: `resira_live_<hex>`). */
160
+ apiKey: string;
161
+ /**
162
+ * Base URL of the API.
163
+ * Overrides default endpoint resolution when set.
164
+ */
165
+ baseUrl?: string;
166
+ /**
167
+ * Ordered fallback API origins.
168
+ * The SDK uses the first valid entry deterministically and does not persist routing state in browser storage.
169
+ */
170
+ baseUrls?: Array<string | WeightedBaseUrl>;
171
+ /**
172
+ * Maximum number of retry attempts for retryable errors (429, 5xx).
173
+ * @default 3
174
+ */
175
+ maxRetries?: number;
176
+ /**
177
+ * Base delay in milliseconds for exponential backoff.
178
+ * @default 500
179
+ */
180
+ retryBaseDelay?: number;
181
+ /**
182
+ * Custom `fetch` implementation (for testing or Node 16 polyfills).
183
+ * Defaults to the global `fetch`.
184
+ */
185
+ fetch?: typeof globalThis.fetch;
186
+ }
187
+ /** Display settings for a resource image (CSS-level transform hints). */
188
+ interface ResourceImageDisplaySettings {
189
+ /** How the image fits the container. */
190
+ objectFit?: "cover" | "contain" | "fill" | "none";
191
+ /** CSS object-position value (e.g. "center center", "top left"). */
192
+ objectPosition?: string;
193
+ /** Zoom level (1.0 = no zoom, 2.0 = 200%). */
194
+ zoom?: number;
195
+ }
196
+ /** A single image entry for a resource (multi-image support). */
197
+ interface ResourceImage {
198
+ /** CDN URL of the image. */
199
+ url: string;
200
+ /** Per-image display preferences. */
201
+ displaySettings?: ResourceImageDisplaySettings;
202
+ }
203
+ /** A bookable resource as returned by the public API. */
204
+ interface PublicResource {
205
+ /** Unique resource identifier. */
206
+ id: string;
207
+ /** Human-readable name. */
208
+ name: string;
209
+ /** URL-friendly slug. */
210
+ slug: string;
211
+ /** Resource type (e.g. "boat", "property", "vehicle"). */
212
+ resourceType: string;
213
+ /** Max capacity / seats. */
214
+ capacity: number | null;
215
+ /** Whether the resource is active. */
216
+ active: boolean;
217
+ /** Optional description. */
218
+ description?: string;
219
+ /** Optional primary image URL (first image). */
220
+ imageUrl?: string;
221
+ /** All images for this resource (ordered). The first is the primary/cover image. */
222
+ images?: ResourceImage[];
223
+ /** Price per session in cents (watersport/service). */
224
+ pricePerSession?: number;
225
+ /** Session duration in minutes (watersport/service). */
226
+ durationMinutes?: number;
227
+ /** Currency code (e.g. "EUR"). */
228
+ currency?: string;
229
+ /** Subtype (e.g. "jet_ski", "kayak"). */
230
+ boatType?: string;
231
+ }
232
+ /** Response wrapper for resource listing. */
233
+ interface ResourceListResponse {
234
+ resources: PublicResource[];
235
+ count: number;
236
+ }
237
+ /** Raw error body returned by the API (`{ "error": "..." }`). */
238
+ interface ApiErrorBody {
239
+ error: string;
240
+ retryAfter?: number;
241
+ }
242
+ /** Pricing model for a product/service. */
243
+ type PricingModel = "per_session" | "per_person" | "per_rider";
244
+ /** A duration-price pair for multi-duration services. */
245
+ interface DurationPrice {
246
+ /** Duration in minutes. */
247
+ durationMinutes: number;
248
+ /** Price in the smallest currency unit (cents). */
249
+ priceCents: number;
250
+ }
251
+ /** A rider-tier with its own set of duration-price pairs. */
252
+ interface RiderTierPrice {
253
+ /** Number of riders this tier applies to. */
254
+ riders: number;
255
+ /** Duration-price options for this rider count. */
256
+ durationPricing: DurationPrice[];
257
+ }
258
+ /** A bookable product/service as returned by the public API. */
259
+ interface Product {
260
+ /** Unique product identifier. */
261
+ id: string;
262
+ /** Human-readable name. */
263
+ name: string;
264
+ /** Optional description. */
265
+ description?: string;
266
+ /** Default duration in minutes (first/shortest option). */
267
+ durationMinutes: number;
268
+ /** Default price in the smallest currency unit (cents). */
269
+ priceCents: number;
270
+ /** ISO 4217 currency code (e.g. `"EUR"`). */
271
+ currency: string;
272
+ /** Optional image URL. */
273
+ imageUrl?: string;
274
+ /** Optional calendar/display color for this service, usually configured in admin settings. */
275
+ serviceColor?: string;
276
+ /** Whether the product is active. */
277
+ active: boolean;
278
+ /** Sort order. */
279
+ sortOrder?: number;
280
+ /** Pricing model: flat rate per session or per person. */
281
+ pricingModel: PricingModel;
282
+ /** IDs of linked equipment/resources. */
283
+ equipmentIds: string[];
284
+ /** Equipment names (resolved by the server). */
285
+ equipmentNames?: string[];
286
+ /** Maximum party size for this service (derived from linked equipment's maxPeople). */
287
+ maxPartySize?: number;
288
+ /** Available duration options with per-duration pricing. If absent, single duration. */
289
+ durationPricing?: DurationPrice[];
290
+ /** Rider-tier pricing (per_rider model). Each tier has a rider count and its own duration-price set. */
291
+ riderTierPricing?: RiderTierPrice[];
292
+ /** Normalized product variants with duration and price (returned by v2 API). */
293
+ variants?: ProductVariant[];
294
+ /** Available slot durations in minutes (returned by v2 API). */
295
+ slotDurations?: number[];
296
+ }
297
+ /** Response wrapper for product listing. */
298
+ interface ProductListResponse {
299
+ products: Product[];
300
+ count: number;
301
+ }
302
+ /** Request body for creating a payment intent. */
303
+ interface CreatePaymentIntentRequest {
304
+ /** Product ID being booked. */
305
+ productId?: string;
306
+ /** Resource/equipment ID. */
307
+ resourceId?: string;
308
+ /** Party size. */
309
+ partySize?: number;
310
+ /** Selected duration in minutes (for multi-duration products). */
311
+ durationMinutes?: number;
312
+ /** Start date (YYYY-MM-DD). */
313
+ startDate?: string;
314
+ /** Start time (ISO 8601, optional). */
315
+ startTime?: string;
316
+ /** End time (ISO 8601, optional). */
317
+ endTime?: string;
318
+ /** Guest name. */
319
+ guestName: string;
320
+ /** Guest email. Optional for restaurant reservations. */
321
+ guestEmail?: string;
322
+ /** Guest phone. Required for restaurant if email not provided. */
323
+ guestPhone?: string;
324
+ /** Notes (optional). */
325
+ notes?: string;
326
+ /** Promo/discount code (optional). Validated server-side. */
327
+ promoCode?: string;
328
+ /** Whether the guest accepted terms & conditions. Required when property has termsRequired=true. */
329
+ termsAccepted?: boolean;
330
+ /** Checkout session token. When provided, session data is merged with the payload. */
331
+ checkoutSessionToken?: string;
332
+ }
333
+ /** Response from creating a payment intent. */
334
+ interface PaymentIntentResponse {
335
+ /** Stripe client secret for confirming payment. */
336
+ clientSecret: string;
337
+ /** Payment intent ID. */
338
+ paymentIntentId: string;
339
+ /** Amount due now (cents) — maps from backend `amountDue`. */
340
+ amountNow: number;
341
+ /** Amount to charge at venue (cents) — computed: totalAmount - amountNow. */
342
+ amountAtVenue: number;
343
+ /** Total amount (cents) — maps from backend `totalPrice`. */
344
+ totalAmount: number;
345
+ /** Currency code. */
346
+ currency: string;
347
+ /** Payment option: "full" or "deposit". */
348
+ paymentOption?: string;
349
+ /** The reservation created in pending state (may not be returned). */
350
+ reservationId?: string;
351
+ /** Discount amount in cents (if a promo code was applied). */
352
+ discountAmount?: number;
353
+ /** Original price before discount (cents). */
354
+ originalPrice?: number;
355
+ /** The promo code that was applied (echoed back by server). */
356
+ promoCodeApplied?: string;
357
+ }
358
+ /** Request to confirm payment was successful. */
359
+ interface ConfirmPaymentRequest {
360
+ /** The payment intent ID from Stripe. */
361
+ paymentIntentId: string;
362
+ /** The reservation ID to confirm. */
363
+ reservationId: string;
364
+ }
365
+ /** Response after confirming payment. */
366
+ interface ConfirmPaymentResponse {
367
+ /** The confirmed reservation. */
368
+ reservation: Reservation;
369
+ /** Whether payment was successfully captured. */
370
+ paymentStatus: "succeeded" | "requires_action" | "failed";
371
+ }
372
+ /** Public-safe property configuration returned by GET /v1/public/config. */
373
+ interface PropertyConfig {
374
+ /** Property name. */
375
+ name?: string;
376
+ /** ISO 4217 currency code. */
377
+ currency?: string;
378
+ /** Whether online bookings are enabled. */
379
+ bookingsEnabled?: boolean;
380
+ /** Deposit percentage (0–100). */
381
+ depositPercent?: number;
382
+ /** Primary brand color. */
383
+ primaryColor?: string;
384
+ /** Stripe publishable key (pk_test_… or pk_live_…). */
385
+ stripePublishableKey?: string | null;
386
+ /** Whether multi-resource selection is allowed. */
387
+ allowMultiResourceSelect?: boolean;
388
+ /** Whether guests must accept terms & conditions before booking. */
389
+ termsRequired?: boolean;
390
+ /** Custom terms & conditions text shown to guests. */
391
+ termsText?: string;
392
+ /** Refund policy rules (sorted by hoursBeforeStart descending). */
393
+ refundPolicy?: RefundRule[];
394
+ }
395
+ /** A single refund policy rule: if cancellation is >= hoursBeforeStart hours before the booking, refund refundPercent%. */
396
+ interface RefundRule {
397
+ /** Minimum hours before the booking start time for this tier to apply. */
398
+ hoursBeforeStart: number;
399
+ /** Percentage of the payment to refund (0–100). */
400
+ refundPercent: number;
401
+ }
402
+ /** Response from validating a promo code. */
403
+ interface ValidatePromoCodeResponse {
404
+ /** Whether the code is valid. */
405
+ valid: boolean;
406
+ /** Discount type: "percent" or "fixed". */
407
+ discountType?: "percent" | "fixed";
408
+ /** Discount value (percentage 0-100 or fixed amount in cents). */
409
+ discountValue?: number;
410
+ /** Currency for fixed discounts. */
411
+ currency?: string;
412
+ /** Minimum order amount in cents (if applicable). */
413
+ minOrderCents?: number;
414
+ /** Error message if invalid. */
415
+ error?: string;
416
+ }
417
+ /** A promo code as returned by the admin API. */
418
+ interface PromoCode {
419
+ id: string;
420
+ propertyId: string;
421
+ code: string;
422
+ discountType: "percent" | "fixed";
423
+ discountValue: number;
424
+ currency: string;
425
+ maxUses: number | null;
426
+ timesUsed: number;
427
+ minOrderCents: number;
428
+ expiresAt: string | null;
429
+ active: boolean;
430
+ createdAt: string;
431
+ updatedAt: string;
432
+ }
433
+ /** A 3D model asset attached to a dish. */
434
+ interface DishModel {
435
+ /** URL to the GLB/glTF model file. */
436
+ glbUrl: string;
437
+ /** URL to the USDZ model file (iOS AR Quick Look). */
438
+ usdzUrl?: string;
439
+ /** Optional poster/thumbnail shown while the model loads. */
440
+ posterUrl?: string;
441
+ /** Alt text for accessibility. */
442
+ alt?: string;
443
+ }
444
+ /** A dish as returned by the public API. */
445
+ interface Dish {
446
+ /** Unique dish identifier (shown in admin for easy copy). */
447
+ id: string;
448
+ /** Human-readable dish name. */
449
+ name: string;
450
+ /** Optional description. */
451
+ description?: string;
452
+ /** Price in the smallest currency unit (cents). */
453
+ priceCents?: number;
454
+ /** ISO 4217 currency code (e.g. `"EUR"`). */
455
+ currency?: string;
456
+ /** Category or tag (e.g. "Starter", "Main", "Dessert"). */
457
+ category?: string;
458
+ /** Optional flat image URL (fallback when 3D is unavailable). */
459
+ imageUrl?: string;
460
+ /** 3D model data for AR/preview. */
461
+ model?: DishModel;
462
+ /** Whether the dish is currently available. */
463
+ available?: boolean;
464
+ /** Allergen tags (e.g. ["gluten", "dairy"]). */
465
+ allergens?: string[];
466
+ /** Sort order. */
467
+ sortOrder?: number;
468
+ }
469
+ /** Response wrapper for a single dish. */
470
+ interface DishResponse {
471
+ dish: Dish;
472
+ }
473
+ /** Response wrapper for dish listing. */
474
+ interface DishListResponse {
475
+ dishes: Dish[];
476
+ count: number;
477
+ }
478
+ /** Checkout configuration embedded in a checkout session. */
479
+ interface CheckoutConfig {
480
+ /** Stripe publishable key. */
481
+ stripePublishableKey: string;
482
+ /** Deposit percentage (0–100). */
483
+ depositPercent: number;
484
+ /** Whether terms acceptance is required. */
485
+ termsRequired: boolean;
486
+ /** Terms text to display. */
487
+ termsText?: string;
488
+ }
489
+ /** A checkout session as returned by the API. */
490
+ interface CheckoutSession {
491
+ /** Unique session token. */
492
+ sessionToken: string;
493
+ /** Session status. */
494
+ status: "pending" | "consumed" | "expired";
495
+ /** When the session expires (ISO 8601). */
496
+ expiresAt: string;
497
+ /** Product ID. */
498
+ productId: string;
499
+ /** Product display name. */
500
+ productName: string;
501
+ /** Duration in minutes. */
502
+ durationMinutes: number;
503
+ /** Price in smallest currency unit (cents). */
504
+ priceCents: number;
505
+ /** ISO 4217 currency code. */
506
+ currency: string;
507
+ /** Party size / number of riders. */
508
+ partySize: number;
509
+ /** Pricing model. */
510
+ pricingModel: PricingModel;
511
+ /** Booking date (YYYY-MM-DD). */
512
+ date: string;
513
+ /** Start time (ISO 8601). */
514
+ startTime: string;
515
+ /** End time (ISO 8601). */
516
+ endTime: string;
517
+ /** Service display color. */
518
+ serviceColor?: string;
519
+ /** Product image URL. */
520
+ imageUrl?: string;
521
+ /** Pre-filled guest name. */
522
+ guestName?: string;
523
+ /** Pre-filled guest email. */
524
+ guestEmail?: string;
525
+ /** Pre-applied promo code. */
526
+ promoCode?: string;
527
+ /** Checkout-specific configuration. */
528
+ checkoutConfig: CheckoutConfig;
529
+ }
530
+ /** Response wrapper for a checkout session. */
531
+ interface CheckoutSessionResponse {
532
+ session: CheckoutSession;
533
+ }
534
+ /** Request body for creating a checkout session. */
535
+ interface CreateCheckoutSessionRequest {
536
+ /** Product ID. */
537
+ productId: string;
538
+ /** Duration in minutes. */
539
+ durationMinutes: number;
540
+ /** Party size. */
541
+ partySize: number;
542
+ /** Booking date (YYYY-MM-DD). */
543
+ date: string;
544
+ /** Start time (ISO 8601). */
545
+ startTime: string;
546
+ /** End time (ISO 8601). */
547
+ endTime: string;
548
+ /** Guest name (optional). */
549
+ guestName?: string;
550
+ /** Guest email (optional). */
551
+ guestEmail?: string;
552
+ /** Promo code (optional). */
553
+ promoCode?: string;
554
+ }
555
+ /** Response from creating a checkout session. */
556
+ interface CreateCheckoutSessionResponse {
557
+ sessionToken: string;
558
+ expiresAt: string;
559
+ }
560
+ /** A normalized product variant with duration and price. */
561
+ interface ProductVariant {
562
+ /** Duration in minutes. */
563
+ durationMinutes: number;
564
+ /** Price in smallest currency unit (cents). */
565
+ priceCents: number;
566
+ /** Optional display label (e.g. "Full Hour"). */
567
+ label?: string;
568
+ }
569
+
570
+ /**
571
+ * Resira SDK client.
572
+ *
573
+ * ```ts
574
+ * const resira = new Resira({
575
+ * apiKey: "resira_live_abc123…",
576
+ * baseUrl: "https://api.example.com", // optional
577
+ * });
578
+ *
579
+ * const availability = await resira.getAvailability("prop-1", {
580
+ * startDate: "2026-07-01",
581
+ * endDate: "2026-07-07",
582
+ * });
583
+ * ```
584
+ */
585
+ declare class Resira {
586
+ private readonly apiKey;
587
+ private readonly baseUrls;
588
+ private readonly maxRetries;
589
+ private readonly retryBaseDelay;
590
+ private readonly _fetch;
591
+ constructor(config: ResiraConfig);
592
+ /** The resolved API origin used by this client instance. */
593
+ getBaseUrl(): string;
594
+ /**
595
+ * Fetch the public property configuration.
596
+ *
597
+ * Returns non-sensitive settings such as the Stripe publishable
598
+ * key, deposit percentage, currency, and branding info.
599
+ *
600
+ * ```ts
601
+ * const config = await resira.getConfig();
602
+ * console.log(config.stripePublishableKey); // "pk_test_…"
603
+ * ```
604
+ */
605
+ getConfig(): Promise<PropertyConfig>;
606
+ /**
607
+ * Validate a promo/discount code.
608
+ *
609
+ * Returns discount details if valid, or an error message if not.
610
+ *
611
+ * ```ts
612
+ * const result = await resira.validatePromoCode("SUMMER20");
613
+ * if (result.valid) {
614
+ * console.log(result.discountType, result.discountValue);
615
+ * }
616
+ * ```
617
+ */
618
+ validatePromoCode(code: string): Promise<ValidatePromoCodeResponse>;
619
+ /**
620
+ * List all active resources for the organization.
621
+ *
622
+ * Returns resource cards with name, description, price, duration,
623
+ * image, and type — suitable for building a resource picker.
624
+ *
625
+ * ```ts
626
+ * const { resources } = await resira.listResources();
627
+ * ```
628
+ */
629
+ listResources(): Promise<ResourceListResponse>;
630
+ /**
631
+ * Query availability for a resource.
632
+ *
633
+ * **Properties** (date-based):
634
+ * ```ts
635
+ * await resira.getAvailability("prop-1", {
636
+ * startDate: "2026-07-01",
637
+ * endDate: "2026-07-07",
638
+ * });
639
+ * ```
640
+ *
641
+ * **Restaurants** (time-slot):
642
+ * ```ts
643
+ * await resira.getAvailability("table-5", {
644
+ * date: "2026-07-01",
645
+ * partySize: 4,
646
+ * });
647
+ * ```
648
+ *
649
+ * Omit params to get all blocked dates (for calendar rendering).
650
+ */
651
+ getAvailability(resourceId: string, params?: AvailabilityParams): Promise<Availability>;
652
+ /**
653
+ * Query availability for a product/service.
654
+ *
655
+ * Aggregates capacity across all linked equipment. If a product
656
+ * has 2 jet skis (each capacity=1), slots show capacity: 2.
657
+ * Both pending and confirmed reservations count as occupied.
658
+ *
659
+ * ```ts
660
+ * await resira.getProductAvailability("prod-123", {
661
+ * date: "2026-07-01",
662
+ * durationMinutes: 30,
663
+ * });
664
+ * ```
665
+ */
666
+ getProductAvailability(productId: string, params?: AvailabilityParams): Promise<Availability>;
667
+ /**
668
+ * Create a reservation.
669
+ *
670
+ * Uses `POST /v2/api/reservations` — the `resourceId` is sent in
671
+ * the request body, **not** in the URL path.
672
+ *
673
+ * An `Idempotency-Key` header is automatically attached so that
674
+ * retries (including those from exponential backoff) are safe.
675
+ *
676
+ * ```ts
677
+ * const { reservation } = await resira.createReservation({
678
+ * resourceId: "prop-1",
679
+ * guestName: "Jane Doe",
680
+ * guestEmail: "jane@example.com",
681
+ * startDate: "2026-07-01",
682
+ * endDate: "2026-07-07",
683
+ * partySize: 3,
684
+ * });
685
+ * ```
686
+ */
687
+ createReservation(payload: CreateReservationRequest, options?: {
688
+ idempotencyKey?: string;
689
+ }): Promise<ReservationResponse>;
690
+ /**
691
+ * List reservations for a resource (paginated).
692
+ *
693
+ * ```ts
694
+ * const page = await resira.listReservations("prop-1", {
695
+ * status: "confirmed",
696
+ * page: 1,
697
+ * limit: 50,
698
+ * });
699
+ * console.log(page.data); // Reservation[]
700
+ * console.log(page.totalPages); // number
701
+ * ```
702
+ */
703
+ listReservations(resourceId: string, params?: ListReservationsParams): Promise<PaginatedReservations>;
704
+ /**
705
+ * Get a single reservation by ID.
706
+ *
707
+ * ```ts
708
+ * const { reservation } = await resira.getReservation("prop-1", "res-uuid");
709
+ * ```
710
+ */
711
+ getReservation(resourceId: string, reservationId: string): Promise<ReservationResponse>;
712
+ /**
713
+ * List all active products/services for the organisation.
714
+ *
715
+ * Calls `GET /v1/public/products` which returns products with
716
+ * pricing, duration, and linked equipment.
717
+ *
718
+ * Falls back to mapping resources → products if the endpoint
719
+ * returns 404 (backend hasn't been updated yet).
720
+ *
721
+ * ```ts
722
+ * const { products } = await resira.listProducts();
723
+ * ```
724
+ */
725
+ listProducts(): Promise<ProductListResponse>;
726
+ /**
727
+ * List all dishes with 3D model data for the organisation.
728
+ *
729
+ * Returns dishes with name, description, price, image, and
730
+ * 3D model URLs for AR/preview rendering.
731
+ *
732
+ * ```ts
733
+ * const { dishes } = await resira.listDishes();
734
+ * ```
735
+ */
736
+ listDishes(): Promise<DishListResponse>;
737
+ /**
738
+ * Get a single dish by ID.
739
+ *
740
+ * ```ts
741
+ * const { dish } = await resira.getDish("dish-uuid");
742
+ * console.log(dish.name, dish.model?.glbUrl);
743
+ * ```
744
+ */
745
+ getDish(dishId: string): Promise<DishResponse>;
746
+ /**
747
+ * Retrieve a checkout session by its token.
748
+ *
749
+ * Used to hydrate the checkout screen when opening the widget
750
+ * with a pre-created session token (skip service selection).
751
+ *
752
+ * ```ts
753
+ * const { session } = await resira.getCheckoutSession("cs_ab12cd34ef56");
754
+ * console.log(session.productName, session.priceCents);
755
+ * ```
756
+ */
757
+ getCheckoutSession(token: string): Promise<CheckoutSessionResponse>;
758
+ /**
759
+ * Create a new checkout session.
760
+ *
761
+ * External sites can create a session with product, slot, and guest
762
+ * details, then pass the returned token to the widget to skip
763
+ * directly to checkout.
764
+ *
765
+ * ```ts
766
+ * const { sessionToken } = await resira.createCheckoutSession({
767
+ * productId: "prod-123",
768
+ * durationMinutes: 30,
769
+ * partySize: 2,
770
+ * date: "2026-07-01",
771
+ * startTime: "2026-07-01T10:00:00Z",
772
+ * endTime: "2026-07-01T10:30:00Z",
773
+ * });
774
+ * ```
775
+ */
776
+ createCheckoutSession(payload: CreateCheckoutSessionRequest, options?: {
777
+ idempotencyKey?: string;
778
+ }): Promise<CreateCheckoutSessionResponse>;
779
+ /**
780
+ * Create a Stripe payment intent for a booking.
781
+ *
782
+ * The server creates the payment intent, calculates the amount,
783
+ * and returns a `clientSecret` to confirm payment on the frontend
784
+ * using Stripe Elements.
785
+ *
786
+ * ```ts
787
+ * const { clientSecret, amountNow, amountAtVenue } =
788
+ * await resira.createPaymentIntent({
789
+ * productId: "prod-123",
790
+ * resourceId: "res-456",
791
+ * partySize: 2,
792
+ * startDate: "2026-07-01",
793
+ * startTime: "2026-07-01T10:00:00Z",
794
+ * endTime: "2026-07-01T11:00:00Z",
795
+ * guestName: "Jane Doe",
796
+ * guestEmail: "jane@example.com",
797
+ * });
798
+ * ```
799
+ */
800
+ createPaymentIntent(payload: CreatePaymentIntentRequest, options?: {
801
+ idempotencyKey?: string;
802
+ }): Promise<PaymentIntentResponse>;
803
+ /**
804
+ * Confirm that a payment was successful after the guest
805
+ * completes the Stripe payment flow.
806
+ *
807
+ * This transitions the reservation from `pending` to `confirmed`.
808
+ *
809
+ * ```ts
810
+ * const { reservation, paymentStatus } =
811
+ * await resira.confirmPayment({
812
+ * paymentIntentId: "pi_xxx",
813
+ * reservationId: "res-uuid",
814
+ * });
815
+ * ```
816
+ */
817
+ confirmPayment(payload: ConfirmPaymentRequest): Promise<ConfirmPaymentResponse>;
818
+ /**
819
+ * Execute an HTTP request with retry logic and error normalization.
820
+ *
821
+ * - Attaches `Authorization: Bearer <apiKey>` on every request.
822
+ * - Retries on 429 and 5xx with exponential backoff + jitter.
823
+ * - Parses error bodies and throws typed error classes.
824
+ */
825
+ private request;
826
+ /**
827
+ * Calculate backoff delay in milliseconds for a given retry attempt.
828
+ *
829
+ * Uses exponential backoff with full jitter:
830
+ * delay = random(0, base * 2^attempt)
831
+ *
832
+ * For 429 responses, respects the `Retry-After` header as a minimum.
833
+ */
834
+ private calculateBackoff;
835
+ }
836
+
837
+ declare function getRoutingStats(): Record<string, never>;
838
+
839
+ /**
840
+ * Base error class for all SDK errors.
841
+ *
842
+ * Use `instanceof` checks to distinguish error types:
843
+ *
844
+ * ```ts
845
+ * try { … } catch (e) {
846
+ * if (e instanceof ResiraRateLimitError) { … }
847
+ * if (e instanceof ResiraApiError) { … }
848
+ * if (e instanceof ResiraNetworkError) { … }
849
+ * }
850
+ * ```
851
+ */
852
+ declare class ResiraError extends Error {
853
+ constructor(message: string);
854
+ }
855
+ /**
856
+ * Thrown when the API returns a non-2xx response with a JSON body.
857
+ *
858
+ * ```ts
859
+ * err.status // 400, 404, 409, 422, 500, …
860
+ * err.code // HTTP status text (e.g. "Not Found")
861
+ * err.body // Parsed `{ error: "…" }` from the server
862
+ * ```
863
+ */
864
+ declare class ResiraApiError extends ResiraError {
865
+ /** HTTP status code. */
866
+ readonly status: number;
867
+ /** HTTP status text (e.g. `"Bad Request"`). */
868
+ readonly code: string;
869
+ /** Parsed error body from the API. */
870
+ readonly body: ApiErrorBody;
871
+ /** The full `Response` object (headers are still accessible). */
872
+ readonly response: Response;
873
+ constructor(status: number, code: string, body: ApiErrorBody, response: Response);
874
+ /** Whether this error is retryable (5xx or 429). */
875
+ get retryable(): boolean;
876
+ }
877
+ /**
878
+ * Thrown when the API returns 429 Too Many Requests.
879
+ *
880
+ * ```ts
881
+ * err.retryAfter // Seconds until the client should retry
882
+ * ```
883
+ */
884
+ declare class ResiraRateLimitError extends ResiraApiError {
885
+ /** Seconds to wait before retrying (from `Retry-After` header). */
886
+ readonly retryAfter: number;
887
+ constructor(body: ApiErrorBody, response: Response);
888
+ }
889
+ /**
890
+ * Thrown when the request never reached the server.
891
+ *
892
+ * This wraps the underlying `TypeError` or `DOMException` from
893
+ * `fetch()` failures (DNS resolution, TLS, network offline, etc.).
894
+ */
895
+ declare class ResiraNetworkError extends ResiraError {
896
+ /** The original error thrown by `fetch`. */
897
+ readonly cause: unknown;
898
+ constructor(message: string, cause: unknown);
899
+ }
900
+
901
+ export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };