{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "SplitClub Partner API",
    "version": "1.0.0",
    "summary": "Tell SplitClub what you sell; let groups pay for it together.",
    "description": "SplitClub is the payment system for group experiences. Send offerings (with price tiers, availability and policy), dated events and, for boat rentals, your whole fleet; create a Pay with SplitClub checkout when a group books. Money is always integer minor units plus an ISO 4217 currency; times are ISO 8601 with an offset. Test keys (sc_test_, pk_test_) only ever touch test-mode objects. Errors name the field as a JSON pointer with what was expected and an example fix. Guide: https://splitclubapp.com/developers. Generated from the JSON Schemas by scripts/gen_openapi.ts.",
    "contact": {
      "name": "SplitClub developers",
      "url": "https://splitclubapp.com/developers",
      "email": "developers@splitclubapp.com"
    }
  },
  "servers": [
    {
      "url": "https://splitclubapp.com/api",
      "description": "Live and test (the key decides the mode)"
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Who a key is and what it may do."
    },
    {
      "name": "Catalogue",
      "description": "Offerings (with price tiers, availability, policy) and dated events."
    },
    {
      "name": "Boats",
      "description": "A rental fleet's boats, synced in full: specs, captain terms, prices, photos."
    },
    {
      "name": "Analytics",
      "description": "How what you posted performs."
    },
    {
      "name": "Integrations",
      "description": "Webhooks your own systems send to SplitClub."
    },
    {
      "name": "Checkouts",
      "description": "Pay with SplitClub: one checkout per group booking."
    },
    {
      "name": "Webhooks",
      "description": "Signed events SplitClub sends you."
    },
    {
      "name": "Guest",
      "description": "The checkout page, the modal and the app (publishable key or member session)."
    }
  ],
  "paths": {
    "/v1/me": {
      "get": {
        "operationId": "get_v1_me",
        "summary": "Who the key is: venue (or sandbox), limits, scopes; for a sandbox, what to call next",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/experiences": {
      "post": {
        "operationId": "post_v1_experiences",
        "summary": "Submit a dated event for review (idempotent on external_id)",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:write`.",
        "x-scopes": [
          "offerings:write"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "$ref": "#/components/schemas/LegacyExperience"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created (200 with duplicate: true when the external_id was posted before)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    },
                    "duplicate": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "413": {
            "$ref": "#/components/responses/E413"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_experiences",
        "summary": "List submissions, newest first",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:read`.",
        "x-scopes": [
          "offerings:read"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Page backwards from next_before."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "next_before": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/experiences/{id}": {
      "get": {
        "operationId": "get_v1_experiences_id",
        "summary": "One submission",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:read`.",
        "x-scopes": [
          "offerings:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/offerings": {
      "post": {
        "operationId": "post_v1_offerings",
        "summary": "Upsert an offering with its price tiers, availability and policy (idempotent on external_id)",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:write`.",
        "x-scopes": [
          "offerings:write"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Offering"
                  },
                  {
                    "type": "object",
                    "required": [
                      "offerings"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "offerings": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 25,
                        "items": {
                          "$ref": "#/components/schemas/Offering"
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created (200 when it replays or updates an existing external_id; 200 with results[] for a batch)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    },
                    "duplicate": {
                      "type": "boolean"
                    },
                    "updated": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "413": {
            "$ref": "#/components/responses/E413"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_offerings",
        "summary": "List offerings, most recently changed first",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:read`.",
        "x-scopes": [
          "offerings:read"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Page backwards from next_before."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "next_before": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/offerings/{id}": {
      "get": {
        "operationId": "get_v1_offerings_id",
        "summary": "One offering",
        "tags": [
          "Catalogue"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `offerings:read`.",
        "x-scopes": [
          "offerings:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/boats": {
      "post": {
        "operationId": "post_v1_boats",
        "summary": "Upsert one boat, or sync a fleet of up to 100 (idempotent on external_id; \"active\": false deactivates)",
        "tags": [
          "Boats"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "For boat-rental platforms and fleet operators. Each boat is reviewed before SplitClub uses it, and only ever inside a boat-day or tie-up event SplitClub runs. A fleet is processed per boat: valid boats are written even when others aren't; results[] gives each one's outcome (created, updated, unchanged, error) and errors name the field as /boats/<i>/…. Bodies up to 1 MB.\n\nScope: `boats:write`.",
        "x-scopes": [
          "boats:write"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Boat"
                  },
                  {
                    "type": "object",
                    "required": [
                      "boats"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "boats": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/Boat"
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created (200 when it updates or replays an existing external_id; 200 with results[] and summary for a fleet)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    },
                    "result": {
                      "type": "string",
                      "enum": [
                        "created",
                        "updated",
                        "unchanged"
                      ]
                    },
                    "duplicate": {
                      "type": "boolean"
                    },
                    "updated": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "413": {
            "$ref": "#/components/responses/E413"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_boats",
        "summary": "List boats, most recently changed first",
        "tags": [
          "Boats"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `boats:read`.",
        "x-scopes": [
          "boats:read"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "inactive"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Page backwards from next_before."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "next_before": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/boats/{id}": {
      "get": {
        "operationId": "get_v1_boats_id",
        "summary": "One boat",
        "tags": [
          "Boats"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `boats:read`.",
        "x-scopes": [
          "boats:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/boats/{id}/deactivate": {
      "post": {
        "operationId": "post_v1_boats_id_deactivate",
        "summary": "Take a boat out of everything (the same as upserting it with \"active\": false)",
        "tags": [
          "Boats"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `boats:write`.",
        "x-scopes": [
          "boats:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/analytics": {
      "get": {
        "operationId": "get_v1_analytics",
        "summary": "Views, saves, bookings and revenue for what the venue posted",
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `analytics:read`.",
        "x-scopes": [
          "analytics:read"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "experience_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/integrations": {
      "post": {
        "operationId": "post_v1_integrations",
        "summary": "Connect a venue system; returns its webhook URL once (and, for custom, a SplitClub-Signature secret once)",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider"
                ],
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": [
                      "sevenrooms",
                      "opentable",
                      "resy",
                      "tock",
                      "tripleseat",
                      "toast",
                      "square",
                      "clover",
                      "lightspeed",
                      "spoton",
                      "touchbistro",
                      "simphony",
                      "mindbody",
                      "boulevard",
                      "custom"
                    ]
                  },
                  "signing_secret": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Required for square, mindbody and boulevard (their deliveries are signed)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_integrations",
        "summary": "The venue's integrations (never their tokens)",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/integrations/{id}/revoke": {
      "post": {
        "operationId": "post_v1_integrations_id_revoke",
        "summary": "Revoke an integration",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/hooks/{provider}/{token}": {
      "post": {
        "operationId": "post_v1_hooks_provider_token",
        "summary": "Where a venue system delivers its webhooks",
        "tags": [
          "Integrations"
        ],
        "security": [],
        "description": "Authenticated by the token in the URL. Square, Mindbody and Boulevard deliveries must carry their provider signature; custom deliveries sign with SplitClub-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + \".\" + body)>. Bodies up to 256 KB (Toast 1 MB).",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "string"
                    },
                    "duplicate": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "413": {
            "$ref": "#/components/responses/E413"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/checkouts": {
      "post": {
        "operationId": "post_v1_checkouts",
        "summary": "Create a Pay with SplitClub checkout for a party",
        "tags": [
          "Checkouts"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `checkouts:write`.",
        "x-scopes": [
          "checkouts:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Replays return the first result. external_booking_id acts as one when absent."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_checkouts",
        "summary": "List checkouts",
        "tags": [
          "Checkouts"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `checkouts:read`.",
        "x-scopes": [
          "checkouts:read"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "collecting",
                "funded",
                "completed",
                "expired",
                "canceled"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Checkout"
                      }
                    },
                    "next_before": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/checkouts/{id}": {
      "get": {
        "operationId": "get_v1_checkouts_id",
        "summary": "One checkout",
        "tags": [
          "Checkouts"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `checkouts:read`.",
        "x-scopes": [
          "checkouts:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/checkouts/{id}/cancel": {
      "post": {
        "operationId": "post_v1_checkouts_id_cancel",
        "summary": "Cancel a checkout and release every hold",
        "tags": [
          "Checkouts"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `checkouts:write`.",
        "x-scopes": [
          "checkouts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/webhook_endpoints": {
      "post": {
        "operationId": "post_v1_webhook_endpoints",
        "summary": "Subscribe to checkout events; returns the signing secret once",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "events"
                ],
                "additionalProperties": false,
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "pattern": "^https://"
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "checkout.created",
                        "checkout.collecting",
                        "share.held",
                        "checkout.funded",
                        "checkout.completed",
                        "checkout.expired",
                        "checkout.canceled"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "operationId": "get_v1_webhook_endpoints",
        "summary": "List webhook endpoints (never their secrets)",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/webhook_endpoints/{id}": {
      "delete": {
        "operationId": "delete_v1_webhook_endpoints_id",
        "summary": "Delete a webhook endpoint",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "secretKey": []
          }
        ],
        "description": "Scope: `webhooks:write`.",
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/public/checkouts/{id}": {
      "get": {
        "operationId": "get_v1_public_checkouts_id",
        "summary": "The guest-side safe view of a checkout",
        "tags": [
          "Guest"
        ],
        "security": [
          {
            "publishableKey": []
          },
          {
            "memberJwt": []
          }
        ],
        "description": "Publishable key (from a registered origin) or a signed-in SplitClub member's JWT.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/public/checkouts/{id}/party": {
      "post": {
        "operationId": "post_v1_public_checkouts_id_party",
        "summary": "The organizer chooses the party and the split",
        "tags": [
          "Guest"
        ],
        "security": [
          {
            "memberJwt": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "members",
                  "split"
                ],
                "properties": {
                  "members": {
                    "type": "array",
                    "items": {
                      "oneOf": [
                        {
                          "type": "object",
                          "required": [
                            "user_id"
                          ],
                          "properties": {
                            "user_id": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "object",
                          "required": [
                            "phone"
                          ],
                          "properties": {
                            "phone": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string",
                              "description": "What the organizer typed; shown as the share's display_name."
                            }
                          }
                        },
                        {
                          "type": "object",
                          "required": [
                            "channel_id"
                          ],
                          "properties": {
                            "channel_id": {
                              "type": "string"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "split": {
                    "oneOf": [
                      {
                        "const": "equal"
                      },
                      {
                        "type": "object",
                        "required": [
                          "custom"
                        ],
                        "properties": {
                          "custom": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "integer",
                              "minimum": 0
                            }
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "422": {
            "$ref": "#/components/responses/E422"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/public/shares/{share_id}/hold": {
      "post": {
        "operationId": "post_v1_public_shares_share_id_hold",
        "summary": "Hold one share: a manual-capture PaymentIntent",
        "tags": [
          "Guest"
        ],
        "security": [
          {
            "memberJwt": []
          }
        ],
        "parameters": [
          {
            "name": "share_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "client_secret": {
                      "type": "string"
                    },
                    "publishable_key": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    }
  },
  "webhooks": {
    "checkoutEvent": {
      "post": {
        "operationId": "checkoutEvent",
        "security": [],
        "summary": "A checkout or share event, POSTed to your webhook endpoint",
        "description": "Signed: SplitClub-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + \".\" + body)>. Retried with exponential backoff for 72 hours.",
        "parameters": [
          {
            "name": "SplitClub-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the event."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Offering": {
        "title": "Offering",
        "description": "Something a venue sells, repeatedly: a tee time, a table, a cabana, a treatment. Sent with its price tiers, availability and policy in one upsert (POST /v1/offerings), idempotent on external_id.",
        "x-doc": "schema-offering",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_id",
          "kind",
          "title",
          "tiers"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this object. Sending the same external_id again updates or replays it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "tee_time",
              "table",
              "cabana",
              "daybed",
              "spa_treatment",
              "class",
              "boat_day",
              "ticketed_event",
              "package",
              "rental",
              "ride",
              "dining"
            ]
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "examples": [
              "18 holes, cart included"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60,
            "pattern": "^[a-z0-9_-]+$",
            "description": "A SplitClub category slug; GET /v1/me lists the ones you may use.",
            "examples": [
              "golf"
            ]
          },
          "media": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "maxLength": 2000,
                  "pattern": "^https://[^\\s]{4,}$",
                  "format": "uri",
                  "x-expected": "an https:// URL",
                  "examples": [
                    "https://example.com/photo.jpg"
                  ]
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "image",
                    "video"
                  ],
                  "default": "image"
                },
                "alt": {
                  "type": "string",
                  "maxLength": 300
                }
              }
            }
          },
          "tiers": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/PriceTier"
            }
          },
          "availability": {
            "$ref": "#/components/schemas/Availability"
          },
          "policy": {
            "$ref": "#/components/schemas/Policy"
          },
          "booking_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "examples": [
              "https://example.com/photo.jpg"
            ]
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.-]+$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string keys of your own, echoed back on every read and webhook.",
            "examples": [
              {
                "order_id": "A-1042"
              }
            ]
          }
        },
        "examples": [
          {
            "external_id": "18-holes",
            "kind": "tee_time",
            "title": "18 holes, cart included",
            "tiers": [
              {
                "label": "Weekday",
                "amount": 14500,
                "currency": "usd",
                "unit": "per_person",
                "min_party": 2,
                "max_party": 4,
                "days": [
                  "mon",
                  "tue",
                  "wed",
                  "thu"
                ]
              },
              {
                "label": "Twilight",
                "amount": 8900,
                "currency": "usd",
                "unit": "per_person",
                "time_window": {
                  "from": "15:00",
                  "to": "19:00"
                }
              }
            ],
            "availability": {
              "timezone": "America/New_York",
              "recurring": [
                {
                  "rrule": "FREQ=DAILY;BYHOUR=7,8,9;BYMINUTE=0,10,20,30,40,50",
                  "starts_at": "2026-11-01T07:00:00-05:00",
                  "capacity": 4
                }
              ]
            },
            "policy": {
              "cancellation": [
                {
                  "hours_before": 48,
                  "refund_pct": 100
                }
              ]
            }
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/offering.json"
      },
      "PriceTier": {
        "title": "PriceTier",
        "description": "How an offering is priced: an amount per person, group, hour or unit, with optional fees, deposit and minimum spend.",
        "x-doc": "schema-price-tier",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount",
          "currency",
          "unit"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this object. Sending the same external_id again updates or replays it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "examples": [
              "Weekday twilight"
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$",
            "description": "ISO 4217 currency code, lower case.",
            "x-expected": "a three-letter ISO 4217 code in lower case (e.g. \"usd\")",
            "examples": [
              "usd"
            ]
          },
          "unit": {
            "type": "string",
            "enum": [
              "per_person",
              "per_group",
              "per_hour",
              "per_unit"
            ]
          },
          "min_party": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "examples": [
              2
            ]
          },
          "max_party": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "examples": [
              4
            ]
          },
          "days": {
            "type": "array",
            "maxItems": 7,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "mon",
                "tue",
                "wed",
                "thu",
                "fri",
                "sat",
                "sun"
              ]
            },
            "description": "Days of the week this tier applies to; every day when absent.",
            "examples": [
              [
                "mon",
                "tue",
                "wed",
                "thu"
              ]
            ]
          },
          "time_window": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "type": "string",
                "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
                "x-expected": "a local time, HH:MM",
                "examples": [
                  "15:00"
                ]
              },
              "to": {
                "type": "string",
                "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
                "x-expected": "a local time, HH:MM",
                "examples": [
                  "19:00"
                ]
              }
            },
            "description": "Local start times this tier applies to (e.g. twilight from 15:00).",
            "examples": [
              {
                "from": "15:00",
                "to": "19:00"
              }
            ]
          },
          "fees": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/PriceTierFee"
            }
          },
          "deposit": {
            "$ref": "#/components/schemas/PriceTierDeposit"
          },
          "minimum_spend": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "A minimum spend for the party, in minor units (tables, cabanas).",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          }
        },
        "examples": [
          {
            "label": "Weekday",
            "amount": 14500,
            "currency": "usd",
            "unit": "per_person",
            "min_party": 2,
            "max_party": 4,
            "days": [
              "mon",
              "tue",
              "wed",
              "thu"
            ],
            "fees": [
              {
                "type": "tax",
                "percent": 7,
                "included": false
              }
            ]
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/price_tier.json"
      },
      "PriceTierFee": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "type",
          "included"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "service",
              "tax",
              "gratuity",
              "other"
            ]
          },
          "label": {
            "type": "string",
            "maxLength": 80,
            "examples": [
              "Resort fee"
            ]
          },
          "percent": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100,
            "multipleOf": 0.001,
            "x-expected": "a percentage above 0 and at most 100 (e.g. 18 or 8.875)",
            "examples": [
              18
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "A fixed fee in minor units.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          },
          "included": {
            "type": "boolean",
            "description": "true when the tier's amount already includes it; false when it's added on top."
          }
        },
        "oneOf": [
          {
            "required": [
              "percent"
            ],
            "not": {
              "required": [
                "amount"
              ]
            }
          },
          {
            "required": [
              "amount"
            ],
            "not": {
              "required": [
                "percent"
              ]
            }
          }
        ],
        "x-expected": "a fee with either percent or amount (not both)",
        "examples": [
          {
            "type": "gratuity",
            "percent": 18,
            "included": false
          }
        ]
      },
      "PriceTierDeposit": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "percent": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100,
            "examples": [
              25
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          }
        },
        "oneOf": [
          {
            "required": [
              "percent"
            ],
            "not": {
              "required": [
                "amount"
              ]
            }
          },
          {
            "required": [
              "amount"
            ],
            "not": {
              "required": [
                "percent"
              ]
            }
          }
        ],
        "x-expected": "a deposit with either percent or amount (not both)",
        "examples": [
          {
            "percent": 25
          }
        ]
      },
      "Availability": {
        "title": "Availability",
        "description": "When an offering can be bought: explicit slots and/or recurring rules, minus blackout dates.",
        "x-doc": "schema-availability",
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "timezone": {
            "type": "string",
            "maxLength": 64,
            "pattern": "^[A-Za-z_]+(/[A-Za-z0-9_+-]+){0,2}$",
            "x-expected": "an IANA time zone (e.g. \"America/New_York\")",
            "examples": [
              "America/New_York"
            ]
          },
          "slots": {
            "type": "array",
            "maxItems": 1000,
            "items": {
              "$ref": "#/components/schemas/AvailabilitySlot"
            }
          },
          "recurring": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/AvailabilityRule"
            }
          },
          "blackout_dates": {
            "type": "array",
            "maxItems": 366,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "format": "date"
            }
          },
          "lead_time_minutes": {
            "type": "integer",
            "minimum": 0,
            "maximum": 525600,
            "description": "How long before a slot it can still be booked.",
            "examples": [
              60
            ]
          },
          "cutoff_minutes": {
            "type": "integer",
            "minimum": 0,
            "maximum": 525600,
            "description": "How long before a slot the party must be fully paid (the checkout's pay_by default).",
            "examples": [
              120
            ]
          }
        },
        "examples": [
          {
            "timezone": "America/New_York",
            "recurring": [
              {
                "rrule": "FREQ=DAILY;BYHOUR=7,8,9;BYMINUTE=0,10,20,30,40,50",
                "starts_at": "2026-11-01T07:00:00-05:00",
                "duration_minutes": 270,
                "capacity": 4
              }
            ],
            "blackout_dates": [
              "2026-11-26"
            ],
            "lead_time_minutes": 60
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/availability.json"
      },
      "AvailabilitySlot": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "starts_at"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this object. Sending the same external_id again updates or replays it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T08:00:00-05:00"
            ]
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T12:30:00-05:00"
            ]
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
            "examples": [
              4
            ]
          },
          "tier_overrides": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "tier",
                "amount"
              ],
              "properties": {
                "tier": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 128,
                  "description": "The tier's external_id (or label)."
                },
                "amount": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100000000,
                  "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
                  "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
                  "examples": [
                    14500
                  ]
                }
              }
            }
          }
        },
        "examples": [
          {
            "starts_at": "2026-11-07T08:00:00-05:00",
            "capacity": 4
          }
        ]
      },
      "AvailabilityRule": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "rrule",
          "starts_at"
        ],
        "properties": {
          "rrule": {
            "type": "string",
            "maxLength": 500,
            "pattern": "^(RRULE:)?FREQ=(DAILY|WEEKLY|MONTHLY|YEARLY)(;[A-Z]+=[A-Za-z0-9,:+-]+)*$",
            "x-expected": "an RFC 5545 RRULE (e.g. \"FREQ=DAILY;BYHOUR=7,8,9;BYMINUTE=0,10,20,30,40,50\")",
            "examples": [
              "FREQ=DAILY;BYHOUR=7,8,9;BYMINUTE=0,10,20,30,40,50"
            ]
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T08:00:00-05:00"
            ],
            "description": "DTSTART: the first occurrence."
          },
          "until": {
            "type": "string",
            "format": "date"
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 1440,
            "examples": [
              270
            ]
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
            "examples": [
              4
            ]
          }
        }
      },
      "Policy": {
        "title": "Policy",
        "description": "The house rules: cancellation and refunds, age, dress code, arrival.",
        "x-doc": "schema-policy",
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "cancellation": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "hours_before",
                "refund_pct"
              ],
              "properties": {
                "hours_before": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 8760,
                  "examples": [
                    48
                  ]
                },
                "refund_pct": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100,
                  "examples": [
                    100
                  ]
                }
              }
            },
            "description": "Refund tiers: cancelling at least hours_before the start refunds refund_pct.",
            "examples": [
              [
                {
                  "hours_before": 48,
                  "refund_pct": 100
                },
                {
                  "hours_before": 24,
                  "refund_pct": 50
                }
              ]
            ]
          },
          "min_age": {
            "type": "integer",
            "enum": [
              0,
              18,
              21
            ],
            "examples": [
              21
            ]
          },
          "dress_code": {
            "type": "string",
            "maxLength": 200,
            "examples": [
              "Collared shirts, soft spikes"
            ]
          },
          "arrival_window_minutes": {
            "type": "integer",
            "minimum": 0,
            "maximum": 240,
            "examples": [
              30
            ]
          },
          "notes": {
            "type": "string",
            "maxLength": 2000
          }
        },
        "examples": [
          {
            "cancellation": [
              {
                "hours_before": 48,
                "refund_pct": 100
              }
            ],
            "min_age": 0,
            "dress_code": "Collared shirts, soft spikes",
            "arrival_window_minutes": 30
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/policy.json"
      },
      "Event": {
        "title": "Event",
        "description": "A dated instance: a night, a tournament, a show. POST /v1/experiences accepts it (and still accepts the original experience body).",
        "x-doc": "schema-event",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "title",
          "starts_at"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this object. Sending the same external_id again updates or replays it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "offering_external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "The offering this is an instance of, if any.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "examples": [
              "Member-guest scramble"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60,
            "pattern": "^[a-z0-9_-]+$",
            "description": "A SplitClub category slug; GET /v1/me lists the ones you may use.",
            "examples": [
              "golf"
            ]
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T08:00:00-05:00"
            ]
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T14:00:00-05:00"
            ]
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
            "examples": [
              72
            ]
          },
          "tiers": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/PriceTier"
            }
          },
          "on_sale": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "starts_at": {
                "type": "string",
                "format": "date-time",
                "examples": [
                  "2026-11-07T08:00:00-05:00"
                ]
              },
              "ends_at": {
                "type": "string",
                "format": "date-time",
                "examples": [
                  "2026-11-07T08:00:00-05:00"
                ]
              }
            }
          },
          "media": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "maxLength": 2000,
                  "pattern": "^https://[^\\s]{4,}$",
                  "format": "uri",
                  "x-expected": "an https:// URL",
                  "examples": [
                    "https://example.com/photo.jpg"
                  ]
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "image",
                    "video"
                  ],
                  "default": "image"
                },
                "alt": {
                  "type": "string",
                  "maxLength": 300
                }
              }
            }
          },
          "policy": {
            "$ref": "#/components/schemas/Policy"
          },
          "booking_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "examples": [
              "https://example.com/photo.jpg"
            ]
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.-]+$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string keys of your own, echoed back on every read and webhook.",
            "examples": [
              {
                "order_id": "A-1042"
              }
            ]
          }
        },
        "examples": [
          {
            "external_id": "scramble-2026-11-07",
            "title": "Member-guest scramble",
            "starts_at": "2026-11-07T08:00:00-05:00",
            "capacity": 72,
            "tiers": [
              {
                "label": "Per player",
                "amount": 19500,
                "currency": "usd",
                "unit": "per_person"
              }
            ]
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/event.json"
      },
      "CheckoutCreate": {
        "title": "CheckoutCreate",
        "description": "POST /v1/checkouts: start a Pay with SplitClub checkout for a party. The amount is set here, by your server, and nowhere else.",
        "x-doc": "schema-checkout-create",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount",
          "currency",
          "party_size",
          "pay_by",
          "description",
          "return_url",
          "external_booking_id"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "minimum": 100,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units, at least 100 (e.g. 48000 for $480.00)",
            "examples": [
              48000
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$",
            "description": "ISO 4217 currency code, lower case.",
            "x-expected": "a three-letter ISO 4217 code in lower case (e.g. \"usd\")",
            "examples": [
              "usd"
            ]
          },
          "party_size": {
            "type": "integer",
            "minimum": 2,
            "maximum": 50,
            "examples": [
              4
            ]
          },
          "pay_by": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-06T20:00:00-05:00"
            ],
            "description": "When every share must be held; unfunded checkouts expire then and every hold is released."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "examples": [
              "Tee time for four, Sat 8:00"
            ]
          },
          "return_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "examples": [
              "https://golf.example.com/booking/A-1042/done"
            ],
            "description": "Where the guest goes when they're done. Must be on one of your registered origins."
          },
          "cancel_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "examples": [
              "https://golf.example.com/booking/A-1042"
            ]
          },
          "external_booking_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your booking's id. Doubles as the idempotency key when no Idempotency-Key header is sent.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "A-1042"
            ]
          },
          "offering_external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this object. Sending the same external_id again updates or replays it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "tee-sheet-4471"
            ]
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.-]+$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string keys of your own, echoed back on every read and webhook.",
            "examples": [
              {
                "order_id": "A-1042"
              }
            ]
          }
        },
        "examples": [
          {
            "amount": 48000,
            "currency": "usd",
            "party_size": 4,
            "pay_by": "2026-11-06T20:00:00-05:00",
            "description": "Tee time for four, Sat 8:00",
            "return_url": "https://golf.example.com/booking/A-1042/done",
            "external_booking_id": "A-1042",
            "offering_external_id": "18-holes"
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/checkout_create.json"
      },
      "Checkout": {
        "title": "Checkout",
        "description": "A Pay with SplitClub checkout, as the API returns it.",
        "x-doc": "schema-checkout",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "object",
          "mode",
          "status",
          "amount",
          "currency",
          "party_size",
          "pay_by",
          "description",
          "venue",
          "external_booking_id",
          "url",
          "shares",
          "funded_amount",
          "created_at",
          "metadata"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^chk_[A-Za-z0-9]+$",
            "examples": [
              "chk_3fT9"
            ]
          },
          "object": {
            "const": "checkout"
          },
          "mode": {
            "type": "string",
            "enum": [
              "test",
              "live"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "collecting",
              "funded",
              "completed",
              "expired",
              "canceled"
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$",
            "description": "ISO 4217 currency code, lower case.",
            "x-expected": "a three-letter ISO 4217 code in lower case (e.g. \"usd\")",
            "examples": [
              "usd"
            ]
          },
          "party_size": {
            "type": "integer",
            "minimum": 2,
            "maximum": 50
          },
          "pay_by": {
            "type": "string",
            "format": "date-time"
          },
          "description": {
            "type": "string",
            "maxLength": 200
          },
          "venue": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "null for a console sandbox (test mode)."
              },
              "name": {
                "type": "string"
              }
            }
          },
          "external_booking_id": {
            "type": "string",
            "maxLength": 128
          },
          "url": {
            "type": "string",
            "pattern": "^https://checkout\\.splitclubapp\\.com/c/chk_[A-Za-z0-9]+$"
          },
          "shares": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Share"
            }
          },
          "funded_amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          },
          "fee_amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "SplitClub's fee on this checkout, in minor units (snapshotted at creation). Partner view only: guests never see it.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              960
            ],
            "readOnly": true
          },
          "net_amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "What the venue is paid: amount - fee_amount, in minor units. Partner view only.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              47040
            ],
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.-]+$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string keys of your own, echoed back on every read and webhook.",
            "examples": [
              {
                "order_id": "A-1042"
              }
            ]
          }
        },
        "x-schema-url": "https://splitclubapp.com/schemas/v1/checkout.json"
      },
      "Share": {
        "title": "Share",
        "description": "One person's part of a checkout (read-only). Never carries a phone number or email.",
        "x-doc": "schema-share",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "amount",
          "status",
          "is_organizer",
          "display_name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^shr_[A-Za-z0-9]+$",
            "examples": [
              "shr_8Kq2"
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Money in integer minor units (cents for usd): 14500 is $145.00.",
            "x-expected": "an integer in minor units (e.g. 14500 for $145.00)",
            "examples": [
              14500
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "invited",
              "held",
              "captured",
              "released",
              "refunded",
              "failed"
            ]
          },
          "is_organizer": {
            "type": "boolean"
          },
          "display_name": {
            "type": "string",
            "maxLength": 120,
            "examples": [
              "Sam T."
            ]
          },
          "held_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "x-schema-url": "https://splitclubapp.com/schemas/v1/share.json"
      },
      "WebhookEvent": {
        "title": "WebhookEvent",
        "description": "What SplitClub POSTs to your webhook endpoint, signed with SplitClub-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + \".\" + body)>.",
        "x-doc": "schema-webhook-event",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "object",
          "type",
          "mode",
          "created_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^evt_[A-Za-z0-9]+$",
            "examples": [
              "evt_1Zp"
            ]
          },
          "object": {
            "const": "event"
          },
          "type": {
            "type": "string",
            "enum": [
              "checkout.created",
              "checkout.collecting",
              "share.held",
              "checkout.funded",
              "checkout.completed",
              "checkout.expired",
              "checkout.canceled",
              "refund.created",
              "offering.approved",
              "offering.rejected"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "test",
              "live"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "object"
            ],
            "properties": {
              "object": {
                "type": "object",
                "description": "The checkout, share or offering the event is about, as the API returns it."
              },
              "previous_status": {
                "type": "string"
              }
            }
          }
        },
        "x-schema-url": "https://splitclubapp.com/schemas/v1/webhook_event.json"
      },
      "Error": {
        "title": "Error",
        "description": "Every failure. `error` is the first problem (with the request_id to quote); `errors` lists every validation problem when there are several.",
        "x-doc": "schema-error",
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "request_id"
            ],
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "invalid_type"
                ]
              },
              "message": {
                "type": "string",
                "examples": [
                  "`/tiers/0/amount` must be an integer in minor units (e.g. 14500 for $145.00); you sent 145.5."
                ]
              },
              "field": {
                "type": "string",
                "description": "RFC 6901 JSON pointer into the request body; \"\" is the body itself.",
                "examples": [
                  "/tiers/0/amount"
                ]
              },
              "expected": {
                "type": "string"
              },
              "example_fix": {
                "type": "string",
                "examples": [
                  "\"amount\": 14500"
                ]
              },
              "doc_url": {
                "type": "string",
                "format": "uri",
                "examples": [
                  "https://splitclubapp.com/developers#schema-price-tier"
                ]
              },
              "request_id": {
                "type": "string",
                "format": "uuid"
              }
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ErrorApiError"
            }
          }
        },
        "x-schema-url": "https://splitclubapp.com/schemas/v1/error.json"
      },
      "ErrorApiError": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "code",
          "message",
          "field",
          "expected",
          "example_fix",
          "doc_url"
        ],
        "properties": {
          "code": {
            "type": "string",
            "examples": [
              "invalid_type"
            ]
          },
          "message": {
            "type": "string",
            "examples": [
              "`/tiers/0/amount` must be an integer in minor units (e.g. 14500 for $145.00); you sent 145.5."
            ]
          },
          "field": {
            "type": "string",
            "description": "RFC 6901 JSON pointer into the request body; \"\" is the body itself.",
            "examples": [
              "/tiers/0/amount"
            ]
          },
          "expected": {
            "type": "string"
          },
          "example_fix": {
            "type": "string",
            "examples": [
              "\"amount\": 14500"
            ]
          },
          "doc_url": {
            "type": "string",
            "format": "uri",
            "examples": [
              "https://splitclubapp.com/developers#schema-price-tier"
            ]
          }
        }
      },
      "Boat": {
        "title": "Boat",
        "description": "One boat in a rental fleet, with everything SplitClub needs to show it: specs, captain terms, home marina, prices by duration, photos and amenities. Sent one at a time or up to 100 per request (POST /v1/boats), upserted on external_id. Every boat is reviewed before it can appear, and only ever inside a boat-day or tie-up event SplitClub runs; boats are never shown on a map.",
        "x-doc": "schema-boat",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_id",
          "name",
          "type",
          "length_ft",
          "capacity",
          "captain",
          "location",
          "pricing",
          "photo_urls"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "^[^\\s]+$",
            "description": "Your system's id for this boat. Sending the same external_id again updates it; it never makes a second one.",
            "x-expected": "your own id for it, 1–128 characters, no spaces",
            "examples": [
              "listing-88213"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "The boat's name or listing title.",
            "examples": [
              "55' Azimut \"Sea Breeze\""
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "motor_yacht",
              "sport_yacht",
              "catamaran",
              "sailboat",
              "center_console",
              "pontoon",
              "jet_ski",
              "other"
            ]
          },
          "make": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "examples": [
              "Azimut"
            ]
          },
          "model": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "examples": [
              "55 Flybridge"
            ]
          },
          "year": {
            "type": "integer",
            "minimum": 1900,
            "maximum": 2100,
            "examples": [
              2019
            ]
          },
          "length_ft": {
            "type": "number",
            "minimum": 5,
            "maximum": 600,
            "description": "Length overall, in feet.",
            "examples": [
              55
            ]
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "description": "The most guests allowed aboard for a day trip, crew not counted.",
            "examples": [
              12
            ]
          },
          "cabins": {
            "type": "integer",
            "minimum": 0,
            "maximum": 50,
            "examples": [
              3
            ]
          },
          "captain": {
            "type": "string",
            "enum": [
              "included",
              "optional",
              "required_extra",
              "bareboat"
            ],
            "description": "included: a captain comes with every booking; optional: the renter chooses; required_extra: a captain is required and charged on top (see fees_note); bareboat: no captain, the renter skippers."
          },
          "location": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "city"
            ],
            "description": "Where the boat is kept and boards. Used to place it in the right city's events and to tell guests where to go; never drawn on a map.",
            "properties": {
              "city": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80,
                "examples": [
                  "Miami"
                ]
              },
              "region": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80,
                "description": "State, province or region.",
                "examples": [
                  "FL"
                ]
              },
              "country": {
                "type": "string",
                "pattern": "^[A-Z]{2}$",
                "x-expected": "a two-letter ISO 3166-1 country code in upper case (e.g. \"US\")",
                "examples": [
                  "US"
                ]
              },
              "marina": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120,
                "examples": [
                  "Miami Beach Marina"
                ]
              },
              "address": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "examples": [
                  "300 Alton Rd, Miami Beach, FL 33139"
                ]
              },
              "lat": {
                "type": "number",
                "minimum": -90,
                "maximum": 90,
                "examples": [
                  25.7712
                ]
              },
              "lng": {
                "type": "number",
                "minimum": -180,
                "maximum": 180,
                "examples": [
                  -80.1397
                ]
              }
            },
            "dependentRequired": {
              "lat": [
                "lng"
              ],
              "lng": [
                "lat"
              ]
            }
          },
          "pricing": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "description": "What the whole boat costs for each duration you rent it for.",
            "items": {
              "$ref": "#/components/schemas/BoatRate"
            }
          },
          "deposit_amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "Security deposit in integer minor units, in the pricing currency.",
            "x-expected": "an integer in minor units (e.g. 100000 for $1,000.00)",
            "examples": [
              100000
            ]
          },
          "deposit_note": {
            "type": "string",
            "maxLength": 1000,
            "examples": [
              "Refundable $1,000 hold, released within 48 hours of return."
            ]
          },
          "fees_note": {
            "type": "string",
            "maxLength": 1000,
            "description": "Anything charged on top of the rate: fuel, captain's gratuity, cleaning, dockage, taxes.",
            "examples": [
              "Captain's gratuity (18–20%) and Florida sales tax not included."
            ]
          },
          "amenities": {
            "type": "array",
            "maxItems": 40,
            "uniqueItems": true,
            "description": "What's aboard. Free text; these words are recognized: bathroom, air_conditioning, bluetooth_audio, cooler, ice, water_toys, paddleboard, snorkel_gear, floating_mat, seabob, jet_ski, tender, swim_platform, grill, shade, wifi.",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 60
            },
            "examples": [
              [
                "bathroom",
                "air_conditioning",
                "bluetooth_audio",
                "floating_mat"
              ]
            ]
          },
          "photo_urls": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "uniqueItems": true,
            "description": "In the order to show them; the first is the cover.",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "pattern": "^https://[^\\s]{4,}$",
              "format": "uri",
              "x-expected": "an https:// URL",
              "examples": [
                "https://example.com/boats/88213/cover.jpg"
              ]
            }
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "booking_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "description": "Where this boat is booked on your own site.",
            "examples": [
              "https://example.com/boats/88213"
            ]
          },
          "availability": {
            "type": "object",
            "additionalProperties": false,
            "description": "Optional. A calendar feed, a page, or explicit blocks: whichever your system has.",
            "properties": {
              "ical_url": {
                "type": "string",
                "maxLength": 2000,
                "pattern": "^https://[^\\s]{4,}$",
                "format": "uri",
                "x-expected": "an https:// URL to an iCalendar (.ics) feed",
                "examples": [
                  "https://example.com/boats/88213/calendar.ics"
                ]
              },
              "url": {
                "type": "string",
                "maxLength": 2000,
                "pattern": "^https://[^\\s]{4,}$",
                "format": "uri",
                "x-expected": "an https:// URL",
                "examples": [
                  "https://example.com/boats/88213/availability"
                ]
              },
              "timezone": {
                "type": "string",
                "maxLength": 64,
                "pattern": "^[A-Za-z_]+(/[A-Za-z0-9_+-]+){0,2}$",
                "x-expected": "an IANA time zone (e.g. \"America/New_York\")",
                "examples": [
                  "America/New_York"
                ]
              },
              "blocks": {
                "type": "array",
                "maxItems": 500,
                "items": {
                  "$ref": "#/components/schemas/BoatBlock"
                }
              }
            }
          },
          "source_platform": {
            "type": "string",
            "minLength": 1,
            "maxLength": 40,
            "pattern": "^[a-z0-9_-]+$",
            "description": "Where the listing lives, as a lower-case slug: your platform's name, or \"own\" for a fleet's own system.",
            "x-expected": "a lower-case slug (e.g. \"own\")",
            "examples": [
              "own"
            ]
          },
          "source_url": {
            "type": "string",
            "maxLength": 2000,
            "pattern": "^https://[^\\s]{4,}$",
            "format": "uri",
            "x-expected": "an https:// URL",
            "description": "The listing's public page on that platform.",
            "examples": [
              "https://example.com/boats/88213"
            ]
          },
          "active": {
            "type": "boolean",
            "default": true,
            "description": "false takes the boat out of everything at once (sold, laid up, delisted). Send true again to bring it back; an unchanged boat that was approved returns approved."
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.-]+$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string keys of your own, echoed back on every read.",
            "examples": [
              {
                "owner_ref": "OWN-2231"
              }
            ]
          },
          "extra": {
            "type": "object",
            "maxProperties": 50,
            "description": "Anything else your listing has (engines, speed, fuel burn, rules…), in your own shape. Stored with the boat and shown to SplitClub's reviewers; not shown to guests.",
            "examples": [
              {
                "engines": "2 x Volvo IPS 800",
                "cruise_knots": 26
              }
            ]
          }
        },
        "examples": [
          {
            "external_id": "listing-88213",
            "name": "55' Azimut \"Sea Breeze\"",
            "type": "motor_yacht",
            "make": "Azimut",
            "model": "55 Flybridge",
            "year": 2019,
            "length_ft": 55,
            "capacity": 12,
            "cabins": 3,
            "captain": "included",
            "location": {
              "city": "Miami",
              "region": "FL",
              "country": "US",
              "marina": "Miami Beach Marina",
              "address": "300 Alton Rd, Miami Beach, FL 33139",
              "lat": 25.7712,
              "lng": -80.1397
            },
            "pricing": [
              {
                "label": "Half day",
                "duration_hours": 4,
                "amount": 220000,
                "currency": "usd",
                "captain_included": true,
                "fuel_included": true
              },
              {
                "label": "Full day",
                "duration_hours": 8,
                "amount": 380000,
                "currency": "usd",
                "captain_included": true,
                "fuel_included": true
              }
            ],
            "deposit_amount": 100000,
            "deposit_note": "Refundable $1,000 hold, released within 48 hours of return.",
            "fees_note": "Captain's gratuity (18–20%) and Florida sales tax not included.",
            "amenities": [
              "bathroom",
              "air_conditioning",
              "bluetooth_audio",
              "floating_mat",
              "paddleboard",
              "cooler"
            ],
            "photo_urls": [
              "https://example.com/boats/88213/cover.jpg",
              "https://example.com/boats/88213/flybridge.jpg",
              "https://example.com/boats/88213/salon.jpg"
            ],
            "description": "Three-cabin Azimut flybridge with a sunpad forward and a shaded aft deck. Cruise Biscayne Bay, anchor off Nixon Sandbar, and swim from the platform.",
            "booking_url": "https://example.com/boats/88213",
            "availability": {
              "ical_url": "https://example.com/boats/88213/calendar.ics",
              "timezone": "America/New_York"
            },
            "source_platform": "own",
            "source_url": "https://example.com/boats/88213",
            "active": true,
            "metadata": {
              "owner_ref": "OWN-2231"
            }
          }
        ],
        "x-schema-url": "https://splitclubapp.com/schemas/v1/boat.json"
      },
      "BoatRate": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "duration_hours",
          "amount",
          "currency"
        ],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "examples": [
              "Half day"
            ]
          },
          "duration_hours": {
            "type": "number",
            "minimum": 0.5,
            "maximum": 336,
            "examples": [
              4
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000000,
            "description": "The price of the whole boat for this duration, in integer minor units (cents for usd): 220000 is $2,200.00.",
            "x-expected": "an integer in minor units (e.g. 220000 for $2,200.00)",
            "examples": [
              220000
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$",
            "description": "ISO 4217 currency code, lower case.",
            "x-expected": "a three-letter ISO 4217 code in lower case (e.g. \"usd\")",
            "examples": [
              "usd"
            ]
          },
          "captain_included": {
            "type": "boolean",
            "examples": [
              true
            ]
          },
          "fuel_included": {
            "type": "boolean",
            "examples": [
              true
            ]
          },
          "days": {
            "type": "array",
            "minItems": 1,
            "maxItems": 7,
            "uniqueItems": true,
            "description": "Only on these days (weekend rates, say). Omit for every day.",
            "items": {
              "type": "string",
              "enum": [
                "mon",
                "tue",
                "wed",
                "thu",
                "fri",
                "sat",
                "sun"
              ]
            }
          }
        }
      },
      "BoatBlock": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "starts_at",
          "ends_at"
        ],
        "properties": {
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T10:00:00-05:00"
            ]
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "examples": [
              "2026-11-07T14:00:00-05:00"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "unavailable"
            ],
            "default": "unavailable"
          }
        }
      },
      "LegacyExperience": {
        "type": "object",
        "description": "The original experience body (2026-10-12). Still accepted; prefer Event. price_per_person is in dollars here, not minor units.",
        "required": [
          "title",
          "starts_at"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "maxLength": 128
          },
          "title": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "category": {
            "type": "string"
          },
          "starts_at": {
            "type": "string",
            "format": "date-time"
          },
          "ends_at": {
            "type": "string",
            "format": "date-time"
          },
          "price_per_person": {
            "type": "number",
            "minimum": 0,
            "maximum": 100000
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000
          },
          "photo_urls": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "booking_url": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    },
    "securitySchemes": {
      "secretKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sc_test_… / sc_live_…",
        "description": "Secret key, server-side only. Never sent from a browser (no CORS)."
      },
      "publishableKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pk_test_… / pk_live_…",
        "description": "Publishable key, from one of your registered origins only."
      },
      "memberJwt": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "A signed-in SplitClub member's session (the checkout page and the app)."
      }
    },
    "responses": {
      "E400": {
        "description": "Malformed request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E401": {
        "description": "Missing, unknown, revoked or expired key (or a bad webhook signature)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E403": {
        "description": "Wrong key kind, scope, IP or origin",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E404": {
        "description": "Not found for this key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E409": {
        "description": "Conflicts with the object's current state",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E413": {
        "description": "Body too large",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E422": {
        "description": "Validation failed: error.field is a JSON pointer; errors[] lists every problem",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E429": {
        "description": "Rate limited: see Retry-After",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
