@medalsocial/sdk 1.6.0 → 1.7.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.
@@ -21,6 +21,11 @@ tags:
21
21
  description: Manage workspace CRM contacts.
22
22
  - name: Deals
23
23
  description: Manage sponsorship and brand deals.
24
+ - name: Bookings
25
+ description: >-
26
+ Appointment bookings — the service catalogue, free slots, staff actions
27
+ on a booking, and the customer-facing manage-token routes. Money is
28
+ always integer øre.
24
29
  - name: GDPR
25
30
  description: Manage exports, consent records, and cookie consent.
26
31
  - name: Workspaces
@@ -543,6 +548,356 @@ paths:
543
548
  $ref: "#/components/schemas/ApiResponse_DealRemoveResult"
544
549
  default:
545
550
  $ref: "#/components/responses/ApiError"
551
+ /api/v1/bookings:
552
+ get:
553
+ tags: [Bookings]
554
+ operationId: listBookings
555
+ summary: List bookings
556
+ parameters:
557
+ - $ref: "#/components/parameters/Limit"
558
+ - $ref: "#/components/parameters/Cursor"
559
+ - name: from_ts
560
+ in: query
561
+ description: Only bookings starting at or after this instant.
562
+ schema:
563
+ $ref: "#/components/schemas/BookingTimestampInput"
564
+ - name: to_ts
565
+ in: query
566
+ description: Only bookings starting before this instant.
567
+ schema:
568
+ $ref: "#/components/schemas/BookingTimestampInput"
569
+ - name: status
570
+ in: query
571
+ schema:
572
+ $ref: "#/components/schemas/BookingStatus"
573
+ - name: resource_id
574
+ in: query
575
+ schema:
576
+ type: string
577
+ responses:
578
+ "200":
579
+ description: Bookings page.
580
+ content:
581
+ application/json:
582
+ schema:
583
+ $ref: "#/components/schemas/PaginatedResponse_Booking"
584
+ default:
585
+ $ref: "#/components/responses/ApiError"
586
+ post:
587
+ tags: [Bookings]
588
+ operationId: createBooking
589
+ summary: Create a booking or party
590
+ description: >-
591
+ Books every item or none of them. Each created booking carries a
592
+ `manage_token` returned exactly once — only its hash is stored, and an
593
+ idempotent replay omits it.
594
+ requestBody:
595
+ required: true
596
+ content:
597
+ application/json:
598
+ schema:
599
+ $ref: "#/components/schemas/CreateBookingInput"
600
+ responses:
601
+ "201":
602
+ description: Created bookings, in request order.
603
+ content:
604
+ application/json:
605
+ schema:
606
+ $ref: "#/components/schemas/ApiResponse_BookingCreateResult"
607
+ default:
608
+ $ref: "#/components/responses/ApiError"
609
+ /api/v1/bookings/services:
610
+ get:
611
+ tags: [Bookings]
612
+ operationId: listBookingServices
613
+ summary: List bookable services
614
+ parameters:
615
+ - name: include_inactive
616
+ in: query
617
+ description: >-
618
+ Include services with `active: false`. Defaults to active-only.
619
+ schema:
620
+ type: boolean
621
+ responses:
622
+ "200":
623
+ description: Bookable service catalogue.
624
+ content:
625
+ application/json:
626
+ schema:
627
+ $ref: "#/components/schemas/ApiResponse_BookingServiceArray"
628
+ default:
629
+ $ref: "#/components/responses/ApiError"
630
+ /api/v1/bookings/resources:
631
+ get:
632
+ tags: [Bookings]
633
+ operationId: listBookingResources
634
+ summary: List bookable resources
635
+ responses:
636
+ "200":
637
+ description: Bookable resources — staff, rooms, and equipment.
638
+ content:
639
+ application/json:
640
+ schema:
641
+ $ref: "#/components/schemas/ApiResponse_BookingResourceArray"
642
+ default:
643
+ $ref: "#/components/responses/ApiError"
644
+ /api/v1/bookings/availability:
645
+ get:
646
+ tags: [Bookings]
647
+ operationId: listBookingAvailability
648
+ summary: List free slots for a service
649
+ description: >-
650
+ Slots reflect opening hours, time off, buffers, and existing bookings
651
+ at the moment of the call. They are not held.
652
+ parameters:
653
+ - name: service_id
654
+ in: query
655
+ required: true
656
+ schema:
657
+ type: string
658
+ - name: from_ts
659
+ in: query
660
+ required: true
661
+ description: Start of the window.
662
+ schema:
663
+ $ref: "#/components/schemas/BookingTimestampInput"
664
+ - name: to_ts
665
+ in: query
666
+ required: true
667
+ description: End of the window; must be after `from_ts`.
668
+ schema:
669
+ $ref: "#/components/schemas/BookingTimestampInput"
670
+ - name: resource_id
671
+ in: query
672
+ description: Restrict slots to one resource.
673
+ schema:
674
+ type: string
675
+ responses:
676
+ "200":
677
+ description: Free slots.
678
+ content:
679
+ application/json:
680
+ schema:
681
+ $ref: "#/components/schemas/ApiResponse_BookingSlotArray"
682
+ default:
683
+ $ref: "#/components/responses/ApiError"
684
+ /api/v1/bookings/schedule:
685
+ get:
686
+ tags: [Bookings]
687
+ operationId: listBookingSchedule
688
+ summary: List the dates a service can be booked on
689
+ description: >-
690
+ The other half of `availability`. Availability returns free slots and
691
+ nothing else, so a closed day, an evening past closing and a fully
692
+ booked day all come back as the same empty array. This returns one
693
+ entry per date the workspace keeps opening hours on; a date ABSENT from
694
+ the response is closed. `last_start_ts` is the last start this service
695
+ could occupy on that date (it depends on the service's duration and
696
+ buffers, not just the closing time) and is `null` for a date with
697
+ posted hours that is shut outright, such as a public holiday.
698
+ parameters:
699
+ - name: service_id
700
+ in: query
701
+ required: true
702
+ schema:
703
+ type: string
704
+ - name: from_ts
705
+ in: query
706
+ required: true
707
+ description: Start of the window.
708
+ schema:
709
+ $ref: "#/components/schemas/BookingTimestampInput"
710
+ - name: to_ts
711
+ in: query
712
+ required: true
713
+ description: End of the window; must be after `from_ts`.
714
+ schema:
715
+ $ref: "#/components/schemas/BookingTimestampInput"
716
+ - name: resource_id
717
+ in: query
718
+ description: Restrict to one resource's hours.
719
+ schema:
720
+ type: string
721
+ responses:
722
+ "200":
723
+ description: Open dates.
724
+ content:
725
+ application/json:
726
+ schema:
727
+ $ref: "#/components/schemas/ApiResponse_BookingScheduleDayArray"
728
+ default:
729
+ $ref: "#/components/responses/ApiError"
730
+ /api/v1/bookings/{id}:
731
+ parameters:
732
+ - $ref: "#/components/parameters/Id"
733
+ get:
734
+ tags: [Bookings]
735
+ operationId: getBooking
736
+ summary: Get a booking
737
+ responses:
738
+ "200":
739
+ description: Booking.
740
+ content:
741
+ application/json:
742
+ schema:
743
+ $ref: "#/components/schemas/ApiResponse_Booking"
744
+ default:
745
+ $ref: "#/components/responses/ApiError"
746
+ patch:
747
+ tags: [Bookings]
748
+ operationId: updateBooking
749
+ summary: Annotate a booking
750
+ requestBody:
751
+ required: true
752
+ content:
753
+ application/json:
754
+ schema:
755
+ $ref: "#/components/schemas/UpdateBookingInput"
756
+ responses:
757
+ "200":
758
+ description: The updated booking.
759
+ content:
760
+ application/json:
761
+ schema:
762
+ $ref: "#/components/schemas/ApiResponse_Booking"
763
+ default:
764
+ $ref: "#/components/responses/ApiError"
765
+ /api/v1/bookings/{id}/cancel:
766
+ parameters:
767
+ - $ref: "#/components/parameters/Id"
768
+ post:
769
+ tags: [Bookings]
770
+ operationId: cancelBooking
771
+ summary: Cancel a booking as the business
772
+ description: >-
773
+ Staff semantics — the workspace's cancel window is bypassed and the
774
+ cancellation is attributed to staff.
775
+ requestBody:
776
+ required: true
777
+ content:
778
+ application/json:
779
+ schema:
780
+ $ref: "#/components/schemas/CancelBookingInput"
781
+ responses:
782
+ "200":
783
+ description: Cancel result.
784
+ content:
785
+ application/json:
786
+ schema:
787
+ $ref: "#/components/schemas/ApiResponse_BookingActionResult"
788
+ default:
789
+ $ref: "#/components/responses/ApiError"
790
+ /api/v1/bookings/{id}/reschedule:
791
+ parameters:
792
+ - $ref: "#/components/parameters/Id"
793
+ post:
794
+ tags: [Bookings]
795
+ operationId: rescheduleBooking
796
+ summary: Reschedule a booking as the business
797
+ description: >-
798
+ Staff semantics — the reschedule window is bypassed. The old booking is
799
+ cancelled and a new one inserted, so the response carries a new booking
800
+ id and a freshly minted manage token.
801
+ requestBody:
802
+ required: true
803
+ content:
804
+ application/json:
805
+ schema:
806
+ $ref: "#/components/schemas/RescheduleBookingInput"
807
+ responses:
808
+ "200":
809
+ description: Reschedule result.
810
+ content:
811
+ application/json:
812
+ schema:
813
+ $ref: "#/components/schemas/ApiResponse_BookingRescheduleResult"
814
+ default:
815
+ $ref: "#/components/responses/ApiError"
816
+ /api/v1/bookings/{id}/no-show:
817
+ parameters:
818
+ - $ref: "#/components/parameters/Id"
819
+ post:
820
+ tags: [Bookings]
821
+ operationId: markBookingNoShow
822
+ summary: Mark a booking as a no-show
823
+ responses:
824
+ "200":
825
+ description: No-show result.
826
+ content:
827
+ application/json:
828
+ schema:
829
+ $ref: "#/components/schemas/ApiResponse_BookingActionResult"
830
+ default:
831
+ $ref: "#/components/responses/ApiError"
832
+ /api/v1/bookings/manage/{token}:
833
+ parameters:
834
+ - $ref: "#/components/parameters/ManageToken"
835
+ get:
836
+ tags: [Bookings]
837
+ operationId: getManagedBooking
838
+ summary: Get the customer manage summary for a token
839
+ responses:
840
+ "200":
841
+ description: >-
842
+ Manage summary. An unknown token and a token belonging to another
843
+ workspace both answer 404, so this is not an existence oracle.
844
+ content:
845
+ application/json:
846
+ schema:
847
+ $ref: "#/components/schemas/ApiResponse_ManageSummary"
848
+ default:
849
+ $ref: "#/components/responses/ApiError"
850
+ /api/v1/bookings/manage/{token}/cancel:
851
+ parameters:
852
+ - $ref: "#/components/parameters/ManageToken"
853
+ post:
854
+ tags: [Bookings]
855
+ operationId: cancelManagedBooking
856
+ summary: Cancel on the customer's behalf
857
+ description: >-
858
+ Customer semantics — the workspace's cancel window is ENFORCED and the
859
+ cancellation is attributed to the customer.
860
+ requestBody:
861
+ required: true
862
+ content:
863
+ application/json:
864
+ schema:
865
+ $ref: "#/components/schemas/CancelBookingInput"
866
+ responses:
867
+ "200":
868
+ description: Cancel result.
869
+ content:
870
+ application/json:
871
+ schema:
872
+ $ref: "#/components/schemas/ApiResponse_BookingActionResult"
873
+ default:
874
+ $ref: "#/components/responses/ApiError"
875
+ /api/v1/bookings/manage/{token}/reschedule:
876
+ parameters:
877
+ - $ref: "#/components/parameters/ManageToken"
878
+ post:
879
+ tags: [Bookings]
880
+ operationId: rescheduleManagedBooking
881
+ summary: Reschedule on the customer's behalf
882
+ description: >-
883
+ Customer semantics — the reschedule window is ENFORCED. The response
884
+ carries a new booking id and a new manage token; the old token stops
885
+ working.
886
+ requestBody:
887
+ required: true
888
+ content:
889
+ application/json:
890
+ schema:
891
+ $ref: "#/components/schemas/RescheduleBookingInput"
892
+ responses:
893
+ "200":
894
+ description: Reschedule result.
895
+ content:
896
+ application/json:
897
+ schema:
898
+ $ref: "#/components/schemas/ApiResponse_BookingRescheduleResult"
899
+ default:
900
+ $ref: "#/components/responses/ApiError"
546
901
  /api/v1/gdpr/export:
