{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/conduyt-com/json-schema/conduyt-com-booking-page-patch-schema.json",
  "title": "BookingPagePatch",
  "description": "The body of PATCH /booking-pages/{id}. Every field is optional; only supplied fields change. A field the route normalises (clamps, trims, falls back to a default) is documented with the value it stores.",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/conduyt-com-openapi.yaml#/components/schemas/BookingPagePatch",
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "description": "Ignored when blank."
    },
    "slug": {
      "type": "string",
      "description": "Normalised; a slug another page uses is refused with 409."
    },
    "description": {
      "type": [
        "string",
        "null"
      ]
    },
    "durationMinutes": {
      "type": "integer"
    },
    "durationOptions": {
      "type": [
        "array",
        "null"
      ],
      "description": "Selectable durations; entries with no label or outside 5 to 480 minutes are dropped; empty or null clears.",
      "items": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string"
          },
          "minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 480
          }
        }
      }
    },
    "bufferBefore": {
      "type": [
        "integer",
        "null"
      ],
      "description": "Minutes before each booking; clamped."
    },
    "bufferAfter": {
      "type": [
        "integer",
        "null"
      ],
      "description": "Minutes after each booking; clamped."
    },
    "minimumNotice": {
      "type": "integer",
      "minimum": 0,
      "description": "Minutes of notice required; an invalid value keeps the current one."
    },
    "maxAdvanceDays": {
      "type": "integer",
      "description": "How many days ahead bookings open; clamped; an invalid value keeps the current one."
    },
    "maxBookingsPerDay": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 1
    },
    "location": {
      "type": [
        "string",
        "null"
      ]
    },
    "videoProvider": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "zoom",
        null
      ],
      "description": "zoom, or null / empty for none."
    },
    "videoHostEmail": {
      "type": [
        "string",
        "null"
      ],
      "format": "email"
    },
    "color": {
      "type": [
        "string",
        "null"
      ],
      "description": "A hex colour."
    },
    "thankYouMessage": {
      "type": [
        "string",
        "null"
      ],
      "maxLength": 2000
    },
    "redirectUrl": {
      "type": [
        "string",
        "null"
      ],
      "format": "uri"
    },
    "requirePhone": {
      "type": "boolean"
    },
    "embedEnabled": {
      "type": "boolean"
    },
    "customQuestions": {
      "type": "array",
      "maxItems": 50,
      "description": "The booking form's extra questions; an entry without a label or a known type is dropped; an empty list clears them.",
      "items": {
        "$ref": "#/$defs/BookingCustomQuestion",
        "properties": {
          "defaultValue": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "id": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "label": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "options": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "required": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "type": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          }
        },
        "type": "object"
      }
    },
    "formFields": {
      "type": [
        "array",
        "null"
      ],
      "maxItems": 20,
      "description": "The standard form fields; an invalid entry is dropped, and a list with no valid entry (or null) clears the configuration.",
      "items": {
        "$ref": "#/$defs/BookingFormField",
        "properties": {
          "id": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "label": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "locked": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "required": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "show": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "type": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          }
        },
        "type": "object"
      }
    },
    "fieldMappings": {
      "type": [
        "array",
        "null"
      ],
      "maxItems": 20,
      "description": "Form field to contact field mappings; an invalid entry is dropped, and a list with no valid entry (or null) clears them.",
      "items": {
        "$ref": "#/$defs/BookingFieldMapping",
        "properties": {
          "contactField": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          },
          "formFieldId": {
            "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
          }
        },
        "type": "object"
      }
    },
    "availabilityRules": {
      "type": [
        "array",
        "null"
      ],
      "description": "Availability windows overriding the host's global rules; null or an empty list uses the global rules.",
      "items": {
        "type": "object",
        "properties": {
          "dayOfWeek": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "startTime": {
            "type": "string",
            "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
          },
          "endTime": {
            "type": "string",
            "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
          }
        }
      }
    },
    "reminders": {
      "type": "array",
      "maxItems": 10,
      "items": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "email",
              "sms"
            ]
          },
          "minutesBefore": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10080
          }
        }
      }
    },
    "brandName": {
      "type": [
        "string",
        "null"
      ],
      "maxLength": 80
    },
    "logoUrl": {
      "type": [
        "string",
        "null"
      ],
      "format": "uri"
    },
    "hideBranding": {
      "type": "boolean"
    },
    "embedAllowedOrigins": {
      "type": [
        "array",
        "null"
      ],
      "items": {
        "type": "string"
      }
    },
    "template": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "bda",
        null
      ],
      "description": "null for the default page, \"bda\" for the BDA template; anything else is refused with 400."
    },
    "reviews": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "badges": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "count": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              },
              "platform": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              },
              "rating": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              }
            }
          }
        },
        "testimonials": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "author": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              },
              "quote": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              },
              "role": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              },
              "source": {
                "description": "Read by the handler from the JSON body (the route declares no schema for its type)."
              }
            }
          }
        }
      }
    },
    "leadSource": {
      "type": [
        "string",
        "null"
      ]
    },
    "campaign": {
      "type": [
        "string",
        "null"
      ]
    },
    "hyrosTag": {
      "type": [
        "string",
        "null"
      ]
    },
    "documentsEnabled": {
      "type": "boolean",
      "description": "Turns the documents step on or off for this page's bookings."
    },
    "documentsPageUrl": {
      "type": [
        "string",
        "null"
      ],
      "format": "uri",
      "description": "The https page on the customer's site that hosts the upload step; an https URL or null (a supplied non-https value is refused with 400)."
    },
    "morningOfReminderEnabled": {
      "type": "boolean",
      "description": "Turns the 9 AM (prospect-local) morning-of email on or off for this page's bookings; turning it off also withdraws the ones already scheduled. A non-boolean is refused with 400."
    },
    "isActive": {
      "type": "boolean"
    },
    "userId": {
      "type": "string",
      "format": "uuid",
      "description": "The page owner; must be an active member of the account."
    },
    "eventType": {
      "type": "string",
      "enum": [
        "one_on_one",
        "round_robin",
        "collective",
        "group"
      ]
    },
    "maxAttendees": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 1
    },
    "hostUserIds": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "uuid"
      },
      "description": "Users on this account who can host; anything else is refused with 400."
    },
    "hostGroupId": {
      "type": [
        "string",
        "null"
      ],
      "format": "uuid"
    },
    "hostPriorities": {
      "type": [
        "object",
        "null"
      ],
      "description": "Host user id to priority; an invalid map clears to the default.",
      "additionalProperties": {
        "type": "string",
        "enum": [
          "highest",
          "high",
          "low",
          "lowest"
        ]
      }
    },
    "distributionMethod": {
      "type": "string",
      "enum": [
        "maximize",
        "equal"
      ]
    },
    "paymentEnabled": {
      "type": "boolean",
      "description": "Accepted but payment checkout is not implemented yet; the page stays with payment disabled and the response carries a warning."
    },
    "paymentAmount": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 1,
      "description": "Amount in cents."
    },
    "paymentCurrency": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "usd",
        "eur",
        "gbp",
        "cad",
        "aud",
        "mxn",
        null
      ],
      "description": "An unknown currency is stored as usd."
    },
    "stripeProductId": {
      "type": [
        "string",
        "null"
      ]
    },
    "stripePriceId": {
      "type": [
        "string",
        "null"
      ]
    },
    "gdprEnabled": {
      "type": "boolean"
    },
    "gdprText": {
      "type": [
        "string",
        "null"
      ],
      "maxLength": 2000
    },
    "gdprLinkUrl": {
      "type": [
        "string",
        "null"
      ],
      "format": "uri"
    },
    "waitlistEnabled": {
      "type": "boolean"
    },
    "enableIcalFeed": {
      "type": "boolean",
      "description": "true issues a new iCal feed token, false revokes it. Session only: API keys receive 403 (error \"API key denied: the iCal feed token is issued, rotated and cleared from a signed-in session only\")."
    }
  },
  "$defs": {
    "BookingCustomQuestion": {
      "type": "object",
      "required": [
        "label",
        "type"
      ],
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 57,
          "description": "Generated from the label when absent."
        },
        "label": {
          "type": "string",
          "minLength": 1,
          "maxLength": 500
        },
        "type": {
          "type": "string",
          "enum": [
            "short_text",
            "long_text",
            "email",
            "phone",
            "select",
            "checkbox",
            "date",
            "number",
            "hidden"
          ]
        },
        "required": {
          "type": "boolean",
          "default": false
        },
        "options": {
          "type": "array",
          "maxItems": 50,
          "items": {
            "type": "string",
            "maxLength": 500
          }
        },
        "defaultValue": {
          "type": "string",
          "maxLength": 500
        }
      }
    },
    "BookingFieldMapping": {
      "type": "object",
      "required": [
        "formFieldId",
        "contactField"
      ],
      "properties": {
        "formFieldId": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64
        },
        "contactField": {
          "type": "string",
          "maxLength": 96,
          "description": "A standard contact field (firstName, lastName, email, phone, company, jobTitle, address, city, state, zip, country, source, notes, website) or customFields.<key>; protected stamp keys are refused.",
          "pattern": "^(firstName|lastName|email|phone|company|jobTitle|address|city|state|zip|country|source|notes|website|customFields\\.[a-zA-Z_][a-zA-Z0-9_]*)$"
        }
      }
    },
    "BookingFormField": {
      "type": "object",
      "required": [
        "id",
        "label",
        "type",
        "show",
        "required"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64
        },
        "label": {
          "type": "string",
          "minLength": 1,
          "maxLength": 120
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "email",
            "tel",
            "textarea"
          ]
        },
        "show": {
          "type": "boolean"
        },
        "required": {
          "type": "boolean"
        },
        "locked": {
          "type": "boolean"
        }
      }
    }
  }
}