{
  "openapi": "3.0.0",
  "info": {
    "title": "Plek Customer API",
    "description": "The routes under `/api/customer/{org_slug}`: a signed-in customer's own account. Customers sign in with the routes under `/api/public/{org_slug}/auth` and send the token they get as `Authorization: Bearer ...`. A customer token never works on the staff routes, and a staff token or API key never works here.",
    "contact": {
      "name": "Plek",
      "url": "https://development.plekbooking.com"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.plekbooking.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The signed-in customer's profile, password, email address and billing details"
    },
    {
      "name": "Bookings",
      "description": "The customer's bookings: details, cancelling, paying, moving, absences and make-up credits"
    },
    {
      "name": "Calendar and push",
      "description": "Calendar feed of the customer's bookings and push notifications on their devices"
    },
    {
      "name": "Hires",
      "description": "The customer's venue hire requests, quotes and payments"
    },
    {
      "name": "Open amounts",
      "description": "Late-cancellation and no-show fees to pay"
    },
    {
      "name": "Participants",
      "description": "The people the customer books for"
    },
    {
      "name": "Plans and credit",
      "description": "Passes, subscriptions, perks, buying a plan, account credit"
    },
    {
      "name": "Privacy",
      "description": "Personal data export and deleting the account"
    },
    {
      "name": "Reviews",
      "description": "Reviews of activities the customer attended"
    },
    {
      "name": "Waitlist and interest",
      "description": "Waiting lists the customer is on and \"notify me\" requests"
    }
  ],
  "paths": {
    "/api/customer/{org_slug}/credit": {
      "get": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "My account credit",
        "description": "Account credit staff issued to the customer (#752): balances per currency and each credit (never its code: it is spent at checkout or plan purchase with `useAccountCredit: true`, expiring first first). Verified customers only.",
        "operationId": "customerGetAccountCredit",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Credit",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "balances": {
                      "description": "Usable balance per currency",
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerAmount"
                      }
                    },
                    "credits": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerCredit"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/calendar-feed": {
      "get": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "My calendar feed",
        "description": "The customer's subscribable feed of their bookings (#403) with subscribe links, or `feed: null` when they have none. Verified customers only.",
        "operationId": "customerGetCalendarFeed",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerCalendarFeedResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "Make my calendar feed",
        "description": "Makes the customer's feed; when there is one already a new secret URL replaces it (the old URL stops working). Verified customers only.",
        "operationId": "customerProvideCalendarFeed",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerCalendarFeedResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "Stop my calendar feed",
        "description": "Revokes the customer's feed: its URL stops working. Verified customers only.",
        "operationId": "customerRevokeCalendarFeed",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/sessions": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "Sessions of my series booking",
        "description": "The sessions of a series booking with the participant's reported absences, their make-up credits and whether an absence can still be reported or withdrawn (#337), plus the organisation's absence rules. 404 for a booking that is not a series booking of the customer. Verified customers only.",
        "operationId": "customerSeriesBookingSessions",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The sessions",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "rules": {
                      "properties": {
                        "enabled": {
                          "type": "boolean"
                        },
                        "cutoffHours": {
                          "type": "integer"
                        },
                        "makeUpCredits": {
                          "type": "boolean"
                        },
                        "makeUpCreditWeeks": {
                          "type": "integer",
                          "nullable": true
                        }
                      },
                      "type": "object"
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerAbsenceSession"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/absences": {
      "post": {
        "tags": [
          "Bookings"
        ],
        "summary": "Report an absence",
        "description": "Reports that the participant of a series booking will miss one of its sessions (#337), before the organisation's cut-off; it may give a make-up credit. 404 for a session not in the booking; 409 with `code`: `disabled`, `too_late`, `session_cancelled`, `not_in_series`, `no_booking`. Verified customers only.",
        "operationId": "customerReportAbsence",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "sessionId"
                ],
                "properties": {
                  "sessionId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "reason": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Reported",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "absence": {
                      "$ref": "#/components/schemas/CustomerAbsence"
                    },
                    "makeUpCredit": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CustomerAbsenceMakeUpCredit"
                        }
                      ],
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Not allowed (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/absences/{session_id}": {
      "delete": {
        "tags": [
          "Bookings"
        ],
        "summary": "Withdraw a reported absence",
        "description": "The participant comes after all (#337): withdraws the absence and its make-up credit. 409 with `code`: `too_late`, `credit_used` (its make-up credit was already used), `seat_taken` (the seat was given away meanwhile), `disabled`. Verified customers only.",
        "operationId": "customerWithdrawAbsence",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "session_id",
            "in": "path",
            "description": "Session id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Withdrawn"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Not allowed (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/make-up-credits": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "My make-up credits",
        "description": "Usable make-up credits of the customer's participants (#337), each with the participant's name and the activity. With `sessionId` only the ones that can pay for that session (book it at checkout with `participants[].entitlementId`). Verified customers only.",
        "operationId": "customerListMakeUpCredits",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "sessionId",
            "in": "query",
            "description": "Only credits that can pay for this session",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Credits",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "credits": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/CustomerAbsenceMakeUpCredit"
                          },
                          {
                            "properties": {
                              "participantName": {
                                "type": "string"
                              },
                              "activityName": {
                                "type": "string",
                                "nullable": true
                              }
                            },
                            "type": "object"
                          }
                        ]
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "The signed-in customer",
        "description": "Profile of the customer the token belongs to. Unverified customers may call it too (`emailVerified` false).",
        "operationId": "customerGetMe",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAccountCustomerResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/profile": {
      "patch": {
        "tags": [
          "Account"
        ],
        "summary": "Change my profile",
        "description": "Name, phone, email language and opt-ins; fields left out stay as they are. The email address is not changed here: a different `email` is 403 `email_not_verified` for unverified customers and 422 `email_change_not_supported` otherwise (use POST /email-change). Turning text messages on needs a mobile number (422 `mobile_number_required`); an unknown language is 422.",
        "operationId": "customerUpdateProfile",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "firstName": {
                    "type": "string"
                  },
                  "lastName": {
                    "type": "string"
                  },
                  "phone": {
                    "description": "Stored in E.164 when valid; null clears it",
                    "type": "string",
                    "nullable": true
                  },
                  "language": {
                    "description": "The language emails are sent in",
                    "type": "string",
                    "enum": [
                      "en",
                      "nl",
                      "fr",
                      "de"
                    ]
                  },
                  "marketingOptIn": {
                    "type": "boolean"
                  },
                  "smsOptIn": {
                    "type": "boolean"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAccountCustomerResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "422": {
            "description": "Invalid (`email_change_not_supported`, `mobile_number_required`, or a message)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/billing-details": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "My company billing details",
        "description": "The company details used on receipts and sent to the organisation's bookkeeping (#791). Verified customers only.",
        "operationId": "customerGetBillingDetails",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Billing details, or null",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAccountBillingDetailsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Account"
        ],
        "summary": "Set or clear my company billing details",
        "description": "Replaces the stored details; `billingDetails: null` clears them. The VAT number is checked on format per EU country (422 `invalid_billing_details` with `details` per field). Verified customers only.",
        "operationId": "customerUpdateBillingDetails",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerAccountBillingDetailsResponse"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAccountBillingDetailsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "422": {
            "description": "Invalid billing details (`invalid_billing_details`)",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string",
                      "example": "invalid_billing_details"
                    },
                    "details": {
                      "description": "Message per field",
                      "type": "object",
                      "additionalProperties": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/password": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Set or change my password",
        "description": "A password is optional for customers. Changing one needs `currentPassword` (403 when wrong); a weak or missing new password is 422. At most 10 attempts per 15 minutes (429 with Retry-After). Verified customers only.",
        "operationId": "customerChangePassword",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "newPassword"
                ],
                "properties": {
                  "currentPassword": {
                    "description": "Needed when the account has a password",
                    "type": "string",
                    "nullable": true
                  },
                  "newPassword": {
                    "type": "string",
                    "format": "password"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Saved"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Current password is incorrect, or `email_not_verified`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "422": {
            "description": "Invalid new password",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/logout-all": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Sign out everywhere",
        "description": "Ends every session of this customer on every device (their refresh tokens stop working).",
        "operationId": "customerLogoutAll",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "204": {
            "description": "Signed out"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/pay": {
      "post": {
        "tags": [
          "Bookings"
        ],
        "summary": "Pay what is left online",
        "description": "For a booking paid later (on site or by bank transfer, #723): starts an online payment of what is still outstanding; a paid online payment settles it in full. `returnUrl` must be a page the organisation allows, else the booking site is used. Send the browser to `checkoutUrl`. 409 `not_payable` (nothing left to pay, or not payable online), 502 `payment_failed`. Verified customers only.",
        "operationId": "customerPayBookingBalance",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "returnUrl": {
                    "type": "string",
                    "format": "uri"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment started",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "checkoutUrl": {
                      "type": "string",
                      "format": "uri"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`not_payable`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "502": {
            "description": "`payment_failed`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "My bookings",
        "description": "The signed-in customer's bookings (of all their participants and parties), paginated. `when=upcoming`: not ended yet, soonest first; `when=past`: the rest, most recent first; without it all, newest booking first. `status=active` leaves out cancelled and expired bookings. `meta.awaitingPayment` counts unpaid bookings still holding a place. Verified customers only.",
        "operationId": "customerListBookings",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "when",
            "in": "query",
            "description": "upcoming or past",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "upcoming",
                "past"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "active: only pending and confirmed bookings",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bookings",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerBooking"
                      }
                    },
                    "meta": {
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "pages": {
                          "type": "integer"
                        },
                        "awaitingPayment": {
                          "type": "integer"
                        }
                      },
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/receipt.pdf": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "Receipt of a booking (PDF)",
        "description": "A payment confirmation of one of the customer's bookings (#891; not an invoice), in the customer's language. Available when the booking detail says `receiptAvailable`; 404 otherwise. Verified customers only.",
        "operationId": "customerBookingReceipt",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "One of my bookings",
        "description": "One booking of the customer, with the coaches' first names and the \"Good to know\" notes of the activity and location (#704); an appointment only shows the names its staff show on the booking site. 404 for a booking of someone else. Verified customers only.",
        "operationId": "customerGetBooking",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The booking",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "booking": {
                      "$ref": "#/components/schemas/CustomerBookingDetail"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Bookings"
        ],
        "summary": "Cancel my booking",
        "description": "Cancels the booking as the customer; the cancellation policy decides whether that is allowed and what is refunded (#391), and a late-cancellation fee may be charged (#406). 409 `cancellation_not_allowed` with the policy `cancellation` decision, 400 when already cancelled or not cancellable. Verified customers only.",
        "operationId": "customerCancelBooking",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "booking": {
                      "$ref": "#/components/schemas/CustomerBooking"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Already cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`cancellation_not_allowed`",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string",
                      "example": "cancellation_not_allowed"
                    },
                    "cancellation": {
                      "$ref": "#/components/schemas/CustomerBookingCancellation"
                    }
                  },
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/reschedule-options": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "Where can I move this booking?",
        "description": "Whether the customer may move this session booking to another session themselves (#392, within the cancellation policy's window and limit) and, if so, the sessions it can move to. Verified customers only.",
        "operationId": "customerBookingRescheduleOptions",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The decision and the sessions",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "reschedule": {
                      "$ref": "#/components/schemas/CustomerBookingRescheduleDecision"
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerBookingRescheduleOption"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/bookings/{id}/reschedule": {
      "post": {
        "tags": [
          "Bookings"
        ],
        "summary": "Move my booking to another session",
        "description": "Moves the booking to one of the sessions of GET reschedule-options and emails the customer. 400 without a valid `sessionId`; 409 with `code` (e.g. `window_passed`, `limit_reached`, `full`, `already_booked`, `price_differs`, `other_activity`, `not_bookable`, `appointment`, `party_not_supported`). Verified customers only.",
        "operationId": "customerRescheduleBooking",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Booking id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "sessionId"
                ],
                "properties": {
                  "sessionId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Moved",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "booking": {
                      "$ref": "#/components/schemas/CustomerBooking"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Not allowed (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/email-change": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Ask to change my email address",
        "description": "Emails a 6-digit code to the new address (purpose `email_change`); the account keeps its old address until the code is confirmed with POST /email-change/verify. Errors: 422 `invalid_email` / `same_email`, 409 `email_taken` (another account of this organisation uses it), 429 after 5 requests an hour. Verified customers only.",
        "operationId": "customerRequestEmailChange",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 255
                  },
                  "locale": {
                    "description": "Language of the email; default the customer's language",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Code sent",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "email": {
                      "type": "string",
                      "format": "email"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "409": {
            "description": "Address in use (`email_taken`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "422": {
            "description": "Invalid (`invalid_email`, `same_email`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts (`retryAfter` seconds)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/email-change/verify": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Confirm my new email address",
        "description": "Changes the address with the code sent to it; the old address gets a notice (audit `customer.email_changed`). Never signs in. Errors: 400 `invalid_code` (wrong or expired), 409 `email_taken`. Verified customers only.",
        "operationId": "customerVerifyEmailChange",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "example": "123456"
                  },
                  "locale": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Changed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAccountCustomerResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired code (`invalid_code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "409": {
            "description": "Address in use (`email_taken`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/entitlements": {
      "get": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "My passes, subscriptions, perks and make-up credits",
        "description": "What the customer and their participants hold (#374): make-up credits, subscriptions, passes and series perks (granted when looked at), with balances, usage history and the receipt of a plan bought online. With `sessionId`, or `slotOfferId` + `start` for a moment of a service booked at a free moment (#935): per participant whether each one covers it (the checkout uses this; pay with `participants[].entitlementId`). Verified customers only.",
        "operationId": "customerListEntitlements",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "sessionId",
            "in": "query",
            "description": "Check what covers this session",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "slotOfferId",
            "in": "query",
            "description": "Check what covers a moment of this slot offer (with start)",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "start",
            "in": "query",
            "description": "The moment's start as GET /activities/{id}/slots returns it (with slotOfferId)",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Entitlements",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "entitlements": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerEntitlement"
                      }
                    },
                    "awaitingPayment": {
                      "description": "Plans bought to pay on site or by bank transfer, granted once staff record the payment (#607); with sessionId only the ones that would cover it, without offlinePayment",
                      "type": "array",
                      "items": {
                        "properties": {
                          "purchase": {
                            "$ref": "#/components/schemas/CustomerPlanPurchase"
                          },
                          "offlinePayment": {
                            "oneOf": [
                              {
                                "$ref": "#/components/schemas/CustomerPlanPurchaseOfflinePayment"
                              }
                            ],
                            "nullable": true
                          }
                        },
                        "type": "object"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}/calendar.ics": {
      "get": {
        "tags": [
          "Hires"
        ],
        "summary": "My confirmed hire as a calendar file",
        "description": "An .ics file of a confirmed hire of the customer (#838). 422 `invalid_status` when it is not confirmed, 404 for someone else's. Verified customers only.",
        "operationId": "customerHireCalendar",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "iCalendar file",
            "content": {
              "text/calendar": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          },
          "422": {
            "description": "`invalid_status`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires": {
      "get": {
        "tags": [
          "Hires"
        ],
        "summary": "My venue hires",
        "description": "The customer's venue hire requests (#794) in every status. Verified customers only.",
        "operationId": "customerListHires",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Hires",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "hires": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerHire"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}": {
      "get": {
        "tags": [
          "Hires"
        ],
        "summary": "One of my venue hires",
        "description": "A hire of the customer: the party, the quote once sent, open amounts, how to pay and the cancellation deadline. 404 for someone else's. Verified customers only.",
        "operationId": "customerGetHire",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The hire",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "hire": {
                      "$ref": "#/components/schemas/CustomerHire"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}/accept": {
      "post": {
        "tags": [
          "Hires"
        ],
        "summary": "Accept the quote",
        "description": "Accepts a quoted hire: takes its spaces (shared sessions close) and adds the deposit. Paid online (default), the deposit payment starts at once (`checkoutUrl`; it can be retried from Open amounts); on site or by bank transfer the deposit is due by its deadline. 409 `space_conflict` when another hire, block or booked session took a space meanwhile (of two quotes for one space only the first wins); 422 `invalid_status`, `quote_expired`, `payment_method_unavailable`. Verified customers only.",
        "operationId": "customerAcceptHire",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "paymentMethod": {
                    "type": "string",
                    "default": "online",
                    "enum": [
                      "online",
                      "on_site",
                      "bank_transfer"
                    ]
                  },
                  "returnUrl": {
                    "description": "Page to come back to after paying the deposit online",
                    "type": "string",
                    "format": "uri"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "hire": {
                      "$ref": "#/components/schemas/CustomerHire"
                    },
                    "checkoutUrl": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          },
          "409": {
            "description": "`space_conflict`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          },
          "422": {
            "description": "Not possible (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}/decline": {
      "post": {
        "tags": [
          "Hires"
        ],
        "summary": "Decline the quote",
        "description": "Declines a quoted hire, with an optional reason for the organisation. 422 `invalid_status`. Verified customers only.",
        "operationId": "customerDeclineHire",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "reason": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Declined",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "hire": {
                      "$ref": "#/components/schemas/CustomerHire"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          },
          "422": {
            "description": "`invalid_status`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}/cancel": {
      "post": {
        "tags": [
          "Hires"
        ],
        "summary": "Cancel my hire",
        "description": "Cancels an accepted or confirmed hire and frees its spaces. Before the cancellation deadline (the activity's free-cancellation hours before the event) a deposit paid online is refunded (`refunds`), one paid offline is owed back; after it the deposit is kept. 422 `invalid_status`, `cancellation_closed`. Verified customers only.",
        "operationId": "customerCancelHire",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "reason": {
                    "type": "string",
                    "nullable": true
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "hire": {
                      "$ref": "#/components/schemas/CustomerHire"
                    },
                    "refunds": {
                      "description": "Refunds made through the payment provider",
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          },
          "422": {
            "description": "Not possible (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/hires/{id}/charges/{charge_id}/receipt.pdf": {
      "get": {
        "tags": [
          "Hires"
        ],
        "summary": "Receipt of a hire payment (PDF)",
        "description": "A payment confirmation of a paid deposit, balance or extra of the customer's own hire (#891; not an invoice). 404 for another hire's charge or an unpaid one. Verified customers only.",
        "operationId": "customerHireChargeReceipt",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Hire id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "charge_id",
            "in": "path",
            "description": "Charge id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerHireError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/interest": {
      "get": {
        "tags": [
          "Waitlist and interest"
        ],
        "summary": "My \"notify me\" requests",
        "description": "The customer's pending \"notify me when I can book\" requests (#511, #565). Verified customers only.",
        "operationId": "customerListInterest",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Requests",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "requests": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerInterestRequest"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/interest/{id}": {
      "delete": {
        "tags": [
          "Waitlist and interest"
        ],
        "summary": "Cancel a \"notify me\" request",
        "description": "Stops a pending request of the customer. 404 for an unknown request or someone else's. Verified customers only.",
        "operationId": "customerCancelInterest",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Request id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/charges": {
      "get": {
        "tags": [
          "Open amounts"
        ],
        "summary": "My open amounts",
        "description": "Late-cancellation and no-show fees (#406) and venue hire charges (#794) of the customer, with the open total (in the organisation's currency, else the first one; `openTotals` per currency, never added up across currencies), whether one is overdue, whether online booking is blocked by an overdue fee and whether it can be paid online. Verified customers only.",
        "operationId": "customerListCharges",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Charges",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "charges": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerCharge"
                      }
                    },
                    "openTotal": {
                      "$ref": "#/components/schemas/CustomerAmount"
                    },
                    "openTotals": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerAmount"
                      }
                    },
                    "openCount": {
                      "type": "integer"
                    },
                    "overdue": {
                      "type": "boolean"
                    },
                    "bookingBlocked": {
                      "type": "boolean"
                    },
                    "canPayOnline": {
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/charges/{id}": {
      "get": {
        "tags": [
          "Open amounts"
        ],
        "summary": "One open amount",
        "description": "A charge of the customer; an open one with a payment under way is checked with the payment provider first (the return page after paying). 404 for someone else's. Verified customers only.",
        "operationId": "customerGetCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Charge id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The charge",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "charge": {
                      "$ref": "#/components/schemas/CustomerCharge"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/charges/{id}/pay": {
      "post": {
        "tags": [
          "Open amounts"
        ],
        "summary": "Pay an open amount online",
        "description": "Starts an online payment of an open charge; send the browser to `checkoutUrl`. `returnUrl` must be a page the organisation allows, else Open amounts on the booking site. 404 `not_found`; 409 `not_open`, `no_payment_gateway` or a currency the gateway does not take; 502 `payment_failed`. Verified customers only.",
        "operationId": "customerPayCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Charge id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "returnUrl": {
                    "type": "string",
                    "format": "uri"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment started",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "charge": {
                      "$ref": "#/components/schemas/CustomerCharge"
                    },
                    "checkoutUrl": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "`not_found`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "409": {
            "description": "Not payable online (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "502": {
            "description": "`payment_failed`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/participants": {
      "get": {
        "tags": [
          "Participants"
        ],
        "summary": "My participants",
        "description": "The people this customer books for, by first name. With `sessionId` or `seriesId` each says whether it already holds a seat there (`alreadyBooked`, #685); an unknown session is 404 `not_found`. Verified customers only.",
        "operationId": "customerListParticipants",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "sessionId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "seriesId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Participants",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerParticipant"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "Session or series not found (`not_found`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Participants"
        ],
        "summary": "Add a participant",
        "description": "Adds a person this customer books for, with the organisation's participant custom fields. 422 with `errors` per field (custom fields as `customFields.{name}`). Verified customers only.",
        "operationId": "customerCreateParticipant",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerParticipantInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "participant": {
                      "$ref": "#/components/schemas/CustomerParticipant"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "422": {
            "description": "Invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerParticipantValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/participants/{id}": {
      "delete": {
        "tags": [
          "Participants"
        ],
        "summary": "Remove a participant",
        "description": "Refused with 409 `participant_has_upcoming_bookings` while it has bookings to come. Otherwise it leaves the account: unlinked when another customer shares it, deleted when never used, else anonymised so past bookings and payments keep it (#699). Verified customers only.",
        "operationId": "customerRemoveParticipant",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Has upcoming bookings (`participant_has_upcoming_bookings`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Participants"
        ],
        "summary": "Change a participant",
        "description": "Fields left out keep their value; staff-only data (identifiers, notes) is never touched. 404 when the participant is not managed by this customer, 422 with `errors` per field. Verified customers only.",
        "operationId": "customerUpdateParticipant",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerParticipantInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "participant": {
                      "$ref": "#/components/schemas/CustomerParticipant"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerParticipantValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/plan-purchases/quote": {
      "post": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "Price of a plan before buying",
        "description": "What buying a pass or subscription (#377) would cost with a discount code (one that applies to everything), gift cards and optionally account credit (#752). 404 `not_found`; 422 with `code`: `invalid_discount_code`, `discount_not_applicable`, `discount_minimum_not_met`, `discount_currency_mismatch`, `invalid_gift_card`. Verified customers only.",
        "operationId": "customerQuotePlanPurchase",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "planId"
                ],
                "properties": {
                  "planId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "discountCode": {
                    "type": "string"
                  },
                  "giftCardCodes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "useAccountCredit": {
                    "type": "boolean",
                    "default": false
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The quote",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPlanPurchaseQuote"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "`not_found`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "422": {
            "description": "Code or gift card refused (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/plan-purchases": {
      "post": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "Buy a pass or subscription",
        "description": "Buys a plan (#377). Paid online: send the browser to `checkoutUrl` (null when nothing is left to pay); the plan is granted once the payment is paid. With `paymentMethod` on_site or bank_transfer (#607): reserved, with `offlinePayment` saying how to pay, granted once staff record the payment. Discount codes and gift cards are taken up front and given back if it stays unpaid. A pending purchase holds its place within the maximum sold for an hour. 404 `not_found`; 409 with `code` when the plan cannot be bought now (not on sale, sold out, `no_payment_gateway`, `payment_method_unavailable`, a currency the gateway does not take); 422 for the input or a code/gift card (`code`); 502 `payment_failed`. Verified customers only.",
        "operationId": "customerPurchasePlan",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerPlanPurchaseInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Bought or reserved",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "purchase": {
                      "$ref": "#/components/schemas/CustomerPlanPurchase"
                    },
                    "checkoutUrl": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true
                    },
                    "offlinePayment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CustomerPlanPurchaseOfflinePayment"
                        }
                      ],
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "description": "`not_found`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "409": {
            "description": "Not available now (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "422": {
            "description": "Invalid (`code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "502": {
            "description": "`payment_failed`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/plan-purchases/{id}": {
      "get": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "One of my plan purchases",
        "description": "A purchase of the customer; an online one still pending is checked with the payment provider first (the return page after paying). 404 for someone else's. Verified customers only.",
        "operationId": "customerGetPlanPurchase",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Plan purchase id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The purchase",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "purchase": {
                      "$ref": "#/components/schemas/CustomerPlanPurchase"
                    },
                    "offlinePayment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CustomerPlanPurchaseOfflinePayment"
                        }
                      ],
                      "nullable": true,
                      "description": "How to pay a plan bought to pay later"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/plan-purchases/{id}/receipt.pdf": {
      "get": {
        "tags": [
          "Plans and credit"
        ],
        "summary": "Receipt of a plan purchase (PDF)",
        "description": "A payment confirmation of a paid plan purchase (#891; not an invoice) in the customer's language. 404 for someone else's purchase or one that is not paid. Verified customers only.",
        "operationId": "customerPlanPurchaseReceipt",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Plan purchase id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/personal-data": {
      "get": {
        "tags": [
          "Privacy"
        ],
        "summary": "Download my personal data",
        "description": "Everything the organisation keeps about this customer and their participants as a JSON download (`my-data-{date}.json`, GDPR #400). Audit-logged (`customer.data_exported`). Verified customers only.",
        "operationId": "customerExportPersonalData",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The export (attachment)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/deletion-request/code": {
      "post": {
        "tags": [
          "Privacy"
        ],
        "summary": "Email me a code to delete my account",
        "description": "Sends a code (purpose `account_deletion`) to the customer's address, to confirm with POST /deletion-request. At most 3 an hour (429). Verified customers only.",
        "operationId": "customerRequestDeletionCode",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "locale": {
                    "description": "Language of the email; default the customer's language",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Code sent",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "email": {
                      "type": "string",
                      "format": "email"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "429": {
            "description": "Too many attempts (`retryAfter` seconds)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/deletion-request": {
      "post": {
        "tags": [
          "Privacy"
        ],
        "summary": "Delete my account",
        "description": "Confirms with the emailed code (400 `invalid_code` when wrong or expired; a wrong guess counts as an attempt). Without upcoming bookings the account is anonymised now (200, `deleted`); otherwise it is scheduled for when they have passed (202, `scheduled`, `upcomingBookings` true). Verified customers only.",
        "operationId": "customerRequestDeletion",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "example": "123456"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "deleted",
                        "scheduled"
                      ]
                    },
                    "upcomingBookings": {
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "202": {
            "description": "Scheduled until the upcoming bookings have passed",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "deleted",
                        "scheduled"
                      ]
                    },
                    "upcomingBookings": {
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired code (`invalid_code`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/push": {
      "get": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "My push notification devices",
        "description": "Whether this Plek installation offers web push (#356), its VAPID public key for `PushManager.subscribe`, and the customer's devices that receive notifications. Verified customers only.",
        "operationId": "customerGetPush",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Push settings",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "available": {
                      "type": "boolean"
                    },
                    "publicKey": {
                      "description": "VAPID application server key",
                      "type": "string",
                      "nullable": true
                    },
                    "devices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerPushDevice"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/push/subscriptions": {
      "post": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "Turn on push notifications on this device",
        "description": "Stores the browser's push subscription (the JSON of `PushSubscription`) for the customer (#356); the device label comes from the User-Agent. 409 `push_unavailable` without VAPID keys, 400 `invalid_subscription`. Verified customers only.",
        "operationId": "customerSubscribePush",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "endpoint",
                  "keys"
                ],
                "properties": {
                  "endpoint": {
                    "type": "string",
                    "format": "uri"
                  },
                  "keys": {
                    "properties": {
                      "p256dh": {
                        "type": "string"
                      },
                      "auth": {
                        "type": "string"
                      }
                    },
                    "type": "object"
                  },
                  "contentEncoding": {
                    "type": "string",
                    "default": "aes128gcm"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscribed",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "device": {
                      "$ref": "#/components/schemas/CustomerPushDevice"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_subscription`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "409": {
            "description": "`push_unavailable`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/push/subscriptions/{id}": {
      "delete": {
        "tags": [
          "Calendar and push"
        ],
        "summary": "Stop push notifications on a device",
        "description": "Removes one of the customer's devices. 404 for an unknown device. Verified customers only.",
        "operationId": "customerUnsubscribePush",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Device id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/reviews": {
      "get": {
        "tags": [
          "Reviews"
        ],
        "summary": "My reviews and what to review",
        "description": "When the organisation collects reviews (#355): the activities the customer attended to review (`prompts`, with this term's review if written; one review per activity per term of `termWeeks`) and the reviews they wrote. `enabled` false with empty lists otherwise. Verified customers only.",
        "operationId": "customerListReviews",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Reviews",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "enabled": {
                      "type": "boolean"
                    },
                    "termWeeks": {
                      "type": "integer"
                    },
                    "prompts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerReviewPrompt"
                      }
                    },
                    "reviews": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerReview"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Reviews"
        ],
        "summary": "Review an activity",
        "description": "Writes (or within the same term changes) the customer's review of an activity they attended (#355), optionally about one of its coaches. After 4 or 5 stars `googleReviewUrl` is the organisation's Google review page (#753), else null. 400 without an activity or a whole rating 1-5; 422 `not_reviewable` when the customer did not attend it or reviews are off. Verified customers only.",
        "operationId": "customerSubmitReview",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "activityId",
                  "rating"
                ],
                "properties": {
                  "activityId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "rating": {
                    "type": "integer",
                    "maximum": 5,
                    "minimum": 1
                  },
                  "comment": {
                    "type": "string",
                    "nullable": true
                  },
                  "coachId": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "review": {
                      "$ref": "#/components/schemas/CustomerReview"
                    },
                    "googleReviewUrl": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "422": {
            "description": "`not_reviewable`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/waitlist": {
      "get": {
        "tags": [
          "Waitlist and interest"
        ],
        "summary": "My waiting lists",
        "description": "The waiting lists the customer's participants and parties are on (active entries: waiting, or offered a spot until `expiresAt`), including seats kept for next term (re-enrolment, #736), soonest first. Verified customers only.",
        "operationId": "customerListWaitlist",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Entries",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomerWaitlistEntry"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    },
    "/api/customer/{org_slug}/waitlist/{id}": {
      "delete": {
        "tags": [
          "Waitlist and interest"
        ],
        "summary": "Leave a waiting list",
        "description": "Takes the participant or party off the waiting list; a spot offered to them passes on to the next in line. For a re-enrolment offer (#736) this declines the seat kept for next term. 409 `not_active` when no longer on the list. Verified customers only.",
        "operationId": "customerLeaveWaitlist",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlug"
          },
          {
            "name": "id",
            "in": "path",
            "description": "Waiting list entry id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Left",
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "entry": {
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string"
                        }
                      },
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CustomerEmailNotVerified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`not_active`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerErrorWithCode"
                }
              }
            }
          }
        },
        "security": [
          {
            "customerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "CustomerAbsence": {
        "description": "A reported absence of a participant from one session of a series booking (#337)",
        "properties": {
          "id": {
            "type": "string"
          },
          "sessionId": {
            "type": "string",
            "format": "uuid"
          },
          "participantId": {
            "type": "string",
            "format": "uuid"
          },
          "bookingId": {
            "type": "string",
            "format": "uuid"
          },
          "reportedBy": {
            "description": "customer or staff",
            "type": "string"
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "reportedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "CustomerAbsenceMakeUpCredit": {
        "description": "A make-up credit: one free session of the activity instead of a missed one (#337, #374)",
        "properties": {
          "id": {
            "type": "string"
          },
          "entitlementId": {
            "type": "string"
          },
          "participantId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "activityId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "missedSessionId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "validUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "usedBookingId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "usedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerAbsenceSession": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "startTime": {
            "type": "string",
            "format": "date-time"
          },
          "endTime": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string"
          },
          "absence": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CustomerAbsence"
              }
            ],
            "nullable": true
          },
          "makeUpCredit": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CustomerAbsenceMakeUpCredit"
              }
            ],
            "nullable": true
          },
          "canReport": {
            "type": "boolean"
          },
          "canWithdraw": {
            "description": "Reported, before the deadline, and its make-up credit not used",
            "type": "boolean"
          },
          "deadline": {
            "description": "Until when the customer may report or withdraw",
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "CustomerAccountBillingDetailsResponse": {
        "properties": {
          "billingDetails": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/StaffBillingDetails"
              }
            ],
            "nullable": true,
            "description": "Null when none are stored"
          }
        },
        "type": "object"
      },
      "CustomerAccountCustomer": {
        "description": "The signed-in customer",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "phone": {
            "description": "E.164 when it is a valid number",
            "type": "string",
            "nullable": true
          },
          "language": {
            "description": "The language emails are sent in (en, nl, fr, de)",
            "type": "string",
            "nullable": true
          },
          "emailVerified": {
            "description": "False for an account made by the booking form until the customer signs in with an emailed code or link",
            "type": "boolean"
          },
          "hasPassword": {
            "type": "boolean"
          },
          "marketingOptIn": {
            "description": "News and offers from the organisation",
            "type": "boolean"
          },
          "smsOptIn": {
            "description": "Text messages (off unless opted in)",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "CustomerAccountCustomerResponse": {
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CustomerAccountCustomer"
          }
        },
        "type": "object"
      },
      "CustomerAmount": {
        "properties": {
          "amount": {
            "description": "Minor units (cents)",
            "type": "integer"
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          }
        },
        "type": "object"
      },
      "CustomerBooking": {
        "description": "One of the customer's bookings: a session, a series or a party (headcount booking, participant null)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "reference": {
            "description": "Short reference for people",
            "type": "string",
            "example": "TT-4F7K2M"
          },
          "type": {
            "type": "string",
            "enum": [
              "session",
              "series"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "confirmed",
              "cancelled",
              "expired"
            ]
          },
          "bookedPrice": {
            "$ref": "#/components/schemas/CustomerBookingAmount"
          },
          "participant": {
            "description": "Null for a party",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              }
            },
            "type": "object",
            "nullable": true
          },
          "partySize": {
            "description": "A party: the number of people",
            "type": "integer",
            "nullable": true
          },
          "seats": {
            "description": "Seats the booking takes",
            "type": "integer"
          },
          "lines": {
            "description": "A party: its tickets and extras",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerBookingPartyLine"
            },
            "nullable": true
          },
          "session": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "startTime": {
                "type": "string",
                "format": "date-time"
              },
              "endTime": {
                "type": "string",
                "format": "date-time"
              }
            },
            "type": "object",
            "nullable": true
          },
          "series": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "startDate": {
                "type": "string",
                "format": "date",
                "nullable": true
              },
              "endDate": {
                "type": "string",
                "format": "date",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "location": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "address": {
                "description": "One line",
                "type": "string",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "startsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "endsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "receiptAvailable": {
            "description": "A receipt can be downloaded at /bookings/{id}/receipt.pdf",
            "type": "boolean"
          },
          "activity": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "type": "object",
            "nullable": true
          },
          "bookedAt": {
            "type": "string",
            "format": "date-time"
          },
          "confirmedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancellation": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CustomerBookingCancellation"
              }
            ],
            "nullable": true,
            "description": "Null when the booking is no longer active"
          },
          "cancellationPolicy": {
            "description": "The policy that applies (freeCancellationHours, lateCancellation, lateRefundPercentage, lateCancellationFee, noShowFee, entitlementBookings)",
            "type": "object",
            "nullable": true
          },
          "offlinePayment": {
            "description": "Paid later on site or by bank transfer (#397): how to pay",
            "type": "object",
            "nullable": true
          },
          "balance": {
            "description": "Paid later: what is due, paid and still outstanding",
            "properties": {
              "state": {
                "type": "string"
              },
              "due": {
                "$ref": "#/components/schemas/CustomerBookingAmount"
              },
              "paid": {
                "$ref": "#/components/schemas/CustomerBookingAmount"
              },
              "outstanding": {
                "$ref": "#/components/schemas/CustomerBookingAmount"
              },
              "overdue": {
                "type": "boolean"
              }
            },
            "type": "object",
            "nullable": true
          },
          "canPayOnline": {
            "description": "Confirmed, paid later and still owing, and a gateway takes the currency: POST /bookings/{id}/pay",
            "type": "boolean"
          },
          "reschedule": {
            "$ref": "#/components/schemas/CustomerBookingRescheduleDecision"
          },
          "rescheduledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "paymentNeeded": {
            "description": "Unpaid and still holding its place (#508)",
            "type": "boolean"
          },
          "reservedUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "amountDue": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CustomerBookingAmount"
              }
            ],
            "nullable": true,
            "description": "What paying costs; a checkout of several bookings is paid as a whole"
          },
          "appointment": {
            "description": "An appointment (#924): with whom (first name, null when hidden)",
            "properties": {
              "with": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "spot": {
            "description": "The assigned spot label (#496)",
            "type": "string",
            "nullable": true
          },
          "checkIn": {
            "description": "Confirmed bookings: shown as a QR code and a short code at the door (#458)",
            "properties": {
              "code": {
                "type": "string"
              },
              "qr": {
                "type": "string"
              }
            },
            "type": "object",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerBookingAmount": {
        "properties": {
          "amount": {
            "description": "Minor units (cents)",
            "type": "integer"
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          }
        },
        "type": "object"
      },
      "CustomerBookingCancellation": {
        "description": "What cancelling now would mean under the cancellation policy (#391)",
        "properties": {
          "allowed": {
            "type": "boolean"
          },
          "reason": {
            "type": "string"
          },
          "refundPercentage": {
            "type": "integer"
          },
          "freeUntil": {
            "description": "Free cancellation until then",
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "CustomerBookingDetail": {
        "description": "A booking with the coaches' first names and the practical notes of the activity and location (#704)",
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomerBooking"
          },
          {
            "properties": {
              "coachNames": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "goodToKnow": {
                "description": "\"Good to know\" notes of the activity and location",
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          }
        ]
      },
      "CustomerBookingPartyLine": {
        "description": "A ticket or extra of a party booking (#786, #793), as booked",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "ticket",
              "extra"
            ]
          },
          "ticketTypeId": {
            "description": "Tickets only",
            "type": "string",
            "format": "uuid"
          },
          "extraId": {
            "description": "Extras only",
            "type": "string",
            "format": "uuid"
          },
          "unit": {
            "description": "Extras only",
            "type": "string",
            "enum": [
              "per_person",
              "per_piece",
              "flat"
            ]
          },
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "integer"
          },
          "unitPrice": {
            "$ref": "#/components/schemas/CustomerBookingAmount"
          },
          "seatWeight": {
            "type": "integer"
          },
          "refundable": {
            "description": "Refunded on a late cancellation",
            "type": "boolean"
          },
          "productCode": {
            "type": "string",
            "nullable": true
          },
          "total": {
            "$ref": "#/components/schemas/CustomerBookingAmount"
          }
        },
        "type": "object"
      },
      "CustomerBookingRescheduleDecision": {
        "description": "Whether the customer may move this booking to another session themselves (#392)",
        "properties": {
          "allowed": {
            "type": "boolean"
          },
          "reason": {
            "type": "string",
            "enum": [
              "allowed",
              "not_a_session",
              "not_confirmed",
              "appointment",
              "window_passed",
              "limit_reached"
            ]
          },
          "until": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerBookingRescheduleOption": {
        "description": "A session the booking can be moved to: same activity, same price, a free seat",
        "properties": {
          "sessionId": {
            "type": "string",
            "format": "uuid"
          },
          "startTime": {
            "type": "string",
            "format": "date-time"
          },
          "endTime": {
            "type": "string",
            "format": "date-time"
          },
          "activity": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "location": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "seriesName": {
            "type": "string",
            "nullable": true
          },
          "coachNames": {
            "description": "First names",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "availableSpots": {
            "type": "integer"
          },
          "price": {
            "$ref": "#/components/schemas/CustomerBookingAmount"
          },
          "samePrice": {
            "type": "boolean"
          },
          "alreadyBooked": {
            "type": "boolean"
          },
          "bookableOnItsOwn": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "CustomerCalendarFeedLinks": {
        "properties": {
          "url": {
            "description": "The feed (.ics); secret: whoever has it sees the bookings",
            "type": "string",
            "format": "uri"
          },
          "webcalUrl": {
            "description": "The same as webcal://, opens the calendar app",
            "type": "string"
          },
          "googleUrl": {
            "description": "Subscribe in Google Calendar",
            "type": "string",
            "format": "uri"
          },
          "outlookUrl": {
            "description": "Subscribe in Outlook",
            "type": "string",
            "format": "uri"
          }
        },
        "type": "object"
      },
      "CustomerCalendarFeedResponse": {
        "properties": {
          "feed": {
            "description": "Null when the customer has no feed",
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/CustomerCalendarFeedLinks"
              },
              {
                "properties": {
                  "createdAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "wholeSchedule": {
                    "description": "Always null for customers",
                    "type": "object",
                    "nullable": true
                  }
                },
                "type": "object"
              }
            ]
          }
        },
        "type": "object"
      },
      "CustomerCharge": {
        "description": "An amount the customer owes: a late-cancellation or no-show fee (#406), or a venue hire deposit, balance or extra (#794)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "kind": {
            "type": "string",
            "enum": [
              "late_cancellation",
              "no_show",
              "hire_deposit",
              "hire_balance",
              "hire_extra"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "paid",
              "waived",
              "cancelled"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "bookingId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "hireId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "lines": {
            "description": "Lines of an extra hire charge",
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "refunded": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "refundedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "sessionId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "activityName": {
            "type": "string",
            "nullable": true
          },
          "eventStart": {
            "type": "string",
            "format": "date-time"
          },
          "dueAt": {
            "type": "string",
            "format": "date-time"
          },
          "overdue": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "waivedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerCredit": {
        "description": "Account credit staff issued to the customer (#752); spent at checkout with useAccountCredit, never by code",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "initialAmount": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "balance": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "usable": {
            "type": "boolean"
          },
          "expiresAt": {
            "description": "null: no expiry",
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "CustomerEntitlement": {
        "description": "A make-up credit, subscription, pass or series perk held by the customer or one of their participants",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "description": "The plan's name in the customer's language when translated, else the name it was sold under",
            "type": "string"
          },
          "sourceType": {
            "type": "string",
            "enum": [
              "absence",
              "subscription",
              "pass",
              "series_perk",
              "manual"
            ]
          },
          "sourceId": {
            "type": "string",
            "nullable": true
          },
          "customerId": {
            "description": "Set for a pass (shared by all the customer's participants)",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "participantId": {
            "description": "Set when bound to one participant",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "participantName": {
            "type": "string",
            "nullable": true
          },
          "services": {
            "type": "array",
            "items": {
              "properties": {
                "activityId": {
                  "type": "string",
                  "format": "uuid"
                },
                "activityName": {
                  "type": "string",
                  "nullable": true
                },
                "rule": {
                  "description": "unlimited, limited(count, per week|month|validity) or credits(cost)",
                  "type": "object"
                }
              },
              "type": "object"
            }
          },
          "credits": {
            "description": "Credits of a pass",
            "type": "integer",
            "nullable": true
          },
          "balance": {
            "description": "Credits left; null when unlimited",
            "type": "integer",
            "nullable": true
          },
          "used": {
            "description": "Active bookings made with it",
            "type": "integer"
          },
          "validFrom": {
            "type": "string",
            "format": "date-time"
          },
          "validUntil": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "cancelled"
            ]
          },
          "expired": {
            "type": "boolean"
          },
          "usable": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "cancelledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancellationReason": {
            "type": "string",
            "nullable": true
          },
          "receipt": {
            "description": "Bought online and paid: the receipt at /plan-purchases/{purchaseId}/receipt.pdf",
            "properties": {
              "purchaseId": {
                "type": "string",
                "format": "uuid"
              }
            },
            "type": "object",
            "nullable": true
          },
          "ledger": {
            "description": "Usage history, newest first",
            "type": "array",
            "items": {
              "properties": {
                "id": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "booking",
                    "adjustment"
                  ]
                },
                "units": {
                  "type": "integer"
                },
                "bookingId": {
                  "type": "string",
                  "format": "uuid",
                  "nullable": true
                },
                "sessionStartsAt": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true
                },
                "activityName": {
                  "type": "string",
                  "nullable": true
                },
                "participantName": {
                  "type": "string",
                  "nullable": true
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                },
                "reversedAt": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true
                }
              },
              "type": "object"
            }
          },
          "participants": {
            "description": "Only with ?sessionId=: per participant whether it covers that session",
            "type": "array",
            "items": {
              "properties": {
                "participantId": {
                  "type": "string",
                  "format": "uuid"
                },
                "participantName": {
                  "type": "string"
                },
                "covered": {
                  "type": "boolean"
                },
                "reason": {
                  "type": "string",
                  "nullable": true,
                  "enum": [
                    "not_active",
                    "not_started",
                    "expired",
                    "other_participant",
                    "service_not_covered",
                    "not_individually_bookable",
                    "session_excluded",
                    "session_started",
                    "limit_reached",
                    "no_credits_left",
                    "already_used"
                  ]
                },
                "units": {
                  "type": "integer",
                  "nullable": true
                },
                "rule": {
                  "type": "object",
                  "nullable": true
                },
                "used": {
                  "type": "integer",
                  "nullable": true
                },
                "balance": {
                  "type": "integer",
                  "nullable": true
                }
              },
              "type": "object"
            }
          }
        },
        "type": "object"
      },
      "CustomerErrorWithCode": {
        "properties": {
          "error": {
            "description": "Message for people",
            "type": "string"
          },
          "code": {
            "description": "Stable code for clients",
            "type": "string"
          }
        },
        "type": "object"
      },
      "CustomerHire": {
        "description": "A venue hire request of the customer (#794): the party, the quote once sent, open amounts, how to pay and the cancellation deadline. Never the staff note, tax categories or answers.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "referenceCode": {
            "type": "string"
          },
          "reference": {
            "description": "Reference shown to the customer",
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "quoted",
              "accepted",
              "confirmed",
              "declined",
              "expired",
              "cancelled"
            ]
          },
          "activityId": {
            "type": "string",
            "format": "uuid"
          },
          "locationId": {
            "type": "string",
            "format": "uuid"
          },
          "dayPartId": {
            "type": "string",
            "format": "uuid"
          },
          "activity": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "location": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "dayPart": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "startsAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "endsAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "spaces": {
            "description": "Empty while the request is new",
            "type": "array",
            "items": {
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string",
                  "nullable": true
                }
              },
              "type": "object"
            }
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "startsAt": {
            "type": "string",
            "format": "date-time"
          },
          "endsAt": {
            "type": "string",
            "format": "date-time"
          },
          "tickets": {
            "type": "array",
            "items": {
              "properties": {
                "ticketTypeId": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "quantity": {
                  "type": "integer"
                },
                "seatWeight": {
                  "type": "integer"
                }
              },
              "type": "object"
            }
          },
          "extras": {
            "type": "array",
            "items": {
              "properties": {
                "extraId": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "unit": {
                  "type": "string"
                },
                "quantity": {
                  "type": "integer"
                }
              },
              "type": "object"
            }
          },
          "partySize": {
            "type": "integer"
          },
          "seats": {
            "type": "integer"
          },
          "contact": {
            "properties": {
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              },
              "email": {
                "type": "string"
              },
              "phone": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "billingDetails": {
            "properties": {
              "companyName": {
                "type": "string"
              },
              "vatNumber": {
                "type": "string",
                "nullable": true
              },
              "street": {
                "type": "string"
              },
              "postcode": {
                "type": "string"
              },
              "town": {
                "type": "string"
              },
              "country": {
                "type": "string"
              }
            },
            "type": "object",
            "nullable": true
          },
          "remarks": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "quote": {
            "description": "Once a quote was sent",
            "properties": {
              "lines": {
                "type": "array",
                "items": {
                  "properties": {
                    "type": {
                      "type": "string"
                    },
                    "itemId": {
                      "type": "string",
                      "nullable": true
                    },
                    "name": {
                      "type": "string"
                    },
                    "quantity": {
                      "type": "integer"
                    },
                    "unitPrice": {
                      "$ref": "#/components/schemas/CustomerAmount"
                    },
                    "productCode": {
                      "type": "string",
                      "nullable": true
                    },
                    "total": {
                      "$ref": "#/components/schemas/CustomerAmount"
                    }
                  },
                  "type": "object"
                }
              },
              "total": {
                "$ref": "#/components/schemas/CustomerAmount"
              },
              "deposit": {
                "$ref": "#/components/schemas/CustomerAmount"
              },
              "balance": {
                "$ref": "#/components/schemas/CustomerAmount"
              },
              "validUntil": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "sentAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true,
            "enum": [
              "online",
              "bank_transfer",
              "on_site"
            ]
          },
          "paymentReference": {
            "type": "string",
            "nullable": true
          },
          "acceptedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acceptedByStaff": {
            "type": "boolean"
          },
          "confirmedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "declinedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "declineReason": {
            "type": "string",
            "nullable": true
          },
          "expiredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelledBy": {
            "type": "string",
            "nullable": true,
            "enum": [
              "customer",
              "staff"
            ]
          },
          "cancelReason": {
            "type": "string",
            "nullable": true
          },
          "depositKept": {
            "type": "boolean",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "charges": {
            "description": "Deposit, balance and extras (cancelled ones left out); pay an open one with POST /charges/{id}/pay",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerCharge"
            }
          },
          "canAccept": {
            "type": "boolean"
          },
          "canDecline": {
            "type": "boolean"
          },
          "paymentOptions": {
            "description": "How open amounts can be paid while the hire is open",
            "properties": {
              "online": {
                "type": "boolean"
              },
              "bankTransfer": {
                "type": "boolean"
              },
              "onSite": {
                "type": "boolean"
              }
            },
            "type": "object",
            "nullable": true
          },
          "bankTransfer": {
            "description": "Paid by bank transfer and still open",
            "properties": {
              "iban": {
                "type": "string",
                "nullable": true
              },
              "bic": {
                "type": "string",
                "nullable": true
              },
              "accountHolder": {
                "type": "string",
                "nullable": true
              },
              "reference": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "cancellation": {
            "properties": {
              "deadline": {
                "description": "Before it the deposit is refunded, after it kept",
                "type": "string",
                "format": "date-time"
              },
              "depositKeptNow": {
                "type": "boolean"
              },
              "customerMayCancel": {
                "type": "boolean"
              },
              "depositPaid": {
                "type": "boolean"
              }
            },
            "type": "object"
          }
        },
        "type": "object"
      },
      "CustomerHireError": {
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "reason": {
            "description": "space_conflict only",
            "type": "string"
          },
          "conflicts": {
            "description": "space_conflict only",
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "details": {
            "type": "object"
          }
        },
        "type": "object"
      },
      "CustomerInterestRequest": {
        "description": "A pending \"notify me when I can book\" request (#511, #565)",
        "properties": {
          "id": {
            "type": "string"
          },
          "activityId": {
            "type": "string",
            "format": "uuid"
          },
          "activityName": {
            "type": "string",
            "nullable": true
          },
          "sessionId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "seriesId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "seriesName": {
            "type": "string",
            "nullable": true
          },
          "startsAt": {
            "description": "A session: when it starts; a series: its first day",
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "CustomerParticipant": {
        "description": "A person the customer books for. Staff-only data (internal notes, identifiers) is never included.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "dateOfBirth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "remarks": {
            "type": "string",
            "nullable": true
          },
          "customFields": {
            "description": "The organisation's participant custom fields customers may see, by field name",
            "type": "object",
            "additionalProperties": true
          },
          "alreadyBooked": {
            "description": "Only when listed with sessionId or seriesId: the participant already holds a seat there (#685)",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "CustomerParticipantInput": {
        "description": "On an update, fields left out keep their value; custom fields left out are kept.",
        "required": [
          "firstName",
          "lastName",
          "dateOfBirth"
        ],
        "properties": {
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "dateOfBirth": {
            "description": "YYYY-MM-DD, not in the future",
            "type": "string",
            "format": "date"
          },
          "remarks": {
            "type": "string",
            "nullable": true,
            "maxLength": 1000
          },
          "customFields": {
            "description": "Participant custom field values by field name",
            "type": "object",
            "additionalProperties": true
          }
        },
        "type": "object"
      },
      "CustomerParticipantValidationError": {
        "properties": {
          "error": {
            "type": "string"
          },
          "errors": {
            "description": "Message per field; custom fields as `customFields.{name}`",
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "type": "object"
      },
      "CustomerPlanPurchase": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "planId": {
            "type": "string",
            "format": "uuid"
          },
          "planName": {
            "type": "string"
          },
          "participantId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "paid",
              "cancelled"
            ]
          },
          "listPrice": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "discount": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "giftCards": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "amountDue": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "refunded": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "offlinePaymentMethod": {
            "type": "string",
            "nullable": true,
            "enum": [
              "on_site",
              "bank_transfer"
            ]
          },
          "paymentDueAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "paidMethod": {
            "type": "string",
            "nullable": true
          },
          "entitlementId": {
            "description": "The pass or subscription granted once paid",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cancelledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerPlanPurchaseInput": {
        "required": [
          "planId"
        ],
        "properties": {
          "planId": {
            "type": "string",
            "format": "uuid"
          },
          "participantId": {
            "description": "The customer's participant a subscription is bound to",
            "type": "string",
            "format": "uuid"
          },
          "startDate": {
            "description": "When the plan starts (local date), where the plan allows choosing",
            "type": "string",
            "format": "date"
          },
          "discountCode": {
            "type": "string"
          },
          "giftCardCodes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "useAccountCredit": {
            "description": "Spend the customer's account credit (#752) after the typed gift cards",
            "type": "boolean",
            "default": false
          },
          "paymentMethod": {
            "type": "string",
            "default": "online",
            "enum": [
              "online",
              "on_site",
              "bank_transfer"
            ]
          },
          "returnUrl": {
            "description": "Page to come back to after paying; kept to pages the organisation allows, else the booking site's purchase return page",
            "type": "string"
          }
        },
        "type": "object"
      },
      "CustomerPlanPurchaseOfflinePayment": {
        "description": "How to pay a plan bought to pay on site or by bank transfer (#607); granted once staff record the payment",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "on_site",
              "bank_transfer"
            ]
          },
          "reference": {
            "description": "Structured payment reference",
            "type": "string",
            "nullable": true
          },
          "dueAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "iban": {
            "description": "Bank transfer only",
            "type": "string",
            "nullable": true
          },
          "bic": {
            "type": "string",
            "nullable": true
          },
          "accountHolder": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "$ref": "#/components/schemas/CustomerAmount"
          }
        },
        "type": "object"
      },
      "CustomerPlanPurchaseQuote": {
        "properties": {
          "price": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "discount": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "giftCards": {
            "description": "Typed gift cards and what each one pays",
            "type": "array",
            "items": {
              "properties": {
                "code": {
                  "type": "string"
                },
                "amount": {
                  "$ref": "#/components/schemas/CustomerAmount"
                }
              },
              "type": "object"
            }
          },
          "giftCardTotal": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "accountCreditTotal": {
            "$ref": "#/components/schemas/CustomerAmount"
          },
          "due": {
            "$ref": "#/components/schemas/CustomerAmount"
          }
        },
        "type": "object"
      },
      "CustomerPushDevice": {
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "description": "The device, from its user agent",
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "type": "object"
      },
      "CustomerReview": {
        "description": "A review the customer wrote (#355)",
        "properties": {
          "id": {
            "type": "string"
          },
          "activityId": {
            "type": "string",
            "format": "uuid"
          },
          "activityName": {
            "type": "string",
            "nullable": true
          },
          "coach": {
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "rating": {
            "type": "integer",
            "maximum": 5,
            "minimum": 1
          },
          "comment": {
            "type": "string",
            "nullable": true
          },
          "reply": {
            "description": "The organisation's reply",
            "type": "string",
            "nullable": true
          },
          "repliedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "published",
              "hidden"
            ]
          }
        },
        "type": "object"
      },
      "CustomerReviewPrompt": {
        "description": "An activity the customer attended, to review (or whose review of this term to change)",
        "properties": {
          "activityId": {
            "type": "string",
            "format": "uuid"
          },
          "activityName": {
            "type": "string"
          },
          "lastAttendedAt": {
            "type": "string",
            "format": "date-time"
          },
          "coaches": {
            "type": "array",
            "items": {
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                }
              },
              "type": "object"
            }
          },
          "review": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CustomerReview"
              }
            ],
            "nullable": true,
            "description": "This term's review, if any"
          }
        },
        "type": "object"
      },
      "CustomerWaitlistEntry": {
        "description": "A place on a waiting list: one of the customer's participants, or the customer's party (#796)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "session",
              "series"
            ]
          },
          "sessionId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "seriesId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "status": {
            "description": "notified: a spot is kept until expiresAt",
            "type": "string",
            "enum": [
              "waiting",
              "notified"
            ]
          },
          "origin": {
            "description": "reenrolment: a seat of the next term kept for a participant of this one (#736)",
            "type": "string",
            "enum": [
              "waitlist",
              "reenrolment"
            ]
          },
          "place": {
            "description": "Place in line",
            "type": "integer"
          },
          "participantFirstName": {
            "description": "Null for a party",
            "type": "string",
            "nullable": true
          },
          "partySummary": {
            "description": "A party: its tickets, e.g. \"2 × Adult, 1 × Child\"",
            "type": "string",
            "nullable": true
          },
          "seats": {
            "type": "integer"
          },
          "activityName": {
            "type": "string",
            "nullable": true
          },
          "seriesName": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "startsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "endsAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expiresAt": {
            "description": "Offered a spot: book it before this moment",
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "ErrorResponse": {
        "description": "Standard error response",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "description": "Error message",
            "type": "string",
            "example": "Resource not found"
          }
        },
        "type": "object"
      },
      "StaffBillingDetails": {
        "description": "Company billing details (#791); the VAT number is checked on format per EU country",
        "required": [
          "companyName",
          "street",
          "postcode",
          "town",
          "country"
        ],
        "properties": {
          "companyName": {
            "type": "string"
          },
          "vatNumber": {
            "type": "string",
            "nullable": true
          },
          "street": {
            "type": "string"
          },
          "postcode": {
            "type": "string"
          },
          "town": {
            "type": "string"
          },
          "country": {
            "description": "ISO 3166-1 alpha-2",
            "type": "string",
            "example": "BE"
          }
        },
        "type": "object"
      }
    },
    "responses": {
      "CustomerEmailNotVerified": {
        "description": "The customer has not confirmed their email address yet (`code: email_not_verified`). Unverified customers (accounts made by the booking form) may book and pay, but not see stored participants, booking history, balances or other stored data until they sign in with an emailed code or link.",
        "content": {
          "application/json": {
            "schema": {
              "properties": {
                "error": {
                  "type": "string"
                },
                "code": {
                  "type": "string",
                  "example": "email_not_verified"
                }
              },
              "type": "object"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "parameters": {
      "OrgSlug": {
        "name": "org_slug",
        "in": "path",
        "description": "Organisation slug identifier",
        "required": true,
        "schema": {
          "type": "string",
          "example": "my-organisation"
        }
      }
    },
    "securitySchemes": {
      "customerAuth": {
        "type": "http",
        "description": "A customer access token (JWT with the customer audience), sent as `Authorization: Bearer ...`. A customer\ngets it from the sign-in routes under `/api/public/{org_slug}/auth/...`: an emailed 6-digit code\n(`/auth/code` + `/auth/code/verify`), a magic link (`/auth/link`), a password (`/auth/login`), or Google /\nMicrosoft (`/auth/oidc/...`); `/auth/refresh` renews it. Customers are separate from staff: a token is bound\nto the one organisation it was issued for (the `org_slug` must match, else 401) and never works on staff\nroutes, nor a staff token here. A deactivated account gets 401.",
        "bearerFormat": "JWT",
        "scheme": "bearer"
      }
    }
  }
}