547
902
  post:
548
903
  tags: [GDPR]
@@ -1177,6 +1532,15 @@ components:
1177
1532
  required: true
1178
1533
  schema:
1179
1534
  type: string
1535
+ ManageToken:
1536
+ name: token
1537
+ in: path
1538
+ required: true
1539
+ description: >-
1540
+ The show-once manage token handed out when the booking was created.
1541
+ Possession of it authorizes the customer's own cancel or reschedule.
1542
+ schema:
1543
+ type: string
1180
1544
  Cursor:
1181
1545
  name: cursor
1182
1546
  in: query
@@ -2051,6 +2415,496 @@ components:
2051
2415
  format: date
2052
2416
  notes:
2053
2417
  type: string
2418
+ BookingTimestampInput:
2419
+ description: >-
2420
+ A timestamp on the way in — Unix milliseconds, or an ISO 8601
2421
+ date-time string. Responses always render timestamps as ISO 8601.
2422
+ type: [integer, string]
2423
+ BookingStatus:
2424
+ type: string
2425
+ enum: [pending, confirmed, completed, cancelled, no_show]
2426
+ BookingCancelledBy:
2427
+ description: >-
2428
+ Who cancelled. `staff` for the id-addressed cancel, `customer` for the
2429
+ manage-token cancel, `system` for an automated one.
2430
+ type: string
2431
+ enum: [customer, staff, system]
2432
+ BookingPaymentStatus:
2433
+ type: string
2434
+ enum: [none, reserved, captured, refunded]
2435
+ BookingCreatedVia:
2436
+ type: string
2437
+ enum: [web, dashboard, walk_in, api]
2438
+ BookingResourceType:
2439
+ type: string
2440
+ enum: [staff, room, equipment]
2441
+ Booking:
2442
+ type: object
2443
+ required:
2444
+ - id
2445
+ - contact_id
2446
+ - service_id
2447
+ - resource_id
2448
+ - start_ts
2449
+ - end_ts
2450
+ - booked_for_name
2451
+ - booked_for_birth_year
2452
+ - party_sequence_id
2453
+ - status
2454
+ - cancelled_by
2455
+ - cancel_reason
2456
+ - rescheduled_from_id
2457
+ - payment_status
2458
+ - amount_ore
2459
+ - notes
2460
+ - internal_notes
2461
+ - created_via
2462
+ - created_at
2463
+ - updated_at
2464
+ properties:
2465
+ id:
2466
+ type: string
2467
+ contact_id:
2468
+ type: [string, "null"]
2469
+ service_id:
2470
+ type: [string, "null"]
2471
+ resource_id:
2472
+ type: [string, "null"]
2473
+ start_ts:
2474
+ type: [string, "null"]
2475
+ format: date-time
2476
+ end_ts:
2477
+ type: [string, "null"]
2478
+ format: date-time
2479
+ booked_for_name:
2480
+ type: [string, "null"]
2481
+ booked_for_birth_year:
2482
+ description: A birth year, not a birthdate — the age bracket is all that is stored.
2483
+ type: [integer, "null"]
2484
+ party_sequence_id:
2485
+ description: Shared by every booking created in the same party request.
2486
+ type: [string, "null"]
2487
+ status:
2488
+ $ref: "#/components/schemas/BookingStatus"
2489
+ cancelled_by:
2490
+ oneOf:
2491
+ - $ref: "#/components/schemas/BookingCancelledBy"
2492
+ - type: "null"
2493
+ cancel_reason:
2494
+ type: [string, "null"]
2495
+ rescheduled_from_id:
2496
+ description: On a booking created by a reschedule, the booking it replaced.
2497
+ type: [string, "null"]
2498
+ payment_status:
2499
+ $ref: "#/components/schemas/BookingPaymentStatus"
2500
+ amount_ore:
2501
+ description: Price in integer øre. Never a float and never kroner.
2502
+ type: [integer, "null"]
2503
+ notes:
2504
+ description: Customer-visible note.
2505
+ type: [string, "null"]
2506
+ internal_notes:
2507
+ description: Staff-only note; never shown to the customer.
2508
+ type: [string, "null"]
2509
+ created_via:
2510
+ oneOf:
2511
+ - $ref: "#/components/schemas/BookingCreatedVia"
2512
+ - type: "null"
2513
+ created_at:
2514
+ type: [string, "null"]
2515
+ format: date-time
2516
+ updated_at:
2517
+ type: [string, "null"]
2518
+ format: date-time
2519
+ BookingService:
2520
+ type: object
2521
+ required:
2522
+ - id
2523
+ - name
2524
+ - description
2525
+ - category
2526
+ - duration_minutes
2527
+ - buffer_before_minutes
2528
+ - buffer_after_minutes
2529
+ - price_ore
2530
+ - weekend_surcharge_pct
2531
+ - resource_requirements
2532
+ - bookable_online
2533
+ - max_per_booking
2534
+ - color
2535
+ - sort_order
2536
+ - active
2537
+ - created_at
2538
+ - updated_at
2539
+ properties:
2540
+ id:
2541
+ type: string
2542
+ name:
2543
+ type: [string, "null"]
2544
+ description:
2545
+ type: [string, "null"]
2546
+ category:
2547
+ type: [string, "null"]
2548
+ duration_minutes:
2549
+ type: [integer, "null"]
2550
+ buffer_before_minutes:
2551
+ type: [integer, "null"]
2552
+ buffer_after_minutes:
2553
+ type: [integer, "null"]
2554
+ price_ore:
2555
+ description: Price in integer øre.
2556
+ type: [integer, "null"]
2557
+ weekend_surcharge_pct:
2558
+ type: [number, "null"]
2559
+ resource_requirements:
2560
+ description: Resource types this service needs, e.g. `["staff"]`.
2561
+ type: array
2562
+ items:
2563
+ type: string
2564
+ bookable_online:
2565
+ type: boolean
2566
+ max_per_booking:
2567
+ type: [integer, "null"]
2568
+ color:
2569
+ type: [string, "null"]
2570
+ sort_order:
2571
+ type: [integer, "null"]
2572
+ active:
2573
+ type: boolean
2574
+ created_at:
2575
+ type: [string, "null"]
2576
+ format: date-time
2577
+ updated_at:
2578
+ type: [string, "null"]
2579
+ format: date-time
2580
+ BookingResource:
2581
+ type: object
2582
+ required:
2583
+ - id
2584
+ - type
2585
+ - name
2586
+ - photo_url
2587
+ - bio
2588
+ - service_ids
2589
+ - capacity
2590
+ - sort_order
2591
+ - active
2592
+ - created_at
2593
+ - updated_at
2594
+ properties:
2595
+ id:
2596
+ type: string
2597
+ type:
2598
+ oneOf:
2599
+ - $ref: "#/components/schemas/BookingResourceType"
2600
+ - type: "null"
2601
+ name:
2602
+ type: [string, "null"]
2603
+ photo_url:
2604
+ type: [string, "null"]
2605
+ format: uri
2606
+ bio:
2607
+ type: [string, "null"]
2608
+ service_ids:
2609
+ description: Services this resource can perform.
2610
+ type: array
2611
+ items:
2612
+ type: string
2613
+ capacity:
2614
+ type: [integer, "null"]
2615
+ sort_order:
2616
+ type: [integer, "null"]
2617
+ active:
2618
+ type: boolean
2619
+ created_at:
2620
+ type: [string, "null"]
2621
+ format: date-time
2622
+ updated_at:
2623
+ type: [string, "null"]
2624
+ format: date-time
2625
+ BookingSlot:
2626
+ type: object
2627
+ required: [start_ts, end_ts, resource_id]
2628
+ properties:
2629
+ start_ts:
2630
+ type: [string, "null"]
2631
+ format: date-time
2632
+ end_ts:
2633
+ type: [string, "null"]
2634
+ format: date-time
2635
+ resource_id:
2636
+ type: [string, "null"]
2637
+ BookingScheduleDay:
2638
+ description: One date a service can be booked on. `date` is the workspace's own calendar date, not a timestamp.
2639
+ type: object
2640
+ required: [date, opens_ts, closes_ts, last_start_ts]
2641
+ properties:
2642
+ date:
2643
+ type: [string, "null"]
2644
+ format: date
2645
+ opens_ts:
2646
+ type: [string, "null"]
2647
+ format: date-time
2648
+ closes_ts:
2649
+ type: [string, "null"]
2650
+ format: date-time
2651
+ last_start_ts:
2652
+ description: Last start this service could occupy on the date; `null` when the date is shut outright.
2653
+ type: [string, "null"]
2654
+ format: date-time
2655
+ BookingContactInput:
2656
+ description: The person the booking is made under. Phone is the CRM dedupe key.
2657
+ type: object
2658
+ required: [phone]
2659
+ properties:
2660
+ phone:
2661
+ type: string
2662
+ maxLength: 40
2663
+ email:
2664
+ type: string
2665
+ maxLength: 320
2666
+ name:
2667
+ type: string
2668
+ maxLength: 200
2669
+ CreateBookingItemInput:
2670
+ description: One line of a party — a single service on a single slot.
2671
+ type: object
2672
+ required: [service_id, start_ts]
2673
+ properties:
2674
+ service_id:
2675
+ type: string
2676
+ resource_id:
2677
+ description: Omit to let the engine pick a free resource.
2678
+ type: string
2679
+ start_ts:
2680
+ $ref: "#/components/schemas/BookingTimestampInput"
2681
+ booked_for_name:
2682
+ type: string
2683
+ maxLength: 200
2684
+ booked_for_birth_year:
2685
+ type: integer
2686
+ minimum: 1900
2687
+ maximum: 2200
2688
+ CreateBookingInput:
2689
+ type: object
2690
+ required: [items, contact]
2691
+ properties:
2692
+ items:
2693
+ description: >-
2694
+ A PARTY — one request books a whole family in one all-or-nothing
2695
+ transaction.
2696
+ type: array
2697
+ minItems: 1
2698
+ maxItems: 50
2699
+ items:
2700
+ $ref: "#/components/schemas/CreateBookingItemInput"
2701
+ contact:
2702
+ $ref: "#/components/schemas/BookingContactInput"
2703
+ notes:
2704
+ type: string
2705
+ maxLength: 5000
2706
+ created_via:
2707
+ description: >-
2708
+ Where the booking came from. Defaults to `api`. A workspace's OWN
2709
+ website should send `web`, so its bookings can be told apart from
2710
+ integrations. `dashboard` and `walk_in` are staff-only and are
2711
+ rejected with 400 — a bearer token proves which workspace is calling,
2712
+ not that a member typed the booking in.
2713
+ type: string
2714
+ enum: [web, api]
2715
+ CreatedBooking:
2716
+ type: object
2717
+ required: [id]
2718
+ properties:
2719
+ id:
2720
+ type: string
2721
+ manage_token:
2722
+ description: >-
2723
+ Show-once secret for the customer's manage link. Only its hash is
2724
+ stored, and an idempotent replay omits this field entirely.
2725
+ type: string
2726
+ BookingCreateResult:
2727
+ type: object
2728
+ required: [bookings, contact_id]
2729
+ properties:
2730
+ bookings:
2731
+ description: One entry per created booking, in request order.
2732
+ type: array
2733
+ items:
2734
+ $ref: "#/components/schemas/CreatedBooking"
2735
+ contact_id:
2736
+ type: string
2737
+ BookingActionResult:
2738
+ type: object
2739
+ required: [success]
2740
+ properties:
2741
+ success:
2742
+ type: boolean
2743
+ const: true
2744
+ BookingRescheduleResult:
2745
+ type: object
2746
+ required: [success, booking_id]
2747
+ properties:
2748
+ success:
2749
+ type: boolean
2750
+ const: true
2751
+ booking_id:
2752
+ description: >-
2753
+ The NEW booking's id — a reschedule cancels the old row and inserts
2754
+ a new one.
2755
+ type: string
2756
+ manage_token:
2757
+ description: >-
2758
+ Freshly minted manage token for the new booking; omitted on an
2759
+ idempotent replay.
2760
+ type: string
2761
+ ManageSummary:
2762
+ description: >-
2763
+ What the holder of a manage token may see and do. `can_cancel` and
2764
+ `can_reschedule` already apply the workspace's policy windows.
2765
+ type: object
2766
+ required:
2767
+ - booking_id
2768
+ - contact_id
2769
+ - status
2770
+ - cancelled_by
2771
+ - cancel_reason
2772
+ - rescheduled_from_id
2773
+ - start_ts
2774
+ - end_ts
2775
+ - service_id
2776
+ - service_name
2777
+ - resource_id
2778
+ - resource_name
2779
+ - booked_for_name
2780
+ - party_sequence_id
2781
+ - amount_ore
2782
+ - payment_status
2783
+ - time_zone
2784
+ - cancel_window_hours
2785
+ - reschedule_window_hours
2786
+ - can_cancel
2787
+ - can_reschedule
2788
+ properties:
2789
+ booking_id:
2790
+ type: string
2791
+ contact_id:
2792
+ type: [string, "null"]
2793
+ status:
2794
+ oneOf:
2795
+ - $ref: "#/components/schemas/BookingStatus"
2796
+ - type: "null"
2797
+ cancelled_by:
2798
+ oneOf:
2799
+ - $ref: "#/components/schemas/BookingCancelledBy"
2800
+ - type: "null"
2801
+ cancel_reason:
2802
+ type: [string, "null"]
2803
+ rescheduled_from_id:
2804
+ type: [string, "null"]
2805
+ start_ts:
2806
+ type: [string, "null"]
2807
+ format: date-time
2808
+ end_ts:
2809
+ type: [string, "null"]
2810
+ format: date-time
2811
+ service_id:
2812
+ type: [string, "null"]
2813
+ service_name:
2814
+ type: [string, "null"]
2815
+ resource_id:
2816
+ type: [string, "null"]
2817
+ resource_name:
2818
+ type: [string, "null"]
2819
+ booked_for_name:
2820
+ type: [string, "null"]
2821
+ party_sequence_id:
2822
+ type: [string, "null"]
2823
+ amount_ore:
2824
+ description: Price in integer øre.
2825
+ type: [integer, "null"]
2826
+ payment_status:
2827
+ oneOf:
2828
+ - $ref: "#/components/schemas/BookingPaymentStatus"
2829
+ - type: "null"
2830
+ time_zone:
2831
+ description: IANA zone the booking's local times should be rendered in.
2832
+ type: [string, "null"]
2833
+ cancel_window_hours:
2834
+ type: [number, "null"]
2835
+ reschedule_window_hours:
2836
+ type: [number, "null"]
2837
+ can_cancel:
2838
+ type: boolean
2839
+ can_reschedule:
2840
+ type: boolean
2841
+ UpdateBookingInput:
2842
+ description: >-
2843
+ At least one of `notes` or `internal_notes` is required — the API
2844
+ rejects a body carrying neither with a 400. `""` is a meaningful value
2845
+ that clears the field, so the constraint is on presence.
2846
+ # Spelled out as two fully-typed branches rather than the terser
2847
+ # `anyOf: [{required: [notes]}, {required: [internal_notes]}]`, because a
2848
+ # branch carrying only `required` generates as `unknown` — and `T |
2849
+ # unknown` collapses to `unknown`, which accepts everything and is worse
2850
+ # than the unconstrained object. Each branch therefore repeats the
2851
+ # properties so openapi-typescript emits a real discriminating union.
2852
+ #
2853
+ # `minProperties: 1` is deliberately absent: `anyOf` on two named
2854
+ # properties already implies it and is strictly stronger (it also rejects
2855
+ # `{ unrelated_key: 1 }`), so keeping both would be two statements of one
2856
+ # invariant to drift apart.
2857
+ anyOf:
2858
+ - type: object
2859
+ required: [notes]
2860
+ properties:
2861
+ notes:
2862
+ description: Customer-visible note.
2863
+ type: string
2864
+ maxLength: 5000
2865
+ internal_notes:
2866
+ description: Staff-only note.
2867
+ type: string
2868
+ maxLength: 5000
2869
+ - type: object
2870
+ required: [internal_notes]
2871
+ properties:
2872
+ notes:
2873
+ description: Customer-visible note.
2874
+ type: string
2875
+ maxLength: 5000
2876
+ internal_notes:
2877
+ description: Staff-only note.
2878
+ type: string
2879
+ maxLength: 5000
2880
+ CancelBookingInput:
2881
+ type: object
2882
+ properties:
2883
+ reason:
2884
+ type: string
2885
+ maxLength: 500
2886
+ RescheduleBookingInput:
2887
+ type: object
2888
+ required: [new_start_ts]
2889
+ properties:
2890
+ new_start_ts:
2891
+ $ref: "#/components/schemas/BookingTimestampInput"
2892
+ new_resource_id:
2893
+ type: string
2894
+ BookingsPagination:
2895
+ description: >-
2896
+ Pagination for a bookings page. `truncated` is the extra statement:
2897
+ the underlying read is capped, and when the cap binds there are
2898
+ matching bookings no cursor from this call reaches — narrow the window.
2899
+ type: object
2900
+ required: [has_more, next_cursor, truncated]
2901
+ properties:
2902
+ has_more:
2903
+ type: boolean
2904
+ next_cursor:
2905
+ type: [string, "null"]
2906
+ truncated:
2907
+ type: boolean
2054
2908
  GdprExport:
2055
2909
  type: object
2056
2910
  required: [id, request_type, status, submitted_at, completed_at]
@@ -2743,6 +3597,24 @@ components:
2743
3597
  $ref: "#/components/schemas/Envelope_DealUpdateResult"
2744
3598
  ApiResponse_DealRemoveResult:
2745
3599
  $ref: "#/components/schemas/Envelope_DealRemoveResult"
3600
+ ApiResponse_Booking:
3601
+ $ref: "#/components/schemas/Envelope_Booking"
3602
+ ApiResponse_BookingServiceArray:
3603
+ $ref: "#/components/schemas/Envelope_BookingServiceArray"
3604
+ ApiResponse_BookingResourceArray:
3605
+ $ref: "#/components/schemas/Envelope_BookingResourceArray"
3606
+ ApiResponse_BookingSlotArray:
3607
+ $ref: "#/components/schemas/Envelope_BookingSlotArray"
3608
+ ApiResponse_BookingScheduleDayArray:
3609
+ $ref: "#/components/schemas/Envelope_BookingScheduleDayArray"
3610
+ ApiResponse_BookingCreateResult:
3611
+ $ref: "#/components/schemas/Envelope_BookingCreateResult"
3612
+ ApiResponse_BookingActionResult:
3613
+ $ref: "#/components/schemas/Envelope_BookingActionResult"
3614
+ ApiResponse_BookingRescheduleResult:
3615
+ $ref: "#/components/schemas/Envelope_BookingRescheduleResult"
3616
+ ApiResponse_ManageSummary:
3617
+ $ref: "#/components/schemas/Envelope_ManageSummary"
2746
3618
  ApiResponse_GdprExportRequest:
2747
3619
  $ref: "#/components/schemas/Envelope_GdprExportRequest"
2748
3620
  ApiResponse_GdprExportArray:
@@ -2832,6 +3704,16 @@ components:
2832
3704
  $ref: "#/components/schemas/Deal"
2833
3705
  pagination:
2834
3706
  $ref: "#/components/schemas/Pagination"
3707
+ PaginatedResponse_Booking:
3708
+ type: object
3709
+ required: [data, pagination]
3710
+ properties:
3711
+ data:
3712
+ type: array
3713
+ items:
3714
+ $ref: "#/components/schemas/Booking"
3715
+ pagination:
3716
+ $ref: "#/components/schemas/BookingsPagination"
2835
3717
  PaginatedResponse_HelpdeskConversation:
2836
3718
  type: object
2837
3719
  required: [data, pagination]
@@ -3002,6 +3884,68 @@ components:
3002
3884
  properties:
3003
3885
  data:
3004
3886
  $ref: "#/components/schemas/DealRemoveResult"
3887
+ Envelope_Booking:
3888
+ type: object
3889
+ required: [data]
3890
+ properties:
3891
+ data:
3892
+ $ref: "#/components/schemas/Booking"
3893
+ Envelope_BookingServiceArray:
3894
+ type: object
3895
+ required: [data]
3896
+ properties:
3897
+ data:
3898
+ type: array
3899
+ items:
3900
+ $ref: "#/components/schemas/BookingService"
3901
+ Envelope_BookingResourceArray:
3902
+ type: object
3903
+ required: [data]
3904
+ properties:
3905
+ data:
3906
+ type: array
3907
+ items:
3908
+ $ref: "#/components/schemas/BookingResource"
3909
+ Envelope_BookingSlotArray:
3910
+ type: object
3911
+ required: [data]
3912
+ properties:
3913
+ data:
3914
+ type: array
3915
+ items:
3916
+ $ref: "#/components/schemas/BookingSlot"
3917
+ Envelope_BookingScheduleDayArray:
3918
+ type: object
3919
+ required: [data]
3920
+ properties:
3921
+ data:
3922
+ type: array
3923
+ items:
3924
+ $ref: "#/components/schemas/BookingScheduleDay"
3925
+ Envelope_BookingCreateResult:
3926
+ type: object
3927
+ required: [data]
3928
+ properties:
3929
+ data:
3930
+ $ref: "#/components/schemas/BookingCreateResult"
3931
+ Envelope_BookingActionResult:
3932
+ type: object
3933
+ required: [data]
3934
+ properties:
3935
+ data:
3936
+ $ref: "#/components/schemas/BookingActionResult"
3937
+ Envelope_BookingRescheduleResult:
3938
+ type: object
3939
+ required: [data]
3940
+ properties:
3941
+ data:
3942
+ $ref: "#/components/schemas/BookingRescheduleResult"
3943
+ Envelope_ManageSummary:
3944
+ type: object
3945
+ required: [data]
3946
+ properties:
3947
+ data:
3948
+ $ref: "#/components/schemas/ManageSummary"
3005
3949
  ScanCreateInput:
3006
3950
  type: object
3007
3951
  description: Provide exactly one of `url`, `orgnr`, or `name`.