{"openapi":"3.1.0","info":{"title":"ProhostAI API","description":"External API for ProhostAI property management platform","version":"1.0.0"},"paths":{"/.well-known/oauth-protected-resource":{"get":{"tags":["OAuth 2.1"],"summary":"Protected Resource Metadata","description":"Return OAuth 2.0 Protected Resource Metadata (RFC 9728) for the API root.","operationId":"protected_resource_metadata__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2ProtectedResourceMetadata"}}}}},"security":[]}},"/.well-known/oauth-protected-resource/mcp":{"get":{"tags":["OAuth 2.1"],"summary":"Protected Resource Metadata Mcp","description":"Return RFC 9728 metadata for the ``/mcp`` resource specifically.\n\nRFC 9728 §3.1 derives the metadata URL from the resource identifier by\ninserting ``/.well-known/oauth-protected-resource`` *before* the resource's\npath — so a resource of ``https://connect.prohost.ai/mcp`` is described at\n``/.well-known/oauth-protected-resource/mcp``, which is exactly what MCP\nclients request. Until now that path 404'd and clients fell back to the\nroot document, whose ``resource`` is the API root and therefore does not\nmatch the URL they are actually calling.\n\n``resource`` here is the full MCP URL; the root document is left alone\nbecause it still correctly describes the REST surface.","operationId":"protected_resource_metadata_mcp__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2ProtectedResourceMetadata"}}}}},"security":[]}},"/.well-known/oauth-authorization-server":{"get":{"tags":["OAuth 2.1"],"summary":"Server Metadata","description":"Return OAuth 2.1 Authorization Server Metadata (RFC 8414).","operationId":"server_metadata__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2ServerMetadata"}}}}},"security":[]}},"/.well-known/oauth-authorization-server/mcp":{"get":{"tags":["OAuth 2.1"],"summary":"Server Metadata Mcp","description":"Point ``/mcp``-suffixed probes at the canonical RFC 8414 document.\n\nMCP clients derive this URL from the resource path and request it before\nthe root; it used to 404. It cannot simply *serve* the metadata, though:\nRFC 8414 §3.3 requires the returned ``issuer`` to equal the issuer the\ndiscovery URL was built from, which here would be\n``https://connect.prohost.ai/mcp``. Our issuer has no path component, so a\nstrict client would reject a document claiming the root as its issuer —\nworse than the 404 it replaced, since a 404 at least fell through cleanly.\n\nA redirect gives both audiences what they need: lenient clients follow it\nand get working metadata, strict clients validate the document against the\ncanonical URL it actually came from. Unlike the protected-resource\nmetadata, which genuinely does describe ``/mcp`` as a distinct resource,\nthere is only ever one authorization server here.","operationId":"server_metadata_mcp__well_known_oauth_authorization_server_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[]}},"/oauth/grant/check":{"get":{"tags":["OAuth 2.1"],"summary":"Grant Check","description":"Return whether the user already has a non-revoked grant covering ``scope``.\n\nRead-only probe used by the frontend consent page (``app.prohost.ai/oauth/consent``)\nto decide whether to skip its own UI. When the user has previously\nauthorised this client for at least the requested scopes, the frontend\nforwards straight to ``/oauth/authorize/complete`` — no consent click,\nno flash of the consent UI.\n\nRequired because ``connect.prohost.ai`` and ``app.prohost.ai`` do not\nshare Clerk session cookies, so users always traverse the frontend\nconsent route even when the server-side silent-grant in\n``/oauth/authorize`` would have fired. Without this endpoint the\nfrontend has no way to know a grant exists.\n\nAuthentication: ``Authorization: Bearer <clerk_jwt>``. The token MUST\nNOT travel as a query parameter — bearer credentials in URLs leak into\nbrowser history, access logs, proxy logs, and any URL-retention layer\n(Sentry breadcrumbs, Datadog spans, third-party CDNs). The endpoint is\nrate-limited per IP via ``_check_grant_check_rate_limit``.\n\nReturns:\n    ``{\"has_grant\": bool, \"account_id\": str | null}``. ``account_id`` is\n    populated only when ``has_grant`` is true so the frontend has the\n    identifier it needs for the redirect (single-account users; an\n    explicit ``account_id`` query param wins for multi-account). The\n    response sets ``Cache-Control: no-store`` so intermediaries never\n    cache grant-existence signals across users.","operationId":"grant_check_oauth_grant_check_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string","title":"Scope"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/register":{"post":{"tags":["OAuth 2.1"],"summary":"Register Client","description":"Dynamic Client Registration (RFC 7591).\n\nAllows MCP clients (e.g. Claude Code) to self-register and obtain\na client_id + optional client_secret without manual pre-configuration.\n\nRate limiting runs here rather than as a route dependency because the\nbucket key needs the parsed body (``software_id`` / ``redirect_uris``) —\nsee ``api_public.oauth.dcr_rate_limit``. The consequence is that a request\nrejected by body validation (422) never consumes a slot, which is fine:\nthe limiter exists to bound ``OAuth2Application`` inserts, and a request\nthat fails validation writes nothing.\n\nPublic clients (token_endpoint_auth_method=\"none\") receive no client_secret\nand must use PKCE for token exchange.","operationId":"register_client_oauth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2ClientRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/oauth/authorize":{"get":{"tags":["OAuth 2.1"],"summary":"Authorize","description":"OAuth 2.1 authorization endpoint.\n\nRenders a consent page for authenticated users or a login prompt otherwise.\n\nPer RFC 6749 Section 4.1.2.1, errors related to invalid client_id or\nredirect_uri are shown to the user (not redirected). Other errors are\nredirected back to the client.","operationId":"authorize_oauth_authorize_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","title":"Redirect Uri"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string","title":"Scope"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","title":"Code Challenge"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","default":"S256","title":"Code Challenge Method"}},{"name":"response_type","in":"query","required":false,"schema":{"type":"string","default":"code","title":"Response Type"}},{"name":"resource","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"}},{"name":"__session","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"  Session"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize/approve":{"post":{"tags":["OAuth 2.1"],"summary":"Authorize Approve","description":"Handle user approval of the OAuth consent form.\n\nVerifies the Clerk session and CSRF token, creates an authorization code,\nand redirects to the redirect_uri with the code and state.\n\nTwo forms post here. The single-workspace form names ``account_id``. The\nmulti-workspace form (``workspace_consent``) names the ticked\n``workspace_id`` values, ``include_future_workspaces`` and\n``default_workspace_id``. When ``/oauth/authorize/complete`` rendered it,\nthe frontend flow has no session cookie here, so it carries a one-time\n``consent_ticket`` bound to the person and this request\n(``api_public/oauth/consent_tickets.py``) instead of a session credential.","operationId":"authorize_approve_oauth_authorize_approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"__session","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"  Session"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_authorize_approve_oauth_authorize_approve_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize/deny":{"get":{"tags":["OAuth 2.1"],"summary":"Authorize Deny","description":"Handle user denial of the OAuth consent form.\n\nRedirects to the redirect_uri with an access_denied error.","operationId":"authorize_deny_oauth_authorize_deny_get","parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","title":"Redirect Uri"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/oauth/authorize/complete":{"get":{"tags":["OAuth 2.1"],"summary":"Authorize Complete","description":"Complete the OAuth authorization using a Clerk JWT from the frontend.\n\nThe frontend consent page (app.prohost.ai/oauth/consent) gets a Clerk\nsession token via getToken() and redirects here with it. We verify the\nJWT, identify the user, and issue an authorization code.\n\nFor users with multiple accounts, the account_id query parameter specifies\nwhich account to authorize. If omitted and the user has multiple accounts,\nan account selector page is rendered.","operationId":"authorize_complete_oauth_authorize_complete_get","parameters":[{"name":"clerk_token","in":"query","required":true,"schema":{"type":"string","title":"Clerk Token"}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","title":"Redirect Uri"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string","title":"Scope"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","title":"Code Challenge"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","default":"S256","title":"Code Challenge Method"}},{"name":"response_type","in":"query","required":false,"schema":{"type":"string","default":"code","title":"Response Type"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}},{"name":"resource","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/oauth/token":{"post":{"tags":["OAuth 2.1"],"summary":"Token","description":"OAuth 2.1 token endpoint.\n\nHandles authorization_code and refresh_token grants.\nError responses follow RFC 6749 Section 5.2 format.\n\nClient authentication:\n- client_secret_post: client_id + client_secret in the request body (default).\n- client_secret_basic: credentials in the Authorization: Basic header (RFC 6749 §2.3.1).\n- none: public clients (PKCE only, no secret required).\n\n``resource`` (RFC 8707) binds the token to a resource; an unknown one, or\none other than the grant's, is ``invalid_target``.","operationId":"token_oauth_token_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_token_oauth_token_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/oauth/revoke":{"post":{"tags":["OAuth 2.1"],"summary":"Revoke","description":"OAuth 2.1 token revocation endpoint (RFC 7009).\n\nAccepts client authentication via:\n- Form body (client_id + client_secret)\n- Authorization: Basic header (RFC 6749 §2.3.1)\n- Public clients (token_endpoint_auth_method=none): only client_id required","operationId":"revoke_oauth_revoke_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_revoke_oauth_revoke_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/reservations":{"get":{"tags":["Reservations"],"summary":"List reservations","description":"Retrieve a paginated list of reservations for the account, with optional filters by listing, status, date range, and guest search.","operationId":"list_reservations_v1_reservations_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by reservation status (confirmed, pending, cancelled, inquiry, unknown)","title":"Status"},"description":"Filter by reservation status (confirmed, pending, cancelled, inquiry, unknown)"},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ReservationSourceName"},{"type":"null"}],"description":"Filter by reservation source name (e.g. hostaway, airbnb, guesty).","title":"Source"},"description":"Filter by reservation source name (e.g. hostaway, airbnb, guesty)."},{"name":"source_reservation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by OTA/PMS reservation identifier.","title":"Source Reservation Id"},"description":"Filter by OTA/PMS reservation identifier."},{"name":"channel_reservation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by booking-channel confirmation code.","title":"Channel Reservation Id"},"description":"Filter by booking-channel confirmation code."},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter reservations checking in after this date","title":"Start Date"},"description":"Filter reservations checking in after this date"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter reservations checking out before this date","title":"End Date"},"description":"Filter reservations checking out before this date"},{"name":"search_query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Substring search across guest name, guest email, and the reservation's confirmation code — matching both the booking-channel code and the OTA/PMS identifier. For an exact match on one of those, use `channel_reservation_id` / `source_reservation_id` instead.","title":"Search Query"},"description":"Substring search across guest name, guest email, and the reservation's confirmation code — matching both the booking-channel code and the OTA/PMS identifier. For an exact match on one of those, use `channel_reservation_id` / `source_reservation_id` instead."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ReservationExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Reservations"],"summary":"Create a reservation","description":"Create a confirmed ProhostAI booking on one of the workspace's listings: a direct booking\n(`channel: \"direct\"`) or an owner stay (`channel: \"owner\"`). It is the same booking the app's\n\"Create reservation\" dialog makes, with the same turnover cleaning, guest conversation, triggered\ntasks, calendar block and template scheduled messages (on by default for `direct`, off for `owner`;\noverride with `scheduled_messages`).\n\n**Dates** are listing-local dates; times default to the listing's check-in and check-out times.\n\n**Idempotency:** send an `Idempotency-Key` header to make a retry replay the first response for\n24 hours, and an `external_id` (your own booking id) to dedupe for good: a second create with the\nsame `external_id` answers 409 `reservation_exists` with the existing `reservation_id`. An\n`external_id` that is the confirmation code of a booking a channel imported answers 409\n`duplicate_of_imported_reservation`.\n\n**Conflicts:** nights a confirmed booking (on this listing or one sharing its calendar) already holds\nanswer 409 `dates_unavailable` with the conflicting stays, unless `allow_overlap` is true. Nights\nclosed by a calendar block are allowed and reported as a `dates_blocked` warning.\n\n**Airbnb:** a listing connected through Airbnb only stops selling these nights once Airbnb reads\nthe listing's ProhostAI calendar export feed; the response warns `not_blocked_on_channel` until it\ndoes. Listings whose bookings a connected PMS manages (Hostaway, Guesty, OwnerRez, ...) refuse with\n422 `listing_managed_by_pms`.\n\n**From an inquiry:** pass the `conversation_id` of a conversation started through\n`POST /v1/conversations` to make it the booking's conversation (needs `conversations:ingest` too).\n\n**Webhooks:** the `reservation.created` event for a booking your credential created is not sent to\nthat credential's own webhook subscriptions.\n\nRequires `reservations:write`. Agent-bound keys cannot create bookings. Supports `?dry_run=true`\n(validates and returns the booking that would be created, writing nothing). A workspace may create\nup to 200 bookings a day this way.","operationId":"create_reservation_v1_reservations_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationCreateExternal"},"examples":{"direct":{"summary":"Direct booking","description":"A guest booking taken off-platform, priced line by line.","value":{"listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","external_id":"BK-48213","channel":"direct","check_in":"2026-11-20","check_out":"2026-11-23","guest":{"first_name":"Alex","last_name":"Rivera","email":"alex.rivera@example.com"},"guests":{"adults":2},"invoice_items":[{"type":"accommodation_fare","amount":450.0},{"type":"cleaning_fee","amount":80.0},{"type":"lodging_tax","amount":36.5,"host_remitted":true}]}},"owner":{"summary":"Owner stay","description":"The owner blocking their own property: no guest name or price needed.","value":{"listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","external_id":"OWN-2026-11","channel":"owner","check_in":"2026-12-24","check_out":"2026-12-28"}}}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationCreatedExternal"}}}},"403":{"description":"Not enabled for this workspace, an agent-bound key, or the key's listing scope."},"404":{"description":"Listing not found."},"409":{"description":"`reservation_exists`, `duplicate_of_imported_reservation` or `dates_unavailable`."},"422":{"description":"Invalid dates, guest, price lines or currency; inactive or PMS-managed listing."},"429":{"description":"The workspace's daily create limit is reached."}}}},"/v1/reservations/find":{"get":{"tags":["Reservations"],"summary":"Find a reservation by external identifiers","description":"Find a single reservation by OTA/PMS identifiers such as ``source_reservation_id``. If more than one reservation matches, include ``source`` to disambiguate.\n\n**Conditional requests:** the response carries a strong ``ETag`` over the reservation payload. Send it back in ``If-None-Match`` on the next poll — an unchanged reservation returns ``304 Not Modified`` with an empty body (saves serialization + bandwidth).\n\n**Delta syncs:** pass ``updated_since`` (ISO-8601) to only match a reservation that changed after that instant — combine it with your last successful poll's timestamp so a reservation you already have returns ``404`` until it next changes.","operationId":"find_reservation_v1_reservations_find_get","parameters":[{"name":"source_reservation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"OTA/PMS reservation identifier.","title":"Source Reservation Id"},"description":"OTA/PMS reservation identifier."},{"name":"channel_reservation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Booking-channel confirmation code.","title":"Channel Reservation Id"},"description":"Booking-channel confirmation code."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ReservationSourceName"},{"type":"null"}],"description":"Reservation source name (e.g. hostaway, airbnb, guesty).","title":"Source"},"description":"Reservation source name (e.g. hostaway, airbnb, guesty)."},{"name":"updated_since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only match a reservation whose ``updated_at`` is strictly after this ISO-8601 instant. Use it for delta syncs — pass your last successful poll's timestamp.","title":"Updated Since"},"description":"Only match a reservation whose ``updated_at`` is strictly after this ISO-8601 instant. Use it for delta syncs — pass your last successful poll's timestamp."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationExternal"}}}},"304":{"description":"Not modified — the reservation still hashes to the ``ETag`` supplied in ``If-None-Match``. Empty body; the ``ETag`` header is echoed back."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}":{"get":{"tags":["Reservations"],"summary":"Get a reservation","description":"Retrieve a single reservation by its ID.","operationId":"get_reservation_v1_reservations__reservation_id__get","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Reservations"],"summary":"Update a reservation","description":"Update a reservation. ``custom_fields`` and the guest's contact details can be changed on any reservation. The stay itself — ``check_in`` / ``check_out`` (listing-local dates), their times, ``guests`` and ``invoice_items`` (which replace every price line) — can be changed only on a booking ProhostAI owns; a channel's booking answers 403 ``reservation_not_editable`` and must change on that channel, and a booking the guest paid for through ProhostAI's booking site answers 403 ``reservation_has_guest_payment``: change it in the app, which charges or refunds the difference. New nights another confirmed booking holds answer 409 ``dates_unavailable`` unless ``allow_overlap`` is true. The ``reservation.updated`` event for a change your credential made is not sent to that credential's own webhook subscriptions. Cancel through ``POST /v1/reservations/{id}/cancel``.","operationId":"update_reservation_v1_reservations__reservation_id__put","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}/financials":{"get":{"tags":["Reservations"],"summary":"Get a reservation's financial breakdown","description":"Return the per-reservation money breakdown: what the guest paid, the fee breakdown (cleaning, service, other), taxes, the host payout, and per-night rates when available. Amounts are in the reservation's currency. A ``null`` amount means the reservation has no line item for that category (e.g. a direct booking imported without an invoice) — never a fabricated zero.","operationId":"get_reservation_financials_v1_reservations__reservation_id__financials_get","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationFinancialsExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}/cancel":{"post":{"tags":["Reservations"],"summary":"Cancel a reservation","description":"Cancel a booking ProhostAI owns (created in ProhostAI). Frees its nights, cancels its turnover cleaning, scheduled messages and open triggered tasks, clears its price lines, and fires ``reservation.cancelled`` (not to your credential's own webhook subscriptions). A channel's booking answers 403 ``reservation_not_cancellable``: cancel it on that channel. A booking the guest paid for through ProhostAI's booking site answers 403 ``reservation_has_guest_payment``: cancel it in the app, which refunds the guest under its cancellation policy. Cancelling a booking that is already cancelled returns it unchanged. ``reason`` is recorded on the booking's conversation timeline and never sent to the guest.","operationId":"cancel_reservation_v1_reservations__reservation_id__cancel_post","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ReservationCancelExternal"},{"type":"null"}],"title":"Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReservationExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}/custom-fields":{"get":{"tags":["Reservations"],"summary":"Get reservation custom fields","description":"Return the resolved custom-field values for a reservation, with provenance. Merge order: account → listing tags by specificity → reservation source → reservation. Reservation-level values win on conflict.","operationId":"get_reservation_custom_fields_v1_reservations__reservation_id__custom_fields_get","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsResolved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/custom-fields/batch":{"post":{"tags":["Reservations"],"summary":"Batch-set reservation custom fields","description":"Merge ``fields`` into ``custom_fields`` on every reservation in ``ids``. Existing keys are overwritten; keys absent from ``fields`` are preserved. Listing-scoped API keys must own every reservation's listing.","operationId":"batch_set_reservation_custom_fields_v1_reservations_custom_fields_batch_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchSetRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/custom-fields/batch/delete":{"post":{"tags":["Reservations"],"summary":"Batch-delete reservation custom-field keys","description":"Remove the named keys from ``custom_fields`` on every reservation in ``ids``. Listing-scoped API keys must own every reservation's listing.","operationId":"batch_delete_reservation_custom_fields_v1_reservations_custom_fields_batch_delete_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}/guest-form":{"get":{"tags":["Guest check-in forms"],"summary":"Get a reservation's guest check-in form submission","description":"The guest's Welcome Pass check-in form for one reservation — the same payload the `guest_form.submitted` webhook delivers, readable on demand. Uploaded files are listed under `files` as private key references; exchange one for a download link with `GET /reservations/{reservation_id}/guest-form/file-url`.","operationId":"get_guest_form_v1_reservations__reservation_id__guest_form_get","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestForm"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reservations/{reservation_id}/guest-form/file-url":{"get":{"tags":["Guest check-in forms"],"summary":"Get a short-lived download link for a guest check-in form upload","description":"Exchange a `files[].key` value from the guest form payload (or the `guest_form.submitted` webhook) for a presigned download URL valid for a few minutes. The key must belong to this reservation. Each link minted is recorded in the reservation's file-access audit trail.","operationId":"get_guest_form_file_url_v1_reservations__reservation_id__guest_form_file_url_get","parameters":[{"name":"reservation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Reservation Id"}},{"name":"key","in":"query","required":true,"schema":{"type":"string","description":"A `files[].key` value from the guest form payload.","title":"Key"},"description":"A `files[].key` value from the guest form payload."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestFormFileUrl"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/tags":{"get":{"tags":["Listing Tags"],"summary":"List listing tags","description":"List all tags on the account, optionally filtered by tag_type.","operationId":"list_listing_tags_v1_listings_tags_get","parameters":[{"name":"tag_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by tag_type (region, building, ...)","title":"Tag Type"},"description":"Filter by tag_type (region, building, ...)"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ListingTagExternal"},"title":"Response List Listing Tags V1 Listings Tags Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Listing Tags"],"summary":"Create a listing tag","description":"Create a new tag on the account. Tag names are unique per (account, tag_type).","operationId":"create_listing_tag_v1_listings_tags_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/tags/{tag_id}":{"get":{"tags":["Listing Tags"],"summary":"Get a listing tag","description":"Fetch a single tag by id.","operationId":"get_listing_tag_v1_listings_tags__tag_id__get","parameters":[{"name":"tag_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tag Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Listing Tags"],"summary":"Update a listing tag","description":"Update one or more fields on a tag. Only provided fields are changed.","operationId":"update_listing_tag_v1_listings_tags__tag_id__put","parameters":[{"name":"tag_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tag Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Listing Tags"],"summary":"Delete a listing tag","description":"Delete a tag and all of its listing assignments. Returns 404 if the tag does not exist — clients implementing retry-after-timeout should tolerate 404 as a \"successful prior call\" signal.\n\nReturns 409 if content is scoped to the tag (guidebook sections, place pins, memories, rules, direct-booking settings). That content is cascade-deleted with the tag, so the call requires `?force=true` to proceed. The 409 body lists the affected counts by kind.\n\nReturns 422 for system-managed tags, which cannot be deleted at all; `force` does not override this.","operationId":"delete_listing_tag_v1_listings_tags__tag_id__delete","parameters":[{"name":"tag_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tag Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","description":"Delete the tag AND all content scoped to it. Irreversible.","default":false,"title":"Force"},"description":"Delete the tag AND all content scoped to it. Irreversible."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/tags/bulk-assign":{"post":{"tags":["Listing Tags"],"summary":"Bulk-assign tags to listings","description":"Assign every tag in ``tag_ids`` to every listing in ``listing_ids``. Returns the count of assignments actually applied — per-listing skips (e.g. single-tag-type conflicts) are surfaced as ``skipped`` rather than silent no-ops.","operationId":"bulk_assign_listing_tags_v1_listings_tags_bulk_assign_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagBulkAssignExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"anyOf":[{"type":"integer"},{"type":"boolean"}]},"title":"Response Bulk Assign Listing Tags V1 Listings Tags Bulk Assign Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/tags/bulk-remove":{"post":{"tags":["Listing Tags"],"summary":"Bulk-remove tags from listings","description":"Remove every tag in ``tag_ids`` from every listing in ``listing_ids``. Returns the count of assignments actually removed.\n\nSystem-managed tags in ``tag_ids`` are skipped rather than rejected — their assignments are maintained by the platform. Their ids come back in ``skipped_system_tag_ids`` so a partial removal is never silent.","operationId":"bulk_remove_listing_tags_v1_listings_tags_bulk_remove_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingTagBulkRemoveExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"anyOf":[{"type":"integer"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"title":"Response Bulk Remove Listing Tags V1 Listings Tags Bulk Remove Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings":{"get":{"tags":["Listings"],"summary":"List listings","description":"Retrieve a paginated list of property listings for the account, with optional text search by title, address, or city.","operationId":"list_listings_v1_listings_get","parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by title, address, or city","title":"Search"},"description":"Search by title, address, or city"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ListingExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Listings"],"summary":"Create a listing","description":"Create a new manual listing on the account. Thin wrapper over the internal ``POST /listings/v2`` endpoint — supports manual listings (no OTA connection). OTA-backed listings must be created via OTA connection sync. Listing-scoped API keys cannot create new listings.","operationId":"create_listing_v1_listings_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}":{"get":{"tags":["Listings"],"summary":"Get a listing","description":"Retrieve a single property listing by its ID.","operationId":"get_listing_v1_listings__listing_id__get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Listings"],"summary":"Update a listing","description":"Patch one or more fields on a listing. Only the fields actually supplied (with non-null values) are written; omitted fields and explicit ``null`` values are left unchanged. OTA-managed fields (host roles, connection role, import status) are not exposed here and must continue to flow through OTA sync.","operationId":"update_listing_v1_listings__listing_id__put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/photos":{"get":{"tags":["Listings"],"summary":"List photos for a listing","description":"Return every photo currently attached to the listing, ordered by the ``order`` field.","operationId":"list_listing_photos_v1_listings__listing_id__photos_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ListingPhotoExternal"},"title":"Response List Listing Photos V1 Listings  Listing Id  Photos Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Listings"],"summary":"Replace listing photos","description":"Replace the listing's photo set with the supplied list. Existing photos are deleted first; pass an empty list to clear all photos. The first photo (``order=1``) becomes the listing thumbnail. This explicit write makes the account the photo owner, so channel refreshes never replace the gallery.","operationId":"replace_listing_photos_v1_listings__listing_id__photos_put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ListingPhotoCreateExternal"},"maxItems":100,"title":"Photos"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ListingPhotoExternal"},"title":"Response Replace Listing Photos V1 Listings  Listing Id  Photos Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/host_role":{"put":{"tags":["Listings"],"summary":"Set host role","description":"Set the host role (owner/cohost) for a listing. Only supported for Hospitable-connected listings; manual and other-OTA listings return 400.","operationId":"update_listing_host_role_v1_listings__listing_id__host_role_put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostRoleUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/channel-urls":{"get":{"tags":["Listings"],"summary":"Get OTA channel URLs","description":"Return the public OTA URLs (Airbnb, VRBO, Expedia, Google VR, booking engine) for a listing.","operationId":"get_listing_channel_urls_v1_listings__listing_id__channel_urls_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingChannelUrlsExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/custom-fields/resolved":{"get":{"tags":["Listings"],"summary":"Resolve merged custom fields for a listing","description":"Return the merged custom-field dict, walking the ``account → tag → source → listing`` precedence. When ``with_provenance=true``, also returns where each value came from.","operationId":"get_resolved_custom_fields_v1_listings__listing_id__custom_fields_resolved_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"with_provenance","in":"query","required":false,"schema":{"type":"boolean","description":"Include the source scope of each value.","default":false,"title":"With Provenance"},"description":"Include the source scope of each value."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedCustomFieldsExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/custom-fields/batch":{"post":{"tags":["Listings"],"summary":"Batch-set listing custom fields","description":"Set custom fields on many listings (or on a tag / the account) in one transaction. ``scope`` selects the layer; ``mode=merge`` keeps existing keys, ``mode=replace`` overwrites the full dict. Set ``dry_run=true`` to preview the diff without committing.","operationId":"batch_set_custom_fields_v1_listings_custom_fields_batch_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchSetRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/custom-fields/batch/delete":{"post":{"tags":["Listings"],"summary":"Batch-delete listing custom fields","description":"Remove the supplied ``field_keys`` from every target row at the chosen scope. POST (not DELETE) because the request needs a body.","operationId":"batch_delete_custom_fields_v1_listings_custom_fields_batch_delete_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchDeleteRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/custom-fields/batch/check-missing":{"post":{"tags":["Listings"],"summary":"Find listings missing custom-field values","description":"For a set of field keys, return which listings (under a tag or an explicit ID list) don't have a value for them in the merged hierarchy. Useful for validating that a tag-scoped guidebook reference resolves across every listing under that tag before saving.","operationId":"check_missing_custom_fields_v1_listings_custom_fields_batch_check_missing_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsCheckMissingRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsCheckMissingResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/child-listings":{"get":{"tags":["Listings"],"summary":"Get child listings (listing group)","description":"Return the parent/child relationships for a listing group. Empty when the listing has no group.","operationId":"get_listing_children_v1_listings__listing_id__child_listings_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingChildrenExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Listings"],"summary":"Replace child listings (listing group)","description":"Replace the children list for a parent listing. The supplied IDs must all belong to the caller's account and be within the API key's listing scope. Cycles, self-references, and listings already involved in another group are rejected with 400.","operationId":"update_listing_children_v1_listings__listing_id__child_listings_put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingChildrenUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingChildrenExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations":{"get":{"tags":["Conversations"],"summary":"List conversations","description":"Retrieve a paginated list of guest conversations for the account, with optional filters mirroring the web inbox tabs (needs-response, follow-up, starred, done, snoozed, business purpose, channel).\n\n**Internal-channel caveat:** internal (team-chat) threads track the inbox-status flags (`needs_response`, `is_starred`, snooze) per-user on `ConversationUserMetadata`, so their thread-level columns stay false — those filters are meaningful for guest/OTA/account-wide channels, not for internal team chats. `needs_follow_up` and `follow_up` are the exception: they resolve internal threads against the calling credential's own per-user flag, and the `needs_follow_up` field on each returned internal thread reports that same per-user value.","operationId":"list_conversations_v1_conversations_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"channel","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by channel (ota, internal, gmail, whatsapp, sms)","title":"Channel"},"description":"Filter by channel (ota, internal, gmail, whatsapp, sms)"},{"name":"channels","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Filter by multiple channels (OR logic) — e.g. the web 'Calls' tab sends ['voice', 'sms']. When provided, takes precedence over the singular `channel` param.","title":"Channels"},"description":"Filter by multiple channels (OR logic) — e.g. the web 'Calls' tab sends ['voice', 'sms']. When provided, takes precedence over the singular `channel` param."},{"name":"needs_response","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by whether the thread is awaiting a host response","title":"Needs Response"},"description":"Filter by whether the thread is awaiting a host response"},{"name":"needs_follow_up","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by whether the thread needs a follow-up (AI-detected or manual). Internal team chats are matched on the calling credential's per-user flag.","title":"Needs Follow Up"},"description":"Filter by whether the thread needs a follow-up (AI-detected or manual). Internal team chats are matched on the calling credential's per-user flag."},{"name":"is_starred","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by whether the thread is manually starred","title":"Is Starred"},"description":"Filter by whether the thread is manually starred"},{"name":"is_done","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by whether the thread is marked done","title":"Is Done"},"description":"Filter by whether the thread is marked done"},{"name":"follow_up","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Web inbox 'Follow Up' tab filter. When true, returns threads where needs_follow_up=True OR is_starred=True; when false, returns the complement.","title":"Follow Up"},"description":"Web inbox 'Follow Up' tab filter. When true, returns threads where needs_follow_up=True OR is_starred=True; when false, returns the complement."},{"name":"snoozed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"When true, returns ONLY currently-snoozed threads (snoozed_until in the future). When false, excludes them (snoozed_until NULL or already elapsed).","title":"Snoozed"},"description":"When true, returns ONLY currently-snoozed threads (snoozed_until in the future). When false, excludes them (snoozed_until NULL or already elapsed)."},{"name":"business_purpose","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by the thread's business_purpose discriminator — e.g. 'support_messaging_thread' (host↔Airbnb-support, the web 'Support' tab) or 'prohost_support'.","title":"Business Purpose"},"description":"Filter by the thread's business_purpose discriminator — e.g. 'support_messaging_thread' (host↔Airbnb-support, the web 'Support' tab) or 'prohost_support'."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ConversationExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Conversations"],"summary":"Bulk patch conversations","description":"Apply the same patch (e.g. mute AI, mark done, star) to many conversations in one call. Account-wide — listing-scoped API keys are rejected.\n\n`needs_follow_up` goes through the shared channel-aware mutation: internal team-chat threads track it per-user (the patch lands on the acting user's Follow Up tab rather than the unused thread-level column), and a conversation carrying a newer follow-up update is reported under `skipped` instead of being clobbered.\n\n`is_done` on an internal team-chat thread is per-user: it marks the thread done (or not done) for the acting user only, exactly like the inbox's Done button, and leaves the other participants' inboxes untouched. An API key with no associated user cannot do this, so the field is reported under `skipped` for those threads.","operationId":"bulk_patch_conversations_v1_conversations_patch","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPatchConversationsExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPatchConversationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Start a conversation from your website or form","description":"Bring a guest inquiry from your own website, booking engine, contact form or Zapier into the inbox. Creates a conversation for the guest and, with `message`, posts their first message — which flags the conversation for a response, notifies your team, wakes autopilot when it is on for the channel, and fires the `message.received` webhook (not to this key's own subscriptions).\n\nReplies reach the guest by **email** (default): from your workspace's branded address, with replies threading back into the conversation. Or by **SMS** (`reply_via: sms`), from your SMS number, on the one conversation the workspace has with that number.\n\n**Idempotent on `external_id`:** a repeat returns the same conversation with 200 and posts nothing; add later messages with `POST /v1/conversations/{id}/inbound-messages`.\n\nRequires the `conversations:ingest` scope, granted on its own (`*` does not include it). Listing-scoped keys must name one of their listings. Up to 500 new conversations a day per workspace.","operationId":"create_ingested_conversation_v1_conversations_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIngestedConversationExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestedConversationResponse"}}}},"200":{"description":"`external_id` already started this conversation; nothing was posted."},"403":{"description":"Missing `conversations:ingest`, an AI employee's key, outside the key's listings, or `channel_not_authorized` (a private SMS number)."},"409":{"description":"`thread_not_adoptable`: a listing-scoped key, and the guest's number already has a conversation outside its listings."},"404":{"description":"Listing or reservation not found."},"422":{"description":"`email_required`, `phone_required`, `invalid_phone`, `sms_unavailable`, `listing_mismatch`."},"429":{"description":"The workspace's daily limit of new conversations is reached."}}}},"/v1/conversations/message-templates":{"get":{"tags":["Conversations"],"summary":"List message templates","description":"List all message templates configured on the account.","operationId":"list_message_templates_v1_conversations_message_templates_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Create a message template","operationId":"create_message_template_v1_conversations_message_templates_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/saved-replies":{"get":{"tags":["Conversations"],"summary":"List saved replies","description":"List all saved replies (canned responses) configured on the account.","operationId":"list_saved_replies_v1_conversations_saved_replies_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Create a saved reply","operationId":"create_saved_reply_v1_conversations_saved_replies_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}":{"get":{"tags":["Conversations"],"summary":"Get a conversation","description":"Retrieve a single conversation thread by its ID.","operationId":"get_conversation_v1_conversations__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Conversations"],"summary":"Attach a conversation to a listing or booking","description":"Attach a conversation this API started to a listing, or link it to a booking (for example the one your booking engine made from the inquiry). A linked booking becomes the conversation's reservation when it has none, and the conversation's listing follows it. Requires `conversations:ingest`.","operationId":"update_ingested_conversation_v1_conversations__conversation_id__patch","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchIngestedConversationExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationExternal"}}}},"404":{"description":"Conversation, listing or reservation not found."},"409":{"description":"`not_an_api_conversation`; `has_reservation` (a listing change on a conversation linked to a booking — its listing follows the booking); `conversation_busy` (retry)."},"422":{"description":"`listing_mismatch`, or neither field sent."}}}},"/v1/conversations/{conversation_id}/messages":{"get":{"tags":["Conversations"],"summary":"List conversation messages","description":"Retrieve a paginated list of messages within a conversation, ordered newest first.","operationId":"list_conversation_messages_v1_conversations__conversation_id__messages_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ConversationMessageExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Send a message","description":"Send a host message in a conversation. The message is dispatched through the real message delivery pipeline (OTA adapter or internal-channel handler) with async fallback for retryable errors. Returns 202 with the final send status: 'sent' if delivery completed synchronously, 'pending' if queued for async retry. Supports ``?dry_run=true`` — validates ownership and tier gating, then returns the response that *would* be produced (status 'pending', synthetic id) without actually sending or persisting the message.\n\nChannel rules: internal team chat, webchat, and intercom are open to all tiers; OTA requires Pro; the host's own SMS, WhatsApp, and Gmail channels carry no tier gate but require either an OAuth credential whose user holds inbox write access, or an API key granted the ``conversations:write_guest_external`` scope. Anything else returns 403 ``channel_not_api_sendable``.","operationId":"send_message_v1_conversations__conversation_id__messages_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageExternal"},"examples":{"internal":{"summary":"Internal team note","description":"Post an internal message in a team chat (available on all tiers).","value":{"message":"FYI — cleaner confirmed arrival at 11am."}},"ota":{"summary":"Reply to guest on OTA","description":"Reply to a guest on the OTA channel (Airbnb/Hostaway/etc.). Requires Pro tier.","value":{"message":"Hi Sarah! Welcome — check-in is at 3pm. The keypad code is 4827. Let me know if you need anything."}},"intercom":{"summary":"Reply into a mirrored Intercom conversation","description":"Reply into a ProhostAI support conversation mirrored from Intercom (available on all tiers). Delivers through the Intercom adapter.","value":{"message":"Thanks for reaching out — I've bumped your plan to Pro."}}}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/notes":{"post":{"tags":["Conversations"],"summary":"Leave an internal note","description":"Create a team-only internal note in a conversation. Notes appear in the conversation timeline with an 'Internal note' badge and are **never** delivered to the guest — the send pipeline hard-fails on ``INTERNAL_NOTE``, so this is a structurally different operation from ``POST /{conversation_id}/messages``. Works on any conversation in the account (guest thread or internal team channel) on every tier. Supports ``<@user_id>`` mentions, and runs the full team fan-out: unread badges, realtime inbox/thread updates, and a severity-routed push.","operationId":"create_note_v1_conversations__conversation_id__notes_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInternalNoteExternal"},"examples":{"log":{"summary":"Silent record (default)","description":"Write an investigation summary to the thread without notifying anyone.","value":{"message":"Traced the duplicate payout to a Hostaway webhook replay at 04:12 UTC. No guest impact; no action needed.","severity":"log"}},"act":{"summary":"Action needed, with an @mention","description":"``act`` always pushes — reserve it for 'a human must do something now'.","value":{"message":"<@0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b> guest is locked out and needs a new code tonight.","severity":"act","source_name":"Support Agent"}}}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalNoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/scheduled-messages":{"post":{"tags":["Conversations"],"summary":"Schedule a message","description":"Schedule a host message to be delivered at a future time. The scheduled message is tagged ``source=api`` so downstream analytics and the send pipeline can distinguish externally-scheduled messages from system-origin (autopilot, template, workflow) sends. Supports ``Idempotency-Key`` — retries with the same key + body replay the cached response instead of scheduling a second send.","operationId":"schedule_message_v1_conversations__conversation_id__scheduled_messages_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleMessageExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Conversations"],"summary":"List scheduled messages","description":"Return scheduled messages for the conversation, optionally filtered by status. Mirrors the existing POST endpoint at the same prefix.","operationId":"list_scheduled_messages_v1_conversations__conversation_id__scheduled_messages_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["scheduled","paused","sent","failed","cancelled"],"type":"string"},{"type":"null"}],"description":"Filter by status (scheduled, paused, sent, failed, cancelled)","title":"Status"},"description":"Filter by status (scheduled, paused, sent, failed, cancelled)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"List with a `{items, total, limit}` envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePage_ScheduledMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/scheduled-messages/{scheduled_message_id}/cancel":{"post":{"tags":["Conversations"],"summary":"Cancel a scheduled message","description":"Cancel a scheduled message that has not yet been sent. Returns 400 if the message is already in a terminal state (sent / failed / cancelled). Flips the DB row to ``cancelled`` (so the worker skips delivery when the scheduler fires) and cancels the pending Hatchet run so long-horizon schedules don't sit in the queue.","operationId":"cancel_scheduled_message_v1_conversations__conversation_id__scheduled_messages__scheduled_message_id__cancel_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"scheduled_message_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scheduled Message Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/ai-state/pause":{"post":{"tags":["Conversations"],"summary":"Pause AI on a conversation","description":"Mute AI replies on a single conversation. The AI agent will no longer respond automatically; @mention it in the conversation to wake it back up.","operationId":"pause_ai_v1_conversations__conversation_id__ai_state_pause_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/ai-state/resume":{"post":{"tags":["Conversations"],"summary":"Resume AI on a conversation","description":"Re-enable AI replies on a single conversation that was previously paused.","operationId":"resume_ai_v1_conversations__conversation_id__ai_state_resume_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/suggestions":{"get":{"tags":["Conversations"],"summary":"List AI suggestions for a conversation","description":"Return AI-generated draft replies (autopilot suggestions) attached to messages in this conversation. Newest first.","operationId":"list_suggestions_v1_conversations__conversation_id__suggestions_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestionsListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/suggestions/{suggestion_id}/publish":{"post":{"tags":["Conversations"],"summary":"Publish an AI suggestion as a sent message","description":"Send the suggestion text (or its host-edited override) as a host message on this conversation. Subject to the same channel/tier paywall as ``POST /messages`` — OTA requires Pro tier.","operationId":"publish_suggestion_v1_conversations__conversation_id__suggestions__suggestion_id__publish_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"suggestion_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Suggestion Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/suggestions/{suggestion_id}/revise":{"post":{"tags":["Conversations"],"summary":"Request a rewrite of an AI suggestion","description":"Record a host rewrite instruction on the suggestion. The instruction is stored on the suggestion row so the next agent run can pick it up; the suggestion's ``edited_message`` is left untouched (heavy rewrite generation only happens in the in-app streaming surface). This endpoint is queue-intent, not block-on-AI — returns immediately with the unchanged suggestion shape.","operationId":"revise_suggestion_v1_conversations__conversation_id__suggestions__suggestion_id__revise_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"suggestion_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Suggestion Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseSuggestionExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/scheduled-messages/{scheduled_message_id}":{"patch":{"tags":["Conversations"],"summary":"Edit a scheduled message","description":"Update the message body and/or send time of a scheduled message that hasn't been sent yet. Only ``scheduled`` and ``paused`` rows are editable; terminal statuses return 400.","operationId":"update_scheduled_message_v1_conversations__conversation_id__scheduled_messages__scheduled_message_id__patch","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"scheduled_message_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scheduled Message Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledMessageUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledMessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/messages/{message_id}":{"patch":{"tags":["Conversations"],"summary":"Edit a sent message (internal channels only)","description":"Edit the body of a previously-sent message. Mirrors the in-app rule: editing is only supported on internal team chat messages. OTA / SMS / WhatsApp / Gmail edits return 403.","operationId":"edit_message_v1_conversations__conversation_id__messages__message_id__patch","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"message_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Message Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditMessageExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageEditedExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/messages/{message_id}/toggle-reaction":{"post":{"tags":["Conversations"],"summary":"Toggle an emoji reaction on a message","description":"Add or remove the API-key user's reaction with this emoji on a message. Reactions are per-emoji: sending an emoji the user has already used removes just that one, and any other emoji is added alongside their existing reactions. Returns the resulting action (`added` or `removed`).","operationId":"toggle_reaction_v1_conversations__conversation_id__messages__message_id__toggle_reaction_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"message_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Message Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleReactionExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleReactionExternalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/mark-read":{"post":{"tags":["Conversations"],"summary":"Mark a conversation as read","description":"Mark messages in this conversation as read for the API key's user. If ``message_ids`` is omitted, all unread messages NOT sent by the user are marked.","operationId":"mark_conversation_read_v1_conversations__conversation_id__mark_read_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MarkReadExternal"},{"type":"null"}],"title":"Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/message-templates/{template_id}":{"patch":{"tags":["Conversations"],"summary":"Update a message template","description":"Update fields on an account-wide message template.","operationId":"update_message_template_account_wide_v1_conversations_message_templates__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete a message template","operationId":"delete_message_template_account_wide_v1_conversations_message_templates__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/message-templates/{template_id}":{"patch":{"tags":["Conversations"],"summary":"Update a message template (legacy alias)","description":"**Deprecated alias.** Prefer ``PATCH /v1/conversations/message-templates/{template_id}``. ``conversation_id`` is ignored — message templates are account-wide.","operationId":"update_message_template_v1_conversations__conversation_id__message_templates__template_id__patch","deprecated":true,"parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTemplateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete a message template (legacy alias)","description":"**Deprecated alias.** Prefer ``DELETE /v1/conversations/message-templates/{template_id}``. ``conversation_id`` is ignored — message templates are account-wide.","operationId":"delete_message_template_v1_conversations__conversation_id__message_templates__template_id__delete","deprecated":true,"parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Template Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/saved-replies/{saved_reply_id}":{"patch":{"tags":["Conversations"],"summary":"Update a saved reply","description":"Update fields on an account-wide saved reply.","operationId":"update_saved_reply_account_wide_v1_conversations_saved_replies__saved_reply_id__patch","parameters":[{"name":"saved_reply_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Saved Reply Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete a saved reply","operationId":"delete_saved_reply_account_wide_v1_conversations_saved_replies__saved_reply_id__delete","parameters":[{"name":"saved_reply_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Saved Reply Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/saved-replies/{saved_reply_id}":{"patch":{"tags":["Conversations"],"summary":"Update a saved reply (legacy alias)","description":"**Deprecated alias.** Prefer ``PATCH /v1/conversations/saved-replies/{saved_reply_id}``. ``conversation_id`` is ignored — saved replies are account-wide.","operationId":"update_saved_reply_v1_conversations__conversation_id__saved_replies__saved_reply_id__patch","deprecated":true,"parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"saved_reply_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Saved Reply Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedReplyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete a saved reply (legacy alias)","description":"**Deprecated alias.** Prefer ``DELETE /v1/conversations/saved-replies/{saved_reply_id}``. ``conversation_id`` is ignored — saved replies are account-wide.","operationId":"delete_saved_reply_v1_conversations__conversation_id__saved_replies__saved_reply_id__delete","deprecated":true,"parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"saved_reply_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Saved Reply Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/spaces":{"post":{"tags":["Conversations"],"summary":"Create a team-chat space","description":"Create an Inbox Space — a topic-first team channel — and return it. The calling key's user is the creator and is always on the roster; the account's AI employee is added automatically.\n\nCreating an OPEN space is **idempotent on name**: if one already exists with the same name (case-insensitive, trimmed) it is returned untouched with `created: false`, so a retried or replayed call cannot fork a second channel. Private spaces never dedup.\n\nPair this with a `channel_post` inbound webhook to stand up an alert channel in two calls: create the space, then bind a webhook to the returned `id`.","operationId":"create_space_v1_conversations_spaces_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpaceExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/inbound-messages":{"post":{"tags":["Conversations"],"summary":"Post a guest's message","description":"Add what the guest wrote to a conversation this API started. It is handled like any guest message that arrives on its own: the conversation is flagged for a response, your team is notified, autopilot answers when it is on for the channel, and `message.received` fires (not to this key's own subscriptions).\n\nSend `external_message_id` to make retries safe: a repeat on the same conversation returns the stored message with 200. Requires `conversations:ingest`.","operationId":"post_inbound_message_v1_conversations__conversation_id__inbound_messages_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundMessageExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundMessageResponse"}}}},"200":{"description":"`external_message_id` was already posted; the stored message is returned."},"403":{"description":"Missing `conversations:ingest`, or an AI employee's key."},"404":{"description":"Conversation not found."},"409":{"description":"`not_an_api_conversation`: the conversation was not started through this API."},"422":{"description":"Blank text, or `sent_at` in the future."}}}},"/v1/ai-chat/sessions":{"post":{"tags":["Ask AI"],"summary":"Create Ai Chat Session","description":"Create an Ask-AI chat session (global property assistant).","operationId":"create_ai_chat_session_v1_ai_chat_sessions_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatSessionCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatSessionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Ask AI"],"summary":"List Ai Chat Sessions","description":"List the credential's Ask-AI chat sessions (newest first).","operationId":"list_ai_chat_sessions_v1_ai_chat_sessions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatSessionListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ai-chat/sessions/{session_id}/messages":{"get":{"tags":["Ask AI"],"summary":"Get Ai Chat Messages","description":"Read a session's message history (oldest first).","operationId":"get_ai_chat_messages_v1_ai_chat_sessions__session_id__messages_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatMessageListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Ask AI"],"summary":"Run Ai Chat Turn","description":"Run one Ask-AI turn: append the user message, run the agent, return the reply.\n\nThe turn executes in-process (same engine and time budgets as the in-app\nAsk AI) — expect long-poll response times on tool-heavy questions.","operationId":"run_ai_chat_turn_v1_ai_chat_sessions__session_id__messages_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatTurnRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIChatTurnResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guests":{"get":{"tags":["Guests"],"summary":"List guests","description":"Retrieve a paginated list of guests for the account, with optional search by name/email and filter by listing.","operationId":"list_guests_v1_guests_get","parameters":[{"name":"search_query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by guest name or email","title":"Search Query"},"description":"Search by guest name or email"},{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID (guests with reservations at this listing)","title":"Listing Id"},"description":"Filter by listing ID (guests with reservations at this listing)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_GuestExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Guests"],"summary":"Create a guest","description":"Create a new guest record on the account. Listing-scoped API keys cannot create guests because guests are account-scoped (no listing FK).","operationId":"create_guest_v1_guests_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guests/{guest_id}":{"get":{"tags":["Guests"],"summary":"Get a guest","description":"Retrieve a single guest by their ID.","operationId":"get_guest_v1_guests__guest_id__get","parameters":[{"name":"guest_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guest Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Guests"],"summary":"Update a guest","description":"Update an existing guest. Only provided fields are written. Listing-scoped API keys cannot mutate guests because guests are account-scoped and may back reservations on listings outside the key's allowlist — a name/email/photo change leaks across listings.","operationId":"update_guest_v1_guests__guest_id__patch","parameters":[{"name":"guest_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guest Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guests/{guest_id}/custom-fields":{"get":{"tags":["Guests"],"summary":"Get guest custom fields","description":"Return the resolved custom-field values for a guest, with provenance. Merge order: account → guest. Guest-level values win on conflict.","operationId":"get_guest_custom_fields_v1_guests__guest_id__custom_fields_get","parameters":[{"name":"guest_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guest Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsResolved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guests/custom-fields/batch":{"post":{"tags":["Guests"],"summary":"Batch-set guest custom fields","description":"Merge ``fields`` into ``custom_fields`` on every guest in ``ids``. Listing-scoped API keys cannot use this endpoint (guests are account-scoped).","operationId":"batch_set_guest_custom_fields_v1_guests_custom_fields_batch_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchSetRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guests/custom-fields/batch/delete":{"post":{"tags":["Guests"],"summary":"Batch-delete guest custom-field keys","description":"Remove the named keys from ``custom_fields`` on every guest in ``ids``. Listing-scoped API keys cannot use this endpoint.","operationId":"batch_delete_guest_custom_fields_v1_guests_custom_fields_batch_delete_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks":{"get":{"tags":["Tasks"],"summary":"List tasks","description":"Retrieve a paginated list of tasks for the account, with optional filters by status, priority, and listing.","operationId":"list_tasks_v1_tasks_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: a workflow state id, slug or name, a category word, or a legacy label (see GET /v1/tasks/workflow-states). A system or legacy status matches every task carrying that legacy status; a custom state matches tasks on that exact state.","title":"Status"},"description":"Filter by status: a workflow state id, slug or name, a category word, or a legacy label (see GET /v1/tasks/workflow-states). A system or legacy status matches every task carrying that legacy status; a custom state matches tasks on that exact state."},{"name":"priority","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by priority","title":"Priority"},"description":"Filter by priority"},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by category (e.g. maintenance, cleanliness)","title":"Category"},"description":"Filter by category (e.g. maintenance, cleanliness)"},{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_TaskExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Tasks"],"summary":"Create a task","description":"Create a new task, optionally associated with a listing. Supports ``?dry_run=true`` — validates inputs and returns the task that *would* be created, without persisting.","operationId":"create_task_v1_tasks_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreateExternal"},"examples":{"urgent":{"summary":"Urgent repair","description":"High-priority task with no due date — appears at top of the open tasks list.","value":{"title":"Fix leaking kitchen sink","description":"Guest reports water pooling under the sink cabinet.","priority":"high"}},"scheduled":{"summary":"Scheduled maintenance","description":"Lower-priority task scheduled for a future date.","value":{"title":"Replace HVAC air filter","description":"Quarterly maintenance.","priority":"low","due_date":"2026-07-01T09:00:00Z"}}}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/bulk":{"post":{"tags":["Tasks"],"summary":"Create many tasks","description":"Create up to 100 tasks in one request, each optionally carrying its own checklists (subtasks) with nested items. Built for punch lists: turn a property walkthrough into a task list and transfer the whole thing in one call.\n\nWell-formed entries are independent: one that can't be applied — unknown category or priority, a listing this key can't reach, an assignee outside the account — is reported in `failed` with its index while the rest are still created, so the response is 200 with a per-entry breakdown. Retry only the failed indices; re-sending a successful entry creates a second task.\n\nA request whose *shape* is invalid (an entry missing `title`, a malformed UUID, more than 100 entries) is rejected whole with 422 and creates nothing — the body is a client bug, and the field path in the 422 is more useful than a partial write. The `bulk_create_tasks` MCP tool validates entry shape per-entry instead, because an LLM caller benefits from partial progress.","operationId":"create_tasks_bulk_route_v1_tasks_bulk_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskBulkCreateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskBulkCreateResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/recurring":{"post":{"tags":["Tasks"],"summary":"Create a recurring task","description":"Create a recurring-task schedule that pre-generates task instances for a rolling window (90 days for daily, 6 months for weekly, 2 years for monthly/yearly) and keeps generating on that cadence.\n\nSchedule semantics: `duration_unit` + `recurrence_interval` is the cadence (`weekly` + `2` = every 2 weeks). `days_of_week` (weekly only) emits one occurrence per selected day — 'every weekday' is `weekly` + `[monday..friday]`, never `daily`. At most ONE of `ends_on` / `ends_after_occurrences` may be set; omit both for a schedule with no end. Rule violations return 422; bad account data (unknown category, non-member assignee, listing outside the account) returns 400.\n\nFind-or-create: when an ACTIVE schedule with the same normalized title already covers every requested listing, that schedule is returned with status 200 and `already_exists: true` instead of minting a duplicate — so a retried create cannot produce a second schedule that double-fires forever. Use a different title (or update the existing schedule) to intentionally run two schedules on the same listings.","operationId":"create_recurring_task_route_v1_tasks_recurring_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringTaskCreateExternal"}}}},"responses":{"201":{"description":"Recurring task created; instances pre-generated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringTaskCreateResultExternal"}}}},"200":{"description":"An active schedule with this title already covers the requested listings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringTaskCreateResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/workflow-states":{"get":{"tags":["Tasks"],"summary":"List workflow states","description":"The workspace's task statuses (workflow states), grouped by category in display order. Pass a state's `slug`, `name` or `id` as `status` when creating, updating or filtering tasks; a category word (todo, in_progress, paused, blocked, in_review, completed, cancelled) is accepted too and lands on that category's default status. `creation_default_state_id` is where a task created without a `status` lands.","operationId":"list_workflow_states_route_v1_tasks_workflow_states_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskWorkflowStatesExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}":{"get":{"tags":["Tasks"],"summary":"Get a task","description":"Retrieve a single task by its ID.","operationId":"get_task_v1_tasks__task_id__get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Tasks"],"summary":"Update a task","description":"Update one or more fields on an existing task. Supports ``?dry_run=true`` — returns the resulting row without persisting.\n\nA `status` change runs the same work-session state machine the in-app task timer uses. Moving to `in_progress` opens a work session, stamps `actual_starts_at`, and snapshots the assignee's rate; any other status closes the open session; `completed` additionally finalizes `calculated_duration_minutes` and bills the resulting labor. Re-sending the status a task already has is a no-op and does not restart the timer.","operationId":"update_task_v1_tasks__task_id__patch","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Tasks"],"summary":"Delete a task","description":"Move a task to trash. Returns 204 on success. The task is soft-deleted — the row is preserved server-side and disappears from list/get responses with a 404, matching the prior delete UX. The host can restore it from the in-app trash UI. Supports ``?dry_run=true`` — returns the task that *would* be trashed (status 200 + ``X-Dry-Run: true`` header) without actually trashing.","operationId":"delete_task_v1_tasks__task_id__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Task moved to trash."},"200":{"description":"Dry-run preview of the task that would be trashed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/pull-requests":{"get":{"tags":["Tasks"],"summary":"List linked pull requests","description":"Every GitHub pull request linked to this task.","operationId":"list_task_pull_requests_v1_tasks__task_id__pull_requests_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskPullRequestExternal"},"title":"Response List Task Pull Requests V1 Tasks  Task Id  Pull Requests Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Tasks"],"summary":"Link a pull request to a task","description":"Attach a GitHub pull request to a task. Supply either `pr_url` on its own, or `repo` plus `pr_number`. Idempotent — re-linking the same pull request returns the existing link.\n\nThe link is recorded in the `open` state. Pull-request state and any resulting task status change are owned by the GitHub integration, which observes the pull request directly; a client cannot assert that a pull request merged.","operationId":"link_task_pull_request_v1_tasks__task_id__pull_requests_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskPullRequestLinkExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskPullRequestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/pull-requests/{link_id}":{"delete":{"tags":["Tasks"],"summary":"Unlink a pull request","description":"Detach a pull request from a task. Returns 204 on success.","operationId":"unlink_task_pull_request_v1_tasks__task_id__pull_requests__link_id__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"link_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Link Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/checklists":{"get":{"tags":["Tasks"],"summary":"List checklists on a task","operationId":"list_task_checklists_v1_tasks__task_id__checklists_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskChecklistExternal"},"title":"Response List Task Checklists V1 Tasks  Task Id  Checklists Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Tasks"],"summary":"Create a checklist on a task","operationId":"create_task_checklist_v1_tasks__task_id__checklists_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/checklists/from-template":{"post":{"tags":["Tasks"],"summary":"Create a task checklist from a template","operationId":"create_task_checklist_from_template_v1_tasks__task_id__checklists_from_template_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistFromTemplateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/checklists/reorder":{"patch":{"tags":["Tasks"],"summary":"Reorder checklists on a task","operationId":"reorder_task_checklists_v1_tasks__task_id__checklists_reorder_patch","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskChecklistExternal"},"title":"Response Reorder Task Checklists V1 Tasks  Task Id  Checklists Reorder Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/checklists/{checklist_id}":{"patch":{"tags":["Tasks"],"summary":"Update a task checklist","operationId":"update_task_checklist_v1_tasks__task_id__checklists__checklist_id__patch","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Tasks"],"summary":"Delete a task checklist","operationId":"delete_task_checklist_v1_tasks__task_id__checklists__checklist_id__delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/checklists/{checklist_id}/translate":{"post":{"tags":["Tasks"],"summary":"Translate a task checklist to a target language","operationId":"translate_task_checklist_route_v1_tasks__task_id__checklists__checklist_id__translate_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"target_language","in":"query","required":true,"schema":{"type":"string","description":"Target language code (e.g. 'en-US', 'ja-JP').","title":"Target Language"},"description":"Target language code (e.g. 'en-US', 'ja-JP')."},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","description":"Force re-translation even if cached.","default":false,"title":"Force"},"description":"Force re-translation even if cached."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/comments":{"post":{"tags":["Tasks"],"summary":"Add a comment to a task","description":"Post a comment on a task. This is the reply surface for an AI employee woken by a task mention — `agent.run_requested` points at it in `reply_instructions`. Mirrors `POST /v1/cleanings/{cleaning_id}/comments`, including the `content` body field.","operationId":"create_task_comment_route_v1_tasks__task_id__comments_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCommentCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCommentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings":{"get":{"tags":["Cleanings"],"summary":"List cleanings","description":"Retrieve a paginated list of cleaning jobs for the account, with optional filters by listing, status, and date range.","operationId":"list_cleanings_v1_cleanings_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status","title":"Status"},"description":"Filter by status"},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter to cleanings overlapping this date or later, in the listing's own timezone","title":"Date From"},"description":"Filter to cleanings overlapping this date or later, in the listing's own timezone"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter to cleanings overlapping this date or earlier, in the listing's own timezone","title":"Date To"},"description":"Filter to cleanings overlapping this date or earlier, in the listing's own timezone"},{"name":"inspector_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only cleanings this user is assigned to inspect","title":"Inspector Id"},"description":"Only cleanings this user is assigned to inspect"},{"name":"stage","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by inspection stage: cleaning, awaiting_inspection, inspecting, fixes_needed, done (see ``stage`` on the cleaning)","title":"Stage"},"description":"Filter by inspection stage: cleaning, awaiting_inspection, inspecting, fixes_needed, done (see ``stage`` on the cleaning)"},{"name":"claimable_inspection","in":"query","required":false,"schema":{"type":"boolean","description":"Only open inspections the key's user may claim (no inspector yet; they are in the listing's default-inspector pool or manage cleaning settings)","default":false,"title":"Claimable Inspection"},"description":"Only open inspections the key's user may claim (no inspector yet; they are in the listing's default-inspector pool or manage cleaning settings)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_CleaningExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Cleanings"],"summary":"Create a cleaning","description":"Schedule a new cleaning job for a listing. Supports ``?dry_run=true`` — validates inputs and returns the cleaning that *would* be created without persisting.","operationId":"create_cleaning_v1_cleanings_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}":{"get":{"tags":["Cleanings"],"summary":"Get a cleaning","description":"Retrieve a single cleaning job by its ID.","operationId":"get_cleaning_v1_cleanings__cleaning_id__get","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Cleanings"],"summary":"Update a cleaning","description":"Update one or more fields on an existing cleaning job, including its status. Supports ``?dry_run=true`` — returns the resulting row without persisting.","operationId":"update_cleaning_v1_cleanings__cleaning_id__patch","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Cleanings"],"summary":"Delete a cleaning","description":"Delete a cleaning job. Mirrors the internal delete behavior (hard delete). The cleanings data model has no 'cancelled' status, so there is no soft-cancel transition; deletion is the supported cancellation path. Any pending offers for the cleaning are expired/cancelled before the row is removed.","operationId":"delete_cleaning_v1_cleanings__cleaning_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/assign":{"post":{"tags":["Cleanings"],"summary":"Assign or unassign the cleaner","description":"Set the primary cleaner for a cleaning. Pass ``{\"cleaner_id\": null}`` to unassign. The cleaner must be a member of the same account. Routed through the cleaning service so the assignee junction table (and any offer-mode invariants the service enforces) are updated together.","operationId":"assign_cleaning_v1_cleanings__cleaning_id__assign_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningAssignExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/start":{"post":{"tags":["Cleanings"],"summary":"Start a cleaning","description":"Transition a cleaning to ``in_progress``. Routes through the cleaning service so ``actual_starts_at`` and the work-session row are populated just like the in-app flow.","operationId":"start_cleaning_v1_cleanings__cleaning_id__start_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/complete":{"post":{"tags":["Cleanings"],"summary":"Complete a cleaning","description":"Transition a cleaning to ``completed``. Routes through the cleaning service so completion side effects run (work-session closure, billable duration, expense creation, notifications, workflow dispatch) and any completion prerequisites configured on the account (minimum attachments, checklist completion) are enforced. Prerequisite failures return ``422``.","operationId":"complete_cleaning_v1_cleanings__cleaning_id__complete_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/inspectors":{"post":{"tags":["Cleanings"],"summary":"Set the inspectors","description":"Replace the users who inspect a cleaning once its cleaners hand it in (``ready_for_inspection``). Cleaners are never touched. Every inspector must be a member of the account; ``[]`` removes them all. Only a user who manages cleaning settings may change inspectors (403 ``cleaning_settings_write_required``), and assigning them requires Cleaning Inspector to be enabled for the workspace (403 ``cleaning_inspections_not_enabled``).","operationId":"set_cleaning_inspectors_v1_cleanings__cleaning_id__inspectors_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningInspectorsExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/inspection/claim":{"post":{"tags":["Cleanings"],"summary":"Claim an open inspection","description":"Add the key's user as the inspector of a cleaning that has none and is awaiting (or requires) an inspection. Open to the listing's default-inspector pool and to managers (403 ``inspection_forbidden`` otherwise); idempotent for the same user. 409 ``inspection_already_claimed`` when someone else inspects it, 409 ``inspection_not_ready`` when it is done or not awaiting inspection.","operationId":"claim_cleaning_inspection_v1_cleanings__cleaning_id__inspection_claim_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/inspection/start":{"post":{"tags":["Cleanings"],"summary":"Start an inspection","description":"Open an inspection attempt on a cleaning that is ``ready_for_inspection``. The status does not move; ``stage`` becomes ``inspecting``. Idempotent for the same inspector. Only an assigned inspector or a manager (owner, admin, or cleaning-settings write) may do this — judged for the user the key acts for; 403 ``inspection_forbidden`` otherwise. 409 ``inspection_not_ready`` when the cleaning is not ready for inspection.","operationId":"start_cleaning_inspection_v1_cleanings__cleaning_id__inspection_start_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/inspection/pass":{"post":{"tags":["Cleanings"],"summary":"Pass an inspection","description":"Pass the inspection and complete the cleaning through the normal completion path (guest-ready notice, expense, workflows). Only an assigned inspector or a manager (owner, admin, or cleaning-settings write) may do this — judged for the user the key acts for; 403 ``inspection_forbidden`` otherwise. 409 ``inspection_not_ready`` when the cleaning is not ready for inspection; completion prerequisites unmet return 422.","operationId":"pass_cleaning_inspection_v1_cleanings__cleaning_id__inspection_pass_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CleaningInspectionPassExternal"},{"type":"null"}],"title":"Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/inspection/fail":{"post":{"tags":["Cleanings"],"summary":"Fail an inspection","description":"Fail the inspection: the notes are recorded, the cleaning goes back to ``in_progress`` (``stage`` ``fixes_needed``) and its cleaners are notified with the notes. Optional ``failed_item_ids`` grades those inspection-checklist items ``fail`` (the fix list). Only an assigned inspector or a manager (owner, admin, or cleaning-settings write) may do this — judged for the user the key acts for; 403 ``inspection_forbidden`` otherwise. 409 ``inspection_not_ready`` when the cleaning is not ready for inspection.","operationId":"fail_cleaning_inspection_v1_cleanings__cleaning_id__inspection_fail_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningInspectionFailExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/checklists":{"get":{"tags":["Cleanings"],"summary":"List checklists for a cleaning","operationId":"list_cleaning_checklists_v1_cleanings__cleaning_id__checklists_get","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChecklistExternal"},"title":"Response List Cleaning Checklists V1 Cleanings  Cleaning Id  Checklists Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Cleanings"],"summary":"Create a checklist on a cleaning","operationId":"create_cleaning_checklist_v1_cleanings__cleaning_id__checklists_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/checklists/{checklist_id}":{"patch":{"tags":["Cleanings"],"summary":"Update a checklist on a cleaning","operationId":"update_cleaning_checklist_v1_cleanings__cleaning_id__checklists__checklist_id__patch","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Cleanings"],"summary":"Delete a checklist on a cleaning","operationId":"delete_cleaning_checklist_v1_cleanings__cleaning_id__checklists__checklist_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/checklists/{checklist_id}/items":{"post":{"tags":["Cleanings"],"summary":"Add an item to a checklist","operationId":"create_cleaning_checklist_item_v1_cleanings__cleaning_id__checklists__checklist_id__items_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/checklists/{checklist_id}/items/{item_id}":{"patch":{"tags":["Cleanings"],"summary":"Update a checklist item","operationId":"update_cleaning_checklist_item_v1_cleanings__cleaning_id__checklists__checklist_id__items__item_id__patch","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Cleanings"],"summary":"Delete a checklist item","operationId":"delete_cleaning_checklist_item_v1_cleanings__cleaning_id__checklists__checklist_id__items__item_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"checklist_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Checklist Id"}},{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/comments":{"post":{"tags":["Cleanings"],"summary":"Add a comment to a cleaning","operationId":"create_cleaning_comment_v1_cleanings__cleaning_id__comments_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningCommentCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningCommentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/comments/{comment_id}":{"patch":{"tags":["Cleanings"],"summary":"Update a comment on a cleaning","operationId":"update_cleaning_comment_v1_cleanings__cleaning_id__comments__comment_id__patch","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Comment Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningCommentUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningCommentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Cleanings"],"summary":"Delete a comment on a cleaning","operationId":"delete_cleaning_comment_v1_cleanings__cleaning_id__comments__comment_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Comment Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/attachments":{"get":{"tags":["Cleanings"],"summary":"List attachments for a cleaning","operationId":"list_cleaning_attachments_v1_cleanings__cleaning_id__attachments_get","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CleaningAttachmentExternal"},"title":"Response List Cleaning Attachments V1 Cleanings  Cleaning Id  Attachments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Cleanings"],"summary":"Register attachments on a cleaning","description":"Register uploaded attachment URLs (clients upload to S3 first via the in-app presigned URLs).","operationId":"create_cleaning_attachments_v1_cleanings__cleaning_id__attachments_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningAttachmentCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CleaningAttachmentExternal"},"title":"Response Create Cleaning Attachments V1 Cleanings  Cleaning Id  Attachments Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/attachments/{attachment_id}":{"delete":{"tags":["Cleanings"],"summary":"Delete an attachment on a cleaning","operationId":"delete_cleaning_attachment_v1_cleanings__cleaning_id__attachments__attachment_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Attachment Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/issues":{"post":{"tags":["Cleanings"],"summary":"Report an issue on a cleaning","operationId":"create_cleaning_issue_v1_cleanings__cleaning_id__issues_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningIssueCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningIssueExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/issues/{issue_id}":{"patch":{"tags":["Cleanings"],"summary":"Update an issue on a cleaning","operationId":"update_cleaning_issue_v1_cleanings__cleaning_id__issues__issue_id__patch","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningIssueUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleaningIssueExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Cleanings"],"summary":"Delete an issue on a cleaning","operationId":"delete_cleaning_issue_v1_cleanings__cleaning_id__issues__issue_id__delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/watch":{"post":{"tags":["Followers"],"summary":"Follow a task","description":"Follow a task so the follower is notified when it changes (an AI-employee follower is woken instead and checks each change against its `instruction`). `who='me'` follows for the calling member; pass a user id to add someone else (needs the write scope). Following never grants access — a person who can't see the item can't follow it. Idempotent.","operationId":"follow_task_v1_tasks__task_id__watch_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Followers"],"summary":"Unfollow a task","description":"Stop following a task. For `who=me` on a task or cleaning this records a mute, so the item stays silent even for an assignee; pass another user id to remove that follower.","operationId":"unfollow_task_v1_tasks__task_id__watch_delete","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"who","in":"query","required":false,"schema":{"type":"string","description":"`me` or the user id of the follower to remove (needs write scope).","default":"me","title":"Who"},"description":"`me` or the user id of the follower to remove (needs write scope)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/watch/mute":{"post":{"tags":["Followers"],"summary":"Mute a task","description":"Mute notifications about one task for the calling member — works on assigned items too. Omit `until` to mute until unmuted.","operationId":"mute_task_v1_tasks__task_id__watch_mute_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MuteRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tasks/{task_id}/watchers":{"get":{"tags":["Followers"],"summary":"List a task's followers","description":"Everyone with a standing follow choice on a task — people and AI employees — with each follower's level, mute state and (for AI employees) the brief they watch for. Assignees are not listed unless they also follow the item.","operationId":"list_task_followers_v1_tasks__task_id__watchers_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Task Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowersListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/watch":{"post":{"tags":["Followers"],"summary":"Follow a cleaning","description":"Follow a cleaning so the follower is notified when it changes (an AI-employee follower is woken instead and checks each change against its `instruction`). `who='me'` follows for the calling member; pass a user id to add someone else (needs the write scope). Following never grants access — a person who can't see the item can't follow it. Idempotent.","operationId":"follow_cleaning_v1_cleanings__cleaning_id__watch_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Followers"],"summary":"Unfollow a cleaning","description":"Stop following a cleaning. For `who=me` on a task or cleaning this records a mute, so the item stays silent even for an assignee; pass another user id to remove that follower.","operationId":"unfollow_cleaning_v1_cleanings__cleaning_id__watch_delete","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"who","in":"query","required":false,"schema":{"type":"string","description":"`me` or the user id of the follower to remove (needs write scope).","default":"me","title":"Who"},"description":"`me` or the user id of the follower to remove (needs write scope)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/watch/mute":{"post":{"tags":["Followers"],"summary":"Mute a cleaning","description":"Mute notifications about one cleaning for the calling member — works on assigned items too. Omit `until` to mute until unmuted.","operationId":"mute_cleaning_v1_cleanings__cleaning_id__watch_mute_post","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MuteRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cleanings/{cleaning_id}/watchers":{"get":{"tags":["Followers"],"summary":"List a cleaning's followers","description":"Everyone with a standing follow choice on a cleaning — people and AI employees — with each follower's level, mute state and (for AI employees) the brief they watch for. Assignees are not listed unless they also follow the item.","operationId":"list_cleaning_followers_v1_cleanings__cleaning_id__watchers_get","parameters":[{"name":"cleaning_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Cleaning Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowersListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/watch":{"post":{"tags":["Followers"],"summary":"Follow a conversation","description":"Follow a conversation so the follower is notified when it changes (an AI-employee follower is woken instead and checks each change against its `instruction`). `who='me'` follows for the calling member; pass a user id to add someone else (needs the write scope). Following never grants access — a person who can't see the item can't follow it. Idempotent.","operationId":"follow_conversation_v1_conversations__conversation_id__watch_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Followers"],"summary":"Unfollow a conversation","description":"Stop following a conversation. For `who=me` on a task or cleaning this records a mute, so the item stays silent even for an assignee; pass another user id to remove that follower.","operationId":"unfollow_conversation_v1_conversations__conversation_id__watch_delete","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"who","in":"query","required":false,"schema":{"type":"string","description":"`me` or the user id of the follower to remove (needs write scope).","default":"me","title":"Who"},"description":"`me` or the user id of the follower to remove (needs write scope)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/watch/mute":{"post":{"tags":["Followers"],"summary":"Mute a conversation","description":"Mute notifications about one conversation for the calling member — works on assigned items too. Omit `until` to mute until unmuted.","operationId":"mute_conversation_v1_conversations__conversation_id__watch_mute_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MuteRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResultExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/conversations/{conversation_id}/watchers":{"get":{"tags":["Followers"],"summary":"List a conversation's followers","description":"Everyone with a standing follow choice on a conversation — people and AI employees — with each follower's level, mute state and (for AI employees) the brief they watch for. Assignees are not listed unless they also follow the item.","operationId":"list_conversation_followers_v1_conversations__conversation_id__watchers_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowersListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/watch-scopes/{scope_type}/{scope_id}":{"get":{"tags":["Followers"],"summary":"Get a scope's follow state","description":"A listing, department or recurring series: whether a person follows it, at what level, and everyone who does. Following a scope follows every task and cleaning under it, present and future. Omit `who` for the calling member (an account-level key then gets the follower list only).","operationId":"get_scope_follow_state_v1_watch_scopes__scope_type___scope_id__get","parameters":[{"name":"scope_type","in":"path","required":true,"schema":{"enum":["listing","department","recurring_task"],"type":"string","title":"Scope Type"}},{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scope Id"}},{"name":"who","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`me` or a workspace member / AI employee user id.","title":"Who"},"description":"`me` or a workspace member / AI employee user id."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopeFollowStateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Followers"],"summary":"Follow a scope","description":"Follow a whole listing, department or recurring series: the follower hears about every task and cleaning under it, present and future, that they can see. `who='me'` follows for the calling member; pass a user id to add someone else (needs `tasks:write`, or `cleanings:write` for a listing or department). Following never grants access — a person who can't see the scope can't follow it, and each item is still checked before every notification. A listing-scoped key can follow only its own listings. Idempotent; a repeat follow updates the level.","operationId":"follow_scope_v1_watch_scopes__scope_type___scope_id__post","parameters":[{"name":"scope_type","in":"path","required":true,"schema":{"enum":["listing","department","recurring_task"],"type":"string","title":"Scope Type"}},{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scope Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopeFollowRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopeFollowStateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Followers"],"summary":"Unfollow a scope","description":"Stop following a listing, department or recurring series. Items under it you follow on their own stay followed. Pass another user id as `who` to remove that follower (needs the write scope). Idempotent — unfollowing a scope nobody follows is a no-op.","operationId":"unfollow_scope_v1_watch_scopes__scope_type___scope_id__delete","parameters":[{"name":"scope_type","in":"path","required":true,"schema":{"enum":["listing","department","recurring_task"],"type":"string","title":"Scope Type"}},{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scope Id"}},{"name":"who","in":"query","required":false,"schema":{"type":"string","description":"`me` or the user id of the follower to remove (needs write scope).","default":"me","title":"Who"},"description":"`me` or the user id of the follower to remove (needs write scope)."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScopeFollowStateExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me/following":{"get":{"tags":["Followers"],"summary":"List followed items","description":"The tasks, cleanings and conversations a person follows, newest first (muted follows excluded). Whole listings, departments and recurring series they follow are listed only on opt-in — `include=scopes`, or an `entity_type` naming a scope type. `who=me` for the calling member, or a teammate / AI employee user id. Only types the credential can read are listed, and only what that person can still see. A listing-scoped key sees its own listings' rows only.","operationId":"list_following_v1_me_following_get","parameters":[{"name":"who","in":"query","required":false,"schema":{"type":"string","description":"`me` or a workspace member / AI employee user id.","default":"me","title":"Who"},"description":"`me` or a workspace member / AI employee user id."},{"name":"entity_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional filter: `task`, `cleaning`, `conversation`, or a scope type — `listing`, `department` or `recurring_task`.","title":"Entity Type"},"description":"Optional filter: `task`, `cleaning`, `conversation`, or a scope type — `listing`, `department` or `recurring_task`."},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"const":"scopes","type":"string"}},{"type":"null"}],"description":"`scopes` to also list followed listings, departments and recurring series.","title":"Include"},"description":"`scopes` to also list followed listings, departments and recurring series."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowingListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/memories":{"get":{"tags":["Memories"],"summary":"List memories","description":"Retrieve a paginated list of property knowledge memories for the account, with optional filters by scope and listing.","operationId":"list_memories_v1_memories_get","parameters":[{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by scope (listing, all_listings, listing_group)","title":"Scope"},"description":"Filter by scope (listing, all_listings, listing_group)"},{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_MemoryExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Memories"],"summary":"Create a memory","description":"Create a new property knowledge memory. Memories are used by the AI to answer guest questions. Keys bound to an AI employee (agent pairing / managed-agent connections) always create INTERNAL memories: `is_internal` is forced to `true` and the source is recorded as `agent_run`, so an agent-authored memory can inform a guest-facing reply but is never quoted to a guest verbatim.","operationId":"create_memory_v1_memories_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/memories/counts":{"get":{"tags":["Memories"],"summary":"Get memory counts","description":"Get the total number of memories grouped by scope (listing, all_listings, listing_group).","operationId":"get_memory_counts_v1_memories_counts_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Memory Counts V1 Memories Counts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/memories/property-knowledge/{listing_id}":{"get":{"tags":["Memories"],"summary":"Get property knowledge","description":"Get all memories for a specific property, grouped by scope (listing-specific, all-listings, and listing-group).","operationId":"get_property_knowledge_v1_memories_property_knowledge__listing_id__get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Property Knowledge V1 Memories Property Knowledge  Listing Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/memories/search":{"post":{"tags":["Memories"],"summary":"Search memories","description":"Perform a semantic search across memories using a natural language query.","operationId":"search_memories_v1_memories_search_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemorySearchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemorySearchResult"},"title":"Response Search Memories V1 Memories Search Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/memories/{memory_id}":{"get":{"tags":["Memories"],"summary":"Get a memory","description":"Retrieve a single memory by its ID.","operationId":"get_memory_v1_memories__memory_id__get","parameters":[{"name":"memory_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Memory Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Memories"],"summary":"Update a memory","description":"Update the content, scope, or visibility of an existing memory. Restricted internal-only writers cannot update existing memories (403); they may only save new internal memories.","operationId":"update_memory_v1_memories__memory_id__put","parameters":[{"name":"memory_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Memory Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Memories"],"summary":"Delete a memory","description":"Move a memory to the trash by its ID. Soft-deleted memories stop appearing in lists and AI recall but can be restored from the app's trash. Not available to keys bound to an AI employee (403).","operationId":"delete_memory_v1_memories__memory_id__delete","parameters":[{"name":"memory_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Memory Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skills":{"get":{"tags":["Skills"],"summary":"List skills","description":"List the account's skill library (host playbooks): reusable procedure packs the AI follows for specific situations. Returns routing metadata without bodies — fetch one skill's body via GET /skills/{key}.","operationId":"list_skills_v1_skills_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skills/{key}":{"get":{"tags":["Skills"],"summary":"Get skill","description":"Load one skill (host playbook) by key, including its full body. Records a use.","operationId":"get_skill_v1_skills__key__get","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/analytics/messages/total":{"get":{"tags":["Analytics"],"summary":"Get total message count","description":"Get the total number of messages sent and received within an optional date range.","operationId":"get_messages_total_v1_analytics_messages_total_get","parameters":[{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of period","title":"Start Date"},"description":"Start of period"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"End of period","title":"End Date"},"description":"End of period"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTotalExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/analytics/messages/response-times":{"get":{"tags":["Analytics"],"summary":"Get message response times","description":"Get average, median, and 75th-percentile response time metrics within an optional date range.","operationId":"get_message_response_times_v1_analytics_messages_response_times_get","parameters":[{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of period","title":"Start Date"},"description":"Start of period"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"End of period","title":"End Date"},"description":"End of period"},{"name":"exclude_api","in":"query","required":false,"schema":{"type":"boolean","description":"If true, exclude messages sent via the external API / MCP from the response-time calculation. Useful for measuring response times without external API/MCP traffic.","default":false,"title":"Exclude Api"},"description":"If true, exclude messages sent via the external API / MCP from the response-time calculation. Useful for measuring response times without external API/MCP traffic."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseTimeExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/dashboard/summary":{"get":{"tags":["Dashboard"],"summary":"Get dashboard summary","description":"Get a composite dashboard view including today's check-ins/check-outs, unread conversations, pending tasks, and upcoming reservations for the next 7 days.","operationId":"get_dashboard_summary_v1_dashboard_summary_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/departments":{"get":{"tags":["Departments"],"summary":"List departments","description":"Retrieve a paginated list of departments for the account, including their members.","operationId":"list_departments_v1_departments_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list using the offset envelope (`items`, `total`, `limit`, `offset`, `has_more`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffsetPage_DepartmentExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/departments/{department_id}":{"get":{"tags":["Departments"],"summary":"Get a department","description":"Retrieve a single department by its ID, including its members.","operationId":"get_department_v1_departments__department_id__get","parameters":[{"name":"department_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Department Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepartmentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents":{"get":{"tags":["AI Employees"],"summary":"List AI employees","description":"List every AI employee on the account, with its activation state.","operationId":"list_ai_employees_v1_agents_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"The full collection with an `{items, total}` envelope (not paginated).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemsPage_AIEmployeeExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["AI Employees"],"summary":"Create a custom AI employee","description":"Create a brand-new custom AI employee (not from a template). It is created inactive.","operationId":"create_ai_employee_v1_agents_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAIEmployeeRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_id}":{"get":{"tags":["AI Employees"],"summary":"Get an AI employee","description":"Fetch a single AI employee by id.","operationId":"get_ai_employee_v1_agents__agent_id__get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["AI Employees"],"summary":"Configure an AI employee","description":"Update an AI employee — only supplied fields are written.","operationId":"configure_ai_employee_v1_agents__agent_id__patch","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigureAIEmployeeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["AI Employees"],"summary":"Delete an AI employee","description":"Delete an AI employee. It stops working and leaves the roster, but its past messages keep its name and face; hiring the same template again brings it back. The default agent cannot be deleted.","operationId":"delete_ai_employee_v1_agents__agent_id__delete","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/hire":{"post":{"tags":["AI Employees"],"summary":"Hire an AI employee","description":"Activate one of the pre-built launch-lineup template AI employees.","operationId":"hire_ai_employee_v1_agents_hire_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HireAIEmployeeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_id}/triggers":{"get":{"tags":["AI Employees"],"summary":"List an AI employee's triggers","description":"List the event triggers wired to an AI employee.","operationId":"list_ai_employee_triggers_v1_agents__agent_id__triggers_get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"The full collection with an `{items, total}` envelope (not paginated).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemsPage_AIEmployeeTriggerExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["AI Employees"],"summary":"Add a trigger to an AI employee","description":"Wire an event trigger to an AI employee.","operationId":"create_ai_employee_trigger_v1_agents__agent_id__triggers_post","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAIEmployeeTriggerRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeTriggerExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_id}/triggers/{trigger_id}":{"patch":{"tags":["AI Employees"],"summary":"Update an AI employee trigger","description":"Update an agent trigger — only supplied fields are written.","operationId":"update_ai_employee_trigger_v1_agents__agent_id__triggers__trigger_id__patch","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"trigger_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Trigger Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAIEmployeeTriggerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIEmployeeTriggerExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["AI Employees"],"summary":"Delete an AI employee trigger","description":"Remove an agent trigger.","operationId":"delete_ai_employee_trigger_v1_agents__agent_id__triggers__trigger_id__delete","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"trigger_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Trigger Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agent-runtime/agents/{agent_id}/context":{"get":{"tags":["Agent runtime"],"summary":"Get an AI employee's runtime context","description":"Fetch the persona text and member identity an external agent runtime needs to act as this AI employee. Distinct from `GET /v1/agents/{agent_id}`, which returns the host-facing summary without the system prompt or the agent's user id.","operationId":"get_agent_runtime_context_v1_agent_runtime_agents__agent_id__context_get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Agent Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRuntimeContextExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agent-runtime/conversations/{conversation_id}/team-chat":{"get":{"tags":["Agent runtime"],"summary":"Get an internal team-chat transcript","description":"Fetch the recent transcript of an INTERNAL team-chat thread, in transcript order (oldest first). Refuses any conversation on a guest-facing channel (OTA, webchat, SMS, email, …) with a 403, and any conversation outside the calling key's account with a 404.","operationId":"get_team_chat_context_v1_agent_runtime_conversations__conversation_id__team_chat_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamChatContextExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_ref}/dm":{"post":{"tags":["AI Employee DMs"],"summary":"Open (or reuse) a DM with an AI employee","description":"Resolve the deterministic 1:1 DM thread between you and the AI employee, creating it if none exists. ``agent_ref`` is the employee's id or handle. The same pair always resolves to the same thread, so calling this repeatedly is safe and idempotent.","operationId":"ensure_agent_dm_v1_agents__agent_ref__dm_post","parameters":[{"name":"agent_ref","in":"path","required":true,"schema":{"type":"string","title":"Agent Ref"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDMExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_ref}/dm/messages":{"post":{"tags":["AI Employee DMs"],"summary":"Message an AI employee","description":"Post a message into your DM with the AI employee and dispatch their run. The reply is asynchronous: the employee's worker posts it back into the same thread, typically within seconds to a few minutes depending on the work involved. Poll ``GET .../dm/messages`` (pass ``since``) or subscribe to the ``message.team_chat`` webhook event to receive it. ``run_id`` is null when a dispatch guard (credit budget, billing gate, agent-chain depth, in-flight dedup) suppressed the run — the message is still delivered to the thread.","operationId":"send_agent_dm_message_v1_agents__agent_ref__dm_messages_post","parameters":[{"name":"agent_ref","in":"path","required":true,"schema":{"type":"string","title":"Agent Ref"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAgentDMRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAgentDMResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["AI Employee DMs"],"summary":"Poll an AI-employee DM for messages","description":"Read the DM thread's messages, oldest first. Pass ``since`` (the ``sent_at`` of the last message you've seen) to fetch only newer messages — the employee's reply shows up with ``from_agent: true``. Returns an empty page with ``conversation_id: null`` when no DM exists yet. The ``message.team_chat`` webhook event is the push alternative to polling.","operationId":"get_agent_dm_messages_v1_agents__agent_ref__dm_messages_get","parameters":[{"name":"agent_ref","in":"path","required":true,"schema":{"type":"string","title":"Agent Ref"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only messages sent strictly after this timestamp.","title":"Since"},"description":"Only messages sent strictly after this timestamp."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDMMessagesPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agent-runs/{run_id}/complete":{"post":{"tags":["Agent runs"],"summary":"Complete an agent run","description":"Report a run dispatched to you via the `agent.run_requested` webhook as finished. Requires the paired agent credential that owns the run (the key bound to that run's AI employee) holding `agent_runs:write`. Completing clears the thinking-indicator shown to whoever triggered the run, so call it even when you decide not to reply — use `status: succeeded` with `outcome: silent` for that. Completing an already-terminal run returns `409 already_resolved`.","operationId":"complete_agent_run_v1_agent_runs__run_id__complete_post","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunCompleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunCompleteResponse"}}}},"404":{"description":"No such run for this credential."},"409":{"description":"The run already reached a terminal state."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agent-runs/{run_id}/heartbeat":{"post":{"tags":["Agent runs"],"summary":"Heartbeat an in-flight agent run","description":"Renew the liveness lease on a run dispatched to you via the `agent.run_requested` webhook. Requires the same credential that would complete the run (the paired agent key bound to that run's AI employee) holding `agent_runs:write`.\n\n**Call this every ~60 seconds for as long as the run is alive** — including while the run is only queued on your side and has not started executing yet, since a run you are holding in a queue is still a run the user is waiting on. A run that has heartbeated at least once is reaped after roughly 10 minutes of silence rather than the 3 hours a run with no heartbeats gets, so a crashed runtime stops spinning the sender's thinking-indicator in minutes. Runs that never heartbeat keep the old behaviour, so adopting this is safe to do incrementally.\n\n**`cancel_requested: true` means the user pressed Stop.** Stop the run and report it via `POST /v1/agent-runs/{run_id}/complete` with `status: failed` and `error: cancelled_by_user` — ProhostAI cannot kill your process, so this response is the only way the request reaches you.\n\nHeartbeating an already-terminal run returns `409 already_resolved`: the lease is over and the run should stop.\n\n**Working on a task?** Add `task_id` (and, as you go, `phase`, `current_step`, `repo`, `branch`, diffstat, test counts and `pr_number`) and the task shows your run as an AI working on it until the run completes. All optional; a heartbeat without `task_id` behaves exactly as before.","operationId":"heartbeat_agent_run_v1_agent_runs__run_id__heartbeat_post","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunHeartbeatRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunHeartbeatResponse"}}}},"404":{"description":"No such run for this credential, or `task_not_found`."},"409":{"description":"The run already reached a terminal state."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agent-runs/{run_id}/events":{"post":{"tags":["Agent runs"],"summary":"Report tool events for an in-flight agent run","description":"Stream what a run dispatched to you via the `agent.run_requested` webhook is doing, one event per tool-call start and end. Same credential as the heartbeat (the paired agent key bound to that run's AI employee, holding `agent_runs:write`) and the same 404 / 409 semantics.\n\nEvents land on the run's durable timeline and are shown live in the conversation the run is answering, exactly as an in-product AI employee's tool calls are. Send them in small batches (the CLI debounces ~1s) and always before you post the reply or complete the run.\n\n**Limits.** At most 50 events per request (422 beyond that); at most 200 tool rows are kept per run — past that the newest are kept, the oldest are dropped, and the run carries a single `tool_timeline_truncated` marker event with the cumulative count. Idempotent per `(run_id, tool_id, status)`: replaying a batch is safe and reports the replayed events as `ignored`. Send `args_preview` as a small JSON object of the call's headline fields (`{\"command\": \"git status\"}`) — a bare string is accepted and stored under a generic key.\n\nPurely optional — a runtime that never calls this keeps the heartbeat's one-line `progress` as its only narration.","operationId":"post_agent_run_events_v1_agent_runs__run_id__events_post","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunToolEventsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunToolEventsResponse"}}}},"404":{"description":"No such run for this credential."},"409":{"description":"The run already reached a terminal state."},"422":{"description":"Malformed batch — empty, too large, or an unknown status."}}}},"/v1/approvals":{"post":{"tags":["Approvals"],"summary":"File an approval request","description":"File a human-in-the-loop approval request. Requires a paired agent credential (from the agent-pairing flow) holding `approvals:write`. The request surfaces on the account's home approvals widget and as an interactive team-chat card; the decision is delivered via the `agent.approval_resolved` webhook and this API's GET surface. Supports Stripe-style `Idempotency-Key` request replay protection.","operationId":"create_approval_v1_approvals_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequestCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Approvals"],"summary":"List approval requests","description":"List approval requests visible to this credential (a paired agent credential sees its own agent's requests), newest first.","operationId":"list_approvals_v1_approvals_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pending|approved|rejected|expired)$"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequestListExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/approvals/{request_id}":{"get":{"tags":["Approvals"],"summary":"Get an approval request","description":"Fetch one approval request by id — the polling fallback for the `agent.approval_resolved` webhook.","operationId":"get_approval_v1_approvals__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Request Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalRequestExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/notifications/settings":{"get":{"tags":["Notifications"],"summary":"Get notification settings","description":"Notification preferences for the user this credential acts as, within the selected account: the scope arrays, the full category x channel delivery matrix, the AI-employee email cadence, the reminder / needs-attention sub-toggles, the per-guest-channel message matrix, and the read-only escalation reachability cap. Settings are created with defaults on first read.","operationId":"get_notification_settings_v1_notifications_settings_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNotificationSettingsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Notifications"],"summary":"Update notification settings","description":"Only provided fields are written. Scope arrays replace wholesale (an empty list silences that category); channel_preferences and message_channel_preferences merge per key, so categories and channels omitted from the payload keep their stored values. Enabling the sms channel requires an active paid subscription, and slack a linked Slack workspace — an unentitled enable is refused (402 / 409) and writes nothing at all, while turning either off is always allowed. escalation_reachability is not accepted here.","operationId":"update_notification_settings_v1_notifications_settings_patch","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSettingsUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNotificationSettingsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/lounges":{"get":{"tags":["Community"],"summary":"List community lounges","description":"All listed community lounges with the acting user's standing in each: whether they have joined and whether their credentials make them eligible. Materializes the user's pseudonymous community profile on first call and returns its handle — every join and post is attributed to that handle, never to the user's real name. Member counts are approximate: `member_count_display` reads like \"250+\" or \"<10\", and `member_count` is the same bucket as an integer, not the exact size.","operationId":"list_lounges_v1_community_lounges_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoungeListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/lounges/{lounge_slug}/posts":{"post":{"tags":["Community"],"summary":"Create a community post","description":"Post into a lounge as the acting user's pseudonymous community profile. The body is rendered as plain text (newlines preserved, no markdown). Requires the user's credentials to satisfy the lounge's eligibility rule; joins the lounge first by default (idempotent). Rate-limited to 5 posts per minute per profile.","operationId":"create_post_v1_community_lounges__lounge_slug__posts_post","parameters":[{"name":"lounge_slug","in":"path","required":true,"schema":{"type":"string","title":"Lounge Slug"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityPostCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityPostResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/lounges/{lounge_slug}/feed":{"get":{"tags":["Community"],"summary":"Read a lounge feed","description":"One page of a lounge's posts, newest first, as the acting user's community profile sees them. Pinned posts come back separately on every page. Pass `next_cursor` back as `cursor` for the next page. The user must be a member of the lounge or have credentials that make them eligible for it; otherwise 403 `not_eligible`.","operationId":"get_lounge_feed_v1_community_lounges__lounge_slug__feed_get","parameters":[{"name":"lounge_slug","in":"path","required":true,"schema":{"type":"string","title":"Lounge Slug"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`next_cursor` from the previous page.","title":"Cursor"},"description":"`next_cursor` from the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityLoungeFeedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/posts/{post_id}":{"get":{"tags":["Community"],"summary":"Read a community post with its comments","description":"A post and its comment thread: top-level comments oldest first, each with its replies (comments nest two levels deep). Hidden posts and comments are never returned. Same lounge access rule as the feed.","operationId":"get_post_v1_community_posts__post_id__get","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityPostDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/posts/{post_id}/comments":{"post":{"tags":["Community"],"summary":"Comment on a community post","description":"Comment on a post, or reply to a top-level comment with `parent_id`, as the acting user's pseudonymous community profile. Plain text, up to 2000 characters. Replies nest one level: replying to a reply is refused with 400 `comment_depth_exceeded`. Rate-limited to 10 comments per minute per profile.","operationId":"create_comment_v1_community_posts__post_id__comments_post","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityCommentCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityCommentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/posts/{post_id}/like":{"put":{"tags":["Community"],"summary":"Like a community post","description":"Like a post as the acting user. Idempotent: liking a post already liked changes nothing.","operationId":"like_post_v1_community_posts__post_id__like_put","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityLikeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Community"],"summary":"Unlike a community post","description":"Remove the acting user's like from a post. Idempotent: unliking a post not liked changes nothing.","operationId":"unlike_post_v1_community_posts__post_id__like_delete","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityLikeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/posts/{post_id}/flag":{"post":{"tags":["Community"],"summary":"Flag a community post","description":"Report a post to the ProhostAI community moderators, as the acting user. `reason` is one of spam, harassment, hate, self_promotion, identifying_info, off_topic, other. A user can flag the same a post once (409 `already_flagged` after that); enough distinct reports hide it automatically. Rate-limited to 20 flags per hour per profile.","operationId":"flag_post_v1_community_posts__post_id__flag_post","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityFlagCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityFlagResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/comments/{comment_id}/flag":{"post":{"tags":["Community"],"summary":"Flag a community comment","description":"Report a comment to the ProhostAI community moderators, as the acting user. `reason` is one of spam, harassment, hate, self_promotion, identifying_info, off_topic, other. A user can flag the same a comment once (409 `already_flagged` after that); enough distinct reports hide it automatically. Rate-limited to 20 flags per hour per profile.","operationId":"flag_comment_v1_community_comments__comment_id__flag_post","parameters":[{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Comment Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityFlagCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityFlagResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/lounges/{lounge_slug}/join":{"post":{"tags":["Community"],"summary":"Join a community lounge","description":"Join a lounge as the acting user. Requires the user's credentials to satisfy the lounge's eligibility rule (403 `not_eligible` otherwise). Idempotent.","operationId":"join_lounge_v1_community_lounges__lounge_slug__join_post","parameters":[{"name":"lounge_slug","in":"path","required":true,"schema":{"type":"string","title":"Lounge Slug"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityMembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/lounges/{lounge_slug}/leave":{"post":{"tags":["Community"],"summary":"Leave a community lounge","description":"Leave a lounge as the acting user. Their posts stay in the lounge, and the lounge will not add them back automatically. Idempotent.","operationId":"leave_lounge_v1_community_lounges__lounge_slug__leave_post","parameters":[{"name":"lounge_slug","in":"path","required":true,"schema":{"type":"string","title":"Lounge Slug"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityMembershipResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/community/me":{"get":{"tags":["Community"],"summary":"Read the acting user's community profile","description":"The acting user's own pseudonymous community profile: handle, level, their verified credentials, and the lounges they belong to. Every post, comment, like and flag made through this API is attributed to this handle, never to the user's real name.","operationId":"get_my_profile_v1_community_me_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityMyProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/whats-new":{"get":{"tags":["What's New"],"summary":"List What's New stories","description":"Published What's New stories (ProhostAI product news), newest first, as the credential's user sees them in the app: only stories for the account's workspace type, and none about a feature the user cannot use yet. Cursor-paginated: pass `next_cursor` back as `cursor`.","operationId":"list_stories_v1_whats_new_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`next_cursor` from the previous page.","title":"Cursor"},"description":"`next_cursor` from the previous page."},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Locale (e.g. 'de-DE'). Stories are served in this locale when a translation exists, else canonical English; each story's `language` reports what was served.","title":"Lang"},"description":"Locale (e.g. 'de-DE'). Stories are served in this locale when a translation exists, else canonical English; each story's `language` reports what was served."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsNewStoryList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/whats-new/{story_id}":{"get":{"tags":["What's New"],"summary":"Get a What's New story","description":"One published What's New story by id. 404 for an unknown or unpublished story, for a story written for other workspace types, and for a story about a feature the credential's user cannot use yet — exactly the stories the list leaves out.","operationId":"get_story_v1_whats_new__story_id__get","parameters":[{"name":"story_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Story Id"}},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Locale (e.g. 'de-DE'). Stories are served in this locale when a translation exists, else canonical English; each story's `language` reports what was served.","title":"Lang"},"description":"Locale (e.g. 'de-DE'). Stories are served in this locale when a translation exists, else canonical English; each story's `language` reports what was served."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsNewStory"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents":{"get":{"tags":["Documents"],"summary":"List documents","description":"Retrieve a paginated list of uploaded documents for the account, with an optional filter by listing.","operationId":"list_documents_v1_documents_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_DocumentExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/upsells":{"get":{"tags":["Upsells"],"summary":"List upsell offers","description":"Retrieve a paginated list of upsell offers for the account, with optional filters by listing and status.","operationId":"list_upsell_offers_v1_upsells_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status","title":"Status"},"description":"Filter by status"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_UpsellOfferExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/upsells/upgrades":{"get":{"tags":["Upsells"],"summary":"List upgrades","description":"List purchaseable upgrade definitions for the account, optionally filtered by listing IDs.","operationId":"list_upgrades_v1_upsells_upgrades_get","parameters":[{"name":"listing_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"null"}],"description":"Filter by listing IDs","title":"Listing Ids"},"description":"Filter by listing IDs"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UpsellUpgradeWithListingsExternal"},"title":"Response List Upgrades V1 Upsells Upgrades Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners/statements":{"get":{"tags":["Owners"],"summary":"List owner statements","description":"List owner statements for the account, optionally filtered by status, owner, and title search.","operationId":"list_owner_statements_v1_owners_statements_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerStatementStatus"},{"type":"null"}],"description":"Filter by statement status","title":"Status"},"description":"Filter by statement status"},{"name":"owner_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by owner ID","title":"Owner Id"},"description":"Filter by owner ID"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by title","title":"Search"},"description":"Search by title"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list using the offset envelope (`items`, `total`, `limit`, `offset`, `has_more`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffsetPage_OwnerStatementExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Owners"],"summary":"Create an owner statement","description":"Create a new owner statement. The owner must belong to the caller's account.","operationId":"create_owner_statement_v1_owners_statements_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerStatementCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerStatementExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners/statements/{statement_id}":{"get":{"tags":["Owners"],"summary":"Get an owner statement","description":"Retrieve a single owner statement by its ID.","operationId":"get_owner_statement_v1_owners_statements__statement_id__get","parameters":[{"name":"statement_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Statement Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerStatementExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Owners"],"summary":"Update an owner statement","description":"Update an existing owner statement. Only provided fields are written.","operationId":"update_owner_statement_v1_owners_statements__statement_id__patch","parameters":[{"name":"statement_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Statement Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerStatementUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerStatementExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Owners"],"summary":"Delete an owner statement","description":"Delete an owner statement. Returns 404 if the statement does not exist — clients implementing retry-after-timeout should tolerate 404 as a \"successful prior call\" signal.","operationId":"delete_owner_statement_v1_owners_statements__statement_id__delete","parameters":[{"name":"statement_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Statement Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners/statements/{statement_id}/rental-activity":{"get":{"tags":["Owners"],"summary":"Get owner statement rental activity","description":"Return rental-activity totals for the statement window: per-reservation and per-listing breakdowns plus aggregate totals. Honors the statement's ``rental_activity_display_type``.","operationId":"get_owner_statement_rental_activity_v1_owners_statements__statement_id__rental_activity_get","parameters":[{"name":"statement_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Statement Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners/statements/{statement_id}/expenses":{"get":{"tags":["Owners"],"summary":"Get owner statement expense activity","description":"Return expense totals for the statement window, broken down per listing.","operationId":"get_owner_statement_expense_activity_v1_owners_statements__statement_id__expenses_get","parameters":[{"name":"statement_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Statement Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseActivityResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners":{"get":{"tags":["Owners"],"summary":"List owners","description":"Retrieve a paginated list of property owners for the account, with optional filters by status and text search.","operationId":"list_owners_v1_owners_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OwnerStatus"},{"type":"null"}],"description":"Filter by owner status","title":"Status"},"description":"Filter by owner status"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by name, email, or company","title":"Search"},"description":"Search by name, email, or company"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list using the offset envelope (`items`, `total`, `limit`, `offset`, `has_more`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffsetPage_OwnerExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Owners"],"summary":"Create an owner","description":"Create a new property owner on the account. Optionally pass ``listing_ids`` to assign existing listings to this owner in the same call (mirrors the internal ``POST /owners`` behavior).","operationId":"create_owner_v1_owners_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/owners/{owner_id}":{"get":{"tags":["Owners"],"summary":"Get an owner","description":"Retrieve a single property owner by their ID.","operationId":"get_owner_v1_owners__owner_id__get","parameters":[{"name":"owner_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Owner Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Owners"],"summary":"Update an owner","description":"Update an existing owner. Only provided fields are written.","operationId":"update_owner_v1_owners__owner_id__patch","parameters":[{"name":"owner_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Owner Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/expenses/categories":{"get":{"tags":["Expenses"],"summary":"List expense categories","description":"Retrieve all expense categories for the account. System categories are materialised lazily on first read, so this endpoint may create rows the first time it's called for a given account.","operationId":"list_expense_categories_v1_expenses_categories_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExpenseCategoryExternal"},"title":"Response List Expense Categories V1 Expenses Categories Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Expenses"],"summary":"Create an expense category","description":"Create a new custom expense category for the account.","operationId":"create_expense_category_v1_expenses_categories_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCategoryCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCategoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/expenses/categories/{category_id}":{"get":{"tags":["Expenses"],"summary":"Get an expense category","description":"Retrieve a single expense category by its ID.","operationId":"get_expense_category_v1_expenses_categories__category_id__get","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCategoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Expenses"],"summary":"Update an expense category","description":"Rename a custom expense category. System categories can be renamed but not deleted.","operationId":"update_expense_category_v1_expenses_categories__category_id__put","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCategoryUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCategoryExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Expenses"],"summary":"Delete an expense category","description":"Permanently delete a custom expense category. System categories cannot be deleted — the service returns 400 in that case.","operationId":"delete_expense_category_v1_expenses_categories__category_id__delete","parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Category Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/expenses":{"get":{"tags":["Expenses"],"summary":"List expenses","description":"Retrieve a paginated list of expenses for the account, with optional filters by listing, category, payment status, date range, and text search.","operationId":"list_expenses_v1_expenses_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"category_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by category ID","title":"Category Id"},"description":"Filter by category ID"},{"name":"payment_status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PaymentStatus"},{"type":"null"}],"description":"Filter by payment status","title":"Payment Status"},"description":"Filter by payment status"},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter expenses on or after this date","title":"Start Date"},"description":"Filter expenses on or after this date"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Filter expenses on or before this date","title":"End Date"},"description":"Filter expenses on or before this date"},{"name":"search_query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by expense name or description","title":"Search Query"},"description":"Search by expense name or description"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ExpenseExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Expenses"],"summary":"Create an expense","description":"Record a new expense, optionally associated with a listing and category.","operationId":"create_expense_v1_expenses_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/expenses/bulk":{"put":{"tags":["Expenses"],"summary":"Bulk update expenses","description":"Update multiple expenses with the same payload in a single request. All expenses must belong to the caller's account; any foreign IDs appear under ``failed``. Up to 100 IDs per call.","operationId":"bulk_update_expenses_v1_expenses_bulk_put","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExpenseUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExpenseUpdateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Expenses"],"summary":"Bulk delete expenses","description":"Delete multiple expenses in a single request. All expenses must belong to the caller's account; any foreign IDs appear under ``failed``. Up to 100 IDs per call.","operationId":"bulk_delete_expenses_v1_expenses_bulk_delete","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExpenseDeleteExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExpenseDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/expenses/{expense_id}":{"get":{"tags":["Expenses"],"summary":"Get an expense","description":"Retrieve a single expense by its ID.","operationId":"get_expense_v1_expenses__expense_id__get","parameters":[{"name":"expense_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Expense Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Expenses"],"summary":"Update an expense","description":"Update one or more fields on an existing expense. Only fields present in the request body are modified — omitted fields keep their current value.","operationId":"update_expense_v1_expenses__expense_id__put","parameters":[{"name":"expense_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Expense Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Expenses"],"summary":"Delete an expense","description":"Permanently delete an expense by its ID.","operationId":"delete_expense_v1_expenses__expense_id__delete","parameters":[{"name":"expense_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Expense Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/calendar/days":{"get":{"tags":["Calendar"],"summary":"Get calendar days","description":"Retrieve calendar day entries for one or all listings within a date range, including availability and pricing data.","operationId":"get_calendar_days_v1_calendar_days_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"Start date of the range","title":"Start Date"},"description":"Start date of the range"},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"End date of the range","title":"End Date"},"description":"End date of the range"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"The full collection with an `{items, total}` envelope (not paginated).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemsPage_CalendarDayExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/calendar/occupancy":{"get":{"tags":["Calendar"],"summary":"Get occupancy statistics","description":"Get forward-looking occupancy rates (7, 30, and 60 days) per listing and as an aggregate across all listings.","operationId":"get_occupancy_stats_v1_calendar_occupancy_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OccupancyResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/calendar/days/{listing_id}":{"put":{"tags":["Calendar"],"summary":"Update calendar days (batch)","description":"Push price / availability / min-stay updates for a range of dates on a listing's OTA. Dispatched asynchronously — a 202 response means the request was accepted and will be processed in the background. Up to 1095 updates per request, dates must be unique.","operationId":"update_calendar_days_v1_calendar_days__listing_id__put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarBatchUpdateRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarBatchUpdateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/calendar/days/{listing_id}/{day}":{"put":{"tags":["Calendar"],"summary":"Update a single calendar day","description":"Push a price / availability / min-stay update for a single date. Unlike the batch endpoint this awaits the OTA push and returns the persisted calendar day. At least one field must be provided.","operationId":"update_calendar_day_v1_calendar_days__listing_id___day__put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"day","in":"path","required":true,"schema":{"type":"string","format":"date","title":"Day"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarDayUpdateBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarDayExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reviews":{"get":{"tags":["Reviews"],"summary":"List reviews","description":"Retrieve a paginated list of guest reviews for the account, with optional filters by listing, star rating, and date range.","operationId":"list_reviews_v1_reviews_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"min_stars","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":5,"minimum":1},{"type":"null"}],"description":"Minimum star rating","title":"Min Stars"},"description":"Minimum star rating"},{"name":"max_stars","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":5,"minimum":1},{"type":"null"}],"description":"Maximum star rating","title":"Max Stars"},"description":"Maximum star rating"},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter reviews from this date","title":"Start Date"},"description":"Filter reviews from this date"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter reviews until this date","title":"End Date"},"description":"Filter reviews until this date"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ReviewExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Reviews"],"summary":"Add a review","description":"Add a guest review by hand, for a channel whose reviews ProhostAI doesn't sync (Booking.com, Vrbo, Google, a direct booking...). It counts in ratings and analytics and shows on the direct-booking site like any review; it can't be replied to or disputed from ProhostAI. Set ``run_automations`` for a review that just came in, to detect tasks and fire your review workflows and the ``review.received`` webhook.\n\nFor a site that isn't one of the channels (TripAdvisor...), send ``other`` and its ``source_name``. ``rating`` is on the channel's own scale: 1-10 for ``bookingcom``, 1-5 otherwise. Link it to a stay with ``reservation_id`` or the stay's ``confirmation_code`` (the channel's booking code, or the PMS's), or leave both out for a listing-wide review. Pass ``external_id`` to make retries safe: a second create with it is refused with the existing ``review_id``.","operationId":"create_review_v1_reviews_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewExternal"}}}},"403":{"description":"Missing ``reviews:write`` scope or listing not in scope."},"404":{"description":"Listing or review not found (``code``: ``listing_not_found`` / ``review_not_found``)."},"409":{"description":"Refused: ``stay_has_review``, ``duplicate_external_id`` (``review_id`` names the existing one), ``channel_synced`` (Airbnb reviews on an Airbnb-connected listing sync on their own), or ``review_not_external`` (a synced review can't be changed)."},"422":{"description":"Invalid: ``rating_out_of_range``, ``stay_not_found``, ``confirmation_code_ambiguous``, ``channel_mismatch`` or ``field_required``."}}}},"/v1/reviews/analytics":{"get":{"tags":["Reviews"],"summary":"Get review analytics","description":"Get aggregate review statistics including average rating, weekly trends, rating trends, and review rate metrics.","operationId":"get_review_analytics_v1_reviews_analytics_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter from this date","title":"Start Date"},"description":"Filter from this date"},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter until this date","title":"End Date"},"description":"Filter until this date"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewAnalyticsExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reviews/{review_id}/publish-reply":{"post":{"tags":["Reviews"],"summary":"Publish an AI-authored review reply","description":"Publish a previously-generated auto-review (AI-authored host-to-guest reply) to the upstream OTA (currently Airbnb only).\n\n``review_id`` is the **auto-review** ID returned by the internal auto-reviews pipeline — not a guest ``Review`` ID. A review whose auto-review row has not been generated yet cannot be published via this endpoint; call the auto-reviews workflow first or wait for the post-checkout scheduled generation to run.\n\nThe auto-review must be in ``scheduled`` state. The call is synchronous: it returns once the OTA write has been attempted and the row's status has been updated to ``published`` or ``skipped``.","operationId":"publish_review_reply_v1_reviews__review_id__publish_reply_post","parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Review Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoReview"}}}},"400":{"description":"Review already published, host review not found, or auto-review in wrong state."},"403":{"description":"Missing ``reviews:write`` scope or listing not in scope."},"404":{"description":"Auto-review not found."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reviews/{review_id}":{"patch":{"tags":["Reviews"],"summary":"Edit a review you added","description":"Change the fields you send on a review added by hand. A review synced from a connection is refused.","operationId":"update_review_v1_reviews__review_id__patch","parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Review Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalReviewContent"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewExternal"}}}},"403":{"description":"Missing ``reviews:write`` scope or listing not in scope."},"404":{"description":"Listing or review not found (``code``: ``listing_not_found`` / ``review_not_found``)."},"409":{"description":"Refused: ``stay_has_review``, ``duplicate_external_id`` (``review_id`` names the existing one), ``channel_synced`` (Airbnb reviews on an Airbnb-connected listing sync on their own), or ``review_not_external`` (a synced review can't be changed)."},"422":{"description":"Invalid: ``rating_out_of_range``, ``stay_not_found``, ``confirmation_code_ambiguous``, ``channel_mismatch`` or ``field_required``."}}},"delete":{"tags":["Reviews"],"summary":"Delete a review you added","description":"Delete a review added by hand. A review synced from a connection is refused.","operationId":"delete_review_v1_reviews__review_id__delete","parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Review Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"403":{"description":"Missing ``reviews:write`` scope or listing not in scope."},"404":{"description":"Listing or review not found (``code``: ``listing_not_found`` / ``review_not_found``)."},"409":{"description":"Refused: ``stay_has_review``, ``duplicate_external_id`` (``review_id`` names the existing one), ``channel_synced`` (Airbnb reviews on an Airbnb-connected listing sync on their own), or ``review_not_external`` (a synced review can't be changed)."},"422":{"description":"Invalid: ``rating_out_of_range``, ``stay_not_found``, ``confirmation_code_ambiguous``, ``channel_mismatch`` or ``field_required``."}}}},"/v1/guidebooks":{"get":{"tags":["Guidebooks"],"summary":"List guidebooks","description":"Retrieve a paginated list of guidebooks for the account, with optional filters by listing and text search.","operationId":"list_guidebooks_v1_guidebooks_get","parameters":[{"name":"listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by listing ID","title":"Listing Id"},"description":"Filter by listing ID"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by title","title":"Search"},"description":"Search by title"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list using the offset envelope (`items`, `total`, `limit`, `offset`, `has_more`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffsetPage_GuidebookExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Guidebooks"],"summary":"Create a guidebook","description":"Create a new guidebook attached to a listing. Unlike the internal endpoint, this does NOT seed default sections or upgrade options — use the section + upgrade-option endpoints to populate the guidebook.","operationId":"create_guidebook_v1_guidebooks_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/tag-sections":{"get":{"tags":["Guidebooks"],"summary":"List tag-scoped sections","description":"List every tag-scoped section that renders through a listing tag — sections whose primary `listing_tag_id` is the tag and sections linked to it via `additional_tag_ids` — with their sub-sections. Roots come first.","operationId":"list_tag_sections_v1_guidebooks_tag_sections_get","parameters":[{"name":"listing_tag_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"Listing tag to list sections for.","title":"Listing Tag Id"},"description":"Listing tag to list sections for."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagSectionsListResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Guidebooks"],"summary":"Create a tag-scoped section","description":"Create a section attached to a listing tag. Tag-scoped sections are inherited by every guidebook on a listing carrying that tag.","operationId":"create_tag_section_v1_guidebooks_tag_sections_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagSectionCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}":{"get":{"tags":["Guidebooks"],"summary":"Get a guidebook","description":"Retrieve a single guidebook by its ID: its own `sections` plus the tag-scoped `shared_sections` it inherits from its listing's tags.","operationId":"get_guidebook_v1_guidebooks__guidebook_id__get","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookDetailExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Guidebooks"],"summary":"Update a guidebook","description":"Patch one or more fields on a guidebook. Only fields present in the body are applied. Reassigning ``listing_id`` is allowed but the new listing must be reachable by the API key.","operationId":"update_guidebook_v1_guidebooks__guidebook_id__put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/sections":{"post":{"tags":["Guidebooks"],"summary":"Create a section","description":"Create a guidebook-scoped section. ``parent_id`` nests under another section.","operationId":"create_section_v1_guidebooks__guidebook_id__sections_post","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Guidebooks"],"summary":"List a guidebook's sections","description":"List the guidebook's own `sections` and the tag-scoped `shared_sections` it inherits from its listing's tags.","operationId":"list_sections_v1_guidebooks__guidebook_id__sections_get","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionsListResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/sections/reorder":{"put":{"tags":["Guidebooks"],"summary":"Reorder sections","description":"Bulk-update section positions and parent relationships.","operationId":"reorder_sections_v1_guidebooks__guidebook_id__sections_reorder_put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"title":"Response Reorder Sections V1 Guidebooks  Guidebook Id  Sections Reorder Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/sections/{section_id}":{"put":{"tags":["Guidebooks"],"summary":"Update a section","description":"Patch fields on a guidebook-scoped section.","operationId":"update_section_v1_guidebooks__guidebook_id__sections__section_id__put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"section_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Guidebooks"],"summary":"Delete a section","description":"Move a guidebook-scoped section (and its sub-sections) to the trash and shift sibling positions. The section stops appearing everywhere immediately; the account owner can restore it, with its edit history, from the ProhostAI app.","operationId":"delete_section_v1_guidebooks__guidebook_id__sections__section_id__delete","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"section_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/tag-sections/reorder":{"put":{"tags":["Guidebooks"],"summary":"Reorder tag-scoped sections","description":"Bulk-update positions of sections inside a single listing-tag scope.","operationId":"reorder_tag_sections_v1_guidebooks_tag_sections_reorder_put","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagSectionReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"title":"Response Reorder Tag Sections V1 Guidebooks Tag Sections Reorder Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/tag-sections/{section_id}":{"put":{"tags":["Guidebooks"],"summary":"Update a tag-scoped section","description":"Patch fields on a tag-scoped section.","operationId":"update_tag_section_v1_guidebooks_tag_sections__section_id__put","parameters":[{"name":"section_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagSectionUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Guidebooks"],"summary":"Delete a tag-scoped section","description":"Move a tag-scoped section (and its sub-sections) to the trash. It disappears from every guidebook the tag renders into; the account owner can restore it, with its edit history, from the ProhostAI app.","operationId":"delete_tag_section_v1_guidebooks_tag_sections__section_id__delete","parameters":[{"name":"section_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/sections/{section_id}/move-scope":{"put":{"tags":["Guidebooks"],"summary":"Move a section between guidebook and tag scopes","description":"Move a section between guidebook-scoped and tag-scoped (XOR).","operationId":"move_section_scope_v1_guidebooks_sections__section_id__move_scope_put","parameters":[{"name":"section_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveSectionScopeExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/mystay-section-order":{"put":{"tags":["Guidebooks"],"summary":"Update the My Stay section order","description":"Set the order in which sections appear on the My Stay tab of the guidebook.","operationId":"update_mystay_section_order_v1_guidebooks__guidebook_id__mystay_section_order_put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyStaySectionOrderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/upgrade-options":{"post":{"tags":["Guidebooks"],"summary":"Create an upgrade option","description":"Create a paid upgrade (e.g. early check-in) attached to a guidebook.","operationId":"create_upgrade_option_v1_guidebooks__guidebook_id__upgrade_options_post","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookUpgradeOptionCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookUpgradeOptionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Guidebooks"],"summary":"List upgrade options","description":"List the upgrade options attached to a guidebook.","operationId":"list_upgrade_options_v1_guidebooks__guidebook_id__upgrade_options_get","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GuidebookUpgradeOptionExternal"},"title":"Response List Upgrade Options V1 Guidebooks  Guidebook Id  Upgrade Options Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/upgrade-options/{upgrade_option_id}":{"put":{"tags":["Guidebooks"],"summary":"Update an upgrade option","description":"Patch fields on an existing upgrade option.","operationId":"update_upgrade_option_v1_guidebooks__guidebook_id__upgrade_options__upgrade_option_id__put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"upgrade_option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Upgrade Option Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookUpgradeOptionUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookUpgradeOptionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Guidebooks"],"summary":"Delete an upgrade option","description":"Delete an upgrade option from a guidebook.","operationId":"delete_upgrade_option_v1_guidebooks__guidebook_id__upgrade_options__upgrade_option_id__delete","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"upgrade_option_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Upgrade Option Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/images":{"post":{"tags":["Guidebooks"],"summary":"Get presigned URL for guidebook image upload","description":"Returns a presigned ``PUT`` URL for uploading a guidebook image directly to S3. After the PUT, embed the public form of the URL (the presigned URL minus its query string) in a section's markdown ``content``.","operationId":"create_guidebook_image_url_v1_guidebooks__guidebook_id__images_post","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookImageUrlRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookImageUrlResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/coding-sessions/callbacks/hook-events":{"post":{"tags":["coding-sessions"],"summary":"Coding Session Hook Event","description":"Accept one Claude Code hook event from a coding session's sandbox.","operationId":"coding_session_hook_event_v1_coding_sessions_callbacks_hook_events_post","responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/guidebooks/{guidebook_id}/pins":{"get":{"tags":["Guidebook Pins"],"summary":"List pins for a guidebook","description":"List guidebook-scoped pins plus tag-scoped pins inherited via the guidebook's listing tags.","operationId":"list_pins_for_guidebook_v1_guidebooks__guidebook_id__pins_get","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPinsResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Guidebook Pins"],"summary":"Pin a place to a guidebook","description":"Create a guidebook-scoped pin (path supplies the guidebook id).","operationId":"create_guidebook_pin_v1_guidebooks__guidebook_id__pins_post","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPinCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tag-pins":{"post":{"tags":["Guidebook Pins"],"summary":"Pin a place to a listing tag","description":"Create a tag-scoped pin. The pin is inherited by every guidebook on a listing carrying the tag. Account-wide mutation — listing-scoped API keys are rejected.","operationId":"create_tag_pin_v1_tag_pins_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagPinCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/pins/{pin_id}":{"put":{"tags":["Guidebook Pins"],"summary":"Update a pin","description":"Patch ``category``, ``position``, or ``host_note_override`` on a pin.","operationId":"update_pin_v1_pins__pin_id__put","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pin Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Guidebook Pins"],"summary":"Delete a pin","description":"Remove a pin (sub-resource — allowed even though guidebook delete is not).","operationId":"delete_pin_v1_pins__pin_id__delete","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pin Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/pins/{pin_id}/move-scope":{"put":{"tags":["Guidebook Pins"],"summary":"Move a pin between guidebook and tag scope","description":"Move a pin to a different guidebook OR to a listing tag. Exactly one of ``target_guidebook_id`` / ``target_listing_tag_id`` must be set.","operationId":"move_pin_scope_v1_pins__pin_id__move_scope_put","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pin Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinMoveScopeExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/guidebooks/{guidebook_id}/pins/reorder":{"put":{"tags":["Guidebook Pins"],"summary":"Reorder pins within a guidebook","description":"Bulk-update positions of guidebook-scoped pins.","operationId":"reorder_guidebook_pins_v1_guidebooks__guidebook_id__pins_reorder_put","parameters":[{"name":"guidebook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Guidebook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidebookPinReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"},"title":"Response Reorder Guidebook Pins V1 Guidebooks  Guidebook Id  Pins Reorder Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tag-pins/reorder":{"put":{"tags":["Guidebook Pins"],"summary":"Reorder pins within a listing tag","description":"Bulk-update positions of tag-scoped pins.","operationId":"reorder_tag_pins_v1_tag_pins_reorder_put","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagPinReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"},"title":"Response Reorder Tag Pins V1 Tag Pins Reorder Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places":{"post":{"tags":["Places"],"summary":"Create a place","description":"Create a new place (recommendation, vendor, point of interest).","operationId":"create_place_v1_places_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Places"],"summary":"List places","description":"List places for the account with optional filters.","operationId":"list_places_v1_places_get","parameters":[{"name":"listing_tag_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PlacePinCategory"},{"type":"null"}],"title":"Category"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Q"}},{"name":"has_google_id","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Google Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlaceExternal"},"title":"Response List Places V1 Places Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/google/autocomplete":{"get":{"tags":["Places"],"summary":"Google Places autocomplete","description":"Server-side proxy to Google Places Autocomplete (v1). Pass ``near_listing_id`` to bias results to a listing's location.","operationId":"autocomplete_places_v1_places_google_autocomplete_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"title":"Q"}},{"name":"session_token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Token"}},{"name":"near_listing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Near Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceAutocompleteResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/google/details":{"post":{"tags":["Places"],"summary":"Google Places details","description":"Server-side proxy to Google Places Details (v1). Result is NOT persisted; use the response to seed a ``POST /v1/places`` call.","operationId":"fetch_place_details_v1_places_google_details_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceDetailsRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceDetailsResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/{place_id}":{"get":{"tags":["Places"],"summary":"Get a place","description":"Retrieve a single place by ID.","operationId":"get_place_v1_places__place_id__get","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Places"],"summary":"Update a place","description":"Patch fields on a place. Only fields present in the body are applied. Pass ``null`` to clear a nullable field.","operationId":"update_place_v1_places__place_id__put","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Places"],"summary":"Delete a place","description":"Delete a place and (via cascade) every pin and tag association that references it.","operationId":"delete_place_v1_places__place_id__delete","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/{place_id}/photo":{"post":{"tags":["Places"],"summary":"Get presigned URL for place photo upload","description":"Returns a presigned ``PUT`` URL for uploading a place photo directly to S3. The frontend then PATCHes the place's ``photo_url`` with the public form of the URL via ``PUT /v1/places/{id}``.","operationId":"create_place_photo_url_v1_places__place_id__photo_post","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacePhotoUrlRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacePhotoUrlResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/{place_id}/tags":{"post":{"tags":["Places"],"summary":"Associate a place with a listing tag","description":"Attach a listing tag to a place (idempotent).","operationId":"associate_place_with_tag_v1_places__place_id__tags_post","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceTagAssociationCreateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlaceTagInfoExternal"},"title":"Response Associate Place With Tag V1 Places  Place Id  Tags Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Places"],"summary":"List a place's tag associations","description":"List the listing tags attached to a place.","operationId":"list_place_tags_v1_places__place_id__tags_get","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlaceTagInfoExternal"},"title":"Response List Place Tags V1 Places  Place Id  Tags Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/places/{place_id}/tags/{listing_tag_id}":{"delete":{"tags":["Places"],"summary":"Remove a tag association from a place","description":"Detach a listing tag from a place (idempotent).","operationId":"disassociate_place_from_tag_v1_places__place_id__tags__listing_tag_id__delete","parameters":[{"name":"place_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Place Id"}},{"name":"listing_tag_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Tag Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlaceTagInfoExternal"},"title":"Response Disassociate Place From Tag V1 Places  Place Id  Tags  Listing Tag Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/integrations/pricelabs/status":{"get":{"tags":["PriceLabs"],"summary":"PriceLabs integration status","description":"Whether PriceLabs is connected, the last test result, and the PMS the account routes through.","operationId":"get_pricelabs_status_v1_integrations_pricelabs_status_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/integrations/pricelabs/test-connection":{"post":{"tags":["PriceLabs"],"summary":"Test the PriceLabs connection","description":"Issues a single ``get_all_listings`` call against PriceLabs to verify credentials.","operationId":"test_pricelabs_connection_v1_integrations_pricelabs_test_connection_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsTestConnectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/integrations/pricelabs/listings/mapping":{"get":{"tags":["PriceLabs"],"summary":"Listing mapping between ProhostAI and PriceLabs","operationId":"get_pricelabs_mapping_v1_integrations_pricelabs_listings_mapping_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsMappingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricelabs":{"get":{"tags":["PriceLabs"],"summary":"PriceLabs metadata for a single listing","operationId":"get_listing_pricelabs_v1_listings__listing_id__pricelabs_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsListingDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/integrations/pricelabs/listings/{listing_id}/manual-link":{"post":{"tags":["PriceLabs"],"summary":"Manually link a ProhostAI listing to a PriceLabs listing","operationId":"manual_link_pricelabs_v1_integrations_pricelabs_listings__listing_id__manual_link_post","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsManualLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsManualLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricing/min-base-max":{"get":{"tags":["PriceLabs"],"summary":"Get the min/base/max for a listing on PriceLabs","operationId":"get_listing_min_base_max_v1_listings__listing_id__pricing_min_base_max_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MinBaseMaxResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["PriceLabs"],"summary":"Update the min/base/max for a listing on PriceLabs","operationId":"update_listing_min_base_max_v1_listings__listing_id__pricing_min_base_max_put","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MinBaseMaxUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MinBaseMaxResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricing/recommendations":{"get":{"tags":["PriceLabs"],"summary":"Get PriceLabs recommended prices for a listing","operationId":"get_listing_recommendations_v1_listings__listing_id__pricing_recommendations_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO date (inclusive)","title":"Date From"},"description":"ISO date (inclusive)"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO date (inclusive)","title":"Date To"},"description":"ISO date (inclusive)"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingRecommendationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricing/overrides":{"get":{"tags":["PriceLabs"],"summary":"List date-specific price overrides","operationId":"list_listing_overrides_v1_listings__listing_id__pricing_overrides_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingOverridesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["PriceLabs"],"summary":"Upsert date-specific price overrides","operationId":"upsert_listing_overrides_v1_listings__listing_id__pricing_overrides_post","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingOverrideUpsertRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingOverrideUpsertResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["PriceLabs"],"summary":"Delete date-specific price overrides","operationId":"delete_listing_overrides_v1_listings__listing_id__pricing_overrides_delete","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingOverrideDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingOverrideDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricing/neighborhood":{"get":{"tags":["PriceLabs"],"summary":"Get neighborhood pricing data for a listing","operationId":"get_listing_neighborhood_v1_listings__listing_id__pricing_neighborhood_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeighborhoodResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/listings/{listing_id}/pricing/rate-plans":{"get":{"tags":["PriceLabs"],"summary":"Get rate plans for a listing","operationId":"get_listing_rate_plans_v1_listings__listing_id__pricing_rate_plans_get","parameters":[{"name":"listing_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Listing Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatePlansResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connections/pricelabs":{"post":{"tags":["PriceLabs"],"summary":"Create a PriceLabs connection","description":"Persists an encrypted PriceLabs API key. Validates the key with a test ``get_all_listings`` call before commit. Blocks accounts with no PMS connection — PriceLabs requires the ``pms`` field on every request.","operationId":"create_pricelabs_connection_v1_connections_pricelabs_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsConnectionCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceLabsConnectionCreatedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","description":"Retrieve a paginated list of contacts for the account, with optional search by name/email/company and filter by role.","operationId":"list_contacts_v1_contacts_get","parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by name, email, or company","title":"Search"},"description":"Search by name, email, or company"},{"name":"role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by role","title":"Role"},"description":"Filter by role"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0).","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor; when cursor is provided, offset must be 0)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When provided, `offset` must remain 0."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list. Without `?cursor` the legacy offset envelope is returned (`items`, `total`, `limit`, `offset`, `has_more`); when `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`). `items`, `limit` and `has_more` are always present; the remaining fields depend on which mode you request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ContactExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Contacts"],"summary":"Create a contact","description":"Create a new contact record for the account.","operationId":"create_contact_v1_contacts_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts/{contact_id}":{"get":{"tags":["Contacts"],"summary":"Get a contact","description":"Retrieve a single contact by their ID.","operationId":"get_contact_v1_contacts__contact_id__get","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Contacts"],"summary":"Update a contact","description":"Update an existing contact. Only provided fields are written.","operationId":"update_contact_v1_contacts__contact_id__patch","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Contacts"],"summary":"Delete a contact","description":"Delete a contact and cascade to its listing associations. Returns 404 if the contact does not exist — clients implementing retry-after-timeout should tolerate 404 as a \"successful prior call\" signal. Returns 409 with error code `contact_has_records` when the contact is referenced by records that must be kept, such as orders; delete or reassign those first.","operationId":"delete_contact_v1_contacts__contact_id__delete","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts/{contact_id}/photo_url":{"post":{"tags":["Contacts"],"summary":"Generate a presigned upload URL for a contact's photo","description":"Returns a presigned S3 PUT URL the client should upload the photo bytes to. The eventual public URL settles at ``s3://<bucket>/accounts/<account_id>/contacts/<contact_id>/photo``.","operationId":"create_contact_photo_upload_url_v1_contacts__contact_id__photo_url_post","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPhotoUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPhotoUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts/{contact_id}/custom-fields":{"get":{"tags":["Contacts"],"summary":"Get contact custom fields","description":"Return the resolved custom-field values for a contact, with provenance. Merge order: account → contact. Contact-level values win on conflict.","operationId":"get_contact_custom_fields_v1_contacts__contact_id__custom_fields_get","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsResolved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts/custom-fields/batch":{"post":{"tags":["Contacts"],"summary":"Batch-set contact custom fields","description":"Merge ``fields`` into ``custom_fields`` on every contact in ``ids``. Listing-scoped API keys cannot use this endpoint.","operationId":"batch_set_contact_custom_fields_v1_contacts_custom_fields_batch_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchSetRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/contacts/custom-fields/batch/delete":{"post":{"tags":["Contacts"],"summary":"Batch-delete contact custom-field keys","description":"Remove the named keys from ``custom_fields`` on every contact in ``ids``.","operationId":"batch_delete_contact_custom_fields_v1_contacts_custom_fields_batch_delete_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldsBatchResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/opportunities":{"get":{"tags":["CRM"],"summary":"List opportunities","description":"List opportunities for the account, with optional pipeline / stage / status filters and a title search.","operationId":"list_opportunities_v1_crm_opportunities_get","parameters":[{"name":"pipeline_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by pipeline","title":"Pipeline Id"},"description":"Filter by pipeline"},{"name":"stage_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by stage","title":"Stage Id"},"description":"Filter by stage"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status (open, won, lost)","title":"Status"},"description":"Filter by status (open, won, lost)"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive title search","title":"Q"},"description":"Case-insensitive title search"},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived opportunities","default":false,"title":"Include Archived"},"description":"Include archived opportunities"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":100,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OpportunityExternal"},"title":"Response List Opportunities V1 Crm Opportunities Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Create an opportunity","operationId":"create_opportunity_v1_crm_opportunities_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/opportunities/{opportunity_id}":{"get":{"tags":["CRM"],"summary":"Get an opportunity","operationId":"get_opportunity_v1_crm_opportunities__opportunity_id__get","parameters":[{"name":"opportunity_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Opportunity Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["CRM"],"summary":"Update an opportunity","operationId":"update_opportunity_v1_crm_opportunities__opportunity_id__patch","parameters":[{"name":"opportunity_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Opportunity Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Archive an opportunity","description":"Soft-archive an opportunity (sets archived_at; the row is preserved).","operationId":"archive_opportunity_v1_crm_opportunities__opportunity_id__delete","parameters":[{"name":"opportunity_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Opportunity Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/opportunities/{opportunity_id}/move":{"post":{"tags":["CRM"],"summary":"Move an opportunity to a stage + position","description":"Move a card to a stage and position. Entering a won/lost stage stamps status + closed_at; moving back to an open stage reopens it.","operationId":"move_opportunity_v1_crm_opportunities__opportunity_id__move_post","parameters":[{"name":"opportunity_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Opportunity Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityMoveExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines":{"get":{"tags":["CRM"],"summary":"List pipelines","operationId":"list_pipelines_v1_crm_pipelines_get","parameters":[{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived pipelines","default":false,"title":"Include Archived"},"description":"Include archived pipelines"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PipelineExternal"},"title":"Response List Pipelines V1 Crm Pipelines Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Create a pipeline","operationId":"create_pipeline_v1_crm_pipelines_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines/from-template":{"post":{"tags":["CRM"],"summary":"Create a pipeline from a template","description":"Clone a gallery blueprint (stages + suggested fields + one sample card) into the account.","operationId":"create_pipeline_from_template_v1_crm_pipelines_from_template_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineFromTemplateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines/{pipeline_id}":{"get":{"tags":["CRM"],"summary":"Get a pipeline","operationId":"get_pipeline_v1_crm_pipelines__pipeline_id__get","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pipeline Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["CRM"],"summary":"Update a pipeline","operationId":"update_pipeline_v1_crm_pipelines__pipeline_id__patch","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pipeline Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Archive a pipeline","operationId":"archive_pipeline_v1_crm_pipelines__pipeline_id__delete","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pipeline Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines/reorder":{"post":{"tags":["CRM"],"summary":"Reorder pipelines","operationId":"reorder_pipelines_v1_crm_pipelines_reorder_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PipelineExternal"},"title":"Response Reorder Pipelines V1 Crm Pipelines Reorder Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines/{pipeline_id}/stages":{"post":{"tags":["CRM"],"summary":"Create a stage","operationId":"create_stage_v1_crm_pipelines__pipeline_id__stages_post","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pipeline Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StageCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StageExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/stages/{stage_id}":{"patch":{"tags":["CRM"],"summary":"Update a stage","operationId":"update_stage_v1_crm_stages__stage_id__patch","parameters":[{"name":"stage_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Stage Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StageUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StageExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Delete a stage","description":"Delete an empty stage. A stage holding live opportunities returns 409 — move or archive them first.","operationId":"delete_stage_v1_crm_stages__stage_id__delete","parameters":[{"name":"stage_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Stage Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/pipelines/{pipeline_id}/stages/reorder":{"post":{"tags":["CRM"],"summary":"Reorder stages within a pipeline","operationId":"reorder_stages_v1_crm_pipelines__pipeline_id__stages_reorder_post","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pipeline Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StageExternal"},"title":"Response Reorder Stages V1 Crm Pipelines  Pipeline Id  Stages Reorder Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/contacts":{"get":{"tags":["CRM"],"summary":"List contacts","operationId":"list_contacts_v1_crm_contacts_get","parameters":[{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived contacts","default":false,"title":"Include Archived"},"description":"Include archived contacts"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactExternal"},"title":"Response List Contacts V1 Crm Contacts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Create a contact","operationId":"create_contact_v1_crm_contacts_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/contacts/{contact_id}":{"get":{"tags":["CRM"],"summary":"Get a contact","operationId":"get_contact_v1_crm_contacts__contact_id__get","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["CRM"],"summary":"Update a contact","operationId":"update_contact_v1_crm_contacts__contact_id__patch","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Archive a contact","operationId":"archive_contact_v1_crm_contacts__contact_id__delete","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/companies":{"get":{"tags":["CRM"],"summary":"List companies","operationId":"list_companies_v1_crm_companies_get","parameters":[{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived companies","default":false,"title":"Include Archived"},"description":"Include archived companies"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompanyExternal"},"title":"Response List Companies V1 Crm Companies Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Create a company","operationId":"create_company_v1_crm_companies_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/companies/{company_id}":{"get":{"tags":["CRM"],"summary":"Get a company","operationId":"get_company_v1_crm_companies__company_id__get","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Company Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["CRM"],"summary":"Update a company","operationId":"update_company_v1_crm_companies__company_id__patch","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Company Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Archive a company","operationId":"archive_company_v1_crm_companies__company_id__delete","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Company Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/comments":{"get":{"tags":["CRM"],"summary":"List comments on an object","description":"List comments attached to a CRM object (opportunity / contact / company), oldest first.","operationId":"list_comments_v1_crm_comments_get","parameters":[{"name":"object_type","in":"query","required":true,"schema":{"$ref":"#/components/schemas/CrmCommentObjectType","description":"The commented object's type"},"description":"The commented object's type"},{"name":"object_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"The commented object's id","title":"Object Id"},"description":"The commented object's id"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CommentExternal"},"title":"Response List Comments V1 Crm Comments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Add a comment to an object","operationId":"create_comment_v1_crm_comments_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/meetings":{"get":{"tags":["CRM"],"summary":"List meetings","operationId":"list_meetings_v1_crm_meetings_get","parameters":[{"name":"opportunity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by opportunity","title":"Opportunity Id"},"description":"Filter by opportunity"},{"name":"contact_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by contact","title":"Contact Id"},"description":"Filter by contact"},{"name":"company_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by company","title":"Company Id"},"description":"Filter by company"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":100,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MeetingExternal"},"title":"Response List Meetings V1 Crm Meetings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["CRM"],"summary":"Log a meeting","operationId":"create_meeting_v1_crm_meetings_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/meetings/{meeting_id}":{"get":{"tags":["CRM"],"summary":"Get a meeting","operationId":"get_meeting_v1_crm_meetings__meeting_id__get","parameters":[{"name":"meeting_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Meeting Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["CRM"],"summary":"Update a meeting","operationId":"update_meeting_v1_crm_meetings__meeting_id__patch","parameters":[{"name":"meeting_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Meeting Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["CRM"],"summary":"Delete a meeting","operationId":"delete_meeting_v1_crm_meetings__meeting_id__delete","parameters":[{"name":"meeting_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Meeting Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/opportunities/{opportunity_id}/custom-fields":{"put":{"tags":["CRM"],"summary":"Set custom-field values on an opportunity","operationId":"set_opportunity_custom_fields_v1_crm_opportunities__opportunity_id__custom_fields_put","parameters":[{"name":"opportunity_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Opportunity Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldValuesExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/contacts/{contact_id}/custom-fields":{"put":{"tags":["CRM"],"summary":"Set custom-field values on a contact","operationId":"set_contact_custom_fields_v1_crm_contacts__contact_id__custom_fields_put","parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Contact Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldValuesExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api_public__schemas__crm__ContactExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/crm/companies/{company_id}/custom-fields":{"put":{"tags":["CRM"],"summary":"Set custom-field values on a company","operationId":"set_company_custom_fields_v1_crm_companies__company_id__custom_fields_put","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Company Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldValuesExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/earnings/summary":{"get":{"tags":["Earnings"],"summary":"Get earnings summary","description":"Get an earnings report for the account within a date range, including payout totals, occupancy, nightly rates, and booking metrics.","operationId":"get_earnings_summary_v1_earnings_summary_get","parameters":[{"name":"date_start","in":"query","required":true,"schema":{"type":"string","format":"date","description":"Start date for the earnings report, inclusive","title":"Date Start"},"description":"Start date for the earnings report, inclusive"},{"name":"date_end","in":"query","required":true,"schema":{"type":"string","format":"date","description":"End date for the earnings report, inclusive","title":"Date End"},"description":"End date for the earnings report, inclusive"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarningsResponseExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage/summary":{"get":{"tags":["Usage"],"summary":"Get API usage summary","description":"Returns request counts for the specified date range. Default groups by (path, method). Pass `group_by=day` to also receive a day-bucketed time-series and a status-code breakdown.","operationId":"get_usage_summary_v1_usage_summary_get","parameters":[{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"Start date (inclusive, UTC)","title":"Start Date"},"description":"Start date (inclusive, UTC)"},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"End date (inclusive, UTC)","title":"End Date"},"description":"End date (inclusive, UTC)"},{"name":"key_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter by specific API key","title":"Key Id"},"description":"Filter by specific API key"},{"name":"group_by","in":"query","required":false,"schema":{"anyOf":[{"enum":["path","day"],"type":"string"},{"type":"null"}],"description":"`path` (default) groups by (path, method). `day` additionally returns a zero-filled day-bucketed time-series.","title":"Group By"},"description":"`path` (default) groups by (path, method). `day` additionally returns a zero-filled day-bucketed time-series."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage/reports":{"post":{"tags":["Usage"],"summary":"Report this machine's Claude Code / Codex accounts and their capacity","description":"``accepted: 0`` when the machine reported less than 30 seconds ago (nothing is stored).","operationId":"post_cli_usage_report_v1_usage_reports_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliUsageReport"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageAccepted"}}}},"403":{"description":"Missing scope, or Usage Monitor is not enabled for this workspace."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage/token-totals":{"post":{"tags":["Usage"],"summary":"Report daily token totals per account, model and project","description":"Each row replaces the stored row with the same machine, account, day, model and project.\n\nA (day, account) pair listed in ``completeDays`` is replaced whole: this\nmachine's other rows for it are deleted first, and ``replacedDays`` counts\nsuch pairs. Aggregates only — there is no field for prompt text. Days more\nthan a day ahead (UTC) or over 400 days old are skipped and not counted.","operationId":"post_cli_token_totals_v1_usage_token_totals_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenTotalsReport"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenTotalsAccepted"}}}},"403":{"description":"Missing scope, or Usage Monitor is not enabled for this workspace."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks":{"post":{"tags":["Webhooks"],"summary":"Create webhook subscription","description":"Create a new webhook subscription. The signing secret is returned once in the response — store it securely. Supports ``?dry_run=true`` — validates URL + event types and returns the subscription that *would* be created, with a placeholder secret, without persisting.","operationId":"create_subscription_v1_webhooks_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionCreate"},"examples":{"all_events":{"summary":"Subscribe to all supported events","description":"Firehose: receive every event type emitted by ProhostAI (excluding the auto-fired webhook.verification).","value":{"url":"https://example.com/hooks/prohost-firehose","events":["reservation.created","reservation.updated","reservation.cancelled","reservation.check_in","reservation.check_out","message.received","message.sent","message.team_chat","mention.created","message.support_thread","task.created","task.updated","task.commented","cleaning.created","cleaning.updated","cleaning.completed","guest.created","guest_form.submitted","review.received","review.replied","autopilot.escalation","autopilot.reply_sent","smart_device.alert","customer_feedback.submitted","expense.created","agent.approval_requested","agent.approval_resolved","crm.opportunity.created","crm.opportunity.updated","crm.opportunity.moved","crm.opportunity.won","crm.opportunity.lost","crm.opportunity.archived","crm.contact.created","crm.company.created","crm.meeting.logged","crm.comment.added","recruiting.application.created","recruiting.application.moved","recruiting.application.hired","recruiting.application.rejected","recruiting.interview.completed","recruiting.scorecard.submitted","recruiting.offer.sent","recruiting.offer.accepted","recruiting.offer.declined"],"description":"All events — for full mirror / observability"}},"autopilot_escalation":{"summary":"Subscribe to autopilot.escalation only","description":"Receive a webhook whenever autopilot hands a draft off to human review — bad sentiment, low confidence, or a category with autopilot disabled. Common pattern: route via a transformer (Zapier Catch Hook, n8n, Slack Workflow Builder, Lambda) into Slack/PagerDuty/oncall so the on-call sees the conversation, draft reply, and reason without opening the dashboard. Slack's native ``hooks.slack.com`` endpoint expects ``{text}``/``{blocks}`` and won't accept the ProhostAI envelope directly — always front it with a transformer.","value":{"url":"https://transformer.example/hooks/prohostai-zapier-catch","events":["autopilot.escalation"],"description":"Forward autopilot escalations to #host-oncall via Zapier"}},"only_reservation_created":{"summary":"Subscribe to reservation.created only","description":"Fired when a new reservation is ingested from a connected channel or created in ProhostAI (the app or ``POST /v1/reservations``). A booking your own credential created is not sent back to that credential's subscriptions. Payload is ``ReservationExternal``'s core fields plus ``source``, ``channel``, ``source_reservation_id`` and ``channel_reservation_id``.","value":{"url":"https://example.com/hooks/prohost","events":["reservation.created"],"description":"Receive reservation.created events"}},"only_reservation_updated":{"summary":"Subscribe to reservation.updated only","description":"Fired when a reservation's check-in/check-out, guest count, or status changes. Payload is ``ReservationExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["reservation.updated"],"description":"Receive reservation.updated events"}},"only_reservation_cancelled":{"summary":"Subscribe to reservation.cancelled only","description":"Fired when a reservation transitions into the ``cancelled`` status. Payload is ``ReservationExternal`` with ``status: 'cancelled'``.","value":{"url":"https://example.com/hooks/prohost","events":["reservation.cancelled"],"description":"Receive reservation.cancelled events"}},"only_reservation_check_in":{"summary":"Subscribe to reservation.check_in only","description":"Fired by the hourly ``reservation_lifecycle_events`` Hatchet cron on the calendar day the reservation's ``check_in_at`` falls into. Idempotent — fires at most once per reservation. Payload is ``ReservationExternal`` plus an ``event_at`` field pinning the canonical check-in timestamp.","value":{"url":"https://example.com/hooks/prohost","events":["reservation.check_in"],"description":"Receive reservation.check_in events"}},"only_reservation_check_out":{"summary":"Subscribe to reservation.check_out only","description":"Fired by the hourly ``reservation_lifecycle_events`` Hatchet cron on the calendar day the reservation's ``check_out_at`` falls into. Idempotent. Payload mirrors ``reservation.check_in``.","value":{"url":"https://example.com/hooks/prohost","events":["reservation.check_out"],"description":"Receive reservation.check_out events"}},"only_message_received":{"summary":"Subscribe to message.received only","description":"Fired when a guest message is ingested from an OTA inbox or SMS channel. ","value":{"url":"https://example.com/hooks/prohost","events":["message.received"],"description":"Receive message.received events"}},"only_message_sent":{"summary":"Subscribe to message.sent only","description":"Fired when a host or autopilot reply is delivered to the guest. Payload is the inline shape from ``api_public/routers/conversations.py``.","value":{"url":"https://example.com/hooks/prohost","events":["message.sent"],"description":"Receive message.sent events"}},"only_message_team_chat":{"summary":"Subscribe to message.team_chat only","description":"Fired when a message is posted to an internal team-chat thread (``ConversationChannel.internal``) — from a teammate, an AI agent, or an external API/MCP credential. Carries a bounded ``content_preview`` (not the full body) and a normalized ``mentions`` list. The echo guard skips delivering this back to a subscription created by the same credential that authored the message, so a write-and-subscribe integration doesn't loop.","value":{"url":"https://example.com/hooks/prohost","events":["message.team_chat"],"description":"Receive message.team_chat events"}},"only_mention_created":{"summary":"Subscribe to mention.created only","description":"Fired once per resolved participant when a team-chat message @-mentions them — a direct ``<@id>`` mention (``mention_type: 'user'``) or expanded from a group mention (``@here`` / ``@channel`` / ``@everyone``), always excluding the sender.","value":{"url":"https://example.com/hooks/prohost","events":["mention.created"],"description":"Receive mention.created events"}},"only_message_support_thread":{"summary":"Subscribe to message.support_thread only","description":"Fired for a message in a two-sided ProhostAI-support thread (``internal`` channel with ``business_purpose='prohost_support'``) — the internal support threads seeded in each customer account. Emitted under the ProhostAI **support** account (not the thread's home/customer account), so the internal support workspace's subscription receives it. Carries the full ``body``, the thread's ``home_account_id`` (customer account), and the sender identity. Same echo guard as ``message.team_chat`` — the support agent's own external-API reply doesn't loop back to its own subscription.","value":{"url":"https://example.com/hooks/prohost","events":["message.support_thread"],"description":"Receive message.support_thread events"}},"only_task_created":{"summary":"Subscribe to task.created only","description":"Fired when a maintenance/ops task is created. Payload is ``TaskExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["task.created"],"description":"Receive task.created events"}},"only_task_updated":{"summary":"Subscribe to task.updated only","description":"Fired when a task changes — status transition, assignee, due date, etc. Payload is ``TaskExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["task.updated"],"description":"Receive task.updated events"}},"only_task_commented":{"summary":"Subscribe to task.commented only","description":"Fired when a comment is posted on a task (from any writer — internal/public API or an AI employee). Payload carries ``task_id``, ``comment_id``, ``author`` (id/name), ``body``, ``created_at``.","value":{"url":"https://example.com/hooks/prohost","events":["task.commented"],"description":"Receive task.commented events"}},"only_cleaning_created":{"summary":"Subscribe to cleaning.created only","description":"Fired when a turnover cleaning is scheduled. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["cleaning.created"],"description":"Receive cleaning.created events"}},"only_cleaning_updated":{"summary":"Subscribe to cleaning.updated only","description":"Fired on cleaning status transitions and reassignment. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["cleaning.updated"],"description":"Receive cleaning.updated events"}},"only_cleaning_completed":{"summary":"Subscribe to cleaning.completed only","description":"Fires only on the not-completed → completed transition for a cleaning. Distinct from ``cleaning.updated`` (every-change emitter); both can fire for the same write — subscribe to ``cleaning.completed`` only if you want the completion signal alone. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","events":["cleaning.completed"],"description":"Receive cleaning.completed events"}},"only_guest_created":{"summary":"Subscribe to guest.created only","description":"Fired the first time a guest profile is created — typically alongside their first reservation.","value":{"url":"https://example.com/hooks/prohost","events":["guest.created"],"description":"Receive guest.created events"}},"only_guest_form_submitted":{"summary":"Subscribe to guest_form.submitted only","description":"Fired when a guest completes the Welcome Pass check-in form — the in-progress -> completed transition on ``welcome_pass_responses``. Distinct from the internal ``welcome_pass_completed`` workflow trigger (in-product automations only, never leaves the account): this outbound event carries the promoted check-in fields (``eta``, ``num_guests``, ``id_verification_status``, ``deposit_status``, …) plus the raw ``answers`` dict so integrators can push check-in form answers to a third-party system. Uploaded files (ID, selfie, file steps) appear as private-bucket key references — in ``answers`` as ``{\"key\", \"uploaded_at\"}`` and again under ``files`` — never as URLs; exchange a key for a short-lived download link with ``GET /v1/reservations/{id}/guest-form/file-url?key=…`` (``reservations:read``). ``GET /v1/reservations/{id}/guest-form`` returns the same payload on demand.","value":{"url":"https://example.com/hooks/prohost","events":["guest_form.submitted"],"description":"Receive guest_form.submitted events"}},"only_review_received":{"summary":"Subscribe to review.received only","description":"Fired when a guest review is ingested from any OTA (Airbnb, Hostaway, Hospitable, Guesty, etc.) — one event per upserted ``reviews`` row. Payload mirrors the ``Review`` model with category ratings flattened into a ``category_ratings`` sub-object.","value":{"url":"https://example.com/hooks/prohost","events":["review.received"],"description":"Receive review.received events"}},"only_review_replied":{"summary":"Subscribe to review.replied only","description":"Fired when an AI-generated host reply has been successfully posted back to the OTA via the auto-review publish path. Payload includes the body of the reply and the source review identifier.","value":{"url":"https://example.com/hooks/prohost","events":["review.replied"],"description":"Receive review.replied events"}},"only_autopilot_reply_sent":{"summary":"Subscribe to autopilot.reply_sent only","description":"Inverse branch of ``autopilot.escalation`` — fired when autopilot accepts a draft reply and schedules it for delivery. Payload includes the eventual ``scheduled_message_id`` + ``scheduled_at`` so receivers can correlate the eventual ``message.sent`` event. Useful for AI message audit trails.","value":{"url":"https://example.com/hooks/prohost","events":["autopilot.reply_sent"],"description":"Receive autopilot.reply_sent events"}},"only_smart_device_alert":{"summary":"Subscribe to smart_device.alert only","description":"Fired by the Seam smart-device ingest path for high-signal alert events (currently ``noise_sensor.noise_threshold_triggered`` and ``lock.access_denied``). The ``alert_type`` field on the payload echoes the upstream Seam event type so receivers can branch.","value":{"url":"https://example.com/hooks/prohost","events":["smart_device.alert"],"description":"Receive smart_device.alert events"}},"only_customer_feedback_submitted":{"summary":"Subscribe to customer_feedback.submitted only","description":"Fired when a host or guest submits feedback through the in-app form, the MCP tool, or the AI chat bug-report tool. Payload mirrors the ``CustomerFeedback`` row.","value":{"url":"https://example.com/hooks/prohost","events":["customer_feedback.submitted"],"description":"Receive customer_feedback.submitted events"}},"only_expense_created":{"summary":"Subscribe to expense.created only","description":"Fired when a new expense is created via the public or internal API. Payload mirrors the ``Expense`` row — amount is a decimal string for precision.","value":{"url":"https://example.com/hooks/prohost","events":["expense.created"],"description":"Receive expense.created events"}},"only_agent_approval_requested":{"summary":"Subscribe to agent.approval_requested only","description":"Fired when an AI employee escalates an action to a human — i.e. when a request lands in the Pending Approvals queue (an ``ai_agent_approval_requests`` row is persisted). Payload mirrors the approval row: agent id + name, ``action_kind``, title/description, ``risk_level``, ``status: 'pending'``. Common pattern: route to Slack/WhatsApp so a human can approve from their notification surface.","value":{"url":"https://example.com/hooks/prohost","events":["agent.approval_requested"],"description":"Receive agent.approval_requested events"}},"only_agent_approval_resolved":{"summary":"Subscribe to agent.approval_resolved only","description":"Fired when a pending AI-employee approval reaches a terminal state. ``status`` carries ``approved`` / ``rejected`` / ``expired``; ``responded_at`` / ``responded_by_user_id`` / ``rejection_reason`` describe the resolution. Pairs with ``agent.approval_requested`` via the shared ``id``.","value":{"url":"https://example.com/hooks/prohost","events":["agent.approval_resolved"],"description":"Receive agent.approval_resolved events"}},"only_crm_opportunity_created":{"summary":"Subscribe to crm.opportunity.created only","description":"Fired when a CRM opportunity (deal card) is created. Payload is the partner-safe opportunity shape — ids, title, pipeline/stage, status, value, contact/company.","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.created"],"description":"Receive crm.opportunity.created events"}},"only_crm_opportunity_updated":{"summary":"Subscribe to crm.opportunity.updated only","description":"Fired when an opportunity's fields change (title, value, contact/company, custom fields). NOT fired for stage moves (``crm.opportunity.moved``) or archival (``crm.opportunity.archived``).","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.updated"],"description":"Receive crm.opportunity.updated events"}},"only_crm_opportunity_moved":{"summary":"Subscribe to crm.opportunity.moved only","description":"Fired when an opportunity moves to a different stage. When the move flips the card won/lost, the matching ``crm.opportunity.won`` / ``crm.opportunity.lost`` fires alongside this event.","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.moved"],"description":"Receive crm.opportunity.moved events"}},"only_crm_opportunity_won":{"summary":"Subscribe to crm.opportunity.won only","description":"Fired only on the transition into a won stage (status open → won). The payload carries ``status: 'won'`` and the ``closed_at`` timestamp.","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.won"],"description":"Receive crm.opportunity.won events"}},"only_crm_opportunity_lost":{"summary":"Subscribe to crm.opportunity.lost only","description":"Fired only on the transition into a lost stage (status open → lost). The payload carries ``status: 'lost'``, an optional ``lost_reason``, and ``closed_at``.","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.lost"],"description":"Receive crm.opportunity.lost events"}},"only_crm_opportunity_archived":{"summary":"Subscribe to crm.opportunity.archived only","description":"Fired when an opportunity is archived (soft-deleted off the board). The payload carries the ``archived_at`` timestamp.","value":{"url":"https://example.com/hooks/prohost","events":["crm.opportunity.archived"],"description":"Receive crm.opportunity.archived events"}},"only_crm_contact_created":{"summary":"Subscribe to crm.contact.created only","description":"Fired when a CRM contact is created. Payload includes name, email, phone, title, and the linked company id.","value":{"url":"https://example.com/hooks/prohost","events":["crm.contact.created"],"description":"Receive crm.contact.created events"}},"only_crm_company_created":{"summary":"Subscribe to crm.company.created only","description":"Fired when a CRM company is created. Payload includes name, domain, and type.","value":{"url":"https://example.com/hooks/prohost","events":["crm.company.created"],"description":"Receive crm.company.created events"}},"only_crm_meeting_logged":{"summary":"Subscribe to crm.meeting.logged only","description":"Fired when a meeting or call is logged against an opportunity, contact, or company. Payload includes scheduling/actual timestamps, source, and outcome.","value":{"url":"https://example.com/hooks/prohost","events":["crm.meeting.logged"],"description":"Receive crm.meeting.logged events"}},"only_crm_comment_added":{"summary":"Subscribe to crm.comment.added only","description":"Fired when a comment is posted on any CRM object. Payload carries the ``object_type`` / ``object_id`` the comment targets and the comment body.","value":{"url":"https://example.com/hooks/prohost","events":["crm.comment.added"],"description":"Receive crm.comment.added events"}},"only_recruiting_application_created":{"summary":"Subscribe to recruiting.application.created only","description":"Fired when a candidate applies to a job — from the careers form, an AI tool, or the API. Once per candidate/job pair: a re-application returns the existing record and fires nothing.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.application.created"],"description":"Receive recruiting.application.created events"}},"only_recruiting_application_moved":{"summary":"Subscribe to recruiting.application.moved only","description":"Fired when an application moves to a different pipeline stage. The move that lands it in the terminal Hired stage fires ``recruiting.application.hired`` alongside this event.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.application.moved"],"description":"Receive recruiting.application.moved events"}},"only_recruiting_application_hired":{"summary":"Subscribe to recruiting.application.hired only","description":"Fired when an application reaches the Hired stage. Derived from the stage's kind, never its name.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.application.hired"],"description":"Receive recruiting.application.hired events"}},"only_recruiting_application_rejected":{"summary":"Subscribe to recruiting.application.rejected only","description":"Fired when an application ends without a hire. Covers BOTH a rejection and a candidate withdrawal — ``status`` on the payload distinguishes them, and they should not be counted together.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.application.rejected"],"description":"Receive recruiting.application.rejected events"}},"only_recruiting_interview_completed":{"summary":"Subscribe to recruiting.interview.completed only","description":"Fired when an interview genuinely completes. Cancelled and no-show interviews end the interview internally but do NOT fire this event.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.interview.completed"],"description":"Receive recruiting.interview.completed events"}},"only_recruiting_scorecard_submitted":{"summary":"Subscribe to recruiting.scorecard.submitted only","description":"Fired when an evaluator publishes their interview write-up to the hiring team. Carries the overall verdict; the written assessment is never included in the payload.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.scorecard.submitted"],"description":"Receive recruiting.scorecard.submitted events"}},"only_recruiting_offer_sent":{"summary":"Subscribe to recruiting.offer.sent only","description":"Fired when an offer is sent (or re-sent) to the candidate. Carries the offer's state and title; the offer body, the compensation package, and the candidate's view token are never included in the payload.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.offer.sent"],"description":"Receive recruiting.offer.sent events"}},"only_recruiting_offer_accepted":{"summary":"Subscribe to recruiting.offer.accepted only","description":"Fired when the candidate accepts the offer on the public offer page. Does NOT imply hired — a human marks the application hired, which fires ``recruiting.application.hired`` separately.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.offer.accepted"],"description":"Receive recruiting.offer.accepted events"}},"only_recruiting_offer_declined":{"summary":"Subscribe to recruiting.offer.declined only","description":"Fired when the candidate declines the offer on the public offer page. Carries their optional ``decline_reason``.","value":{"url":"https://example.com/hooks/prohost","events":["recruiting.offer.declined"],"description":"Receive recruiting.offer.declined events"}}}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Webhooks"],"summary":"List webhook subscriptions","description":"List all active webhook subscriptions for the account.","operationId":"list_subscriptions_v1_webhooks_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When set, response switches to the cursor envelope.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When set, response switches to the cursor envelope."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"By default a plain array of items (legacy contract). When `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`).","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscriptionExternal"}},{"$ref":"#/components/schemas/CursorPage_WebhookSubscriptionExternal_"}],"title":"Response 200 List Subscriptions V1 Webhooks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/events":{"get":{"tags":["Webhooks"],"summary":"List supported event types","description":"List every event name that can be subscribed to. The response is a flat list of strings to preserve the existing contract — for the full per-event payload shape see the ``POST /webhooks`` and ``POST /webhooks/test`` examples in this same OpenAPI document, which embed the canonical envelope for each event under ``schema_version: 1``. The catalog is also exposed in code at ``shared/events/examples.py::EXAMPLES``.","operationId":"list_events_v1_webhooks_events_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Sorted list of event names that can appear in a subscription's ``events`` array.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response List Events V1 Webhooks Events Get"},"examples":{"all_events":{"summary":"All supported events","value":["reservation.created","reservation.updated","reservation.cancelled","reservation.check_in","reservation.check_out","message.received","message.sent","message.team_chat","mention.created","message.support_thread","task.created","task.updated","task.commented","cleaning.created","cleaning.updated","cleaning.completed","guest.created","guest_form.submitted","review.received","review.replied","autopilot.escalation","autopilot.reply_sent","smart_device.alert","customer_feedback.submitted","expense.created","agent.approval_requested","agent.approval_resolved","crm.opportunity.created","crm.opportunity.updated","crm.opportunity.moved","crm.opportunity.won","crm.opportunity.lost","crm.opportunity.archived","crm.contact.created","crm.company.created","crm.meeting.logged","crm.comment.added","recruiting.application.created","recruiting.application.moved","recruiting.application.hired","recruiting.application.rejected","recruiting.interview.completed","recruiting.scorecard.submitted","recruiting.offer.sent","recruiting.offer.accepted","recruiting.offer.declined","webhook.verification"]}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/{subscription_id}":{"get":{"tags":["Webhooks"],"summary":"Get webhook subscription","description":"Retrieve details for a single webhook subscription.","operationId":"get_subscription_v1_webhooks__subscription_id__get","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Webhooks"],"summary":"Update webhook subscription","description":"Update a subscription's ``url``, ``events``, ``is_active``, or ``description``. Only fields present in the body are changed; pass ``description: null`` to clear it. A new ``url`` is re-validated (HTTPS + SSRF) exactly like create. The signing secret is never returned here — use ``POST /{id}/rotate-secret`` to get a new one.","operationId":"update_subscription_v1_webhooks__subscription_id__patch","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete webhook subscription","description":"Deactivate a webhook subscription. Deliveries already queued will still be attempted. Returns 204 on success. Supports ``?dry_run=true`` — returns the subscription that *would* be deleted (status 200 + ``X-Dry-Run: true`` header) without actually deleting.","operationId":"delete_subscription_v1_webhooks__subscription_id__delete","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Webhook subscription deleted successfully."},"200":{"description":"Dry-run preview of the subscription that would be deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/{subscription_id}/rotate-secret":{"post":{"tags":["Webhooks"],"summary":"Rotate webhook signing secret","description":"Regenerate the subscription's HMAC signing secret and return the new value once — store it securely. The previous secret stops signing immediately, so update your receiver's verification before the next delivery. Use this if a secret leaks.","operationId":"rotate_subscription_secret_v1_webhooks__subscription_id__rotate_secret_post","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/{subscription_id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"List webhook deliveries","description":"List recent delivery attempts for a subscription.","operationId":"list_deliveries_v1_webhooks__subscription_id__deliveries_get","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Legacy offset pagination (deprecated — prefer cursor)","default":0,"title":"Offset"},"description":"Legacy offset pagination (deprecated — prefer cursor)"},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a prior response's `next_cursor`. When set, response switches to the cursor envelope.","title":"Cursor"},"description":"Opaque cursor from a prior response's `next_cursor`. When set, response switches to the cursor envelope."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"By default a plain array of items (legacy contract). When `?cursor` is provided the response switches to the cursor envelope (`items`, `limit`, `has_more`, `next_cursor`).","content":{"application/json":{"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryExternal"}},{"$ref":"#/components/schemas/CursorPage_WebhookDeliveryExternal_"}],"title":"Response 200 List Deliveries V1 Webhooks  Subscription Id  Deliveries Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/{subscription_id}/replay-failed":{"post":{"tags":["Webhooks"],"summary":"Replay failed webhook deliveries","description":"Requeue every terminally-failed delivery for this subscription that was created within the last 7 days (statuses ``failed_permanent`` and ``failed_terminal``). Resets ``status`` to ``pending`` so the delivery worker picks them up on its next poll. Rate-limited to one call per account every 10 seconds (``429 webhook_replay_cooldown``). Supports ``?dry_run=true`` — returns the projected count without mutating. This endpoint is naturally idempotent (replaying again after success is a no-op — the rows have already flipped to ``pending``) and intentionally does not participate in the ``Idempotency-Key`` cache: a cached 429 cooldown response would otherwise be replayed for the full 24h TTL even after the 10s window elapses.","operationId":"replay_failed_deliveries_v1_webhooks__subscription_id__replay_failed_post","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Subscription Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Count of deliveries that were (or would be) requeued.","content":{"application/json":{"schema":{}}}},"404":{"description":"Webhook subscription not found."},"429":{"description":"Replay cooldown in effect for this account."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/test":{"post":{"tags":["Webhooks"],"summary":"Send test webhook","description":"Send a real signed POST to the provided URL to verify connectivity. Fires a ``webhook.verification`` event and returns the actual HTTP status code and response time. Honors the ``?dry_run=true`` query parameter — when set, the ``X-Dry-Run: true`` response header is added. The response includes the ``envelope`` field showing the exact JSON body POSTed to ``url`` so integrators can verify the ``X-Webhook-Signature`` header against the bytes we sent — see the per-event response examples for the canonical shape of every ``schema_version: 1`` envelope.","operationId":"test_webhook_v1_webhooks_test_post","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record.","default":false,"title":"Dry Run"},"description":"If true, validates inputs and returns the response that *would* be produced without persisting any changes. The response includes an ``X-Dry-Run: true`` header. Useful for previewing destructive writes, e.g. before sending a guest message or deleting a record."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestRequest"}}}},"responses":{"200":{"description":"Test delivery completed (or attempted). The ``envelope`` field is the exact body that was POSTed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Test Webhook V1 Webhooks Test Post"},"examples":{"reservation_created":{"summary":"reservation.created test response","description":"Fired when a new reservation is ingested from a connected channel or created in ProhostAI (the app or ``POST /v1/reservations``). A booking your own credential created is not sent back to that credential's subscriptions. Payload is ``ReservationExternal``'s core fields plus ``source``, ``channel``, ``source_reservation_id`` and ``channel_reservation_id``.","value":{"url":"https://example.com/hooks/prohost","event":"reservation.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"reservation.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","guest_id":"22222222-3333-4444-8555-666677778888","guest_first_name":"Alex","guest_last_name":"Rivera","guest_email":"alex.rivera@example.com","guest_phone":"+15551234567","source":"prohost","channel":"direct","source_reservation_id":"PH-01JQXYZ1234567890ABCDEFGHJ","channel_reservation_id":"BK-48213","check_in_at":"2026-05-10T15:00:00Z","check_out_at":"2026-05-14T11:00:00Z","status":"confirmed","num_adults":2,"num_children":0,"num_infants":0,"num_nights":4,"currency":"USD","created_at":"2026-04-24T14:05:00Z","updated_at":"2026-04-24T14:05:00Z"}}}},"reservation_updated":{"summary":"reservation.updated test response","description":"Fired when a reservation's check-in/check-out, guest count, or status changes. Payload is ``ReservationExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"reservation.updated","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"reservation.updated","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","guest_id":"22222222-3333-4444-8555-666677778888","guest_first_name":"Alex","guest_last_name":"Rivera","guest_email":"alex.rivera@example.com","guest_phone":"+15551234567","source":"prohost","channel":"direct","source_reservation_id":"PH-01JQXYZ1234567890ABCDEFGHJ","channel_reservation_id":"BK-48213","check_in_at":"2026-05-10T15:00:00Z","check_out_at":"2026-05-14T11:00:00Z","status":"confirmed","num_adults":2,"num_children":0,"num_infants":0,"num_nights":5,"currency":"USD","created_at":"2026-04-24T14:05:00Z","updated_at":"2026-04-24T14:10:00Z"}}}},"reservation_cancelled":{"summary":"reservation.cancelled test response","description":"Fired when a reservation transitions into the ``cancelled`` status. Payload is ``ReservationExternal`` with ``status: 'cancelled'``.","value":{"url":"https://example.com/hooks/prohost","event":"reservation.cancelled","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"reservation.cancelled","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","guest_id":"22222222-3333-4444-8555-666677778888","guest_first_name":"Alex","guest_last_name":"Rivera","guest_email":"alex.rivera@example.com","guest_phone":"+15551234567","source":"prohost","channel":"direct","source_reservation_id":"PH-01JQXYZ1234567890ABCDEFGHJ","channel_reservation_id":"BK-48213","check_in_at":"2026-05-10T15:00:00Z","check_out_at":"2026-05-14T11:00:00Z","status":"cancelled","num_adults":2,"num_children":0,"num_infants":0,"num_nights":4,"currency":"USD","created_at":"2026-04-24T14:05:00Z","updated_at":"2026-04-24T14:15:00Z"}}}},"reservation_check_in":{"summary":"reservation.check_in test response","description":"Fired by the hourly ``reservation_lifecycle_events`` Hatchet cron on the calendar day the reservation's ``check_in_at`` falls into. Idempotent — fires at most once per reservation. Payload is ``ReservationExternal`` plus an ``event_at`` field pinning the canonical check-in timestamp.","value":{"url":"https://example.com/hooks/prohost","event":"reservation.check_in","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"reservation.check_in","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","guest_id":"22222222-3333-4444-8555-666677778888","guest_first_name":"Alex","guest_last_name":"Rivera","guest_email":"alex.rivera@example.com","guest_phone":"+15551234567","source":"prohost","channel":"direct","source_reservation_id":"PH-01JQXYZ1234567890ABCDEFGHJ","channel_reservation_id":"BK-48213","check_in_at":"2026-05-10T15:00:00Z","check_out_at":"2026-05-14T11:00:00Z","status":"confirmed","num_adults":2,"num_children":0,"num_infants":0,"num_nights":4,"currency":"USD","created_at":"2026-04-24T14:05:00Z","updated_at":"2026-04-24T14:05:00Z","event_at":"2026-05-10T15:00:00Z"}}}},"reservation_check_out":{"summary":"reservation.check_out test response","description":"Fired by the hourly ``reservation_lifecycle_events`` Hatchet cron on the calendar day the reservation's ``check_out_at`` falls into. Idempotent. Payload mirrors ``reservation.check_in``.","value":{"url":"https://example.com/hooks/prohost","event":"reservation.check_out","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"reservation.check_out","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","guest_id":"22222222-3333-4444-8555-666677778888","guest_first_name":"Alex","guest_last_name":"Rivera","guest_email":"alex.rivera@example.com","guest_phone":"+15551234567","source":"prohost","channel":"direct","source_reservation_id":"PH-01JQXYZ1234567890ABCDEFGHJ","channel_reservation_id":"BK-48213","check_in_at":"2026-05-10T15:00:00Z","check_out_at":"2026-05-14T11:00:00Z","status":"confirmed","num_adults":2,"num_children":0,"num_infants":0,"num_nights":4,"currency":"USD","created_at":"2026-04-24T14:05:00Z","updated_at":"2026-04-24T14:05:00Z","event_at":"2026-05-14T11:00:00Z"}}}},"message_received":{"summary":"message.received test response","description":"Fired when a guest message is ingested from an OTA inbox or SMS channel. ","value":{"url":"https://example.com/hooks/prohost","event":"message.received","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"message.received","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"33333333-4444-4555-8666-777788889999","conversation_id":"44444444-5555-4666-8777-888899990000","message":"Hi! What time is check-in?","channel":"airbnb","sent_at":"2026-04-24T14:20:00Z"}}}},"message_sent":{"summary":"message.sent test response","description":"Fired when a host or autopilot reply is delivered to the guest. Payload is the inline shape from ``api_public/routers/conversations.py``.","value":{"url":"https://example.com/hooks/prohost","event":"message.sent","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"message.sent","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"55555555-6666-4777-8888-999900001111","conversation_id":"44444444-5555-4666-8777-888899990000","message":"Check-in is from 3pm onward — full instructions arrive 24h before arrival.","channel":"airbnb","sent_at":"2026-04-24T14:20:59Z"}}}},"message_team_chat":{"summary":"message.team_chat test response","description":"Fired when a message is posted to an internal team-chat thread (``ConversationChannel.internal``) — from a teammate, an AI agent, or an external API/MCP credential. Carries a bounded ``content_preview`` (not the full body) and a normalized ``mentions`` list. The echo guard skips delivering this back to a subscription created by the same credential that authored the message, so a write-and-subscribe integration doesn't loop.","value":{"url":"https://example.com/hooks/prohost","event":"message.team_chat","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"message.team_chat","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"message_id":"aaaa1111-2222-4333-8444-555566667777","conversation_id":"bbbb2222-3333-4444-8555-666677778888","sender_user_id":"cccc3333-4444-4555-8666-777788889999","sender_type":"host_manual","content_preview":"Heads-up @here — the Elm St turnover slipped to 3pm.","mentions":[{"type":"here","user_id":"00000000-0000-0000-0000-000000000000","name":"@here"}],"created_at":"2026-07-05T12:00:00Z"}}}},"mention_created":{"summary":"mention.created test response","description":"Fired once per resolved participant when a team-chat message @-mentions them — a direct ``<@id>`` mention (``mention_type: 'user'``) or expanded from a group mention (``@here`` / ``@channel`` / ``@everyone``), always excluding the sender.","value":{"url":"https://example.com/hooks/prohost","event":"mention.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"mention.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"mentioned_user_id":"dddd4444-5555-4666-8777-888899990000","mention_type":"here","message_id":"aaaa1111-2222-4333-8444-555566667777","conversation_id":"bbbb2222-3333-4444-8555-666677778888","sender_user_id":"cccc3333-4444-4555-8666-777788889999"}}}},"message_support_thread":{"summary":"message.support_thread test response","description":"Fired for a message in a two-sided ProhostAI-support thread (``internal`` channel with ``business_purpose='prohost_support'``) — the internal support threads seeded in each customer account. Emitted under the ProhostAI **support** account (not the thread's home/customer account), so the internal support workspace's subscription receives it. Carries the full ``body``, the thread's ``home_account_id`` (customer account), and the sender identity. Same echo guard as ``message.team_chat`` — the support agent's own external-API reply doesn't loop back to its own subscription.","value":{"url":"https://example.com/hooks/prohost","event":"message.support_thread","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"message.support_thread","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"message_id":"eeee5555-6666-4777-8888-999900001111","conversation_id":"bbbb2222-3333-4444-8555-666677778888","home_account_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","business_purpose":"prohost_support","sender_user_id":"cccc3333-4444-4555-8666-777788889999","sender_type":"host_manual","body":"Any update on the calendar sync issue? Still seeing double bookings.","created_at":"2026-07-15T09:30:00Z"}}}},"task_created":{"summary":"task.created test response","description":"Fired when a maintenance/ops task is created. Payload is ``TaskExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"task.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"task.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"66666666-7777-4888-8999-aaaabbbbcccc","title":"Replace bedroom lightbulb","description":"Guest reports the lamp on the right nightstand isn't working.","status":"open","priority":"normal","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","reservation_id":"11111111-2222-4333-8444-555566667777","due_date":"2026-04-26T17:00:00Z","created_at":"2026-04-24T14:25:00Z","updated_at":"2026-04-24T14:25:00Z"}}}},"task_updated":{"summary":"task.updated test response","description":"Fired when a task changes — status transition, assignee, due date, etc. Payload is ``TaskExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"task.updated","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"task.updated","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"66666666-7777-4888-8999-aaaabbbbcccc","title":"Replace bedroom lightbulb","description":"Guest reports the lamp on the right nightstand isn't working.","status":"completed","priority":"normal","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","reservation_id":"11111111-2222-4333-8444-555566667777","due_date":"2026-04-26T17:00:00Z","created_at":"2026-04-24T14:25:00Z","updated_at":"2026-04-24T14:30:00Z"}}}},"task_commented":{"summary":"task.commented test response","description":"Fired when a comment is posted on a task (from any writer — internal/public API or an AI employee). Payload carries ``task_id``, ``comment_id``, ``author`` (id/name), ``body``, ``created_at``.","value":{"url":"https://example.com/hooks/prohost","event":"task.commented","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"task.commented","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"task_id":"66666666-7777-4888-8999-aaaabbbbcccc","comment_id":"77777777-8888-4999-8aaa-bbbbccccdddd","author":{"id":"22222222-3333-4444-8555-666677778888","name":"Jane Host"},"body":"Vendor is scheduled for tomorrow morning.","created_at":"2026-04-24T14:35:00Z"}}}},"cleaning_created":{"summary":"cleaning.created test response","description":"Fired when a turnover cleaning is scheduled. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"cleaning.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"cleaning.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"88888888-9999-4aaa-8bbb-ccccddddeeee","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","status":"not_started","type":"turnover","title":"Post-checkout turnover","description":"Standard turnover cleaning.","scheduled_starts_at":"2026-05-15T11:00:00Z","scheduled_ends_at":"2026-05-15T14:00:00Z","assignee_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff","reservation_id":"11111111-2222-4333-8444-555566667777","created_at":"2026-04-24T14:35:00Z","updated_at":"2026-04-24T14:35:00Z","inspectors":[{"id":"abababab-cdcd-4efe-8abc-defdefdefdef","name":"Jordan Lee"}],"stage":"cleaning","requires_inspection":true}}}},"cleaning_updated":{"summary":"cleaning.updated test response","description":"Fired on cleaning status transitions and reassignment. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"cleaning.updated","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"cleaning.updated","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"88888888-9999-4aaa-8bbb-ccccddddeeee","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","status":"in_progress","type":"turnover","title":"Post-checkout turnover","description":"Standard turnover cleaning.","scheduled_starts_at":"2026-05-15T11:00:00Z","scheduled_ends_at":"2026-05-15T14:00:00Z","assignee_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff","reservation_id":"11111111-2222-4333-8444-555566667777","created_at":"2026-04-24T14:35:00Z","updated_at":"2026-04-24T14:40:00Z","inspectors":[{"id":"abababab-cdcd-4efe-8abc-defdefdefdef","name":"Jordan Lee"}],"stage":"cleaning","requires_inspection":true}}}},"cleaning_completed":{"summary":"cleaning.completed test response","description":"Fires only on the not-completed → completed transition for a cleaning. Distinct from ``cleaning.updated`` (every-change emitter); both can fire for the same write — subscribe to ``cleaning.completed`` only if you want the completion signal alone. Payload is ``CleaningExternal``.","value":{"url":"https://example.com/hooks/prohost","event":"cleaning.completed","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"cleaning.completed","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"88888888-9999-4aaa-8bbb-ccccddddeeee","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","status":"completed","type":"turnover","title":"Post-checkout turnover","description":"Standard turnover cleaning.","scheduled_starts_at":"2026-05-15T11:00:00Z","scheduled_ends_at":"2026-05-15T14:00:00Z","assignee_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff","reservation_id":"11111111-2222-4333-8444-555566667777","created_at":"2026-04-24T14:35:00Z","updated_at":"2026-04-24T14:42:00Z","inspectors":[{"id":"abababab-cdcd-4efe-8abc-defdefdefdef","name":"Jordan Lee"}],"stage":"cleaning","requires_inspection":true}}}},"guest_created":{"summary":"guest.created test response","description":"Fired the first time a guest profile is created — typically alongside their first reservation.","value":{"url":"https://example.com/hooks/prohost","event":"guest.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"guest.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"22222222-3333-4444-8555-666677778888","first_name":"Alex","last_name":"Rivera","email":"alex.rivera@example.com","phone":"+15551234567","created_at":"2026-04-24T14:45:00Z"}}}},"guest_form_submitted":{"summary":"guest_form.submitted test response","description":"Fired when a guest completes the Welcome Pass check-in form — the in-progress -> completed transition on ``welcome_pass_responses``. Distinct from the internal ``welcome_pass_completed`` workflow trigger (in-product automations only, never leaves the account): this outbound event carries the promoted check-in fields (``eta``, ``num_guests``, ``id_verification_status``, ``deposit_status``, …) plus the raw ``answers`` dict so integrators can push check-in form answers to a third-party system. Uploaded files (ID, selfie, file steps) appear as private-bucket key references — in ``answers`` as ``{\"key\", \"uploaded_at\"}`` and again under ``files`` — never as URLs; exchange a key for a short-lived download link with ``GET /v1/reservations/{id}/guest-form/file-url?key=…`` (``reservations:read``). ``GET /v1/reservations/{id}/guest-form`` returns the same payload on demand.","value":{"url":"https://example.com/hooks/prohost","event":"guest_form.submitted","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"guest_form.submitted","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"response_id":"01HFXGGGGGGGGGGGGGGGGGGG00","reservation_id":"33333333-4444-4555-8666-777788889999","listing_id":"44444444-5555-4666-8777-888899990000","template_id":"55555555-6666-4777-8888-99990000aaaa","template_version":"3","status":"completed","completed_at":"2026-04-24T14:50:00Z","eta":"2026-04-24T17:00:00Z","num_guests":2,"num_pets":0,"id_verification_status":"verified","agreement_signed_at":"2026-04-24T14:48:00Z","deposit_status":"authorized","answers":{"arrival_method":"car","special_requests":"Late check-in around 5pm","guest_names":{"names":["Alex Rivera","Sam Rivera"]},"id_verification":{"key":"welcome-pass/33333333-4444-4555-8666-777788889999/id_verification/01HFXHHHHHHHHHHHHHHHHHHH00.jpg","uploaded_at":"2026-04-24T14:47:10Z"}},"files":[{"step_id":"id_verification","key":"welcome-pass/33333333-4444-4555-8666-777788889999/id_verification/01HFXHHHHHHHHHHHHHHHHHHH00.jpg","uploaded_at":"2026-04-24T14:47:10Z"}]}}}},"review_received":{"summary":"review.received test response","description":"Fired when a guest review is ingested from any OTA (Airbnb, Hostaway, Hospitable, Guesty, etc.) — one event per upserted ``reviews`` row. Payload mirrors the ``Review`` model with category ratings flattened into a ``category_ratings`` sub-object.","value":{"url":"https://example.com/hooks/prohost","event":"review.received","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"review.received","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"01HFXAAAAAAAAAAAAAAAAAAA00","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","reservation_id":"11111111-2222-4333-8444-555566667777","stars":5,"rating":5.0,"public_review":"Great stay — would book again.","source_review_id":"abnb-review-1234","reviewer_role":"guest","published_at":"2026-04-26T10:00:00Z","category_ratings":{"value":5.0,"cleanliness":5.0,"communication":5.0,"location":5.0,"checkin":5.0,"accuracy":5.0},"created_at":"2026-04-26T10:00:00Z"}}}},"review_replied":{"summary":"review.replied test response","description":"Fired when an AI-generated host reply has been successfully posted back to the OTA via the auto-review publish path. Payload includes the body of the reply and the source review identifier.","value":{"url":"https://example.com/hooks/prohost","event":"review.replied","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"review.replied","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"auto_review_id":"01HFXBBBBBBBBBBBBBBBBBBB00","reservation_id":"11111111-2222-4333-8444-555566667777","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","source_review_id":"abnb-review-1234","public_review":"Thanks for staying with us — you were a wonderful guest!","is_reviewee_recommended":true,"submitted_at":"2026-04-27T09:00:00Z"}}}},"autopilot_escalation":{"summary":"autopilot.escalation test response","description":"Fired when autopilot hands a draft reply off to human review — ``reason`` is one of ``category_not_enabled`` / ``low_confidence`` / ``negative_sentiment`` / ``listing_disabled``. Payload reuses ``AutopilotEscalationNotification`` plus webhook-only fields (``reason``, ``sentiment_score``, ``confidence_overall``, ``suggestion_id``, ``trigger_message_id``, ``drafted_reply``). Common pattern: route to Slack/PagerDuty for oncall handoff.","value":{"url":"https://example.com/hooks/prohost","event":"autopilot.escalation","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"autopilot.escalation","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"account_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","conversation_id":"44444444-5555-4666-8777-888899990000","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","suggestion_id":"cccccccc-dddd-4eee-8fff-000011112222","trigger_message_id":"33333333-4444-4555-8666-777788889999","guest_full_name":"Alex Rivera","listing_title":"Sunny Loft Downtown","message_category":"complaint","category_rule_enabled":true,"reason":"negative_sentiment","drafted_reply":"I'm sorry to hear that — let me look into this and get back to you within the hour.","sentiment_score":0.18,"confidence_overall":0.74}}}},"autopilot_reply_sent":{"summary":"autopilot.reply_sent test response","description":"Inverse branch of ``autopilot.escalation`` — fired when autopilot accepts a draft reply and schedules it for delivery. Payload includes the eventual ``scheduled_message_id`` + ``scheduled_at`` so receivers can correlate the eventual ``message.sent`` event. Useful for AI message audit trails.","value":{"url":"https://example.com/hooks/prohost","event":"autopilot.reply_sent","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"autopilot.reply_sent","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"account_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","conversation_id":"44444444-5555-4666-8777-888899990000","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","suggestion_id":"cccccccc-dddd-4eee-8fff-000011112222","trigger_message_id":"33333333-4444-4555-8666-777788889999","scheduled_message_id":"01HFXYZABCDEF0123456789ABCD","scheduled_at":"2026-04-24T14:56:30Z","guest_full_name":"Alex Rivera","listing_title":"Sunny Loft Downtown","message_category":"checkin_question","drafted_reply":"Check-in is from 3pm onward — full instructions arrive 24h before arrival.","sentiment_score":0.62,"confidence_overall":0.91}}}},"smart_device_alert":{"summary":"smart_device.alert test response","description":"Fired by the Seam smart-device ingest path for high-signal alert events (currently ``noise_sensor.noise_threshold_triggered`` and ``lock.access_denied``). The ``alert_type`` field on the payload echoes the upstream Seam event type so receivers can branch.","value":{"url":"https://example.com/hooks/prohost","event":"smart_device.alert","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"smart_device.alert","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"device_id":"01HFXDDDDDDDDDDDDDDDDDDD00","provider":"seam","provider_device_id":"seam-device-xyz","device_type":"noise_sensor","display_name":"Living Room Minut","alert_type":"noise_sensor.noise_threshold_triggered","occurred_at":"2026-04-28T22:30:00Z","raw_payload":{"device_id":"seam-device-xyz","noise_level_decibels":92,"noise_level_threshold_decibels":85}}}}},"customer_feedback_submitted":{"summary":"customer_feedback.submitted test response","description":"Fired when a host or guest submits feedback through the in-app form, the MCP tool, or the AI chat bug-report tool. Payload mirrors the ``CustomerFeedback`` row.","value":{"url":"https://example.com/hooks/prohost","event":"customer_feedback.submitted","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"customer_feedback.submitted","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"01HFXEEEEEEEEEEEEEEEEEEE00","user_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff","type":"bug_report","status":"submitted","source":"api","title":"Reservation list pagination off-by-one","description":"Pages 2+ skip the last item from the previous page.","created_at":"2026-04-24T16:00:00Z"}}}},"expense_created":{"summary":"expense.created test response","description":"Fired when a new expense is created via the public or internal API. Payload mirrors the ``Expense`` row — amount is a decimal string for precision.","value":{"url":"https://example.com/hooks/prohost","event":"expense.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"expense.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"01HFXFFFFFFFFFFFFFFFFFFF00","listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000","reservation_id":"11111111-2222-4333-8444-555566667777","name":"Lightbulb replacement","amount":"12.50","currency":"USD","description":"Replaced bedroom lamp.","date":"2026-04-24","payment_type":"manual","payment_status":"unpaid","created_at":"2026-04-24T16:30:00Z","updated_at":"2026-04-24T16:30:00Z"}}}},"agent_approval_requested":{"summary":"agent.approval_requested test response","description":"Fired when an AI employee escalates an action to a human — i.e. when a request lands in the Pending Approvals queue (an ``ai_agent_approval_requests`` row is persisted). Payload mirrors the approval row: agent id + name, ``action_kind``, title/description, ``risk_level``, ``status: 'pending'``. Common pattern: route to Slack/WhatsApp so a human can approve from their notification surface.","value":{"url":"https://example.com/hooks/prohost","event":"agent.approval_requested","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"agent.approval_requested","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"01HFXAAAAAAAAAAAAAAAAAAA00","account_id":"01HFXBBBBBBBBBBBBBBBBBBB00","agent_id":"01HFXCCCCCCCCCCCCCCCCCCC00","agent_name":"Gabby","run_id":"01HFXDDDDDDDDDDDDDDDDDDD00","action_kind":"create_task","title":"Proposed task: Adjust minimum stay for July","description":"Gabby proposes lowering the 3-night minimum to 2 nights for the July gap weekends.","risk_level":"medium","status":"pending","created_at":"2026-05-28T09:15:00Z"}}}},"agent_approval_resolved":{"summary":"agent.approval_resolved test response","description":"Fired when a pending AI-employee approval reaches a terminal state. ``status`` carries ``approved`` / ``rejected`` / ``expired``; ``responded_at`` / ``responded_by_user_id`` / ``rejection_reason`` describe the resolution. Pairs with ``agent.approval_requested`` via the shared ``id``.","value":{"url":"https://example.com/hooks/prohost","event":"agent.approval_resolved","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"agent.approval_resolved","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"01HFXAAAAAAAAAAAAAAAAAAA00","account_id":"01HFXBBBBBBBBBBBBBBBBBBB00","agent_id":"01HFXCCCCCCCCCCCCCCCCCCC00","agent_name":"Gabby","run_id":"01HFXDDDDDDDDDDDDDDDDDDD00","action_kind":"create_task","title":"Proposed task: Adjust minimum stay for July","description":"Gabby proposes lowering the 3-night minimum to 2 nights for the July gap weekends.","risk_level":"medium","status":"approved","created_at":"2026-05-28T09:15:00Z","responded_at":"2026-05-28T10:02:00Z","responded_by_user_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff"}}}},"agent_run_requested":{"summary":"agent.run_requested test response","description":"The wake-up for a *paired external agent runtime*. When an AI employee has an active external-runtime connection, a trigger (team-chat mention, task comment, internal note, …) dispatches the work to you over this event instead of running ProhostAI's in-product brain. ``data`` carries ``run_id``, the agent's id + synthetic ``agent_user_id``, the ``trigger`` (source, message id, text excerpt, sender), and ``reply_instructions`` naming the conversation to post into. Do the work with your paired credential, then close the run with ``POST /v1/agent-runs/{run_id}/complete`` — an uncompleted run leaves the sender's thinking-indicator spinning until it is swept.","value":{"url":"https://example.com/hooks/prohost","event":"agent.run_requested","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"agent.run_requested","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"run_id":"01HFXEEEEEEEEEEEEEEEEEEE00","agent_id":"01HFXCCCCCCCCCCCCCCCCCCC00","agent_user_id":"01HFXFFFFFFFFFFFFFFFFFFF00","agent_name":"Gabby","account_id":"01HFXBBBBBBBBBBBBBBBBBBB00","conversation_id":"01HFXGGGGGGGGGGGGGGGGGGG00","kind":"mention","trigger":{"source":"team_chat_mention","message_id":"01HFXHHHHHHHHHHHHHHHHHHH00","text_excerpt":"@Gabby can you check whether the Maple St cleaning got reassigned?","text_truncated":false,"user_id":"99999999-aaaa-4bbb-8ccc-ddddeeeeffff"},"reply_instructions":{"surface":"conversation","conversation_id":"01HFXGGGGGGGGGGGGGGGGGGG00","method":"POST","path":"/v1/conversations/01HFXGGGGGGGGGGGGGGGGGGG00/messages","detail":"Post your reply into this conversation as the agent, then call POST /v1/agent-runs/01HFXEEEEEEEEEEEEEEEEEEE00/complete. If you decide not to reply, complete the run anyway with status=succeeded so the sender's thinking-indicator clears."},"completion":{"method":"POST","path":"/v1/agent-runs/01HFXEEEEEEEEEEEEEEEEEEE00/complete","required_scope":"agent_runs:write"},"heartbeat":{"method":"POST","path":"/v1/agent-runs/01HFXEEEEEEEEEEEEEEEEEEE00/heartbeat","required_scope":"agent_runs:write"},"recent_messages":[{"author":"Dana Whitfield","role":"host","at":"2026-07-25T13:58:11Z","text":"Maple St needs a turnover before the 4pm check-in."},{"author":"Gabby","role":"agent","at":"2026-07-25T13:59:04Z","text":"I've offered it to Maria — waiting on her to accept."}],"memories":[{"scope":"user_style","content":"Dana wants cleaner reassignments confirmed in-thread before they're applied."},{"scope":"listing","content":"Maple St's lockbox code rotates on the 1st of each month."}]}}}},"crm_opportunity_created":{"summary":"crm.opportunity.created test response","description":"Fired when a CRM opportunity (deal card) is created. Payload is the partner-safe opportunity shape — ids, title, pipeline/stage, status, value, contact/company.","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-666677778888","status":"open","value_amount":"12000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:00:00Z"}}}},"crm_opportunity_updated":{"summary":"crm.opportunity.updated test response","description":"Fired when an opportunity's fields change (title, value, contact/company, custom fields). NOT fired for stage moves (``crm.opportunity.moved``) or archival (``crm.opportunity.archived``).","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.updated","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.updated","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-666677778888","status":"open","value_amount":"15000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:05:00Z"}}}},"crm_opportunity_moved":{"summary":"crm.opportunity.moved test response","description":"Fired when an opportunity moves to a different stage. When the move flips the card won/lost, the matching ``crm.opportunity.won`` / ``crm.opportunity.lost`` fires alongside this event.","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.moved","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.moved","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-66667777aaaa","status":"open","value_amount":"12000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:10:00Z"}}}},"crm_opportunity_won":{"summary":"crm.opportunity.won test response","description":"Fired only on the transition into a won stage (status open → won). The payload carries ``status: 'won'`` and the ``closed_at`` timestamp.","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.won","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.won","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-666677770001","status":"won","value_amount":"12000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","closed_at":"2026-04-24T15:15:00Z","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:15:00Z"}}}},"crm_opportunity_lost":{"summary":"crm.opportunity.lost test response","description":"Fired only on the transition into a lost stage (status open → lost). The payload carries ``status: 'lost'``, an optional ``lost_reason``, and ``closed_at``.","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.lost","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.lost","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-666677770002","status":"lost","value_amount":"12000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","lost_reason":"Chose a competitor","closed_at":"2026-04-24T15:20:00Z","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:20:00Z"}}}},"crm_opportunity_archived":{"summary":"crm.opportunity.archived test response","description":"Fired when an opportunity is archived (soft-deleted off the board). The payload carries the ``archived_at`` timestamp.","value":{"url":"https://example.com/hooks/prohost","event":"crm.opportunity.archived","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.opportunity.archived","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-1111-4222-8333-444455556666","title":"Acme Corp — 12-unit onboarding","pipeline_id":"cccccccc-2222-4333-8444-555566667777","stage_id":"cccccccc-3333-4444-8555-666677778888","status":"open","value_amount":"12000.00","value_currency":"USD","primary_contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","archived_at":"2026-04-24T15:25:00Z","created_at":"2026-04-24T15:00:00Z","updated_at":"2026-04-24T15:25:00Z"}}}},"crm_contact_created":{"summary":"crm.contact.created test response","description":"Fired when a CRM contact is created. Payload includes name, email, phone, title, and the linked company id.","value":{"url":"https://example.com/hooks/prohost","event":"crm.contact.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.contact.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-4444-4555-8666-777788889999","name":"Jane Doe","email":"jane@acme.example","phone":"+15555550100","title":"Director of Operations","company_id":"cccccccc-5555-4666-8777-888899990000","type":"lead","created_at":"2026-04-24T15:30:00Z","updated_at":"2026-04-24T15:30:00Z"}}}},"crm_company_created":{"summary":"crm.company.created test response","description":"Fired when a CRM company is created. Payload includes name, domain, and type.","value":{"url":"https://example.com/hooks/prohost","event":"crm.company.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.company.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-5555-4666-8777-888899990000","name":"Acme Corp","domain":"acme.example","type":"prospect","created_at":"2026-04-24T15:35:00Z","updated_at":"2026-04-24T15:35:00Z"}}}},"crm_meeting_logged":{"summary":"crm.meeting.logged test response","description":"Fired when a meeting or call is logged against an opportunity, contact, or company. Payload includes scheduling/actual timestamps, source, and outcome.","value":{"url":"https://example.com/hooks/prohost","event":"crm.meeting.logged","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.meeting.logged","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-6666-4777-8888-999900001111","title":"Discovery call","status":"completed","opportunity_id":"cccccccc-1111-4222-8333-444455556666","contact_id":"cccccccc-4444-4555-8666-777788889999","company_id":"cccccccc-5555-4666-8777-888899990000","scheduled_start_at":"2026-04-24T16:00:00Z","scheduled_end_at":"2026-04-24T16:30:00Z","actual_start_at":"2026-04-24T16:01:00Z","actual_end_at":"2026-04-24T16:28:00Z","source":"manual","created_at":"2026-04-24T15:40:00Z","updated_at":"2026-04-24T15:40:00Z"}}}},"crm_comment_added":{"summary":"crm.comment.added test response","description":"Fired when a comment is posted on any CRM object. Payload carries the ``object_type`` / ``object_id`` the comment targets and the comment body.","value":{"url":"https://example.com/hooks/prohost","event":"crm.comment.added","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"crm.comment.added","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"cccccccc-7777-4888-8999-aaaabbbbcccc","object_type":"opportunity","object_id":"cccccccc-1111-4222-8333-444455556666","body":"Following up after the discovery call — sending the proposal Monday.","created_at":"2026-04-24T15:45:00Z","updated_at":"2026-04-24T15:45:00Z"}}}},"recruiting_application_created":{"summary":"recruiting.application.created test response","description":"Fired when a candidate applies to a job — from the careers form, an AI tool, or the API. Once per candidate/job pair: a re-application returns the existing record and fires nothing.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.application.created","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.application.created","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-1111-4222-8333-444455556666","job_id":"eeeeeeee-2222-4333-8444-555566667777","candidate_id":"eeeeeeee-3333-4444-8555-666677778888","opportunity_id":"eeeeeeee-4444-4555-8666-777788889999","status":"active","source":"site_form","applied_at":"2026-04-24T16:00:00Z","created_at":"2026-04-24T16:00:00Z","updated_at":"2026-04-24T16:00:00Z"}}}},"recruiting_application_moved":{"summary":"recruiting.application.moved test response","description":"Fired when an application moves to a different pipeline stage. The move that lands it in the terminal Hired stage fires ``recruiting.application.hired`` alongside this event.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.application.moved","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.application.moved","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-1111-4222-8333-444455556666","job_id":"eeeeeeee-2222-4333-8444-555566667777","candidate_id":"eeeeeeee-3333-4444-8555-666677778888","opportunity_id":"eeeeeeee-4444-4555-8666-777788889999","status":"active","source":"site_form","applied_at":"2026-04-24T16:00:00Z","created_at":"2026-04-24T16:00:00Z","updated_at":"2026-04-24T16:10:00Z","stage_id":"eeeeeeee-5555-4666-8777-888899990000","stage_name":"Screen"}}}},"recruiting_application_hired":{"summary":"recruiting.application.hired test response","description":"Fired when an application reaches the Hired stage. Derived from the stage's kind, never its name.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.application.hired","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.application.hired","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-1111-4222-8333-444455556666","job_id":"eeeeeeee-2222-4333-8444-555566667777","candidate_id":"eeeeeeee-3333-4444-8555-666677778888","opportunity_id":"eeeeeeee-4444-4555-8666-777788889999","status":"hired","source":"site_form","applied_at":"2026-04-24T16:00:00Z","decided_at":"2026-04-24T16:20:00Z","created_at":"2026-04-24T16:00:00Z","updated_at":"2026-04-24T16:20:00Z"}}}},"recruiting_application_rejected":{"summary":"recruiting.application.rejected test response","description":"Fired when an application ends without a hire. Covers BOTH a rejection and a candidate withdrawal — ``status`` on the payload distinguishes them, and they should not be counted together.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.application.rejected","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.application.rejected","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-1111-4222-8333-444455556666","job_id":"eeeeeeee-2222-4333-8444-555566667777","candidate_id":"eeeeeeee-3333-4444-8555-666677778888","opportunity_id":"eeeeeeee-4444-4555-8666-777788889999","status":"rejected","source":"site_form","applied_at":"2026-04-24T16:00:00Z","decided_at":"2026-04-24T16:30:00Z","created_at":"2026-04-24T16:00:00Z","updated_at":"2026-04-24T16:30:00Z","rejected_reason":"Went with a candidate stronger on distributed systems."}}}},"recruiting_interview_completed":{"summary":"recruiting.interview.completed test response","description":"Fired when an interview genuinely completes. Cancelled and no-show interviews end the interview internally but do NOT fire this event.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.interview.completed","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.interview.completed","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-6666-4777-8888-99990000aaaa","application_id":"eeeeeeee-1111-4222-8333-444455556666","loop_stage_key":"screen","status":"completed","scheduled_start_at":"2026-04-24T15:30:00Z","scheduled_end_at":"2026-04-24T16:00:00Z","confirmed_at":"2026-04-23T09:00:00Z","crm_meeting_id":"eeeeeeee-7777-4888-8999-aaaabbbbcccc","created_at":"2026-04-22T12:00:00Z","updated_at":"2026-04-24T16:40:00Z"}}}},"recruiting_scorecard_submitted":{"summary":"recruiting.scorecard.submitted test response","description":"Fired when an evaluator publishes their interview write-up to the hiring team. Carries the overall verdict; the written assessment is never included in the payload.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.scorecard.submitted","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.scorecard.submitted","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-8888-4999-8aaa-bbbbccccdddd","interview_id":"eeeeeeee-6666-4777-8888-99990000aaaa","application_id":"eeeeeeee-1111-4222-8333-444455556666","overall":"yes","submitted_at":"2026-04-24T17:00:00Z","created_at":"2026-04-24T16:45:00Z","updated_at":"2026-04-24T17:00:00Z"}}}},"recruiting_offer_sent":{"summary":"recruiting.offer.sent test response","description":"Fired when an offer is sent (or re-sent) to the candidate. Carries the offer's state and title; the offer body, the compensation package, and the candidate's view token are never included in the payload.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.offer.sent","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.offer.sent","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-9999-4aaa-8bbb-ccccddddeeee","application_id":"eeeeeeee-1111-4222-8333-444455556666","status":"sent","title":"Offer — Senior Engineer","start_date":"2026-06-01","sent_at":"2026-04-25T09:00:00Z","created_at":"2026-04-24T18:00:00Z","updated_at":"2026-04-25T09:00:00Z"}}}},"recruiting_offer_accepted":{"summary":"recruiting.offer.accepted test response","description":"Fired when the candidate accepts the offer on the public offer page. Does NOT imply hired — a human marks the application hired, which fires ``recruiting.application.hired`` separately.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.offer.accepted","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.offer.accepted","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-9999-4aaa-8bbb-ccccddddeeee","application_id":"eeeeeeee-1111-4222-8333-444455556666","status":"accepted","title":"Offer — Senior Engineer","start_date":"2026-06-01","sent_at":"2026-04-25T09:00:00Z","responded_at":"2026-04-26T10:00:00Z","created_at":"2026-04-24T18:00:00Z","updated_at":"2026-04-26T10:00:00Z"}}}},"recruiting_offer_declined":{"summary":"recruiting.offer.declined test response","description":"Fired when the candidate declines the offer on the public offer page. Carries their optional ``decline_reason``.","value":{"url":"https://example.com/hooks/prohost","event":"recruiting.offer.declined","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"recruiting.offer.declined","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"id":"eeeeeeee-9999-4aaa-8bbb-ccccddddeeee","application_id":"eeeeeeee-1111-4222-8333-444455556666","status":"declined","title":"Offer — Senior Engineer","start_date":"2026-06-01","sent_at":"2026-04-25T09:00:00Z","responded_at":"2026-04-26T10:00:00Z","created_at":"2026-04-24T18:00:00Z","updated_at":"2026-04-26T10:00:00Z","decline_reason":"Accepted another role closer to home."}}}},"webhook_verification":{"summary":"webhook.verification test response","description":"Fired on first subscription creation and on every ``POST /webhooks/test`` call. Used to verify HMAC signing + endpoint reachability. ``data`` is best-effort metadata — receivers should key only on ``event == 'webhook.verification'``, not on specific data fields.","value":{"url":"https://example.com/hooks/prohost","event":"webhook.verification","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"webhook.verification","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"message":"This is a test webhook from ProhostAI","account_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000"}}}},"connection_ping":{"summary":"connection.ping test response","description":"The paired-runtime \"Test connection\" probe, fired on demand when a host presses Test connection on an AI employee's connection. Contentless — ``data`` names the ``connection_id`` and ``agent_id`` under test and nothing else. Not subscribable and never persisted as a delivery: it is addressed at one subscription and expects no ack. A runtime should treat it as a no-op heartbeat, not as work.","value":{"url":"https://example.com/hooks/prohost","event":"connection.ping","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"connection.ping","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"connection_id":"dddddddd-1111-4222-8333-444455556666","agent_id":"dddddddd-2222-4333-8444-555566667777"}}}},"agent_config_updated":{"summary":"agent.config_updated test response","description":"Tells a paired runtime its configuration changed — today, which Claude Code or Codex account on its machine it should run on, chosen by a person in ProhostAI. ``account_key`` is the key the runtime generated for that account when it was added locally. Apply it from the next run. Not subscribable; addressed at one subscription, sent once, and repeated in ``auth_ok`` on every reconnect until the runtime reports running on it.","value":{"url":"https://example.com/hooks/prohost","event":"agent.config_updated","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"agent.config_updated","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"connection_id":"dddddddd-1111-4222-8333-444455556666","agent_id":"dddddddd-2222-4333-8444-555566667777","account_key":"7f0c0000-0000-4000-8000-000000000001"}}}},"code_thread_start_requested":{"summary":"code_thread.start_requested test response","description":"Asks the Prohost app on a paired Mac to start a Code thread: open a worktree of ``repo`` on ``branch`` and a terminal ``terminalId``, and run ``agent`` on ``goal``. Not subscribable; addressed at the machine's own connection.","value":{"url":"https://example.com/hooks/prohost","event":"code_thread.start_requested","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"code_thread.start_requested","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"codeThreadId":"01a18000-0000-4000-8000-000000000001","conversationId":"01a18000-0000-4000-8000-000000000002","goal":"Fix the flaky checkout test","repo":"acme/web","branch":"prohost/00000001/fix-the-flaky-checkout-test","agent":"claude_code","terminalId":"01a18000-0000-4000-8000-000000000001"}}}},"code_thread_input_requested":{"summary":"code_thread.input_requested test response","description":"Asks the Prohost app on a paired Mac to type a person's reply into a Code thread's terminal and press Enter. Not subscribable; addressed at the machine's own connection.","value":{"url":"https://example.com/hooks/prohost","event":"code_thread.input_requested","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"code_thread.input_requested","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"codeThreadId":"01a18000-0000-4000-8000-000000000001","terminalId":"01a18000-0000-4000-8000-000000000001","text":"Yes, bump the version too."}}}},"code_thread_approval_decided":{"summary":"code_thread.approval_decided test response","description":"Tells the Prohost app on a paired Mac how a person answered a Code thread's pending permission prompt (``allow`` / ``allow_session`` / ``deny``). Not subscribable; addressed at the machine's own connection.","value":{"url":"https://example.com/hooks/prohost","event":"code_thread.approval_decided","status_code":200,"response_time_ms":142,"delivered":true,"test_secret":"whsec_test_REDACTED","envelope":{"id":"test_f6a7b8c9-d0e1-4234-8567-890abcdef123","event":"code_thread.approval_decided","created_at":"2026-04-24T14:50:00Z","schema_version":1,"data":{"codeThreadId":"01a18000-0000-4000-8000-000000000001","terminalId":"01a18000-0000-4000-8000-000000000001","approvalId":"4b7e1c2a-0000-4000-8000-000000000009","decision":"allow"}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inbound-webhooks":{"get":{"tags":["Inbound webhooks"],"summary":"List inbound webhooks","description":"List the account's inbound webhooks. Tokens are masked to a short prefix.","operationId":"list_inbound_webhooks_v1_inbound_webhooks_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundWebhookListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Inbound webhooks"],"summary":"Create an inbound webhook for a channel","description":"Mint a `/in/<token>` URL bound to a team-chat conversation. Every POST to that URL becomes one markdown message in the channel.\n\n**The full token and URL are returned exactly once, in this response.** Reads mask them, and there is no way to recover a token afterwards — store it, or delete the webhook and mint a new one.\n\nPost bodies accept `{\"text\": \"...\"}` plus a Slack-blocks-lite subset (`header`, `section` with `text` and/or `fields`, `context`, `divider`), so an existing Slack alerter can usually be re-pointed by changing one URL. Unsupported block types are skipped rather than rendered as noise.\n\nSet `secret` to require an `X-Prohost-Signature` header (hex HMAC-SHA256 of the raw body) on every delivery — recommended, since the URL is the only other credential.","operationId":"create_inbound_webhook_v1_inbound_webhooks_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundWebhookCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundWebhookCreatedExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inbound-webhooks/{webhook_id}":{"patch":{"tags":["Inbound webhooks"],"summary":"Update an inbound webhook","description":"Rename, deactivate, or re-point a webhook at a different conversation without re-minting its token — the URL is usually already deployed in someone's CI config.\n\n`mode` is not editable: flipping a live URL between posting verbatim into a channel and waking an agent would silently change what a deployed integration does.","operationId":"update_inbound_webhook_v1_inbound_webhooks__webhook_id__patch","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundWebhookUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundWebhookExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Inbound webhooks"],"summary":"Delete an inbound webhook","description":"Delete a webhook and its delivery log. The URL stops working immediately.","operationId":"delete_inbound_webhook_v1_inbound_webhooks__webhook_id__delete","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Webhook Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/workflows":{"get":{"tags":["Workflows"],"summary":"List workflows","description":"Retrieve a paginated list of automation workflows for the account, with optional filters by enabled status and text search.","operationId":"list_workflows_v1_workflows_get","parameters":[{"name":"enabled","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by enabled status","title":"Enabled"},"description":"Filter by enabled status"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by workflow name","title":"Search"},"description":"Search by workflow name"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Paginated list using the offset envelope (`items`, `total`, `limit`, `offset`, `has_more`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffsetPage_WorkflowExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/workflows/{workflow_id}":{"get":{"tags":["Workflows"],"summary":"Get a workflow","description":"Retrieve a single automation workflow by its ID, including its steps.","operationId":"get_workflow_v1_workflows__workflow_id__get","parameters":[{"name":"workflow_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workflow Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invitations":{"post":{"tags":["Team"],"summary":"Invite a team member","description":"Create an invitation for a new team member. The invitation email is handled by the internal flow.","operationId":"create_invitation_v1_invitations_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Team"],"summary":"List pending invitations","description":"Retrieve all pending (open) invitations for the account.","operationId":"list_invitations_v1_invitations_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvitationExternal"},"title":"Response List Invitations V1 Invitations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invitations/{invitation_id}":{"delete":{"tags":["Team"],"summary":"Revoke an invitation","description":"Cancel a pending invitation so it can no longer be accepted.","operationId":"revoke_invitation_v1_invitations__invitation_id__delete","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/team":{"get":{"tags":["Team"],"summary":"List team members","description":"Retrieve all current team members on the account.","operationId":"list_team_members_v1_team_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberExternal"},"title":"Response List Team Members V1 Team Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/team/{user_id}":{"delete":{"tags":["Team"],"summary":"Remove a team member","description":"Remove a user from the account team.","operationId":"remove_team_member_v1_team__user_id__delete","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/items":{"get":{"tags":["Drive"],"summary":"List drive items","description":"List children of a folder. Defaults to root. Accepts either ``parent_id`` or ``path`` (e.g. ``/Properties/Ocean View``). When both are set, ``parent_id`` wins. Supports offset pagination via the standard ``{items, limit, offset, has_more}`` envelope.","operationId":"list_items_v1_drive_items_get","parameters":[{"name":"parent_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Folder to list. Omit for root.","title":"Parent Id"},"description":"Folder to list. Omit for root."},{"name":"path","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Folder path (e.g. /Properties/Ocean View). Omit for root.","title":"Path"},"description":"Folder path (e.g. /Properties/Ocean View). Omit for root."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paginated_DriveItemExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Drive"],"summary":"Create a drive item","operationId":"create_item_v1_drive_items_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/items/resolve":{"get":{"tags":["Drive"],"summary":"Resolve a drive path to an item","description":"Resolve ``/Properties/Ocean View/Guidebook`` to the corresponding DriveItem. A path the acting user may not read is a 404, exactly like a missing path.","operationId":"resolve_v1_drive_items_resolve_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":2048,"title":"Path"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/items/{item_id}":{"get":{"tags":["Drive"],"summary":"Get a drive item","operationId":"get_item_v1_drive_items__item_id__get","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Drive"],"summary":"Update a drive item","operationId":"update_item_v1_drive_items__item_id__patch","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemUpdateExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Drive"],"summary":"Soft-delete a drive item","operationId":"delete_item_v1_drive_items__item_id__delete","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/items/{item_id}/move":{"post":{"tags":["Drive"],"summary":"Move a drive item","operationId":"move_item_v1_drive_items__item_id__move_post","parameters":[{"name":"item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Item Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveMoveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveItemExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/search":{"get":{"tags":["Drive"],"summary":"Search drive items by name","operationId":"search_items_v1_drive_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Name query","title":"Q"},"description":"Name query"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paginated_DriveItemExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/media/upload-url":{"post":{"tags":["Drive"],"summary":"Start a doc media upload","description":"Presigned PUT for an image, video or audio clip to embed in a doc. Attach it with ``drive_doc_id`` or ``drive_item_id`` (editor required). PUT the bytes with the same ``Content-Type``, then confirm.","operationId":"create_media_upload_url_v1_drive_media_upload_url_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveMediaUploadRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveMediaUploadExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/media/{asset_id}/confirm":{"post":{"tags":["Drive"],"summary":"Confirm a doc media upload","description":"Verify the uploaded bytes and mark the asset ready. Idempotent. Returns the stable ``url`` and the ``markdown`` that embeds it in the doc.","operationId":"confirm_media_upload_v1_drive_media__asset_id__confirm_post","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Asset Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveMediaAssetExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/files/upload-url":{"post":{"tags":["Drive"],"summary":"Start a file upload","description":"Presigned PUT for a file that becomes a ``kind=file`` Drive item. Target folder by ``parent_id`` or ``parent_path`` (editor required; omit both for the root). Same allowed types, size caps and storage quota as the app.","operationId":"create_file_upload_url_v1_drive_files_upload_url_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveFileUploadRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveFileUploadExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/files/{file_id}/confirm":{"post":{"tags":["Drive"],"summary":"Confirm a file upload","description":"Verify the uploaded bytes and create the ``kind=file`` item in the target folder (``parent_id`` / ``parent_path``; neither = root). Pass ``upload_id`` for a multipart upload.","operationId":"confirm_file_upload_v1_drive_files__file_id__confirm_post","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveFileConfirmRequestExternal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveFileExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/docs/{path_or_id}/sections":{"get":{"tags":["Drive Docs"],"summary":"List doc sections (heading-chunked blocks)","operationId":"list_sections_v1_drive_docs__path_or_id__sections_get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DocSectionExternal"},"title":"Response List Sections V1 Drive Docs  Path Or Id  Sections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Drive Docs"],"summary":"Append a new doc section","operationId":"append_section_v1_drive_docs__path_or_id__sections_post","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocSectionWriteRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/docs/{path_or_id}/sections/{section_id}":{"get":{"tags":["Drive Docs"],"summary":"Read a single doc section","operationId":"read_section_v1_drive_docs__path_or_id__sections__section_id__get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"section_id","in":"path","required":true,"schema":{"type":"string","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocSectionExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Drive Docs"],"summary":"Replace a single doc section","operationId":"write_section_v1_drive_docs__path_or_id__sections__section_id__put","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"section_id","in":"path","required":true,"schema":{"type":"string","title":"Section Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocSectionReplaceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/drive/docs/{path_or_id}":{"get":{"tags":["Drive Docs"],"summary":"Read a doc by path or id","description":"Accepts either a UUID or a slash-delimited path (e.g. ``/Properties/Ocean View/Guidebook``).","operationId":"read_doc_v1_drive_docs__path_or_id__get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Drive Docs"],"summary":"Replace a doc body","operationId":"write_doc_v1_drive_docs__path_or_id__put","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocWriteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets":{"get":{"tags":["Drive Sheets"],"summary":"List sheets in the account","description":"List sheet metadata rows for the calling account. Offset-paginated.","operationId":"list_sheets_v1_sheets_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paginated_SheetExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets/{path_or_id}/schema":{"get":{"tags":["Drive Sheets"],"summary":"Get a sheet's schema","operationId":"get_schema_v1_sheets__path_or_id__schema_get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets/{path_or_id}/rows":{"get":{"tags":["Drive Sheets"],"summary":"List rows in a sheet","operationId":"list_rows_v1_sheets__path_or_id__rows_get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paginated_SheetRowExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Drive Sheets"],"summary":"Insert a row","operationId":"insert_row_v1_sheets__path_or_id__rows_post","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetRowCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetRowExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets/{path_or_id}/rows/{row_id}":{"patch":{"tags":["Drive Sheets"],"summary":"Update a row (partial patch)","operationId":"update_row_v1_sheets__path_or_id__rows__row_id__patch","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"row_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Row Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetRowUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetRowExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Drive Sheets"],"summary":"Delete a row","operationId":"delete_row_v1_sheets__path_or_id__rows__row_id__delete","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"row_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Row Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets/{path_or_id}/query":{"post":{"tags":["Drive Sheets"],"summary":"Query rows with a simple filter DSL","description":"Apply column-equality filters and an optional sort key. ``filter`` is a ``{column_id: value}`` map; a row matches when all columns match. ``sort`` is ``column_id`` (ascending) or ``-column_id`` (descending).","operationId":"query_rows_v1_sheets__path_or_id__query_post","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Paginated_SheetRowExternal_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sheets/{path_or_id}":{"get":{"tags":["Drive Sheets"],"summary":"Get sheet metadata","operationId":"get_sheet_v1_sheets__path_or_id__get","parameters":[{"name":"path_or_id","in":"path","required":true,"schema":{"type":"string","title":"Path Or Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SheetExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/customer-feedback":{"post":{"tags":["Customer Feedback"],"summary":"Submit feedback","description":"Submit a bug report, feature request, or question to the ProhostAI team. Feedback is routed into the same triage queue as in-product submissions. Requires the ``feedback:write`` scope (implied by ``*``). Supports idempotent retries via the ``Idempotency-Key`` header.","operationId":"create_feedback_v1_customer_feedback_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerFeedbackCreateExternal"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerFeedbackExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/feature-board/posts":{"get":{"tags":["Feature Board"],"summary":"List Feature Board posts","description":"Page through the published ProhostAI Feature Board. `sort` is `trending` (votes in the last 30 days, the default), `top` (all-time votes) or `new`; `status` narrows to one status. Each post carries the acting user's own `my_vote` / `my_follow`. Pass `next_cursor` back as `cursor` for the next page. Requires `feature_board:read`.","operationId":"list_posts_v1_feature_board_posts_get","parameters":[{"name":"sort","in":"query","required":false,"schema":{"$ref":"#/components/schemas/FeatureBoardSort","default":"trending"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/FeatureBoardPostStatus"},{"type":"null"}],"title":"Status"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostPageExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/feature-board/search":{"get":{"tags":["Feature Board"],"summary":"Search Feature Board posts","description":"Full-text search over the published Feature Board, best match first. Phrase the query the way the user would ask for the feature; quoted phrases, `or` and a leading `-` work as in a web search. Search before filing a feature request — voting for an existing post is a stronger signal than a duplicate. Requires `feature_board:read`.","operationId":"search_posts_v1_feature_board_search_get","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":500,"title":"Query"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":5,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardSearchResultsExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/feature-board/posts/{post_id}":{"get":{"tags":["Feature Board"],"summary":"Get a Feature Board post","description":"One published post with the acting user's vote/follow state. Requires `feature_board:read`.","operationId":"get_post_v1_feature_board_posts__post_id__get","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/feature-board/posts/{post_id}/vote":{"post":{"tags":["Feature Board"],"summary":"Vote for a Feature Board post","description":"Vote for a post as the acting user. Voting also follows the post, so the user is notified when it ships. Idempotent — voting again is a no-op. Refused for AI-employee credentials and credentials that don't name a person. Requires `feature_board:write`.","operationId":"vote_post_v1_feature_board_posts__post_id__vote_post","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Feature Board"],"summary":"Withdraw a Feature Board vote","description":"Withdraw the acting user's vote. Keeps the follow — unfollow separately to stop ship notifications. Idempotent. Requires `feature_board:write`.","operationId":"unvote_post_v1_feature_board_posts__post_id__vote_delete","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/feature-board/posts/{post_id}/follow":{"post":{"tags":["Feature Board"],"summary":"Follow a Feature Board post","description":"Follow a post without voting, so the acting user is notified when it ships. Idempotent. Requires `feature_board:write`.","operationId":"follow_post_v1_feature_board_posts__post_id__follow_post","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Feature Board"],"summary":"Unfollow a Feature Board post","description":"Stop following a post. Leaves any vote in place. Idempotent. Requires `feature_board:write`.","operationId":"unfollow_post_v1_feature_board_posts__post_id__follow_delete","parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Post Id"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureBoardPostExternal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ops-actions":{"post":{"tags":["ops-actions"],"summary":"File Ops Action","description":"File a privileged ops action for a human operator to execute.\n\nIdempotent per (conversation, action_type): an identical open re-file\nreturns the existing row with ``created: false``; a conflicting one 409s\nwith both versions so an operator supersedes deliberately.","operationId":"file_ops_action_v1_ops_actions_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsActionFileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsActionFileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AIChatMessageExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"role":{"type":"string","title":"Role"},"content":{"type":"string","title":"Content"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","role","content","created_at"],"title":"AIChatMessageExternal"},"AIChatMessageListExternal":{"properties":{"session_id":{"type":"string","format":"uuid","title":"Session Id"},"messages":{"items":{"$ref":"#/components/schemas/AIChatMessageExternal"},"type":"array","title":"Messages"}},"type":"object","required":["session_id","messages"],"title":"AIChatMessageListExternal"},"AIChatSessionCreateExternal":{"properties":{"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id","description":"Optional listing to scope the assistant's context to. The listing must be AI-subscribed."},"title":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Title","description":"Optional session title."}},"type":"object","title":"AIChatSessionCreateExternal","description":"Create an Ask-AI chat session (global property assistant)."},"AIChatSessionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","title","listing_id","created_at","updated_at"],"title":"AIChatSessionExternal"},"AIChatSessionListExternal":{"properties":{"sessions":{"items":{"$ref":"#/components/schemas/AIChatSessionExternal"},"type":"array","title":"Sessions"}},"type":"object","required":["sessions"],"title":"AIChatSessionListExternal"},"AIChatTurnRequest":{"properties":{"message":{"type":"string","maxLength":20000,"minLength":1,"title":"Message","description":"The user question / instruction."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA timezone for time-aware answers."}},"type":"object","required":["message"],"title":"AIChatTurnRequest","description":"Run one Ask-AI turn in a session."},"AIChatTurnResponse":{"properties":{"session_id":{"type":"string","format":"uuid","title":"Session Id"},"message":{"type":"string","title":"Message"},"success":{"type":"boolean","title":"Success","default":true},"model_used":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Used"},"tools_used":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Tools Used"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["session_id","message"],"title":"AIChatTurnResponse","description":"The assistant's reply for one turn."},"AIEmployeeCadence":{"type":"string","enum":["immediately","hourly","daily","off"],"title":"AIEmployeeCadence","description":"How often AI-employee notification emails are delivered to a user.\n\nStored as a plain string (never a PostgreSQL enum type), so adding a\nvalue here needs no enum migration.\n\n* ``immediately`` — send the real-time approval email as soon as a\n  request is created (the default, preserving current behavior).\n* ``hourly`` / ``daily`` — suppress the immediate email; the user\n  relies on the daily digest instead.\n* ``off`` — suppress AI-employee emails entirely."},"AIEmployeeExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"template_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Key"},"is_default":{"type":"boolean","title":"Is Default","default":false},"heartbeat_enabled":{"type":"boolean","title":"Heartbeat Enabled","default":false},"heartbeat_interval_seconds":{"type":"integer","title":"Heartbeat Interval Seconds"},"confidence_threshold":{"type":"integer","title":"Confidence Threshold"},"proactiveness":{"type":"string","title":"Proactiveness"},"skill_keys":{"items":{"type":"string"},"type":"array","title":"Skill Keys","description":"Skills attached to the employee."},"tool_allowlist":{"items":{"type":"string"},"type":"array","title":"Tool Allowlist","description":"Tools the employee may use; empty means the default tool set."},"heartbeat_cadence_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Heartbeat Cadence Mode","description":"adaptive / interval / cron."},"heartbeat_schedule_cron":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Heartbeat Schedule Cron"},"heartbeat_schedule_timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Heartbeat Schedule Timezone"},"model_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Tier","description":"Per-employee model tier; null uses the surface default."},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Exact model id when model_tier is 'custom'."},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","heartbeat_interval_seconds","confidence_threshold","proactiveness","created_at"],"title":"AIEmployeeExternal","description":"An AI employee as exposed on the external API."},"AIEmployeeNotificationScope-Input":{"type":"string","enum":["all","approvals","escalations"],"title":"AIEmployeeNotificationScope","description":"Scopes for AI-employee notifications - can be combined additively.\n\nGoverns which AI-employee approval-lifecycle outreach a user receives:\nproactive sign-off requests (``approvals``) vs. the escalation/digest\nnudges that fire when a request sits unanswered (``escalations``).\n``all`` (the default) covers both."},"AIEmployeeNotificationScope-Output":{"type":"string","title":"AIEmployeeNotificationScope","description":"Scopes for AI-employee notifications - can be combined additively.\n\nGoverns which AI-employee approval-lifecycle outreach a user receives:\nproactive sign-off requests (``approvals``) vs. the escalation/digest\nnudges that fire when a request sits unanswered (``escalations``).\n``all`` (the default) covers both.","x-extensible-enum":["all","approvals","escalations"]},"AIEmployeeTriggerExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"trigger_type":{"type":"string","title":"Trigger Type"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What this trigger is for. Injected into the prompt of every run it fires, so on a 'schedule' trigger (a routine) it reads as the standing assignment for that run."},"target_agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Agent Id"},"enabled":{"type":"boolean","title":"Enabled","default":true},"cooldown_seconds":{"type":"integer","title":"Cooldown Seconds","description":"Per-trigger cooldown window in seconds.","default":60},"trigger_config":{"additionalProperties":true,"type":"object","title":"Trigger Config","description":"Trigger configuration: 'schedule' for schedule triggers, 'conditions', 'relevance_screen', 'skill_key'."},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","trigger_type","created_at"],"title":"AIEmployeeTriggerExternal","description":"An agent trigger (an ``is_agent_trigger`` workflow row)."},"AITaskCadence":{"type":"string","enum":["immediately","bundled","daily","off"],"title":"AITaskCadence","description":"How pushes about AI-created tasks reach a user.\n\nSeparate from :class:`TaskNotificationScope` so a user can quiet the tasks\nthe AI files without muting tasks people create or assign to them. Stored as\na plain nullable string on ``user_notification_settings.ai_task_cadence``\n(never a PostgreSQL enum type). NULL means \"never chosen\" and resolves to\nthe default in ``shared.tasks.ai_notification_bundling`` — ``bundled``.\n\n* ``immediately`` — one push per AI-created task (the legacy behavior).\n* ``bundled`` — AI-created tasks collect for a short window and arrive as\n  one push (\"3 new tasks from AI · ...\").\n* ``daily`` — one digest push per day, in the morning of the user's\n  timezone.\n* ``off`` — no push for AI-created tasks.\n\nWhatever the cadence, tasks the always-reach-a-person policy protects\n(``shared.tasks.escalation_policy``) still push immediately."},"AgentDMExternal":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"agent_id":{"type":"string","format":"uuid","title":"Agent Id"},"reused":{"type":"boolean","title":"Reused","description":"True when an existing DM thread was reused; False when this call created it."}},"type":"object","required":["conversation_id","agent_id","reused"],"title":"AgentDMExternal","description":"The deterministic 1:1 thread between the caller and an AI employee.","examples":[{"agent_id":"0195c3aa-2222-7abc-9def-0123456789ab","conversation_id":"0195c3aa-1111-7abc-9def-0123456789ab","reused":true}]},"AgentDMMessageExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"from_agent":{"type":"boolean","title":"From Agent","description":"True when the AI employee sent this message."},"sender_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender Type"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","message","from_agent","sent_at","created_at"],"title":"AgentDMMessageExternal"},"AgentDMMessagesPage":{"properties":{"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id","description":"The DM thread id, or null when no DM exists yet (no messages have been exchanged)."},"items":{"items":{"$ref":"#/components/schemas/AgentDMMessageExternal"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["conversation_id","items","total"],"title":"AgentDMMessagesPage"},"AgentRunChangedFile":{"properties":{"path":{"type":"string","title":"Path","description":"Repo-relative path of a file the run changed."},"additions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Additions"},"deletions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deletions"}},"type":"object","required":["path"],"title":"AgentRunChangedFile"},"AgentRunCompleteRequest":{"properties":{"status":{"type":"string","pattern":"^(succeeded|failed)$","title":"Status","description":"Terminal state of the run."},"error":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Error","description":"Short failure reason, surfaced on the run detail page. Ignored when status is `succeeded`."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"What the run did, in one or two sentences. Shown on the Agent Desk and used to ground end-of-run memory capture. Clipped to 4000 characters."},"tools_used":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tools Used","description":"Names of the tools the run called. Grounds end-of-run memory capture — a run that reports no tools captures no memories, since a turn that established nothing has nothing durable to learn. At most 50 names of 100 characters each; the rest are dropped."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Model id the run used, e.g. `claude-opus-5-5`. Shown as the model an AI employee last ran on. Clipped to 100 characters."},"outcome":{"anyOf":[{"type":"string","enum":["replied","silent"]},{"type":"null"}],"title":"Outcome","description":"How a `succeeded` run ended. `silent` means you decided not to post anything — for example you were woken as a participant (`reply_expected: false` in the work order) and had nothing to add. The run is recorded as a deliberate silence and the thinking indicator clears without implying a reply landed. `replied` means you posted a reply. Omit it and a `succeeded` run is treated as having replied. Only valid with `status: succeeded`."},"failure_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Kind","description":"Why a `failed` run failed, when it is a kind ProhostAI acts on. `usage_limit`: your model subscription's usage limit stopped the run — send `retry_after` too when you know when it lifts, and the request is run again then. Unknown values are ignored, as is the field when status is `succeeded`."},"retry_after":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Retry After","description":"With `failure_kind: usage_limit`: when the limit lifts (ISO 8601). A value that does not parse is ignored."}},"type":"object","required":["status"],"title":"AgentRunCompleteRequest","description":"Body for `POST /v1/agent-runs/{run_id}/complete`.\n\nOnly `status` is required. `summary` and `tools_used` are optional — send\nthem to have the run show what it did on the Agent Desk and to let the\nagent learn from it; omit them and the run completes exactly as before.\nOversized values are clipped, never rejected.\n\n`outcome` says whether a successful run posted a reply (`replied`) or\ndeliberately posted nothing (`silent`). Omit it and a `succeeded` run is\ntreated as having replied, exactly as before.","examples":[{"status":"succeeded"},{"model":"claude-opus-5-5","status":"succeeded","summary":"Confirmed the 2pm early check-in with the cleaner and replied to the guest.","tools_used":["search_reservations","get_cleaning","send_message"]},{"outcome":"silent","status":"succeeded"},{"error":"upstream model timed out after 3 retries","status":"failed"},{"error":"Claude usage limit reached on my-laptop: You've hit your session limit","failure_kind":"usage_limit","retry_after":"2026-10-19T03:00:00Z","status":"failed"}]},"AgentRunCompleteResponse":{"properties":{"run_id":{"type":"string","format":"uuid","title":"Run Id"},"status":{"type":"string","title":"Status"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"}},"type":"object","required":["run_id","status","ended_at"],"title":"AgentRunCompleteResponse","examples":[{"ended_at":"2026-07-25T14:03:42Z","run_id":"01HFXEEEEEEEEEEEEEEEEEEE00","status":"succeeded"}]},"AgentRunHeartbeatRequest":{"properties":{"progress":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Progress","description":"One short line describing what the run is doing right now, shown on the Agent Desk so a long run reads as progress instead of a spinner. Clipped to 200 characters; send it as often as you like, each heartbeat replaces the last."},"task_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Task Id","description":"The task this run is working on. Shows the run as an AI working on that task until the run completes. Must be the task the run was dispatched on (404 `task_not_found` otherwise)."},"phase":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phase","description":"How far the work has got: `investigate`, `change`, `test`, `pr`, `ci` or `merged`. Only moves forward, except back to `change` after failing tests."},"current_step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Step","description":"One line on what the run is doing on the task. Clipped to 280 characters."},"repo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo","description":"Repository, e.g. `ProhostAI/backend-service`."},"branch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch","description":"Branch the work is on."},"additions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Additions","description":"Lines added so far."},"deletions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deletions","description":"Lines deleted so far."},"files_changed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Files Changed","description":"Files changed so far."},"changed_files":{"anyOf":[{"items":{"$ref":"#/components/schemas/AgentRunChangedFile"},"type":"array"},{"type":"null"}],"title":"Changed Files","description":"Per-file diffstat; the first 50 are kept."},"tests_passed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tests Passed","description":"Tests passing on the last run."},"tests_failed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tests Failed","description":"Tests failing on the last run."},"failing_tests":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Failing Tests","description":"Names of failing tests; the first 20 are kept."},"pr_number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pr Number","description":"Pull request number, once one is open."}},"type":"object","title":"AgentRunHeartbeatRequest","description":"Body for `POST /v1/agent-runs/{run_id}/heartbeat`. Everything optional.\n\n`task_id` and the fields after it report the run's work on a task. They\nare ignored unless `task_id` is set; an unknown `phase` and nonsensical\ncounts are dropped rather than rejected.","examples":[{},{"progress":"Reading the last 20 messages on the thread"},{"additions":42,"branch":"fix/checkout-time","current_step":"Running the task tests","deletions":7,"failing_tests":["tests/test_checkout.py::test_late_checkout"],"files_changed":3,"phase":"test","progress":"Running the task tests","repo":"ProhostAI/backend-service","task_id":"01HFXTTTTTTTTTTTTTTTTTTT00","tests_failed":1,"tests_passed":18}]},"AgentRunHeartbeatResponse":{"properties":{"run_id":{"type":"string","format":"uuid","title":"Run Id"},"status":{"type":"string","title":"Status"},"cancel_requested":{"type":"boolean","title":"Cancel Requested"}},"type":"object","required":["run_id","status","cancel_requested"],"title":"AgentRunHeartbeatResponse","examples":[{"cancel_requested":false,"run_id":"01HFXEEEEEEEEEEEEEEEEEEE00","status":"running"}]},"AgentRunToolEvent":{"properties":{"tool_id":{"type":"string","maxLength":128,"minLength":1,"title":"Tool Id","description":"Your identifier for this invocation (Claude Code's `tool_use.id`). One row per `tool_id`; a `calling` opens it, a `completed` / `failed` settles it, and anything that would move it backwards or re-state it is ignored — so replaying a batch is safe."},"tool_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Name","description":"The tool's name as your runtime calls it (`Bash`, `Read`, `mcp__prohost__search_reservations`). Required on `calling`; optional on a terminal event for a `tool_id` already opened. Clipped to 100 characters."},"status":{"type":"string","enum":["calling","completed","failed"],"title":"Status","description":"`calling` when the tool starts; `completed` or `failed` when it returns."},"error_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Summary","description":"One-line reason, shown on `failed` rows only. Clipped to 300 characters."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When the tool started (ISO 8601). Defaults to the server's receipt time."},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the tool returned (ISO 8601). Defaults to the server's receipt time."},"args_preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Args Preview","description":"A short rendering of the call's arguments (the command, the file path, the query). Clipped to 500 characters; do not send secrets."},"result_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Summary","description":"A short rendering of what the tool returned. Whitespace-collapsed, capped to 200 characters on the timeline, and redacted before it reaches a client."}},"type":"object","required":["tool_id","status"],"title":"AgentRunToolEvent","description":"One tool-call lifecycle event. Free-text fields are clipped, never rejected.","examples":[{"args_preview":"git status","started_at":"2026-09-01T14:03:42Z","status":"calling","tool_id":"toolu_01ABC","tool_name":"Bash"},{"ended_at":"2026-09-01T14:03:43Z","result_summary":"On branch main, nothing to commit","status":"completed","tool_id":"toolu_01ABC","tool_name":"Bash"},{"ended_at":"2026-09-01T14:03:50Z","error_summary":"HTTP 503 from upstream","status":"failed","tool_id":"toolu_01DEF","tool_name":"WebFetch"}]},"AgentRunToolEventsRequest":{"properties":{"events":{"items":{"$ref":"#/components/schemas/AgentRunToolEvent"},"type":"array","maxItems":50,"minItems":1,"title":"Events","description":"Between 1 and 50 events, in the order they happened."}},"type":"object","required":["events"],"title":"AgentRunToolEventsRequest","description":"Body for `POST /v1/agent-runs/{run_id}/events`.","examples":[{"events":[{"args_preview":"ls","status":"calling","tool_id":"toolu_01ABC","tool_name":"Bash"},{"result_summary":"3 files","status":"completed","tool_id":"toolu_01ABC"}]}]},"AgentRunToolEventsResponse":{"properties":{"run_id":{"type":"string","format":"uuid","title":"Run Id"},"status":{"type":"string","title":"Status"},"cancel_requested":{"type":"boolean","title":"Cancel Requested"},"accepted":{"type":"integer","title":"Accepted","description":"Events that opened or settled a timeline row."},"ignored":{"type":"integer","title":"Ignored","description":"Events that changed nothing — replays, or a status the row had already passed."},"stored":{"type":"integer","title":"Stored","description":"Tool rows now on the run (at most 200)."},"dropped":{"type":"integer","title":"Dropped","description":"Oldest rows discarded by the per-run cap, cumulative for this run."}},"type":"object","required":["run_id","status","cancel_requested","accepted","ignored","stored","dropped"],"title":"AgentRunToolEventsResponse","examples":[{"accepted":2,"cancel_requested":false,"dropped":0,"ignored":0,"run_id":"01HFXEEEEEEEEEEEEEEEEEEE00","status":"running","stored":2}]},"AgentRuntimeContextExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id","description":"Account the agent belongs to. Always the calling key's account — returned so a runtime can assert its dispatch payload targets the same tenant its credential is bound to."},"name":{"type":"string","title":"Name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"system_prompt":{"type":"string","title":"System Prompt","description":"The agent's operating instructions (its persona)."},"agent_user_id":{"type":"string","format":"uuid","title":"Agent User Id","description":"The agent's synthetic member user. A paired credential minted for this agent carries this id as its `acts_as_user_id`, so writes it makes attribute to the AI employee."},"runtime":{"type":"string","title":"Runtime","description":"Which runtime executes this agent's runs (e.g. `claude_worker`)."},"dispatch_enabled":{"type":"boolean","title":"Dispatch Enabled","description":"The employee's on/off switch. When `false` the host has switched this employee off and it must not start work on its own — an external runtime must refuse autonomous runs (check-ins, triggers, @mentions, task assignments) and run only host-initiated ones. Defaults to `true` so a runtime reading an older server that omits the field is not silently muted.","default":true}},"type":"object","required":["id","account_id","name","system_prompt","agent_user_id","runtime"],"title":"AgentRuntimeContextExternal","description":"Everything an external brain needs to run as this AI employee."},"AiStateResponse":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"ai_muted":{"type":"boolean","title":"Ai Muted"}},"type":"object","required":["conversation_id","ai_muted"],"title":"AiStateResponse","description":"Response for ``POST /conversations/{id}/ai-state/(pause|resume)``."},"ApprovalRequestCreateExternal":{"properties":{"title":{"type":"string","maxLength":300,"minLength":1,"title":"Title","description":"Card headline."},"action_kind":{"type":"string","maxLength":200,"title":"Action Kind","description":"The action the agent wants to perform (e.g. 'send_campaign_email'). Free-form; shown on the card and echoed in webhooks.","default":"external_action"},"description":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Description","description":"Longer explanation shown on the card."},"proposed_action":{"additionalProperties":true,"type":"object","title":"Proposed Action","description":"Structured payload describing the proposed action (max 32KB JSON)."},"context":{"additionalProperties":true,"type":"object","title":"Context","description":"Free-form context shown read-only on the card (max 16KB JSON)."},"risk_level":{"type":"string","pattern":"^(low|medium|high)$","title":"Risk Level","description":"Card risk chip.","default":"medium"},"recipient_user_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":20},{"type":"null"}],"title":"Recipient User Ids","description":"Account members to route the approval to. Omit for the default routing (the agent's configured approvers, else owner + admins)."},"expires_in_hours":{"anyOf":[{"type":"integer","maximum":168.0,"minimum":1.0},{"type":"null"}],"title":"Expires In Hours","description":"Auto-expire the request after this many hours (default 7 days)."}},"type":"object","required":["title"],"title":"ApprovalRequestCreateExternal","description":"Body for ``POST /v1/approvals``.\n\n``proposed_action`` / ``context`` are free-form JSON the approval card\nrenders (recognized shapes richly, unknown shapes as a raw-payload\nview). Size caps are enforced at the shared seam (32KB / 16KB)."},"ApprovalRequestExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status","description":"pending | approved | rejected | expired"},"source":{"type":"string","title":"Source"},"action_kind":{"type":"string","title":"Action Kind"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"proposed_action":{"additionalProperties":true,"type":"object","title":"Proposed Action"},"risk_level":{"type":"string","title":"Risk Level"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"responded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Responded At"},"rejection_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rejection Reason","description":"Reviewer-supplied reason; only ever set on rejected requests."}},"type":"object","required":["id","status","source","action_kind","title","description","proposed_action","risk_level","created_at","expires_at","responded_at"],"title":"ApprovalRequestExternal","description":"One approval request, as exposed to external callers."},"ApprovalRequestListExternal":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ApprovalRequestExternal"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"ApprovalRequestListExternal"},"ArrivalsBuzz":{"type":"string","enum":["urgent","all","none"],"title":"ArrivalsBuzz","description":"When the \"Today's arrivals\" Live Activity alerts (\"buzzes\") this person.\n\nStored as a plain string on ``user_notification_settings.arrivals_buzz``\n(CHECK-constrained to these values). Every other platter update is silent.\n\n* ``urgent`` — an arrival newly turns bad close to its check-in, or a\n  payment / ID / agreement / deposit problem is still open shortly before\n  it (the default).\n* ``all`` — any newly appearing problem.\n* ``none`` — never."},"AutoReview":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"status":{"$ref":"#/components/schemas/AutoReviewStatus"},"skip_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skip Reason"},"withhold_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Withhold Reason"},"public_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Review"},"private_feedback":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Feedback"},"is_reviewee_recommended":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Reviewee Recommended"},"category_ratings":{"items":{"$ref":"#/components/schemas/AutoReviewCategoryRating"},"type":"array","title":"Category Ratings"},"generation_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generation At"},"scheduled_for":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled For"},"submitted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted At"},"listing":{"$ref":"#/components/schemas/AutoReviewListing"},"reservation":{"$ref":"#/components/schemas/AutoReviewReservation"},"published_review":{"anyOf":[{"$ref":"#/components/schemas/AutoReviewPublishedReview"},{"type":"null"}]},"posted_review":{"anyOf":[{"$ref":"#/components/schemas/AutoReviewPostedReview"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","account_id","status","skip_reason","withhold_reason","public_review","private_feedback","is_reviewee_recommended","category_ratings","generation_at","scheduled_for","submitted_at","listing","reservation","published_review","created_at","updated_at"],"title":"AutoReview"},"AutoReviewAirbnbCleanlinessTag":{"type":"string","enum":["host_review_guest_positive_neat_and_tidy","host_review_guest_positive_kept_in_good_condition","host_review_guest_positive_took_care_of_garbage","host_review_guest_negative_ignored_checkout_directions","host_review_guest_negative_garbage","host_review_guest_negative_messy_kitchen","host_review_guest_negative_damage","host_review_guest_negative_ruined_bed_linens"],"title":"AutoReviewAirbnbCleanlinessTag"},"AutoReviewAirbnbCommunicationTag":{"type":"string","enum":["host_review_guest_positive_helpful_messages","host_review_guest_positive_respectful","host_review_guest_positive_always_responded","host_review_guest_negative_unhelpful_messages","host_review_guest_negative_disrespectful","host_review_guest_negative_unreachable","host_review_guest_negative_slow_responses"],"title":"AutoReviewAirbnbCommunicationTag"},"AutoReviewAirbnbHouseRulesTag":{"type":"string","enum":["host_review_guest_negative_arrived_early","host_review_guest_negative_stayed_past_checkout","host_review_guest_negative_unapproved_guests","host_review_guest_negative_unapproved_pet","host_review_guest_negative_did_not_respect_quiet_hours","host_review_guest_negative_unapproved_filming","host_review_guest_negative_unapproved_event","host_review_guest_negative_smoking"],"title":"AutoReviewAirbnbHouseRulesTag"},"AutoReviewCategory":{"type":"string","enum":["cleanliness","communication","respect_house_rules"],"title":"AutoReviewCategory"},"AutoReviewCategoryRating":{"properties":{"category":{"$ref":"#/components/schemas/AutoReviewCategory"},"rating":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rating"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment"},"tags":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/AutoReviewAirbnbCleanlinessTag"},{"$ref":"#/components/schemas/AutoReviewAirbnbCommunicationTag"},{"$ref":"#/components/schemas/AutoReviewAirbnbHouseRulesTag"}]},"type":"array"},{"type":"null"}],"title":"Tags"}},"type":"object","required":["category","rating","comment"],"title":"AutoReviewCategoryRating"},"AutoReviewListing":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"}},"type":"object","required":["id","title","thumbnail_url"],"title":"AutoReviewListing"},"AutoReviewPostedReview":{"properties":{"public_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Review"},"private_feedback":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Feedback"},"category_ratings":{"items":{"$ref":"#/components/schemas/AutoReviewCategoryRating"},"type":"array","title":"Category Ratings"},"submitted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Submitted At"}},"type":"object","required":["public_review","private_feedback","category_ratings","submitted_at"],"title":"AutoReviewPostedReview","description":"The review already on Airbnb when an auto-review was skipped because someone else posted first."},"AutoReviewPublishedReview":{"properties":{"id":{"type":"string","title":"Id"}},"type":"object","required":["id"],"title":"AutoReviewPublishedReview"},"AutoReviewReservation":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"channel":{"$ref":"#/components/schemas/ReservationChannelIdStr"},"guest_name":{"type":"string","title":"Guest Name"},"guest_photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Photo Url"},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id"},"check_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check In At"},"check_out_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check Out At"}},"type":"object","required":["id","channel","guest_name","guest_photo_url","conversation_id","check_in_at","check_out_at"],"title":"AutoReviewReservation"},"AutoReviewStatus":{"type":"string","enum":["generating","scheduled","published","deleted","skipped","paused","error"],"title":"AutoReviewStatus","description":"Client-facing enum: changes require mobile release coordination."},"AutopilotBookingNotificationScope-Input":{"type":"string","enum":["all","booking_requests","inquiries"],"title":"AutopilotBookingNotificationScope","description":"Scopes for Autopilot's Airbnb booking-decision proposals.\n\nGoverns the push / email / Slack outreach sent when Autopilot proposes a\nbooking decision a human must approve (see\n``shared/autopilot/booking_notifications.py``):\n\n* ``booking_requests`` — accept or decline a pending booking request. Airbnb\n  expires these ~24h after the guest asks, so an unseen card is a lost stay.\n* ``inquiries`` — pre-approve a guest's inquiry.\n\n``all`` (the default) covers both. Kept separate from the ``escalated``\nmessage scope because a booking decision is not a guest-message escalation:\na user who silenced drafted-reply escalations still needs to hear about a\nbooking that will otherwise expire. Default-subscribed / explicit-opt-out,\nfor the same reason as :class:`AutopilotNudgeNotificationScope`."},"AutopilotBookingNotificationScope-Output":{"type":"string","title":"AutopilotBookingNotificationScope","description":"Scopes for Autopilot's Airbnb booking-decision proposals.\n\nGoverns the push / email / Slack outreach sent when Autopilot proposes a\nbooking decision a human must approve (see\n``shared/autopilot/booking_notifications.py``):\n\n* ``booking_requests`` — accept or decline a pending booking request. Airbnb\n  expires these ~24h after the guest asks, so an unseen card is a lost stay.\n* ``inquiries`` — pre-approve a guest's inquiry.\n\n``all`` (the default) covers both. Kept separate from the ``escalated``\nmessage scope because a booking decision is not a guest-message escalation:\na user who silenced drafted-reply escalations still needs to hear about a\nbooking that will otherwise expire. Default-subscribed / explicit-opt-out,\nfor the same reason as :class:`AutopilotNudgeNotificationScope`.","x-extensible-enum":["all","booking_requests","inquiries"]},"AutopilotNudgeNotificationScope-Input":{"type":"string","enum":["all","readiness","category_enablement"],"title":"AutopilotNudgeNotificationScope","description":"Scopes for the out-of-app Autopilot readiness/recommendation nudge emails.\n\nGoverns the two data-backed lifecycle nudges the daily\n``autopilot-readiness-nudges`` cron sends to an account OWNER (see\n``lambdas/autopilot_readiness_nudges/handler.py``):\n\n* ``readiness`` — \"you're ready to turn on Autopilot\" (Autopilot off, high\n  draft-accept rate).\n* ``category_enablement`` — \"enable these low-risk categories Autopilot keeps\n  escalating\" (Autopilot on).\n\n``all`` (the default) covers both. Semantics are **default-subscribed /\nexplicit-opt-out**: a user with no settings row — or the default ``[\"all\"]``\n— is subscribed; only an explicit removal excludes them. This is why the\nscope defaults to a SUBSCRIBED value rather than an off boolean — a\npreference that defaulted OFF could not be gated on, because the settings\nPATCH copies stored defaults back and a stored ``false`` would be\nindistinguishable from a copied default (see\n``shared/autopilot/escalation_notifications.py`` for the same trap)."},"AutopilotNudgeNotificationScope-Output":{"type":"string","title":"AutopilotNudgeNotificationScope","description":"Scopes for the out-of-app Autopilot readiness/recommendation nudge emails.\n\nGoverns the two data-backed lifecycle nudges the daily\n``autopilot-readiness-nudges`` cron sends to an account OWNER (see\n``lambdas/autopilot_readiness_nudges/handler.py``):\n\n* ``readiness`` — \"you're ready to turn on Autopilot\" (Autopilot off, high\n  draft-accept rate).\n* ``category_enablement`` — \"enable these low-risk categories Autopilot keeps\n  escalating\" (Autopilot on).\n\n``all`` (the default) covers both. Semantics are **default-subscribed /\nexplicit-opt-out**: a user with no settings row — or the default ``[\"all\"]``\n— is subscribed; only an explicit removal excludes them. This is why the\nscope defaults to a SUBSCRIBED value rather than an off boolean — a\npreference that defaulted OFF could not be gated on, because the settings\nPATCH copies stored defaults back and a stored ``false`` would be\nindistinguishable from a copied default (see\n``shared/autopilot/escalation_notifications.py`` for the same trap).","x-extensible-enum":["all","readiness","category_enablement"]},"Body_authorize_approve_oauth_authorize_approve_post":{"properties":{"client_id":{"type":"string","title":"Client Id"},"redirect_uri":{"type":"string","title":"Redirect Uri"},"scope":{"type":"string","title":"Scope"},"state":{"type":"string","title":"State"},"code_challenge":{"type":"string","title":"Code Challenge"},"code_challenge_method":{"type":"string","title":"Code Challenge Method","default":"S256"},"response_type":{"type":"string","title":"Response Type","default":"code"},"account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"},"csrf_token":{"type":"string","title":"Csrf Token"},"resource":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"},"workspace_consent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Consent"},"workspace_id":{"items":{"type":"string"},"type":"array","title":"Workspace Id","default":[]},"include_future_workspaces":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include Future Workspaces"},"default_workspace_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Workspace Id"},"consent_ticket":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Consent Ticket"}},"type":"object","required":["client_id","redirect_uri","scope","state","code_challenge","csrf_token"],"title":"Body_authorize_approve_oauth_authorize_approve_post"},"Body_revoke_oauth_revoke_post":{"properties":{"token":{"type":"string","title":"Token"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["token"],"title":"Body_revoke_oauth_revoke_post"},"Body_token_oauth_token_post":{"properties":{"grant_type":{"type":"string","title":"Grant Type"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"redirect_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect Uri"},"code_verifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Verifier"},"refresh_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Token"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"},"resource":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource"}},"type":"object","required":["grant_type"],"title":"Body_token_oauth_token_post"},"BulkExpenseDeleteExternal":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":100,"minItems":1,"title":"Ids","description":"Expense IDs to delete"}},"additionalProperties":false,"type":"object","required":["ids"],"title":"BulkExpenseDeleteExternal","description":"Bulk delete expenses."},"BulkExpenseDeleteResponse":{"properties":{"deleted_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Deleted Ids"},"failed":{"items":{"$ref":"#/components/schemas/BulkOperationFailureExternal"},"type":"array","title":"Failed"}},"type":"object","required":["deleted_ids","failed"],"title":"BulkExpenseDeleteResponse"},"BulkExpenseUpdateExternal":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":100,"minItems":1,"title":"Ids","description":"Expense IDs to update"},"data":{"$ref":"#/components/schemas/ExpenseUpdateExternal","description":"Update to apply to every expense"}},"additionalProperties":false,"type":"object","required":["ids","data"],"title":"BulkExpenseUpdateExternal","description":"Bulk update expenses with the same data."},"BulkExpenseUpdateResponse":{"properties":{"updated":{"items":{"$ref":"#/components/schemas/ExpenseExternal"},"type":"array","title":"Updated"},"failed":{"items":{"$ref":"#/components/schemas/BulkOperationFailureExternal"},"type":"array","title":"Failed"}},"type":"object","required":["updated","failed"],"title":"BulkExpenseUpdateResponse"},"BulkOperationFailureExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"success":{"type":"boolean","title":"Success","default":false},"error":{"type":"string","title":"Error"}},"type":"object","required":["id","error"],"title":"BulkOperationFailureExternal"},"BulkPatchConversationsExternal":{"properties":{"conversation_ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":200,"minItems":1,"title":"Conversation Ids"},"patch":{"$ref":"#/components/schemas/_Patch"}},"type":"object","required":["conversation_ids","patch"],"title":"BulkPatchConversationsExternal","description":"Body for ``PATCH /conversations`` — apply a small patch to many conversations.","examples":[{"conversation_ids":["c2d3e4f5-a6b7-4890-b123-4567890abcde","c3d4e5f6-a7b8-4901-b234-5678901abcde"],"patch":{"ai_muted":true}}]},"BulkPatchConversationsResponse":{"properties":{"succeeded":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Succeeded"},"failed":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Failed"},"skipped":{"items":{"$ref":"#/components/schemas/BulkPatchSkippedExternal"},"type":"array","title":"Skipped","description":"Per-field refusals. A conversation appears here when a patch field could not be applied — currently only `needs_follow_up`, which is refused when a newer follow-up update already exists (monotonic guard) or when the thread is an internal team chat and the credential has no associated user to attribute the per-user flag to. The conversation still appears under `succeeded` if another field in the same patch landed. `failed` remains reserved for conversations that don't exist on the account."}},"type":"object","required":["succeeded","failed"],"title":"BulkPatchConversationsResponse"},"BulkPatchSkippedExternal":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"field":{"type":"string","title":"Field","description":"The patch field that was refused.","examples":["needs_follow_up"]},"reason":{"type":"string","title":"Reason","description":"Why it was refused."}},"type":"object","required":["conversation_id","field","reason"],"title":"BulkPatchSkippedExternal","description":"One patch field that could not be applied to one conversation."},"CalendarBatchUpdateRequest":{"properties":{"updates":{"items":{"$ref":"#/components/schemas/CalendarDayUpdateItem"},"type":"array","maxItems":1095,"minItems":1,"title":"Updates"}},"type":"object","required":["updates"],"title":"CalendarBatchUpdateRequest","description":"Batch calendar update request body.\n\nUp to 1095 dates per request (~3 years). Dates must be unique.","examples":[{"updates":[{"date":"2026-04-01","min_nights":3,"price":150.0},{"date":"2026-04-02","price":160.0}]}]},"CalendarBatchUpdateResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"dates_updated":{"type":"integer","title":"Dates Updated"},"platform":{"type":"string","title":"Platform","description":"\"pending\" while the async Hatchet task runs."}},"type":"object","required":["success","dates_updated","platform"],"title":"CalendarBatchUpdateResponse","description":"Response returned from the batch calendar update endpoint."},"CalendarBlockOrigin":{"type":"string","enum":["prohost_manual","prohost_upsell","prohost_hierarchy","ota_sync","ical_import"],"title":"CalendarBlockOrigin","description":"Typed origin of a calendar-day block (``calendar_days.block_origin``).\n\nThe typed successor to the ``notes`` string sentinels: writers DECLARE who\ncreated a block instead of readers inferring it from prefix matching. The\n``notes`` sentinels remain the source of truth during the dual-write\ntransition (readers fall back to them for rows written before the column\nexisted); a follow-up retires them once the prod backfill lands.\n\nOrigins:\n    prohost_manual: Host block created in ProHost (manual availability\n        write via the calendar UI / API / MCP tools).\n    prohost_upsell: Gap-night upsell hold (``upsell_upgrade_request_id``).\n    prohost_hierarchy: Parent/child cross-block mirrored from a booking on\n        a related listing.\n    ota_sync: Imported from an OTA/PMS calendar-API sync\n        (``block_origin_ref`` = ``\"<source>[:<reason>]\"``).\n    ical_import: Imported from an inbound iCal feed\n        (``block_origin_ref`` = the owning ``listing_source_id``)."},"CalendarDayExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"date":{"type":"string","format":"date","title":"Date"},"available":{"type":"boolean","title":"Available"},"status":{"$ref":"#/components/schemas/CalendarDayStatus"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"min_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Nights"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"block_origin":{"anyOf":[{"$ref":"#/components/schemas/CalendarBlockOrigin"},{"type":"null"}]},"block_origin_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Block Origin Ref"},"currency":{"type":"string","title":"Currency"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","listing_id","date","available","status","price","min_nights","notes","currency","created_at","updated_at"],"title":"CalendarDayExternal"},"CalendarDayStatus":{"type":"string","enum":["reserved","available","blocked"],"title":"CalendarDayStatus","description":"Status of a calendar day."},"CalendarDayUpdateBody":{"properties":{"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"min_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Nights"},"max_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Nights"},"available":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Available"},"closed_to_arrival":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Closed To Arrival"},"closed_to_departure":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Closed To Departure"}},"type":"object","title":"CalendarDayUpdateBody","description":"Single calendar day update (used by the single-date endpoint).\n\nAt least one of the optional fields must be set.","examples":[{"available":true,"min_nights":3,"price":150.0}]},"CalendarDayUpdateItem":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"min_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Nights"},"max_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Nights"},"available":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Available"},"closed_to_arrival":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Closed To Arrival"},"closed_to_departure":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Closed To Departure"}},"type":"object","required":["date"],"title":"CalendarDayUpdateItem","description":"Single calendar day update inside a batch.\n\nAll fields except ``date`` are optional — only non-null fields are pushed\nto the platform.","examples":[{"available":true,"date":"2026-04-01","min_nights":3,"price":150.0}]},"ChecklistCreateExternal":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"items":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChecklistItemCreateExternal"},"type":"array"},{"type":"null"}],"title":"Items"},"template_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Template Id"}},"type":"object","required":["title"],"title":"ChecklistCreateExternal"},"ChecklistExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"cleaning_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaning Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"type":"integer","title":"Order","default":0},"items":{"items":{"$ref":"#/components/schemas/ChecklistItemExternal"},"type":"array","title":"Items","default":[]},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","title"],"title":"ChecklistExternal"},"ChecklistItemCreateExternal":{"properties":{"reference_video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Video Url"},"title":{"type":"string","title":"Title"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"reference_photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Photo Url"},"photo_required":{"type":"boolean","title":"Photo Required","default":false}},"type":"object","required":["title"],"title":"ChecklistItemCreateExternal"},"ChecklistItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"order":{"type":"integer","title":"Order"},"completed":{"type":"boolean","title":"Completed","default":false},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"reference_photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Photo Url"},"reference_media":{"anyOf":[{"items":{"$ref":"#/components/schemas/ReferenceMedia"},"type":"array"},{"type":"null"}],"title":"Reference Media"},"reference_video":{"anyOf":[{"$ref":"#/components/schemas/ReferenceVideo"},{"type":"null"}]},"photo_required":{"type":"boolean","title":"Photo Required","default":false},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","title","order"],"title":"ChecklistItemExternal"},"ChecklistItemUpdateExternal":{"properties":{"reference_video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Video Url"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"completed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Completed"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"reference_photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Photo Url"},"photo_required":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Photo Required"}},"type":"object","title":"ChecklistItemUpdateExternal"},"ChecklistUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"}},"type":"object","title":"ChecklistUpdateExternal"},"CleaningAssignExternal":{"properties":{"cleaner_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaner Id"}},"type":"object","title":"CleaningAssignExternal","description":"Assign or unassign the primary cleaner for a cleaning.\n\nPass ``null`` to unassign (clear ``assignee_id``)."},"CleaningAttachmentCreateExternal":{"properties":{"attachment_urls":{"items":{"type":"string"},"type":"array","maxItems":50,"minItems":1,"title":"Attachment Urls"}},"type":"object","required":["attachment_urls"],"title":"CleaningAttachmentCreateExternal","description":"Register one or more attachment URLs (uploaded to S3 by the client) on a cleaning."},"CleaningAttachmentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"cleaning_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaning Id"},"url":{"type":"string","title":"Url"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"uploaded_by_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Uploaded By Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","url"],"title":"CleaningAttachmentExternal"},"CleaningCommentCreateExternal":{"properties":{"content":{"type":"string","maxLength":10000,"minLength":1,"title":"Content"}},"type":"object","required":["content"],"title":"CleaningCommentCreateExternal"},"CleaningCommentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"cleaning_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaning Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"content":{"type":"string","title":"Content"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","content"],"title":"CleaningCommentExternal"},"CleaningCommentUpdateExternal":{"properties":{"content":{"type":"string","maxLength":10000,"minLength":1,"title":"Content"}},"type":"object","required":["content"],"title":"CleaningCommentUpdateExternal"},"CleaningCreateExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"title":{"type":"string","title":"Title"},"type":{"type":"string","title":"Type","description":"Cleaning type. Defaults to ``manual``. ``turnover`` is rejected: turnovers are generated from reservations.","default":"manual"},"scheduled_starts_at":{"type":"string","format":"date-time","title":"Scheduled Starts At"},"scheduled_ends_at":{"type":"string","format":"date-time","title":"Scheduled Ends At"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["listing_id","title","scheduled_starts_at","scheduled_ends_at"],"title":"CleaningCreateExternal","examples":[{"description":"Quarterly deep clean.","listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","scheduled_ends_at":"2026-04-14T14:00:00Z","scheduled_starts_at":"2026-04-14T11:00:00Z","title":"Deep clean","type":"manual"}]},"CleaningExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"scheduled_starts_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Starts At"},"scheduled_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Ends At"},"assignee_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Assignee Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"inspectors":{"items":{"$ref":"#/components/schemas/CleaningInspectorExternal"},"type":"array","title":"Inspectors","description":"Users assigned to inspect the cleaning once it is handed in."},"inspection":{"anyOf":[{"$ref":"#/components/schemas/CleaningInspectionExternal"},{"type":"null"}],"description":"The latest inspection attempt, or null when the cleaning was never inspected."},"stage":{"type":"string","enum":["cleaning","awaiting_inspection","inspecting","fixes_needed","done"],"title":"Stage","description":"Where the cleaning is in the clean → inspect loop, derived from ``status`` and the latest inspection: cleaning, awaiting_inspection, inspecting, fixes_needed (the last inspection failed), done.","default":"cleaning"},"requires_inspection":{"type":"boolean","title":"Requires Inspection","description":"True when only an assigned inspector or a manager may complete the cleaning.","default":false}},"type":"object","required":["id","listing_id","status","type","title","description","scheduled_starts_at","scheduled_ends_at","assignee_id","reservation_id","created_at","updated_at"],"title":"CleaningExternal","examples":[{"created_at":"2026-04-12T09:00:00Z","description":"Standard turnover cleaning.","id":"7d7f3d74-8d86-4af6-a0ce-5e5d4e2f2d7b","listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","reservation_id":"9fa4c218-fd7a-4aa1-a17c-728ec0eb74b5","scheduled_ends_at":"2026-04-14T14:00:00Z","scheduled_starts_at":"2026-04-14T11:00:00Z","status":"not_started","title":"Post-checkout turnover","type":"turnover","updated_at":"2026-04-12T09:00:00Z"}]},"CleaningFailedItemExternal":{"properties":{"checklist_item_id":{"type":"string","format":"uuid","title":"Checklist Item Id"},"title":{"type":"string","title":"Title"},"result_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Result At"}},"type":"object","required":["checklist_item_id","title"],"title":"CleaningFailedItemExternal"},"CleaningInspectionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"attempt":{"type":"integer","title":"Attempt"},"inspector_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Inspector Id"},"inspector_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inspector Name"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At"},"result":{"anyOf":[{"type":"string","enum":["pass","fail"]},{"type":"null"}],"title":"Result"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"failed_items":{"items":{"$ref":"#/components/schemas/CleaningFailedItemExternal"},"type":"array","title":"Failed Items"}},"type":"object","required":["id","attempt"],"title":"CleaningInspectionExternal","description":"One inspection attempt; ``result`` is null while the attempt is still open."},"CleaningInspectionFailExternal":{"properties":{"notes":{"type":"string","maxLength":10000,"minLength":1,"title":"Notes"},"failed_item_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Failed Item Ids"}},"additionalProperties":false,"type":"object","required":["notes"],"title":"CleaningInspectionFailExternal","description":"The notes are required: they are the cleaners' work order for the rework."},"CleaningInspectionPassExternal":{"properties":{"notes":{"anyOf":[{"type":"string","maxLength":10000},{"type":"null"}],"title":"Notes"}},"additionalProperties":false,"type":"object","title":"CleaningInspectionPassExternal"},"CleaningInspectorExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","required":["id"],"title":"CleaningInspectorExternal","description":"A user assigned to inspect a cleaning once the cleaners hand it in."},"CleaningInspectorsExternal":{"properties":{"inspector_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Inspector Ids"}},"additionalProperties":false,"type":"object","required":["inspector_ids"],"title":"CleaningInspectorsExternal","description":"Replace the users who inspect a cleaning. ``[]`` removes them all; cleaners are untouched.","examples":[{"inspector_ids":[]}]},"CleaningIssueCreateExternal":{"properties":{"title":{"type":"string","maxLength":500,"minLength":1,"title":"Title"}},"type":"object","required":["title"],"title":"CleaningIssueCreateExternal"},"CleaningIssueExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"cleaning_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaning Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"status_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id"],"title":"CleaningIssueExternal"},"CleaningIssueUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":500,"minLength":1},{"type":"null"}],"title":"Title"}},"type":"object","title":"CleaningIssueUpdateExternal"},"CleaningNotificationScope-Input":{"type":"string","enum":["all","assigned","commented","reminder_day_before","reminder_morning_of","not_started","needs_attention","following"],"title":"CleaningNotificationScope","description":"Scopes for cleaning notifications - can be combined additively"},"CleaningNotificationScope-Output":{"type":"string","title":"CleaningNotificationScope","description":"Scopes for cleaning notifications - can be combined additively","x-extensible-enum":["all","assigned","commented","reminder_day_before","reminder_morning_of","not_started","needs_attention","following"]},"CleaningUpdateExternal":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"scheduled_starts_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Starts At"},"scheduled_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Ends At"},"cleaner_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cleaner Id"},"inspector_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Inspector Ids","description":"Replace the cleaning's inspectors. Omit to leave them unchanged; [] removes them all."}},"type":"object","title":"CleaningUpdateExternal","examples":[{"status":"completed"}]},"CliUsageReport":{"properties":{"source":{"type":"string","const":"cli","title":"Source","default":"cli"},"machineId":{"type":"string","format":"uuid","title":"Machineid"},"machine":{"type":"string","maxLength":120,"minLength":1,"title":"Machine"},"accounts":{"items":{"$ref":"#/components/schemas/UsageReportAccount"},"type":"array","maxItems":16,"title":"Accounts"}},"type":"object","required":["machineId","machine","accounts"],"title":"CliUsageReport","description":"``POST /v1/usage/reports`` — the same snapshot from ``prohost usage`` (source ``cli``)."},"CommentCreateExternal":{"properties":{"object_type":{"$ref":"#/components/schemas/CrmCommentObjectType"},"object_id":{"type":"string","format":"uuid","title":"Object Id"},"body":{"type":"string","minLength":1,"title":"Body"}},"additionalProperties":false,"type":"object","required":["object_type","object_id","body"],"title":"CommentCreateExternal"},"CommentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"object_type":{"$ref":"#/components/schemas/CrmCommentObjectType"},"object_id":{"type":"string","format":"uuid","title":"Object Id"},"body":{"type":"string","title":"Body"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","object_type","object_id","body","created_at","updated_at"],"title":"CommentExternal"},"CommissionType":{"type":"string","enum":["percentage","fixed_amount","tiered"],"title":"CommissionType","description":"Enum for commission types"},"CommunityCommentCreateExternal":{"properties":{"body":{"type":"string","maxLength":2000,"minLength":1,"title":"Body"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"}},"type":"object","required":["body"],"title":"CommunityCommentCreateExternal"},"CommunityCommentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"post_id":{"type":"string","format":"uuid","title":"Post Id"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"body":{"type":"string","title":"Body"},"author_handle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Handle"},"is_staff_author":{"type":"boolean","title":"Is Staff Author","default":false},"author_credentials":{"additionalProperties":true,"type":"object","title":"Author Credentials"},"likes_count":{"type":"integer","title":"Likes Count"},"replies_count":{"type":"integer","title":"Replies Count"},"viewer_has_liked":{"type":"boolean","title":"Viewer Has Liked","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","post_id","body","likes_count","replies_count","created_at"],"title":"CommunityCommentExternal"},"CommunityCommentThreadExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"post_id":{"type":"string","format":"uuid","title":"Post Id"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"body":{"type":"string","title":"Body"},"author_handle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Handle"},"is_staff_author":{"type":"boolean","title":"Is Staff Author","default":false},"author_credentials":{"additionalProperties":true,"type":"object","title":"Author Credentials"},"likes_count":{"type":"integer","title":"Likes Count"},"replies_count":{"type":"integer","title":"Replies Count"},"viewer_has_liked":{"type":"boolean","title":"Viewer Has Liked","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"replies":{"items":{"$ref":"#/components/schemas/CommunityCommentExternal"},"type":"array","title":"Replies"}},"type":"object","required":["id","post_id","body","likes_count","replies_count","created_at"],"title":"CommunityCommentThreadExternal","description":"A top-level comment with its replies (comments nest two levels deep)."},"CommunityCredentialExternal":{"properties":{"kind":{"type":"string","title":"Kind"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"tenure_months":{"type":"integer","title":"Tenure Months","default":0},"listing_count":{"type":"integer","title":"Listing Count","default":0},"cleaning_count":{"type":"integer","title":"Cleaning Count","default":0},"last_computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Computed At"}},"type":"object","required":["kind"],"title":"CommunityCredentialExternal","description":"One of the acting user's own verified credentials."},"CommunityFlagCreateExternal":{"properties":{"reason":{"$ref":"#/components/schemas/FlagReason"},"detail":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Detail"}},"type":"object","required":["reason"],"title":"CommunityFlagCreateExternal"},"CommunityFlagResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"target_type":{"type":"string","enum":["post","comment"],"title":"Target Type"},"target_id":{"type":"string","format":"uuid","title":"Target Id"},"reason":{"type":"string","title":"Reason"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","target_type","target_id","reason","status","created_at"],"title":"CommunityFlagResponse"},"CommunityLikeResponse":{"properties":{"post_id":{"type":"string","format":"uuid","title":"Post Id"},"liked":{"type":"boolean","title":"Liked"},"likes_count":{"type":"integer","title":"Likes Count"}},"type":"object","required":["post_id","liked","likes_count"],"title":"CommunityLikeResponse"},"CommunityLoungeExternal":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"kind":{"type":"string","title":"Kind"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emoji"},"member_count":{"type":"integer","title":"Member Count"},"member_count_display":{"type":"string","title":"Member Count Display"},"is_joined":{"type":"boolean","title":"Is Joined"},"is_eligible":{"type":"boolean","title":"Is Eligible"},"can_post":{"type":"boolean","title":"Can Post"}},"type":"object","required":["slug","name","kind","member_count","member_count_display","is_joined","is_eligible","can_post"],"title":"CommunityLoungeExternal","description":"The lounge a feed page belongs to, with the viewer's standing."},"CommunityLoungeFeedResponse":{"properties":{"lounge":{"$ref":"#/components/schemas/CommunityLoungeExternal"},"pinned":{"items":{"$ref":"#/components/schemas/CommunityPostExternal"},"type":"array","title":"Pinned"},"items":{"items":{"$ref":"#/components/schemas/CommunityPostExternal"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["lounge"],"title":"CommunityLoungeFeedResponse"},"CommunityMembershipResponse":{"properties":{"lounge_slug":{"type":"string","title":"Lounge Slug"},"is_joined":{"type":"boolean","title":"Is Joined"},"joined_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Joined At"},"is_founding_member":{"type":"boolean","title":"Is Founding Member","default":false}},"type":"object","required":["lounge_slug","is_joined"],"title":"CommunityMembershipResponse"},"CommunityMyProfileResponse":{"properties":{"handle":{"type":"string","title":"Handle"},"avatar_seed":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Seed"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"xp":{"type":"integer","title":"Xp","default":0},"level":{"type":"integer","title":"Level","default":1},"level_title":{"type":"string","title":"Level Title","default":""},"credentials":{"items":{"$ref":"#/components/schemas/CommunityCredentialExternal"},"type":"array","title":"Credentials"},"lounges":{"items":{"$ref":"#/components/schemas/CommunityProfileMembershipExternal"},"type":"array","title":"Lounges"}},"type":"object","required":["handle","created_at"],"title":"CommunityMyProfileResponse","description":"The acting user's own pseudonymous community profile."},"CommunityPostCreateExternal":{"properties":{"body":{"type":"string","maxLength":5000,"minLength":1,"title":"Body"},"join_first":{"type":"boolean","title":"Join First","default":true}},"type":"object","required":["body"],"title":"CommunityPostCreateExternal"},"CommunityPostDetailResponse":{"properties":{"post":{"$ref":"#/components/schemas/CommunityPostExternal"},"comments":{"items":{"$ref":"#/components/schemas/CommunityCommentThreadExternal"},"type":"array","title":"Comments"},"can_comment":{"type":"boolean","title":"Can Comment"}},"type":"object","required":["post","can_comment"],"title":"CommunityPostDetailResponse"},"CommunityPostExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"lounge_slug":{"type":"string","title":"Lounge Slug"},"body":{"type":"string","title":"Body"},"media":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Media"},"author_handle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Handle"},"is_staff_author":{"type":"boolean","title":"Is Staff Author","default":false},"author_credentials":{"additionalProperties":true,"type":"object","title":"Author Credentials"},"is_pinned":{"type":"boolean","title":"Is Pinned","default":false},"is_own":{"type":"boolean","title":"Is Own","default":false},"likes_count":{"type":"integer","title":"Likes Count"},"comments_count":{"type":"integer","title":"Comments Count"},"viewer_has_liked":{"type":"boolean","title":"Viewer Has Liked","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","lounge_slug","body","likes_count","comments_count","created_at"],"title":"CommunityPostExternal","description":"One post as it appears in a lounge feed or on its detail page."},"CommunityPostResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"lounge_slug":{"type":"string","title":"Lounge Slug"},"body":{"type":"string","title":"Body"},"author_handle":{"type":"string","title":"Author Handle"},"is_founding_member":{"type":"boolean","title":"Is Founding Member","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","lounge_slug","body","author_handle","created_at"],"title":"CommunityPostResponse"},"CommunityProfileMembershipExternal":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"joined_at":{"type":"string","format":"date-time","title":"Joined At"},"is_founding_member":{"type":"boolean","title":"Is Founding Member","default":false}},"type":"object","required":["slug","name","joined_at"],"title":"CommunityProfileMembershipExternal"},"CompanyCreateExternal":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"type":{"$ref":"#/components/schemas/CompanyType","default":"prospect"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","required":["name"],"title":"CompanyCreateExternal"},"CompanyExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"type":{"$ref":"#/components/schemas/CompanyType"},"custom_fields":{"additionalProperties":true,"type":"object","title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"archived_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Archived At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","type","created_at","updated_at"],"title":"CompanyExternal"},"CompanyType":{"type":"string","enum":["prospect","partner","vendor","competitor","other"],"title":"CompanyType","description":"High-level classification of a CRM company."},"CompanyUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"type":{"anyOf":[{"$ref":"#/components/schemas/CompanyType"},{"type":"null"}]},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","title":"CompanyUpdateExternal"},"ConfigureAIEmployeeRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"goals":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Goals"},"responsibilities":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Responsibilities"},"heartbeat_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Heartbeat Enabled"},"heartbeat_interval_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Heartbeat Interval Seconds"},"confidence_threshold":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Confidence Threshold"},"proactiveness":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Proactiveness","description":"One of reactive / helpful / proactive / persistent."},"reports_to_agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reports To Agent Id"},"avatar_emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Emoji"},"skill_keys":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skill Keys","description":"Skill keys to attach (replaces the set). Unknown keys are rejected."},"tool_allowlist":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tool Allowlist","description":"Tool names the employee may use (replaces the set); [] means the default tool set."},"heartbeat_cadence_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Heartbeat Cadence Mode","description":"adaptive / interval / cron. 'cron' requires heartbeat_schedule_cron."},"heartbeat_schedule_cron":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Heartbeat Schedule Cron","description":"5-field cron for the heartbeat; fires must be at least the heartbeat floor (15 min) apart. null / '' clears it."},"heartbeat_schedule_timezone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Heartbeat Schedule Timezone","description":"IANA timezone the heartbeat cron is evaluated in."},"model_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Tier","description":"Model tier; 'custom' requires model_override. null clears."},"model_override":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Model Override","description":"Exact model id; only with model_tier='custom'."}},"type":"object","title":"ConfigureAIEmployeeRequest","description":"Patch an existing AI employee. Only supplied fields are written."},"ConnectedTeamMentions":{"type":"string","enum":["notify","quiet"],"title":"ConnectedTeamMentions","description":"How an @mention from a connected team reaches this person.\n\nStored as a plain string on ``user_notification_settings.connected_team_mentions``\n(CHECK-constrained to these values). A connected-team author is someone who\nis not a member of the recipient's workspace but is a member (person or AI\nemployee) of a workspace connected to it (``team_connections``):\n\n* ``notify`` — such a mention notifies like any other (the default).\n* ``quiet`` — it lands in the app (inbox item, unread and mention badges)\n  with no alert outside it (push, email, SMS, Slack). Covers team chat, internal notes and task /\n  cleaning comments; see ``shared/notifications/connected_team_mentions.py``."},"ContactPhotoContentType":{"type":"string","enum":["image/jpeg","image/png"],"title":"ContactPhotoContentType","description":"Whitelisted upload MIME types for contact photo uploads."},"ContactPhotoUploadRequest":{"properties":{"content_type":{"$ref":"#/components/schemas/ContactPhotoContentType"}},"type":"object","required":["content_type"],"title":"ContactPhotoUploadRequest","description":"Request a presigned S3 URL for uploading a contact's photo."},"ContactPhotoUploadResponse":{"properties":{"presigned_url":{"type":"string","title":"Presigned Url"}},"type":"object","required":["presigned_url"],"title":"ContactPhotoUploadResponse","description":"Presigned S3 URL the client should PUT the photo bytes to."},"ContactType":{"type":"string","enum":["lead","owner","vendor","partner","other"],"title":"ContactType","description":"High-level classification of a CRM contact."},"ConversationExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Custom thread name (internal/group conversations)"},"needs_response":{"type":"boolean","title":"Needs Response","description":"Thread is awaiting a host response","default":false},"needs_follow_up":{"type":"boolean","title":"Needs Follow Up","description":"AI-detected or manual follow-up is needed on this thread. For internal (team-chat) threads this is the per-user flag for the calling credential's user, not a thread-wide value.","default":false},"is_starred":{"type":"boolean","title":"Is Starred","description":"Thread has been manually starred","default":false},"is_done":{"type":"boolean","title":"Is Done","description":"Thread has been marked done (archived from the active inbox)","default":false},"snoozed_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Snoozed Until","description":"If set to a future time, the thread is snoozed until then"},"business_purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Purpose","description":"Non-guest OTA thread discriminator (e.g. 'support_messaging_thread' for host↔Airbnb-support). NULL for a normal guest/booking thread."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","listing_id","reservation_id","channel","created_at","updated_at"],"title":"ConversationExternal","examples":[{"channel":"ota","created_at":"2026-04-10T08:00:00Z","id":"c2d3e4f5-a6b7-4890-b123-4567890abcde","is_done":false,"is_starred":false,"listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","needs_follow_up":false,"needs_response":true,"reservation_id":"9fa4c218-fd7a-4aa1-a17c-728ec0eb74b5","updated_at":"2026-04-12T14:30:00Z"}]},"ConversationMessageExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"sender_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender Type","description":"Message sender type","examples":["guest"]},"sender_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender Name","description":"Who sent this message: the teammate's name on an outbound, the guest's name on an inbound. Null when nothing names them — an unnamed sender, or a booking whose PMS supplied filler ('Inquiry guest', 'TBA') rather than a person. Populated only by readers that call `message_external()`; a raw `model_validate` leaves it null.","examples":["Maria Alvarez"]},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"send_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Send Status","description":"Delivery outcome for an outbound message: `sending`, `sent`, `sent_test`, `failed` or `rejected_duplicate`. Null on inbound and legacy rows. A `failed` message was NOT received by the recipient — it is kept only so the attempt is visible. Note that `sent_at` is stamped when the message is created, so it is set on failed rows too and is not on its own proof of delivery.","examples":["sent"]},"attachments":{"anyOf":[{"items":{"$ref":"#/components/schemas/MessageAttachmentExternal"},"type":"array"},{"type":"null"}],"title":"Attachments","description":"Files attached to this message, each with a fetchable URL. Null when the message has no attachment that can be served (including placeholder rows for files skipped over a size cap)."}},"type":"object","required":["id","message","sent_at","created_at"],"title":"ConversationMessageExternal","examples":[{"created_at":"2026-04-12T14:30:00Z","id":"b1a2c3d4-e5f6-4789-a012-3456789abcde","message":"Hi! What time is check-in?","sender_name":"Maria Alvarez","sender_type":"guest","sent_at":"2026-04-12T14:30:00Z"}]},"CreateAIEmployeeRequest":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Display name."},"system_prompt":{"type":"string","minLength":1,"title":"System Prompt","description":"Operating instructions."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"goals":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Goals"},"responsibilities":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Responsibilities"},"skill_keys":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skill Keys","description":"Skill keys to attach (replaces the set). Unknown keys are rejected."},"tool_allowlist":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tool Allowlist","description":"Tool names the employee may use (replaces the set); [] means the default tool set."},"heartbeat_cadence_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Heartbeat Cadence Mode","description":"adaptive / interval / cron. 'cron' requires heartbeat_schedule_cron."},"heartbeat_schedule_cron":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Heartbeat Schedule Cron","description":"5-field cron for the heartbeat; fires must be at least the heartbeat floor (15 min) apart. null / '' clears it."},"heartbeat_schedule_timezone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Heartbeat Schedule Timezone","description":"IANA timezone the heartbeat cron is evaluated in."},"model_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Tier","description":"Model tier; 'custom' requires model_override. null clears."},"model_override":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Model Override","description":"Exact model id; only with model_tier='custom'."}},"type":"object","required":["name","system_prompt"],"title":"CreateAIEmployeeRequest","description":"Create a custom AI employee (no template)."},"CreateAIEmployeeTriggerRequest":{"properties":{"trigger_type":{"type":"string","title":"Trigger Type","description":"Event that fires the trigger."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"enabled":{"type":"boolean","title":"Enabled","default":true},"cooldown_seconds":{"type":"integer","title":"Cooldown Seconds","default":60},"trigger_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Trigger Config","description":"Trigger configuration. A 'schedule' trigger requires {'schedule': {'frequency', 'time', 'timezone', ...}}. Any trigger accepts 'conditions' (list of {field, op, value} pre-filters on the event), 'relevance_screen' (bool) and 'skill_key' (a skill run on every fire). 'listing_ids' limits a listing-bound trigger to those listings; it is rejected (422) on triggers whose events have no listing (GitHub, calls, calendar, email, Slack, webhook, outbound, Airbnb support, recruiting, workflow_chain, gift card)."}},"type":"object","required":["trigger_type"],"title":"CreateAIEmployeeTriggerRequest","description":"Create an agent trigger for an AI employee."},"CreateIngestedConversationExternal":{"properties":{"external_id":{"type":"string","maxLength":255,"minLength":1,"title":"External Id","description":"Your own id for this inquiry (form submission, booking-engine lead, Zap run). Unique in the workspace: sending it again returns the same conversation with 200 and posts nothing."},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id","description":"The listing the inquiry is about. Required for listing-scoped keys."},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id","description":"A booking in this workspace to link the conversation to. Its listing is used when `listing_id` is omitted."},"guest":{"$ref":"#/components/schemas/IngestGuestExternal"},"reply_via":{"type":"string","enum":["email","sms"],"title":"Reply Via","description":"How replies reach the guest. `email` (default) sends from your workspace's branded address, and the guest's email replies come back into this conversation. `sms` texts from the workspace's SMS number and uses the one conversation the workspace has with that number.","default":"email"},"message":{"anyOf":[{"$ref":"#/components/schemas/IngestFirstMessageExternal"},{"type":"null"}],"description":"The guest's first message, posted as if it had arrived through `inbound-messages`."}},"additionalProperties":false,"type":"object","required":["external_id","guest"],"title":"CreateIngestedConversationExternal","examples":[{"external_id":"contact-form-8841","guest":{"email":"maria@example.com","name":"Maria Alvarez","phone":"+14155550123"},"listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","message":{"text":"Hi! Is the cottage free the first week of December? We are two adults."},"reply_via":"email"}]},"CreateInternalNoteExternal":{"properties":{"message":{"type":"string","maxLength":10000,"minLength":1,"title":"Message","description":"Note body. Supports ``<@user_id>`` mentions, which notify the mentioned teammate."},"severity":{"type":"string","enum":["act","inform","log"],"title":"Severity","description":"How loudly the note reaches the team. ``act`` always pushes (reserve it for 'a human must do something now'); ``inform`` is an FYI that respects each teammate's attention level; ``log`` notifies nobody and is the default. Severity routing is per-AI-employee: it applies when the note's author resolves to an AI employee in the account, which is what this endpoint posts as.","default":"log"},"source_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Source Name","description":"Label for the tool or runtime that authored the note, recorded on the message's ``sent_via_client_name`` provenance column. Defaults to ``Support Agent``. This is provenance metadata for auditing — the note's displayed author is the acting member the API key resolves to, not this value."},"ai_agent_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Ai Agent Run Id","description":"The agent run that wrote this note, recorded on the note so its tool timeline opens from it. For a paired AI employee it must be a run this credential was handed (422 `ai_agent_run_not_found` otherwise). Omit it and the note behaves as it always has."}},"type":"object","required":["message"],"title":"CreateInternalNoteExternal","description":"Request body for ``POST /v1/conversations/{id}/notes``.","examples":[{"message":"Checked the Airbnb sync logs — the missing payout is a Hostaway lag, not a bug.","severity":"log","source_name":"Support Agent"}]},"CreateSpaceExternal":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Space name, trimmed. Required."},"visibility":{"type":"string","enum":["open","private"],"title":"Visibility","description":"`open` — every account member can browse and join. `private` — roster-only, and it must include at least one human member (a private space whose only members are AI users is permanently unreachable, so it is rejected).","default":"open"},"participant_user_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Participant User Ids","description":"Additional account members to seed onto the roster. The calling key's user is always included and the AI employee is added automatically. Every id must belong to this account."}},"additionalProperties":false,"type":"object","required":["name"],"title":"CreateSpaceExternal","description":"Body for ``POST /v1/conversations/spaces``.","examples":[{"name":"deploys","visibility":"open"},{"name":"incident-2026-08-05","participant_user_ids":["7c9e6679-7425-40de-944b-e07fc1f90ae7"],"visibility":"private"}]},"CrmCommentObjectType":{"type":"string","enum":["opportunity","contact","company","meeting"],"title":"CrmCommentObjectType","description":"Polymorphic parent object types a CRM comment can attach to."},"CurrencyAmountExternal":{"properties":{"currency":{"type":"string","title":"Currency"},"amount":{"type":"number","title":"Amount"}},"type":"object","required":["currency","amount"],"title":"CurrencyAmountExternal"},"CursorPage_WebhookDeliveryExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WebhookDeliveryExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more","next_cursor"],"title":"CursorPage[WebhookDeliveryExternal]"},"CursorPage_WebhookSubscriptionExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WebhookSubscriptionExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more","next_cursor"],"title":"CursorPage[WebhookSubscriptionExternal]"},"CustomFieldValuesExternal":{"properties":{"custom_fields":{"additionalProperties":true,"type":"object","title":"Custom Fields"}},"additionalProperties":false,"type":"object","title":"CustomFieldValuesExternal","description":"Set/merge an entity's ``custom_fields`` from the external API.\n\nA partial dict — supplied keys are validated against the in-scope field\ndefinitions and merged onto the stored values; omitted keys are left\nuntouched."},"CustomFieldsBatchDeleteRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":500,"minItems":1,"title":"Ids","description":"Entity IDs to mutate."},"field_keys":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Field Keys","description":"Custom-field keys to remove."}},"type":"object","required":["ids","field_keys"],"title":"CustomFieldsBatchDeleteRequest","description":"Remove the named keys from multiple entities."},"CustomFieldsBatchDeleteRequestExternal":{"properties":{"scope":{"type":"string","enum":["account","tag","listing"],"title":"Scope"},"field_keys":{"items":{"type":"string"},"type":"array","title":"Field Keys"},"dry_run":{"type":"boolean","title":"Dry Run","default":false},"targets":{"$ref":"#/components/schemas/CustomFieldsBatchTargetsExternal"}},"additionalProperties":false,"type":"object","required":["scope","field_keys"],"title":"CustomFieldsBatchDeleteRequestExternal","description":"Request body for ``POST /v1/listings/custom-fields/batch/delete``."},"CustomFieldsBatchResponseExternal":{"properties":{"applied":{"type":"integer","title":"Applied"},"would_apply":{"type":"integer","title":"Would Apply"},"dry_run":{"type":"boolean","title":"Dry Run"},"diff":{"items":{"$ref":"#/components/schemas/CustomFieldsBatchTargetDiffExternal"},"type":"array","title":"Diff"},"skipped":{"items":{"$ref":"#/components/schemas/CustomFieldsBatchSkipExternal"},"type":"array","title":"Skipped"},"orphaned_references":{"items":{"$ref":"#/components/schemas/CustomFieldsOrphanedReferenceExternal"},"type":"array","title":"Orphaned References"}},"type":"object","required":["applied","would_apply","dry_run","diff","skipped"],"title":"CustomFieldsBatchResponseExternal"},"CustomFieldsBatchResult":{"properties":{"applied":{"type":"integer","title":"Applied","description":"Count of rows actually mutated."},"diff":{"items":{"$ref":"#/components/schemas/CustomFieldsTargetDiff"},"type":"array","title":"Diff"}},"type":"object","required":["applied"],"title":"CustomFieldsBatchResult","description":"Outcome of a batch set/delete operation."},"CustomFieldsBatchSetRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":500,"minItems":1,"title":"Ids","description":"Entity IDs to mutate."},"fields":{"additionalProperties":true,"type":"object","minProperties":1,"title":"Fields","description":"Key/value pairs to merge into each entity's custom_fields. Must contain at least one key — an empty payload is rejected with 422 (use the delete batch endpoint to remove keys instead)."}},"type":"object","required":["ids","fields"],"title":"CustomFieldsBatchSetRequest","description":"Set the same key/value pairs on multiple entities (merge, not replace)."},"CustomFieldsBatchSetRequestExternal":{"properties":{"scope":{"type":"string","enum":["account","tag","listing"],"title":"Scope"},"fields":{"additionalProperties":true,"type":"object","title":"Fields"},"mode":{"type":"string","enum":["merge","replace"],"title":"Mode","default":"merge"},"dry_run":{"type":"boolean","title":"Dry Run","default":false},"targets":{"$ref":"#/components/schemas/CustomFieldsBatchTargetsExternal"}},"additionalProperties":false,"type":"object","required":["scope","fields"],"title":"CustomFieldsBatchSetRequestExternal","description":"Request body for ``POST /v1/listings/custom-fields/batch``."},"CustomFieldsBatchSkipExternal":{"properties":{"target_id":{"type":"string","title":"Target Id"},"reason":{"type":"string","title":"Reason"},"details":{"additionalProperties":true,"type":"object","title":"Details"}},"type":"object","required":["target_id","reason"],"title":"CustomFieldsBatchSkipExternal"},"CustomFieldsBatchTargetDiffExternal":{"properties":{"target_id":{"type":"string","title":"Target Id"},"target_type":{"type":"string","enum":["account","tag","listing"],"title":"Target Type"},"target_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Label"},"added":{"additionalProperties":true,"type":"object","title":"Added"},"updated":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Updated"},"unchanged":{"items":{"type":"string"},"type":"array","title":"Unchanged"},"removed":{"additionalProperties":true,"type":"object","title":"Removed"}},"type":"object","required":["target_id","target_type"],"title":"CustomFieldsBatchTargetDiffExternal"},"CustomFieldsBatchTargetsExternal":{"properties":{"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids"},"tag_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Tag Ids"},"target_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Tag Id"},"target_tag_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Tag Name"},"all_listings":{"type":"boolean","title":"All Listings","default":false}},"additionalProperties":false,"type":"object","title":"CustomFieldsBatchTargetsExternal","description":"Where a batch custom-fields write should land."},"CustomFieldsCheckMissingRequestExternal":{"properties":{"field_keys":{"items":{"type":"string"},"type":"array","title":"Field Keys"},"tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tag Id"},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids"}},"additionalProperties":false,"type":"object","required":["field_keys"],"title":"CustomFieldsCheckMissingRequestExternal","description":"Request body for ``POST /v1/listings/custom-fields/batch/check-missing``."},"CustomFieldsCheckMissingResponseExternal":{"properties":{"field_keys":{"items":{"type":"string"},"type":"array","title":"Field Keys"},"tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tag Id"},"listings_checked":{"type":"integer","title":"Listings Checked"},"missing":{"items":{"$ref":"#/components/schemas/CustomFieldsMissingForListingExternal"},"type":"array","title":"Missing"}},"type":"object","required":["field_keys","listings_checked","missing"],"title":"CustomFieldsCheckMissingResponseExternal"},"CustomFieldsMissingForListingExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"listing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listing Name"},"missing_field_keys":{"items":{"type":"string"},"type":"array","title":"Missing Field Keys"}},"type":"object","required":["listing_id","missing_field_keys"],"title":"CustomFieldsMissingForListingExternal"},"CustomFieldsOrphanedReferenceExternal":{"properties":{"field_key":{"type":"string","title":"Field Key"},"source_type":{"type":"string","enum":["message_template","upsell_rule"],"title":"Source Type"},"source_id":{"type":"string","title":"Source Id"},"source_label":{"type":"string","title":"Source Label"}},"type":"object","required":["field_key","source_type","source_id","source_label"],"title":"CustomFieldsOrphanedReferenceExternal","description":"An enabled message that would name a field no longer defined anywhere in the account."},"CustomFieldsResolved":{"properties":{"values":{"additionalProperties":true,"type":"object","title":"Values","description":"Merged custom-field values."},"provenance":{"additionalProperties":{"$ref":"#/components/schemas/FieldProvenance"},"type":"object","title":"Provenance","description":"Per-key origin (which level of the hierarchy provided this value)."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Entity-level custom_fields_updated_at, or null when never set."}},"type":"object","title":"CustomFieldsResolved","description":"Merged custom-field values for a single entity, with provenance."},"CustomFieldsTargetDiff":{"properties":{"target_id":{"type":"string","format":"uuid","title":"Target Id"},"added":{"additionalProperties":true,"type":"object","title":"Added"},"updated":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Updated"},"unchanged":{"items":{"type":"string"},"type":"array","title":"Unchanged"},"removed":{"additionalProperties":true,"type":"object","title":"Removed"}},"type":"object","required":["target_id"],"title":"CustomFieldsTargetDiff"},"CustomerFeedbackCreateExternal":{"properties":{"type":{"$ref":"#/components/schemas/CustomerFeedbackType","description":"Kind of feedback: ``bug_report``, ``feature_request``, or ``question``."},"title":{"type":"string","maxLength":255,"title":"Title","description":"Short summary of the feedback."},"description":{"type":"string","title":"Description","description":"Full feedback body."},"steps_to_reproduce":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steps To Reproduce","description":"Reproduction steps for bug reports. Optional."},"attachments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Attachments","description":"Optional list of attachments: ``[{url, type, name}]``."}},"type":"object","required":["type","title","description"],"title":"CustomerFeedbackCreateExternal","examples":[{"description":"After the Hostaway connector reconnected on Apr 10, reservations from Apr 1-9 stopped syncing.","steps_to_reproduce":"1. Go to Calendar\n2. Scroll to April 1-9\n3. Note no bookings shown","title":"Calendar sync missing stays from April","type":"bug_report"},{"description":"We'd like to update cleaning fees across 40+ listings at once.","title":"Bulk edit cleaning fees","type":"feature_request"},{"description":"Trying to understand pricing behavior for multi-unit listings.","title":"How does multi-unit pricing work with Airbnb?","type":"question"}]},"CustomerFeedbackExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"$ref":"#/components/schemas/CustomerFeedbackType"},"status":{"$ref":"#/components/schemas/CustomerFeedbackStatus"},"source":{"$ref":"#/components/schemas/CustomerFeedbackSource"},"title":{"type":"string","title":"Title"},"description":{"type":"string","title":"Description"},"steps_to_reproduce":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steps To Reproduce"},"attachments":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Attachments"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"support_conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Support Conversation Id","description":"The ProhostAI support conversation to check for replies with ``GET /v1/conversations/{id}/messages``. The team may answer by email when in-thread delivery is unavailable; also check the reporter's email inbox before filing a follow-up. Replies are not written back onto the feedback entry. ``null`` when no support conversation was opened."}},"type":"object","required":["id","type","status","source","title","description","steps_to_reproduce","attachments","created_at","updated_at"],"title":"CustomerFeedbackExternal","examples":[{"created_at":"2026-04-18T09:00:00Z","description":"After the Hostaway connector reconnected on Apr 10…","id":"01h5a1b2c3d4e5f6g7h8j9k0mn","source":"api","status":"submitted","steps_to_reproduce":"1. Go to Calendar\n2. Scroll to April 1-9…","support_conversation_id":"01h5a1b2c3d4e5f6g7h8j9k0mp","title":"Calendar sync missing stays from April","type":"bug_report","updated_at":"2026-04-18T09:00:00Z"}]},"CustomerFeedbackSource":{"type":"string","enum":["ai_chat","intercom","email","whatsapp","sms","internal","sentry","api","mcp","slack_customer","lead_session","prohost_message","in_app_report"],"title":"CustomerFeedbackSource"},"CustomerFeedbackStatus":{"type":"string","enum":["submitted","triaged","in_progress","resolved","declined","backlog","duplicate"],"title":"CustomerFeedbackStatus"},"CustomerFeedbackType":{"type":"string","enum":["feature_request","bug_report","question"],"title":"CustomerFeedbackType"},"DailyRatingTrendExternal":{"properties":{"date":{"type":"string","format":"date-time","title":"Date"},"rolling_average":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rolling Average"},"review_count":{"type":"integer","title":"Review Count"}},"type":"object","required":["date","rolling_average","review_count"],"title":"DailyRatingTrendExternal"},"DashboardSummary":{"properties":{"today_check_ins":{"items":{"$ref":"#/components/schemas/ReservationSummary"},"type":"array","title":"Today Check Ins"},"today_check_outs":{"items":{"$ref":"#/components/schemas/ReservationSummary"},"type":"array","title":"Today Check Outs"},"unread_conversations":{"type":"integer","title":"Unread Conversations"},"pending_tasks":{"type":"integer","title":"Pending Tasks"},"upcoming_reservations":{"items":{"$ref":"#/components/schemas/ReservationSummary"},"type":"array","title":"Upcoming Reservations"}},"type":"object","required":["today_check_ins","today_check_outs","unread_conversations","pending_tasks","upcoming_reservations"],"title":"DashboardSummary"},"DepartmentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emoji"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"member_count":{"type":"integer","title":"Member Count","default":0},"members":{"items":{"$ref":"#/components/schemas/DepartmentMemberExternal"},"type":"array","title":"Members"}},"type":"object","required":["id","name","created_at","updated_at"],"title":"DepartmentExternal"},"DepartmentMemberExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","user_id","created_at"],"title":"DepartmentMemberExternal"},"DocExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"drive_item_id":{"type":"string","format":"uuid","title":"Drive Item Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"body_md":{"type":"string","title":"Body Md"},"word_count":{"type":"integer","title":"Word Count"},"last_edited_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Last Edited By"},"last_edited_at":{"type":"string","format":"date-time","title":"Last Edited At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","drive_item_id","account_id","body_md","word_count","last_edited_at","created_at","updated_at"],"title":"DocExternal"},"DocSectionExternal":{"properties":{"id":{"type":"string","title":"Id"},"heading":{"type":"string","title":"Heading"},"level":{"type":"integer","title":"Level"},"body_md":{"type":"string","title":"Body Md"}},"type":"object","required":["id","heading","level","body_md"],"title":"DocSectionExternal"},"DocSectionReplaceRequest":{"properties":{"body_md":{"type":"string","title":"Body Md"}},"type":"object","required":["body_md"],"title":"DocSectionReplaceRequest"},"DocSectionWriteRequest":{"properties":{"heading":{"type":"string","maxLength":255,"minLength":1,"title":"Heading"},"body_md":{"type":"string","title":"Body Md"}},"type":"object","required":["heading","body_md"],"title":"DocSectionWriteRequest"},"DocWriteRequest":{"properties":{"body_md":{"type":"string","title":"Body Md"}},"type":"object","required":["body_md"],"title":"DocWriteRequest"},"DocumentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type"},"content_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Content Length"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","listing_id","filename","content_type","content_length","status","created_at","updated_at"],"title":"DocumentExternal"},"DriveFileConfirmRequestExternal":{"properties":{"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"parent_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Path"},"upload_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Upload Id"}},"type":"object","title":"DriveFileConfirmRequestExternal","description":"Confirm an uploaded file into a folder (``parent_id`` wins over ``parent_path``; neither = root)."},"DriveFileExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"drive_item_id":{"type":"string","format":"uuid","title":"Drive Item Id"},"original_file_name":{"type":"string","title":"Original File Name"},"mime_type":{"type":"string","title":"Mime Type"},"byte_size":{"type":"integer","title":"Byte Size"},"status":{"type":"string","title":"Status"},"item":{"$ref":"#/components/schemas/DriveItemExternal"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","drive_item_id","original_file_name","mime_type","byte_size","status","item","created_at"],"title":"DriveFileExternal","description":"A confirmed file and the Drive item it now lives at."},"DriveFileUploadExternal":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"upload_url":{"type":"string","title":"Upload Url"},"mime_type":{"type":"string","title":"Mime Type"},"expires_in":{"type":"integer","title":"Expires In"},"upload_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Upload Id"},"part_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Part Size"},"parts":{"anyOf":[{"items":{"$ref":"#/components/schemas/DriveFileUploadPartExternal"},"type":"array"},{"type":"null"}],"title":"Parts"}},"type":"object","required":["file_id","upload_url","mime_type","expires_in"],"title":"DriveFileUploadExternal","description":"Presigned PUT for a pending file.\n\nSmall files: PUT the bytes to ``upload_url`` with ``Content-Type: mime_type``.\nFiles over the multipart threshold come back with an empty ``upload_url`` and\n``parts``: PUT byte range ``[(n-1)*part_size, n*part_size)`` to part ``n``,\nthen pass ``upload_id`` to confirm."},"DriveFileUploadPartExternal":{"properties":{"part_number":{"type":"integer","title":"Part Number"},"url":{"type":"string","title":"Url"}},"type":"object","required":["part_number","url"],"title":"DriveFileUploadPartExternal"},"DriveFileUploadRequestExternal":{"properties":{"file_name":{"type":"string","maxLength":512,"minLength":1,"title":"File Name"},"mime_type":{"type":"string","maxLength":255,"minLength":1,"title":"Mime Type"},"byte_size":{"type":"integer","minimum":0.0,"title":"Byte Size","description":"Exact size of the bytes you will PUT."},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"parent_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Path"}},"type":"object","required":["file_name","mime_type","byte_size"],"title":"DriveFileUploadRequestExternal","description":"Ask for a presigned PUT for a file that becomes a ``kind=file`` Drive item.\n\nThe parent folder is ``parent_id`` or ``parent_path`` (``parent_id`` wins);\nomit both for the root. The acting user needs editor on the parent. Allowed\ntypes, per-type size caps and the account storage quota match the in-app\nuploader."},"DriveItemCreateExternal":{"properties":{"kind":{"$ref":"#/components/schemas/DriveItemKind"},"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"parent_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Path"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"cover_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cover Url"},"sort_order":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sort Order"}},"type":"object","required":["kind","name"],"title":"DriveItemCreateExternal","description":"Create a new Drive item.\n\nPath addressing: callers can supply either ``parent_id`` or ``parent_path``\n(e.g. ``/Properties/Ocean View``). When both are given, ``parent_id`` wins."},"DriveItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"kind":{"$ref":"#/components/schemas/DriveItemKind"},"name":{"type":"string","title":"Name"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"cover_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cover Url"},"sort_order":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sort Order"},"owner_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At"}},"type":"object","required":["id","account_id","kind","name","created_at","updated_at"],"title":"DriveItemExternal","description":"External Drive item shape (folder, doc, or sheet reference)."},"DriveItemKind":{"type":"string","enum":["folder","doc","sheet","file"],"title":"DriveItemKind","description":"Kind of item stored in the Drive tree."},"DriveItemUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"cover_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cover Url"},"sort_order":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sort Order"}},"type":"object","title":"DriveItemUpdateExternal","description":"Patch a Drive item. Only fields set in the payload are modified."},"DriveMediaAssetExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"drive_item_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Drive Item Id"},"drive_doc_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Drive Doc Id"},"content_type":{"type":"string","title":"Content Type"},"byte_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Byte Size"},"status":{"type":"string","title":"Status"},"url":{"type":"string","title":"Url"},"markdown":{"type":"string","title":"Markdown"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","content_type","status","url","markdown","created_at"],"title":"DriveMediaAssetExternal","description":"A confirmed media asset and the markdown that embeds it."},"DriveMediaUploadExternal":{"properties":{"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"upload_url":{"type":"string","title":"Upload Url"},"url":{"type":"string","title":"Url"},"content_type":{"type":"string","title":"Content Type"},"expires_in":{"type":"integer","title":"Expires In"}},"type":"object","required":["asset_id","upload_url","url","content_type","expires_in"],"title":"DriveMediaUploadExternal","description":"Presigned PUT for a pending media asset.\n\nPUT the bytes to ``upload_url`` with the same ``Content-Type`` header, then\ncall ``POST /v1/drive/media/{asset_id}/confirm``. ``url`` is the stable\nreference to embed in the doc (``![alt](url)``) — not a signed URL."},"DriveMediaUploadRequestExternal":{"properties":{"file_name":{"type":"string","maxLength":512,"minLength":1,"title":"File Name"},"content_type":{"type":"string","maxLength":255,"minLength":1,"title":"Content Type"},"byte_size":{"type":"integer","minimum":0.0,"title":"Byte Size","description":"Exact size of the bytes you will PUT."},"drive_item_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Drive Item Id"},"drive_doc_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Drive Doc Id"}},"type":"object","required":["file_name","content_type","byte_size"],"title":"DriveMediaUploadRequestExternal","description":"Ask for a presigned PUT for an image, video or audio clip to embed in a doc.\n\nAttach it to the doc (``drive_doc_id``) or its Drive item (``drive_item_id``);\nthe acting user needs editor on that item. Allowed content types and the size\ncap are the same as the in-app editor's."},"DriveMoveRequest":{"properties":{"new_parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"New Parent Id"},"new_parent_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Parent Path"}},"type":"object","title":"DriveMoveRequest","description":"Move a Drive item to a new parent.\n\n``new_parent_id`` of ``None`` moves the item to the root. ``new_parent_path``\nis resolved relative to the account; ``new_parent_id`` wins when both are set."},"EarningsResponseExternal":{"properties":{"totals":{"$ref":"#/components/schemas/EarningsSummaryExternal"}},"type":"object","required":["totals"],"title":"EarningsResponseExternal"},"EarningsSummaryExternal":{"properties":{"payout":{"type":"number","title":"Payout"},"payout_by_currency":{"items":{"$ref":"#/components/schemas/CurrencyAmountExternal"},"type":"array","title":"Payout By Currency","default":[]},"occupancy":{"type":"number","title":"Occupancy"},"avg_nightly_rate":{"type":"number","title":"Avg Nightly Rate"},"avg_nightly_rate_by_currency":{"items":{"$ref":"#/components/schemas/CurrencyAmountExternal"},"type":"array","title":"Avg Nightly Rate By Currency","default":[]},"avg_stay_length":{"type":"number","title":"Avg Stay Length"},"unbooked_nights":{"type":"integer","title":"Unbooked Nights"},"bookable_revenue":{"type":"number","title":"Bookable Revenue"},"bookable_revenue_by_currency":{"items":{"$ref":"#/components/schemas/CurrencyAmountExternal"},"type":"array","title":"Bookable Revenue By Currency","default":[]},"avg_booking_lead_time_days":{"type":"number","title":"Avg Booking Lead Time Days"},"num_reservations":{"type":"integer","title":"Num Reservations"},"total_nights":{"type":"integer","title":"Total Nights"}},"type":"object","required":["payout","occupancy","avg_nightly_rate","avg_stay_length","unbooked_nights","bookable_revenue","avg_booking_lead_time_days","num_reservations","total_nights"],"title":"EarningsSummaryExternal"},"EditMessageExternal":{"properties":{"message":{"type":"string","minLength":1,"title":"Message","description":"New message body."}},"type":"object","required":["message"],"title":"EditMessageExternal","description":"Body for editing an already-sent message (internal channels only).","examples":[{"message":"Edited body."}]},"EscalationReachability":{"type":"string","enum":["off","push","push_and_text","push_text_and_call"],"title":"EscalationReachability","description":"Per-user CAP on how loudly the escalation ladder may reach that user.\n\nThis is the ONLY user-facing escalation preference (rung *timings* are fixed\nserver-side defaults, not user-editable). It gates which rung types may fire\nAT this user; the executor applies it per targeted on-call person — including\nthe ``next_person`` the ladder advances to."},"ExpenseActivityListing":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"listing_name":{"type":"string","title":"Listing Name"},"total_expenses":{"type":"number","minimum":0.0,"title":"Total Expenses"},"num_expenses":{"type":"integer","minimum":0.0,"title":"Num Expenses"}},"type":"object","required":["listing_id","listing_name","total_expenses","num_expenses"],"title":"ExpenseActivityListing"},"ExpenseActivityResponse":{"properties":{"expenses":{"items":{"$ref":"#/components/schemas/StatementExpense"},"type":"array","title":"Expenses"},"expenses_total":{"type":"number","minimum":0.0,"title":"Expenses Total"},"listings":{"items":{"$ref":"#/components/schemas/ExpenseActivityListing"},"type":"array","title":"Listings"},"listings_total":{"type":"number","minimum":0.0,"title":"Listings Total"}},"type":"object","required":["expenses","expenses_total","listings","listings_total"],"title":"ExpenseActivityResponse"},"ExpenseCategoryCreateExternal":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"}},"additionalProperties":false,"type":"object","required":["name"],"title":"ExpenseCategoryCreateExternal"},"ExpenseCategoryExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"name":{"type":"string","title":"Name"},"is_system":{"type":"boolean","title":"Is System"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","account_id","name","is_system","created_at","updated_at"],"title":"ExpenseCategoryExternal"},"ExpenseCategoryUpdateExternal":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"}},"additionalProperties":false,"type":"object","title":"ExpenseCategoryUpdateExternal","description":"Partial update for an expense category.\n\n``name`` must be either omitted (no-op) or a non-null string — explicitly\npassing ``null`` is rejected so the request doesn't reach the service layer\nwith a nullable value that would trip the ``expense_categories.name NOT\nNULL`` constraint at commit time. ``OptionalField`` hides ``null`` from the\ngenerated OpenAPI schema so the spec reads ``\"type\": \"string\"``."},"ExpenseCreateExternal":{"properties":{"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id"},"name":{"type":"string","title":"Name"},"amount":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount"},"currency":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[A-Z]{3}$","title":"Currency","default":"USD"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"date":{"type":"string","format":"date","title":"Date"}},"type":"object","required":["name","amount","date"],"title":"ExpenseCreateExternal"},"ExpenseExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id"},"name":{"type":"string","title":"Name"},"amount":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Amount"},"currency":{"type":"string","title":"Currency"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"date":{"type":"string","format":"date","title":"Date"},"payment_type":{"$ref":"#/components/schemas/PaymentType"},"payment_status":{"$ref":"#/components/schemas/PaymentStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","listing_id","reservation_id","category_id","name","amount","currency","description","date","payment_type","payment_status","created_at","updated_at"],"title":"ExpenseExternal"},"ExpenseUpdateExternal":{"properties":{"name":{"type":"string","title":"Name"},"amount":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount"},"currency":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[A-Z]{3}$","title":"Currency"},"date":{"type":"string","format":"date","title":"Date"},"payment_status":{"$ref":"#/components/schemas/PaymentStatus","title":"Payment Status"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"category_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Category Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"}},"additionalProperties":false,"type":"object","title":"ExpenseUpdateExternal","description":"Partial update for an expense. Only provided fields are modified.\n\nFields that map to non-nullable columns (``name``, ``amount``, ``currency``,\n``date``, ``payment_status``) must be either omitted or set to a non-null\nvalue — explicitly passing ``null`` returns a 422 rather than surfacing a\ndatabase-level ``NOT NULL`` error at commit time."},"ExternalReviewContent":{"properties":{"rating":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating","description":"Overall rating: 1-10 for Booking.com, else 1-5"},"public_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Review"},"private_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Review"},"reviewer_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Reviewer Name"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"host_response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Response"},"host_response_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Host Response At"},"rating_value":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Value"},"rating_cleanliness":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Cleanliness"},"rating_communication":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Communication"},"rating_location":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Location"},"rating_checkin":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Checkin"},"rating_accuracy":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Accuracy"},"rating_facilities":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Facilities"},"rating_staff":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Staff"},"rating_services":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Services"}},"type":"object","title":"ExternalReviewContent","description":"The editable part of a hand-added review. Ratings are on the channel's own scale."},"FeatureBoardPostCategory":{"type":"string","enum":["feature","improvement"],"title":"FeatureBoardPostCategory","description":"Coarse bucket a post belongs to. Drives board filtering only."},"FeatureBoardPostExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"summary_md":{"type":"string","title":"Summary Md","description":"Staff-written markdown summary of the request."},"status":{"$ref":"#/components/schemas/FeatureBoardPostStatus"},"category":{"$ref":"#/components/schemas/FeatureBoardPostCategory"},"vote_count":{"type":"integer","title":"Vote Count"},"my_vote":{"type":"boolean","title":"My Vote","description":"Whether the acting user has voted for this post."},"my_follow":{"type":"boolean","title":"My Follow","description":"Whether the acting user follows this post (gets notified when it ships)."},"feature_release_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Feature Release Id","description":"The release story announcing this post, once it ships. May not resolve."},"url":{"type":"string","title":"Url","description":"Link to the post on the ProhostAI Feature Board."},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","title","summary_md","status","category","vote_count","my_vote","my_follow","url","created_at"],"title":"FeatureBoardPostExternal","description":"One published Feature Board post, with the acting user's own state.\n\n``my_vote`` / ``my_follow`` are always concrete booleans — ``False`` when\nthe user has no relationship to the post."},"FeatureBoardPostPageExternal":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FeatureBoardPostExternal"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"FeatureBoardPostPageExternal"},"FeatureBoardPostStatus":{"type":"string","enum":["planned","under_consideration","building","shipped","closed"],"title":"FeatureBoardPostStatus","description":"Lifecycle of a curated board post, as shown publicly on the board.\n\nMapped onto from ``CustomerFeedbackStatus`` when a linked canonical\nfeedback row transitions — see\n``lambdas/customer_feedback_email_outbox/handler.py``."},"FeatureBoardSearchResultsExternal":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FeatureBoardPostExternal"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"FeatureBoardSearchResultsExternal","description":"Best matches first. Not paginated — refine the query instead."},"FeatureBoardSort":{"type":"string","enum":["new","top","trending"],"title":"FeatureBoardSort"},"FieldProvenance":{"properties":{"source":{"type":"string","title":"Source","description":"One of: account, tag, source, listing, reservation, guest, contact."},"tag_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag Name","description":"Populated when source == 'tag'."},"tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tag Id","description":"Populated when source == 'tag'."}},"type":"object","required":["source"],"title":"FieldProvenance","description":"Where a single custom-field value came from in the merge hierarchy."},"FlagReason":{"type":"string","enum":["spam","harassment","hate","self_promotion","identifying_info","off_topic","other"],"title":"FlagReason","description":"Reporter-selected reason for a flag (§ 6.1)."},"FollowRequestExternal":{"properties":{"who":{"type":"string","title":"Who","description":"`me` (the member the credential acts for) or the user id of a workspace member or AI employee. Acting for someone else needs the item type's write scope.","default":"me"},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level","description":"`all` (default) or `important` — status changes, completion, @mentions, overdue and issues."},"until_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Until Done","description":"Stop following once the task / cleaning is done. Omit for the follower's own default. Ignored for conversations."},"instruction":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Instruction","description":"AI-employee followers only: what to watch for, in plain words."}},"additionalProperties":false,"type":"object","title":"FollowRequestExternal","description":"Follow an item for the calling member or for someone else."},"FollowResultExternal":{"properties":{"entity_type":{"type":"string","enum":["task","cleaning","conversation"],"title":"Entity Type"},"entity_id":{"type":"string","format":"uuid","title":"Entity Id"},"title":{"type":"string","title":"Title"},"state":{"$ref":"#/components/schemas/FollowStateExternal"}},"type":"object","required":["entity_type","entity_id","title","state"],"title":"FollowResultExternal","description":"The item and the resulting follow state."},"FollowStateExternal":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"following":{"type":"boolean","title":"Following","description":"Whether this person is an active (unmuted) follower."},"muted":{"type":"boolean","title":"Muted"},"muted_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Muted Until"},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level"},"until_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Until Done"},"source":{"anyOf":[{"type":"string","enum":["explicit","auto"]},{"type":"null"}],"title":"Source","description":"`explicit` (someone pressed Follow) or `auto` (involvement from commenting / mentions)."},"instruction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instruction"}},"type":"object","required":["user_id","following","muted"],"title":"FollowStateExternal","description":"One person's follow state on one item."},"FollowerExternal":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"following":{"type":"boolean","title":"Following","description":"Whether this person is an active (unmuted) follower."},"muted":{"type":"boolean","title":"Muted"},"muted_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Muted Until"},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level"},"until_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Until Done"},"source":{"anyOf":[{"type":"string","enum":["explicit","auto"]},{"type":"null"}],"title":"Source","description":"`explicit` (someone pressed Follow) or `auto` (involvement from commenting / mentions)."},"instruction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instruction"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"is_ai_employee":{"type":"boolean","title":"Is Ai Employee","default":false}},"type":"object","required":["user_id","following","muted"],"title":"FollowerExternal","description":"One follower of an item."},"FollowersListExternal":{"properties":{"entity_type":{"type":"string","enum":["task","cleaning","conversation"],"title":"Entity Type"},"entity_id":{"type":"string","format":"uuid","title":"Entity Id"},"title":{"type":"string","title":"Title"},"followers":{"items":{"$ref":"#/components/schemas/FollowerExternal"},"type":"array","title":"Followers"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["entity_type","entity_id","title","followers","count"],"title":"FollowersListExternal","description":"Everyone with a standing follow choice on an item — people and AI employees."},"FollowingCadence":{"type":"string","enum":["instant","hourly","daily"],"title":"FollowingCadence","description":"When follow-driven notifications are delivered.\n\n``instant`` pushes as events happen. ``hourly`` / ``daily`` roll the\nfollow-only events up into a summary instead. Only the delivery of\nfollow-only reach is affected: an assignee is paged about their own work\nimmediately regardless."},"FollowingItemExternal":{"properties":{"entity_type":{"type":"string","title":"Entity Type","description":"`task`, `cleaning` or `conversation` for one item; `listing`, `department` or `recurring_task` for a whole scope (every task and cleaning under it). New values may be added — skip ones you don't know.","x-extensible-enum":["task","cleaning","conversation","listing","department","recurring_task"]},"entity_id":{"type":"string","format":"uuid","title":"Entity Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level"},"until_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Until Done"},"followed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Followed At"},"instruction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instruction","description":"AI-employee follows only: the brief it watches for."}},"type":"object","required":["entity_type","entity_id"],"title":"FollowingItemExternal","description":"One item — or whole scope — someone follows."},"FollowingListExternal":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"items":{"items":{"$ref":"#/components/schemas/FollowingItemExternal"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["user_id","items","count"],"title":"FollowingListExternal","description":"The items and scopes a person follows, newest first (muted follows excluded)."},"GuestCreateExternal":{"properties":{"first_name":{"type":"string","maxLength":255,"minLength":1,"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"}},"type":"object","required":["first_name"],"title":"GuestCreateExternal","description":"Create a new guest record on the account.","examples":[{"email":"jane.doe@example.com","first_name":"Jane","last_name":"Doe","phone":"+1-555-0100","tags":["vip"]}]},"GuestExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","first_name","last_name","email","phone","created_at","updated_at"],"title":"GuestExternal"},"GuestForm":{"properties":{"response_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"template_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Template Id"},"template_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Version"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"eta":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eta"},"num_guests":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Guests"},"num_pets":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Pets"},"id_verification_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Verification Status"},"agreement_signed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agreement Signed At"},"deposit_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deposit Status"},"answers":{"additionalProperties":true,"type":"object","title":"Answers"},"files":{"items":{"$ref":"#/components/schemas/GuestFormFile"},"type":"array","title":"Files"}},"type":"object","required":["response_id","reservation_id","listing_id","template_id","template_version","status","completed_at","eta","num_guests","num_pets","id_verification_status","agreement_signed_at","deposit_status","answers","files"],"title":"GuestForm","description":"A reservation's check-in form submission — the same shape the ``guest_form.submitted`` webhook delivers.","examples":[{"agreement_signed_at":"2026-04-24T14:48:00Z","answers":{"guest_names":{"names":["Alex Rivera","Sam Rivera"]},"id_verification":{"key":"welcome-pass/33333333-4444-4555-8666-777788889999/id_verification/01HFX.jpg","uploaded_at":"2026-04-24T14:47:10Z"}},"completed_at":"2026-04-24T14:50:00Z","deposit_status":"authorized","eta":"2026-04-24T17:00:00Z","files":[{"key":"welcome-pass/33333333-4444-4555-8666-777788889999/id_verification/01HFX.jpg","step_id":"id_verification","uploaded_at":"2026-04-24T14:47:10Z"}],"id_verification_status":"verified","listing_id":"44444444-5555-4666-8777-888899990000","num_guests":2,"num_pets":0,"reservation_id":"33333333-4444-4555-8666-777788889999","response_id":"01HFXGGGGGGGGGGGGGGGGGGG00","status":"completed","template_id":"55555555-6666-4777-8888-99990000aaaa","template_version":"3"}]},"GuestFormFile":{"properties":{"step_id":{"type":"string","title":"Step Id"},"key":{"type":"string","title":"Key","description":"Pass to GET /reservations/{id}/guest-form/file-url to obtain a download link."},"uploaded_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploaded At"}},"type":"object","required":["step_id","key"],"title":"GuestFormFile","description":"One guest upload, referenced by private-bucket key (never a URL)."},"GuestFormFileUrl":{"properties":{"url":{"type":"string","title":"Url","description":"Short-lived presigned download URL for the requested upload."},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds until ``url`` stops working."}},"type":"object","required":["url","expires_in"],"title":"GuestFormFileUrl"},"GuestUpdateExternal":{"properties":{"first_name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields","description":"Replaces the entire ``custom_fields`` dict on the guest. For partial updates use the batch custom-fields endpoints."}},"type":"object","title":"GuestUpdateExternal","description":"Update an existing guest. All fields optional; only provided fields are written."},"GuidebookCreateExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"title":{"type":"string","maxLength":255,"minLength":1,"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"default_language":{"$ref":"#/components/schemas/LanguageCode","default":"en-US"}},"additionalProperties":false,"type":"object","required":["listing_id","title"],"title":"GuidebookCreateExternal","description":"Create a new guidebook attached to a listing."},"GuidebookDetailExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"default_language":{"$ref":"#/components/schemas/LanguageCode"},"shareable_link":{"type":"string","title":"Shareable Link"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Guest-facing link to the guidebook, on the account's custom domain when one is active."},"theme":{"$ref":"#/components/schemas/GuidebookTheme"},"view_count":{"type":"integer","title":"View Count"},"custom_primary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Primary Color"},"custom_secondary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Secondary Color"},"custom_font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Font"},"corner_radius":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Corner Radius"},"custom_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Url"},"custom_logo_dark_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Dark Url"},"custom_brand_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Brand Text"},"hide_branding":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hide Branding"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"type":"array","title":"Sections","default":[]},"shared_sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"type":"array","title":"Shared Sections","default":[]}},"type":"object","required":["id","listing_id","title","description","default_language","shareable_link","theme","view_count","created_at","updated_at"],"title":"GuidebookDetailExternal"},"GuidebookExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"default_language":{"$ref":"#/components/schemas/LanguageCode"},"shareable_link":{"type":"string","title":"Shareable Link"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Guest-facing link to the guidebook, on the account's custom domain when one is active."},"theme":{"$ref":"#/components/schemas/GuidebookTheme"},"view_count":{"type":"integer","title":"View Count"},"custom_primary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Primary Color"},"custom_secondary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Secondary Color"},"custom_font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Font"},"corner_radius":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Corner Radius"},"custom_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Url"},"custom_logo_dark_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Dark Url"},"custom_brand_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Brand Text"},"hide_branding":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hide Branding"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","listing_id","title","description","default_language","shareable_link","theme","view_count","created_at","updated_at"],"title":"GuidebookExternal"},"GuidebookImageContentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/heic"],"title":"GuidebookImageContentType","description":"Allowed Content-Type values for the guidebook-image presigned upload.\n\nConstrained to image MIME types so an authenticated client can't ask\nus to sign a PUT for ``text/html`` and serve that out of our public-read\nbucket. Mirrors the ``PlacePhotoContentType`` set."},"GuidebookImageUrlRequestExternal":{"properties":{"content_type":{"$ref":"#/components/schemas/GuidebookImageContentType"}},"type":"object","required":["content_type"],"title":"GuidebookImageUrlRequestExternal"},"GuidebookImageUrlResponseExternal":{"properties":{"presigned_url":{"type":"string","title":"Presigned Url"}},"type":"object","required":["presigned_url"],"title":"GuidebookImageUrlResponseExternal"},"GuidebookPinCreateExternal":{"properties":{"place_id":{"type":"string","format":"uuid","title":"Place Id"},"category":{"$ref":"#/components/schemas/PlacePinCategory"},"host_note_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Note Override"},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position"}},"additionalProperties":false,"type":"object","required":["place_id","category"],"title":"GuidebookPinCreateExternal","description":"Used by ``POST /guidebooks/{id}/pins`` (path supplies the guidebook).\n\n``host_note_override`` and ``position`` are optional; the service layer\nappends a new pin at end-of-scope when ``position`` is omitted."},"GuidebookPinReorderExternal":{"properties":{"pins":{"items":{"$ref":"#/components/schemas/PinReorderItemExternal"},"type":"array","title":"Pins"}},"additionalProperties":false,"type":"object","title":"GuidebookPinReorderExternal","description":"Reorder pins within a single guidebook scope (path supplies guidebook_id)."},"GuidebookPinsResponseExternal":{"properties":{"pins":{"items":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"},"type":"array","title":"Pins"},"tag_pins":{"items":{"$ref":"#/components/schemas/TagPinGroupExternal"},"type":"array","title":"Tag Pins"}},"type":"object","required":["pins"],"title":"GuidebookPinsResponseExternal"},"GuidebookPlacePinExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"place_id":{"type":"string","format":"uuid","title":"Place Id"},"guidebook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Guidebook Id"},"listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"},"category":{"$ref":"#/components/schemas/PlacePinCategory"},"position":{"type":"integer","title":"Position"},"host_note_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Note Override"},"place":{"$ref":"#/components/schemas/PlaceExternal"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","account_id","place_id","guidebook_id","listing_tag_id","category","position","host_note_override","place","created_at","updated_at"],"title":"GuidebookPlacePinExternal","description":"A guidebook- OR tag-scoped pin pointing at a place."},"GuidebookSectionCreateExternal":{"properties":{"title":{"type":"string","maxLength":255,"minLength":1,"title":"Title"},"content":{"type":"string","title":"Content","default":""},"section_type":{"$ref":"#/components/schemas/GuidebookSectionType"},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"unlock_before_checkin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unlock Before Checkin"}},"additionalProperties":false,"type":"object","required":["title","section_type"],"title":"GuidebookSectionCreateExternal","description":"Create a guidebook-scoped section (path supplies the guidebook)."},"GuidebookSectionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"short_id":{"type":"string","title":"Short Id"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Guest-facing link that opens this section, on the account's custom domain when one is active. Share it as-is rather than building links from ``short_id``. In a guidebook's ``shared_sections`` it opens the shared section inside that guidebook. Null when a tag-scoped section is read on its own (the tag-section endpoints), since it renders into every guidebook on a tagged listing."},"title":{"type":"string","title":"Title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"section_type":{"$ref":"#/components/schemas/GuidebookSectionType"},"position":{"type":"integer","title":"Position"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"guidebook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Guidebook Id"},"listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"},"additional_tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Additional Tag Ids"},"unlock_before_checkin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unlock Before Checkin"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","short_id","title","content","section_type","position","created_at","updated_at"],"title":"GuidebookSectionExternal"},"GuidebookSectionReorderExternal":{"properties":{"sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionReorderItemExternal"},"type":"array","title":"Sections"}},"additionalProperties":false,"type":"object","title":"GuidebookSectionReorderExternal"},"GuidebookSectionReorderItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"position":{"type":"integer","title":"Position"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"}},"type":"object","required":["id","position"],"title":"GuidebookSectionReorderItemExternal"},"GuidebookSectionType":{"type":"string","enum":["text","recommendations","house_rules","embedded_content","mystay_content","embed"],"title":"GuidebookSectionType","description":"Types of sections that can be included in a guidebook.\n\n``embed`` and ``embedded_content`` share the same shape (iframe + JSON\npayload at ``GuidebookSection.content``) but differ by surface:\n``embed`` renders in the main guidebook viewer, ``embedded_content``\nis the legacy MyStay-only embed. Keeping them as distinct types\navoids repurposing the opt-in ``mystay_section_order`` sort hint into\na visibility manifest and preserves existing MyStay behavior for\nproduction sections."},"GuidebookSectionUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"section_type":{"anyOf":[{"$ref":"#/components/schemas/GuidebookSectionType"},{"type":"null"}]},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"unlock_before_checkin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unlock Before Checkin"}},"additionalProperties":false,"type":"object","title":"GuidebookSectionUpdateExternal"},"GuidebookSectionsListResponseExternal":{"properties":{"sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"type":"array","title":"Sections"},"shared_sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"type":"array","title":"Shared Sections"}},"type":"object","title":"GuidebookSectionsListResponseExternal","description":"Response for ``GET /guidebooks/{id}/sections``: the guidebook's own sections\nin ``sections`` and the tag-scoped sections it inherits in ``shared_sections``."},"GuidebookTheme":{"type":"string","enum":["light","dark","beach","mountain","desert","custom"],"title":"GuidebookTheme","description":"Available themes for guidebooks. Shared with direct booking sites."},"GuidebookUpdateExternal":{"properties":{"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"theme":{"anyOf":[{"$ref":"#/components/schemas/GuidebookTheme"},{"type":"null"}]},"custom_primary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Primary Color"},"custom_secondary_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Secondary Color"},"custom_font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Font"},"corner_radius":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Corner Radius"},"custom_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Url"},"custom_logo_dark_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Logo Dark Url"},"custom_brand_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Brand Text"},"hide_branding":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hide Branding"}},"additionalProperties":false,"type":"object","title":"GuidebookUpdateExternal","description":"Patch fields on an existing guidebook. Only fields present in the\npayload are applied — clients MUST omit fields they don't want to change.\n\nNote: ``hide_branding`` is ``bool | None`` for typing parity with the\ninternal schema, but ``null`` is rejected because it conflicts with\n\"no-op\" semantics (omit the field instead)."},"GuidebookUpgradeOptionCreateExternal":{"properties":{"title":{"type":"string","maxLength":255,"minLength":1,"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"price":{"type":"number","minimum":0.0,"title":"Price"},"enabled":{"type":"boolean","title":"Enabled","default":true},"upgrade_type":{"$ref":"#/components/schemas/UpgradeOptionType","default":"reservation_wide"}},"additionalProperties":false,"type":"object","required":["title","price"],"title":"GuidebookUpgradeOptionCreateExternal"},"GuidebookUpgradeOptionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"guidebook_id":{"type":"string","format":"uuid","title":"Guidebook Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"price":{"type":"number","title":"Price"},"enabled":{"type":"boolean","title":"Enabled"},"upgrade_type":{"$ref":"#/components/schemas/UpgradeOptionType"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","guidebook_id","title","price","enabled","upgrade_type","created_at","updated_at"],"title":"GuidebookUpgradeOptionExternal"},"GuidebookUpgradeOptionUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Price"},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"upgrade_type":{"anyOf":[{"$ref":"#/components/schemas/UpgradeOptionType"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"GuidebookUpgradeOptionUpdateExternal"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HireAIEmployeeRequest":{"properties":{"template_key":{"type":"string","title":"Template Key","description":"Launch-lineup template slug (e.g. 'claudia')."},"heartbeat_interval_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Heartbeat Interval Seconds","description":"Optional heartbeat cadence override; must be >= the floor (900s)."}},"type":"object","required":["template_key"],"title":"HireAIEmployeeRequest","description":"Hire (activate) a pre-built template AI employee."},"HostRoleUpdateExternal":{"properties":{"user_id":{"type":"string","title":"User Id"},"apply_to_all":{"type":"boolean","title":"Apply To All","default":false}},"additionalProperties":false,"type":"object","required":["user_id"],"title":"HostRoleUpdateExternal","description":"Set the host role (owner / cohost) for a listing."},"InboundMessageExternal":{"properties":{"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text","description":"What the guest wrote."},"external_message_id":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"External Message Id","description":"Your id for this message. Sending it again on the same conversation returns the stored message with 200."},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At","description":"When the guest wrote it; now when omitted. Not in the future."}},"additionalProperties":false,"type":"object","required":["text"],"title":"InboundMessageExternal","examples":[{"external_message_id":"contact-form-8841-reply-1","sent_at":"2026-11-02T18:04:00Z","text":"Thanks! Could we also bring our dog?"}]},"InboundMessageResponse":{"properties":{"message":{"$ref":"#/components/schemas/ConversationMessageExternal"},"created":{"type":"boolean","title":"Created","description":"False when `external_message_id` had already been posted."}},"type":"object","required":["message","created"],"title":"InboundMessageResponse"},"InboundWebhookCreateExternal":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name","description":"Your label for this webhook, e.g. 'CI deploys'. Shown as the message's source."},"target_conversation_id":{"type":"string","format":"uuid","title":"Target Conversation Id","description":"The team-chat conversation to post into. Must be an internal conversation in this account."},"secret":{"anyOf":[{"type":"string","maxLength":256,"minLength":1},{"type":"null"}],"title":"Secret","description":"Optional HMAC-SHA256 signing secret. When set, every delivery must carry an `X-Prohost-Signature` header holding the hex digest of the raw request body. Recommended — without it the URL is the only credential."}},"additionalProperties":false,"type":"object","required":["name","target_conversation_id"],"title":"InboundWebhookCreateExternal","description":"Body for ``POST /v1/inbound-webhooks``.","examples":[{"name":"CI deploys","secret":"s3cr3t-shared-with-the-sender","target_conversation_id":"c2d3e4f5-a6b7-4890-b123-4567890abcde"}]},"InboundWebhookCreatedExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"mode":{"type":"string","title":"Mode","description":"Always `channel_post` on this surface."},"target_conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Conversation Id"},"token_prefix":{"type":"string","title":"Token Prefix","description":"First few characters of the token, for recognizing which URL this is."},"url_masked":{"type":"string","title":"Url Masked"},"has_secret":{"type":"boolean","title":"Has Secret","description":"Whether HMAC signing is configured. The secret itself is never returned."},"is_active":{"type":"boolean","title":"Is Active"},"last_received_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Received At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"token":{"type":"string","title":"Token","description":"The full token. Not recoverable later."},"url":{"type":"string","title":"Url","description":"The delivery URL to POST to. Not recoverable later."}},"additionalProperties":false,"type":"object","required":["id","name","mode","token_prefix","url_masked","has_secret","is_active","created_at","updated_at","token","url"],"title":"InboundWebhookCreatedExternal","description":"Create response — the ONLY place the full token and URL appear."},"InboundWebhookExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"mode":{"type":"string","title":"Mode","description":"Always `channel_post` on this surface."},"target_conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Conversation Id"},"token_prefix":{"type":"string","title":"Token Prefix","description":"First few characters of the token, for recognizing which URL this is."},"url_masked":{"type":"string","title":"Url Masked"},"has_secret":{"type":"boolean","title":"Has Secret","description":"Whether HMAC signing is configured. The secret itself is never returned."},"is_active":{"type":"boolean","title":"Is Active"},"last_received_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Received At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["id","name","mode","token_prefix","url_masked","has_secret","is_active","created_at","updated_at"],"title":"InboundWebhookExternal","description":"Public projection of an inbound webhook. Token masked, secret never shown."},"InboundWebhookListResponse":{"properties":{"webhooks":{"items":{"$ref":"#/components/schemas/InboundWebhookExternal"},"type":"array","title":"Webhooks"}},"additionalProperties":false,"type":"object","required":["webhooks"],"title":"InboundWebhookListResponse"},"InboundWebhookUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Name"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"Set false to make the URL stop posting without deleting it (deliveries are logged as rejected)."},"target_conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Conversation Id","description":"Re-point the webhook at a different conversation, keeping the same URL."}},"additionalProperties":false,"type":"object","title":"InboundWebhookUpdateExternal","description":"Body for ``PATCH /v1/inbound-webhooks/{id}``."},"IngestFirstMessageExternal":{"properties":{"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text","description":"What the guest wrote."}},"additionalProperties":false,"type":"object","required":["text"],"title":"IngestFirstMessageExternal"},"IngestGuestExternal":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"The guest's name as your site collected it."},"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email","description":"Where email replies go. Required for `reply_via: email`."},"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Phone","description":"The guest's number, ideally E.164 (`+14155550123`). A number without a country code is read in the workspace's home country. Required for `reply_via: sms`."}},"additionalProperties":false,"type":"object","required":["name"],"title":"IngestGuestExternal"},"IngestedConversationResponse":{"properties":{"conversation":{"$ref":"#/components/schemas/ConversationExternal"},"created":{"type":"boolean","title":"Created","description":"False when `external_id` had already started this conversation."},"message":{"anyOf":[{"$ref":"#/components/schemas/ConversationMessageExternal"},{"type":"null"}],"description":"The first message, when this call posted one."}},"type":"object","required":["conversation","created"],"title":"IngestedConversationResponse"},"InternalNoteResponse":{"properties":{"message_id":{"type":"string","format":"uuid","title":"Message Id"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["message_id","conversation_id","created_at"],"title":"InternalNoteResponse","examples":[{"conversation_id":"c2d3e4f5-a6b7-4890-b123-4567890abcde","created_at":"2026-07-30T14:31:00Z","message_id":"d3e4f5a6-b7c8-4901-8234-567890abcdef"}]},"InvitationCreateExternal":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"type":"string","title":"Role","description":"Role: 'admin' or 'user'","default":"user"},"permissions":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Permissions","description":"Feature permissions (e.g., {'cleanings': 'write', 'tasks': 'write'})"},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids","description":"Restrict access to specific property IDs"}},"type":"object","required":["email"],"title":"InvitationCreateExternal"},"InvitationExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","description":"Role: 'admin' or 'user'"},"status":{"type":"string","title":"Status","description":"Status: 'pending', 'accepted', or 'expired'"},"permissions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Permissions","description":"Feature permissions (e.g., {'cleanings': 'write'})"},"listing_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Listing Ids","description":"Restricted listing IDs"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","email","role","status","created_at"],"title":"InvitationExternal"},"InvoiceItemTypeName":{"type":"string","enum":["accommodation_fare","cleaning_fee","pet_fee","guest_channel_fee","other_fee","lodging_tax","transient_occupancy_tax","sales_tax","other_tax","host_channel_fee","host_cancellation_fee","payment_processing_fee","discount","refundable_deposit"],"title":"InvoiceItemTypeName"},"ItemsPage_AIEmployeeExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AIEmployeeExternal"},"type":"array","title":"Items","description":"The full collection of results."},"total":{"type":"integer","title":"Total","description":"Number of items returned (equals ``len(items)``)."}},"type":"object","required":["items","total"],"title":"ItemsPage[AIEmployeeExternal]"},"ItemsPage_AIEmployeeTriggerExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AIEmployeeTriggerExternal"},"type":"array","title":"Items","description":"The full collection of results."},"total":{"type":"integer","title":"Total","description":"Number of items returned (equals ``len(items)``)."}},"type":"object","required":["items","total"],"title":"ItemsPage[AIEmployeeTriggerExternal]"},"ItemsPage_CalendarDayExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CalendarDayExternal"},"type":"array","title":"Items","description":"The full collection of results."},"total":{"type":"integer","title":"Total","description":"Number of items returned (equals ``len(items)``)."}},"type":"object","required":["items","total"],"title":"ItemsPage[CalendarDayExternal]"},"LanguageCode":{"type":"string","enum":["en-US","es-ES","fr-FR","it-IT","zh-CN","ja-JP","mn-MN","ko-KR","de-DE","pt-BR","ru-RU","cs-CZ","sk-SK","nl-NL","pl-PL","ar-SA","th-TH","tr-TR","hi-IN","he-IL","el-GR","sv-SE","pt-PT","vi-VN"],"title":"LanguageCode","description":"Supported language codes for the app (user preferences and guidebook translations).\n\nUsed by:\n- User.preferred_language (app UI language)\n- Guidebook translations\n\nKeep in sync with:\n- Frontend: web/src/i18n/supportedLanguages.ts\n- iOS: LanguageCode.swift\n- Database: db/schema.sql (languagecode enum; changed only through dbmate)\n- Translations: shared/i18n/translations/"},"ListingChannelUrlsExternal":{"properties":{"airbnb":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Airbnb"},"vrbo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vrbo"},"google_vr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Google Vr"},"expedia":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expedia"},"booking_engine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Booking Engine"}},"type":"object","title":"ListingChannelUrlsExternal","description":"Public OTA URLs for a listing across the channels it's published to."},"ListingChildrenExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"child_listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Child Listing Ids"},"child_listings":{"items":{"$ref":"#/components/schemas/RelatedListingSummaryExternal"},"type":"array","title":"Child Listings"},"link_type":{"anyOf":[{"type":"string","enum":["composed_of","same_space"]},{"type":"null"}],"title":"Link Type"},"parent_listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Parent Listing Ids"},"parent_listings":{"items":{"$ref":"#/components/schemas/RelatedListingSummaryExternal"},"type":"array","title":"Parent Listings"}},"type":"object","required":["listing_id","child_listing_ids"],"title":"ListingChildrenExternal","description":"Parent/child relationships for a listing group."},"ListingChildrenUpdateExternal":{"properties":{"child_listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Child Listing Ids"},"link_type":{"type":"string","enum":["composed_of","same_space"],"title":"Link Type","default":"composed_of"}},"additionalProperties":false,"type":"object","required":["child_listing_ids"],"title":"ListingChildrenUpdateExternal","description":"Replace the child-listings list for a parent listing."},"ListingCreateExternal":{"properties":{"title":{"type":"string","title":"Title","examples":["Beachfront Villa"]},"internal_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Title"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency code (e.g. USD, EUR)"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA timezone (e.g. America/New_York)"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"rules":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rules"},"num_bedrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bedrooms"},"num_bathrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bathrooms"},"num_beds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Beds"},"max_guests":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Guests"},"check_in_time_start":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time Start"},"check_in_time_end":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time End"},"check_out_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check Out Time"},"wifi_network":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wifi Network"},"wifi_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wifi Password"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat"},"lng":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"}},"type":"object","required":["title"],"title":"ListingCreateExternal","description":"Create a new manual listing.\n\nThin wrapper over the internal ``POST /listings/v2`` endpoint — supports\nboth manual listings and will be extended for iCal-based listings. OTA-\nbacked listings are created via OTA connections, not this endpoint.","examples":[{"address":"123 Ocean Drive","city":"Miami","country":"US","currency":"USD","internal_title":"Villa #12 - Oceanside","max_guests":6,"num_bathrooms":2,"num_bedrooms":3,"postal_code":"33139","timezone":"America/New_York","title":"Beachfront Villa"}]},"ListingExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","examples":["01JQXYZ1234567890ABCDEFGHIJ"]},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","examples":["Beachfront Villa"]},"internal_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Title","examples":["Villa #12 - Oceanside"]},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City","examples":["Miami"]},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country","examples":["US"]},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","examples":["America/New_York"]},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat"},"lng":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng"},"num_bedrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bedrooms"},"num_bathrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bathrooms"},"max_guests":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Guests"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","address","lat","lng","num_bedrooms","num_bathrooms","max_guests","thumbnail_url","created_at","updated_at"],"title":"ListingExternal"},"ListingOccupancyExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"occupancy_7d":{"type":"number","title":"Occupancy 7D"},"occupancy_30d":{"type":"number","title":"Occupancy 30D"},"occupancy_60d":{"type":"number","title":"Occupancy 60D"}},"type":"object","required":["listing_id","occupancy_7d","occupancy_30d","occupancy_60d"],"title":"ListingOccupancyExternal"},"ListingPhotoCreateExternal":{"properties":{"url":{"type":"string","title":"Url"},"order":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Order"}},"additionalProperties":false,"type":"object","required":["url"],"title":"ListingPhotoCreateExternal","description":"Photo entry for the replace-photos endpoint."},"ListingPhotoExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"url":{"type":"string","title":"Url"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","listing_id","url","created_at","updated_at"],"title":"ListingPhotoExternal","description":"A single listing photo row."},"ListingTagBulkAssignExternal":{"properties":{"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids"},"tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Tag Ids"}},"type":"object","required":["listing_ids","tag_ids"],"title":"ListingTagBulkAssignExternal","description":"Bulk-assign tags to multiple listings.","examples":[{"listing_ids":["8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1"],"tag_ids":["2c5d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1"]}]},"ListingTagBulkRemoveExternal":{"properties":{"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids"},"tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Tag Ids"}},"type":"object","required":["listing_ids","tag_ids"],"title":"ListingTagBulkRemoveExternal","description":"Bulk-remove tags from multiple listings."},"ListingTagCreateExternal":{"properties":{"name":{"type":"string","title":"Name"},"tag_type":{"type":"string","title":"Tag Type","description":"Tag category — one of: building, neighborhood, city, area, amenity, property_type, feature, custom."},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"}},"type":"object","required":["name","tag_type"],"title":"ListingTagCreateExternal","description":"Create a new tag on the account.","examples":[{"color":"#FFCC00","icon":"🏖️","name":"Beach","tag_type":"neighborhood"}]},"ListingTagExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"tag_type":{"type":"string","title":"Tag Type"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"system_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Key"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","tag_type","created_at","updated_at"],"title":"ListingTagExternal","description":"A listing tag (e.g. a region, cohort, or amenity bucket)."},"ListingTagUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"}},"type":"object","title":"ListingTagUpdateExternal","description":"Update an existing tag. All fields optional — only provided fields are updated."},"ListingUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"internal_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"rules":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rules"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"num_beds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Beds"},"num_bedrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bedrooms"},"num_bathrooms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Bathrooms"},"max_guests":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Guests"},"private_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Notes"},"amenities":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Amenities"},"amenities_list":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Amenities List"},"check_in_time_start":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time Start"},"check_in_time_end":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time End"},"check_out_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check Out Time"},"wifi_network":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wifi Network"},"wifi_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wifi Password"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"building_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Building Name"},"apt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apt"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat"},"lng":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"}},"additionalProperties":false,"type":"object","title":"ListingUpdateExternal","description":"Update a listing.\n\nMirrors the public-safe subset of the internal ``ListingUpdate`` schema —\ndeliberately excludes OTA-managed fields (e.g. ``connection_role``,\n``host_roles``, ``import_status``) that should only flow in via OTA sync,\nand rejects unknown keys to surface typos as 422 rather than silently\ndropping them."},"LoungeListResponse":{"properties":{"lounges":{"items":{"$ref":"#/components/schemas/LoungeSummary"},"type":"array","title":"Lounges"},"viewer_handle":{"type":"string","title":"Viewer Handle"}},"type":"object","required":["lounges","viewer_handle"],"title":"LoungeListResponse"},"LoungeSummary":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"kind":{"type":"string","title":"Kind"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emoji"},"member_count":{"type":"integer","title":"Member Count"},"member_count_display":{"type":"string","title":"Member Count Display","default":""},"is_joined":{"type":"boolean","title":"Is Joined"},"is_eligible":{"type":"boolean","title":"Is Eligible"}},"type":"object","required":["slug","name","kind","member_count","is_joined","is_eligible"],"title":"LoungeSummary","description":"One lounge on the wall, annotated with the viewer's standing.\n\nMember counts follow the same confidentiality rule as the in-app\nsurface: an exact count discloses how many ProhostAI users there\nare, so only a ProhostAI staff caller receives one.\n``member_count`` carries the bucket FLOOR for everyone else (10, 25,\n250, …; ``0`` below the ladder's floor) and never the real value —\nsee ``shared/data/community/constants.py``."},"MarkReadExternal":{"properties":{"message_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Message Ids","description":"If provided, only those messages are marked read. Otherwise the entire conversation is."}},"type":"object","title":"MarkReadExternal","description":"Body for ``POST /conversations/{id}/mark-read`` — optional per-message scope.","examples":[{}]},"MarkReadResponse":{"properties":{"marked_count":{"type":"integer","title":"Marked Count"},"marked_message_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Marked Message Ids"}},"type":"object","required":["marked_count","marked_message_ids"],"title":"MarkReadResponse"},"MeetingAttendeeExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"meeting_id":{"type":"string","format":"uuid","title":"Meeting Id"},"contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contact Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"role":{"$ref":"#/components/schemas/MeetingAttendeeRole"},"response_status":{"anyOf":[{"$ref":"#/components/schemas/MeetingAttendeeResponseStatus"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","meeting_id","role","created_at","updated_at"],"title":"MeetingAttendeeExternal"},"MeetingAttendeeInputExternal":{"properties":{"contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contact Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"agent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"role":{"$ref":"#/components/schemas/MeetingAttendeeRole","default":"attendee"},"response_status":{"anyOf":[{"$ref":"#/components/schemas/MeetingAttendeeResponseStatus"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"MeetingAttendeeInputExternal"},"MeetingAttendeeResponseStatus":{"type":"string","enum":["accepted","declined","tentative","needs_action","unknown"],"title":"MeetingAttendeeResponseStatus","description":"Invitation response status of a meeting attendee."},"MeetingAttendeeRole":{"type":"string","enum":["host","attendee","optional","ai_note_taker"],"title":"MeetingAttendeeRole","description":"Role of an attendee on a meeting."},"MeetingCreateExternal":{"properties":{"title":{"type":"string","minLength":1,"title":"Title"},"opportunity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Opportunity Id"},"contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"status":{"$ref":"#/components/schemas/MeetingStatus","default":"scheduled"},"scheduled_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Start At"},"scheduled_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled End At"},"actual_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Start At"},"actual_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual End At"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"source":{"$ref":"#/components/schemas/MeetingSource","default":"manual"},"external_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Event Id"},"meeting_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meeting Url"},"recording_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Url"},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url"},"granola_note_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Granola Note Url"},"ai_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Summary"},"outcome":{"anyOf":[{"$ref":"#/components/schemas/MeetingOutcome"},{"type":"null"}]},"sentiment":{"anyOf":[{"$ref":"#/components/schemas/MeetingSentiment"},{"type":"null"}]},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"attendees":{"anyOf":[{"items":{"$ref":"#/components/schemas/MeetingAttendeeInputExternal"},"type":"array"},{"type":"null"}],"title":"Attendees"}},"additionalProperties":false,"type":"object","required":["title"],"title":"MeetingCreateExternal"},"MeetingExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"opportunity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Opportunity Id"},"contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"title":{"type":"string","title":"Title"},"status":{"$ref":"#/components/schemas/MeetingStatus"},"scheduled_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Start At"},"scheduled_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled End At"},"actual_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Start At"},"actual_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual End At"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"source":{"$ref":"#/components/schemas/MeetingSource"},"external_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Event Id"},"meeting_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meeting Url"},"recording_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Url"},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url"},"granola_note_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Granola Note Url"},"ai_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Summary"},"outcome":{"anyOf":[{"$ref":"#/components/schemas/MeetingOutcome"},{"type":"null"}]},"sentiment":{"anyOf":[{"$ref":"#/components/schemas/MeetingSentiment"},{"type":"null"}]},"custom_fields":{"additionalProperties":true,"type":"object","title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"attendees":{"items":{"$ref":"#/components/schemas/MeetingAttendeeExternal"},"type":"array","title":"Attendees"}},"type":"object","required":["id","title","status","source","created_at","updated_at"],"title":"MeetingExternal"},"MeetingOutcome":{"type":"string","enum":["interested","not_interested","follow_up","won","lost","unknown"],"title":"MeetingOutcome","description":"Disposition of a completed meeting."},"MeetingSentiment":{"type":"string","enum":["positive","neutral","negative"],"title":"MeetingSentiment","description":"Sentiment read of a meeting."},"MeetingSource":{"type":"string","enum":["manual","google_calendar","cal_com","granola","zoom","dialpad","ai","prohost_desktop","phone_call"],"title":"MeetingSource","description":"Where a meeting / call originated.\n\nCalls are meetings with a null ``scheduled_*`` window; rely on\n``actual_*`` instead. ``dialpad`` is a Dialpad call; ``phone_call`` is a\ncall on a ProhostAI phone number."},"MeetingStatus":{"type":"string","enum":["scheduled","completed","canceled","no_show"],"title":"MeetingStatus","description":"Lifecycle status of a CRM meeting / call."},"MeetingUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Title"},"opportunity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Opportunity Id"},"contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"status":{"anyOf":[{"$ref":"#/components/schemas/MeetingStatus"},{"type":"null"}]},"scheduled_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Start At"},"scheduled_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled End At"},"actual_start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Start At"},"actual_end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual End At"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"source":{"anyOf":[{"$ref":"#/components/schemas/MeetingSource"},{"type":"null"}]},"external_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Event Id"},"meeting_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meeting Url"},"recording_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Url"},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url"},"granola_note_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Granola Note Url"},"ai_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Summary"},"outcome":{"anyOf":[{"$ref":"#/components/schemas/MeetingOutcome"},{"type":"null"}]},"sentiment":{"anyOf":[{"$ref":"#/components/schemas/MeetingSentiment"},{"type":"null"}]},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","title":"MeetingUpdateExternal"},"MemoryCreateExternal":{"properties":{"content":{"type":"string","maxLength":10000,"minLength":1,"title":"Content","examples":["WiFi password is 'beach2026'. Network name is 'Villa_Guest'."]},"scope":{"type":"string","title":"Scope","default":"all_listings","examples":["listing","all_listings","listing_group"]},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"},"is_internal":{"type":"boolean","title":"Is Internal","default":false}},"type":"object","required":["content"],"title":"MemoryCreateExternal"},"MemoryExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","examples":["01JQXYZ1234567890ABCDEFGHIJ"]},"content":{"type":"string","title":"Content","examples":["Check-in is at 3 PM. Early check-in available upon request."]},"scope":{"type":"string","title":"Scope","examples":["listing","all_listings","listing_group"]},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","examples":["api","conversation","manual"]},"confidence_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence Score"},"is_internal":{"type":"boolean","title":"Is Internal"},"version":{"type":"integer","title":"Version"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","content","scope","listing_id","listing_tag_id","confidence_score","is_internal","version","created_at","updated_at"],"title":"MemoryExternal"},"MemorySearchRequest":{"properties":{"query":{"type":"string","maxLength":1000,"title":"Query"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","default":10}},"type":"object","required":["query"],"title":"MemorySearchRequest"},"MemorySearchResult":{"properties":{"memory":{"$ref":"#/components/schemas/MemoryExternal"},"similarity":{"type":"number","title":"Similarity"}},"type":"object","required":["memory","similarity"],"title":"MemorySearchResult"},"MemoryUpdateExternal":{"properties":{"content":{"anyOf":[{"type":"string","maxLength":10000,"minLength":1},{"type":"null"}],"title":"Content"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"},"is_internal":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Internal"}},"type":"object","title":"MemoryUpdateExternal"},"MessageAttachmentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","description":"Coarse media type","examples":["image","video","audio","file"]},"url":{"type":"string","title":"Url","description":"Fetchable URL. Signed and expiring for private attachments."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Original filename, when the source provided one"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"Image width in pixels as displayed (EXIF orientation applied), when measured"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"Image height in pixels as displayed (EXIF orientation applied), when measured"}},"type":"object","required":["id","type","url"],"title":"MessageAttachmentExternal","description":"A file on a conversation message, with a URL the caller can GET.\n\nAttachments are stored two ways and this flattens the difference: a\npublic/inbound row carries a directly-fetchable ``url``, while a private\nrow (host-uploaded email attachments, inbound MMS media) is addressed by a\nstable, signed download-proxy URL that expires within 24 hours. Rows with\nneither — placeholders for a file skipped over a provider size cap — are\nomitted entirely, so every item here is something you can actually fetch.","examples":[{"id":"d4e5f6a7-b8c9-4012-a345-6789abcdef01","name":"kitchen-leak.jpg","type":"image","url":"https://api.prohost.ai/conversations/v2/attachments/d4e5f6a7-b8c9-4012-a345-6789abcdef01/download?token=1785340800.9f2c"}]},"MessageEditedExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"edited_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Edited At"}},"type":"object","required":["id","conversation_id","message","edited_at"],"title":"MessageEditedExternal","description":"Compact response for ``PATCH /conversations/{id}/messages/{message_id}``."},"MessageNotificationScope-Input":{"type":"string","enum":["all","messages","escalated","following","assigned","needs_response"],"title":"MessageNotificationScope","description":"Scopes for message notifications - can be combined additively"},"MessageNotificationScope-Output":{"type":"string","title":"MessageNotificationScope","description":"Scopes for message notifications - can be combined additively","x-extensible-enum":["all","messages","escalated","following","assigned","needs_response"]},"MessageTemplateCreateExternal":{"properties":{"type":{"type":"string","title":"Type"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title"},"message":{"type":"string","minLength":1,"title":"Message"},"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids"},"tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Tag Ids","description":"Listing tags (groups) the template applies to: every listing carrying one of them when a reservation is scheduled, on top of listing_ids. Requires the workspace's group-scope rollout."},"is_enabled":{"type":"boolean","title":"Is Enabled","default":true},"time_offset_minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Offset Minutes","description":"Signed minutes offset from the event time: NEGATIVE fires BEFORE the event (e.g. -120 = two hours before check-in), positive after, 0 at the event. Applies to booking_confirmed / check_in / checkout (recurring_weekly uses day_of_week + time_of_day instead)."},"day_of_week":{"anyOf":[{"type":"integer","maximum":6.0,"minimum":0.0},{"type":"null"}],"title":"Day Of Week"},"time_of_day":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Of Day"},"send_if_past_due":{"type":"boolean","title":"Send If Past Due","description":"For check_in / checkout templates, a reservation booked AFTER the computed send time is silently skipped unless this is true — in which case the message is sent immediately (or after past_due_delay_minutes). Only affects reservations booked going forward, not the bulk apply-to-existing pass.","default":false},"past_due_delay_minutes":{"type":"integer","title":"Past Due Delay Minutes","default":0},"min_nights":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Min Nights"},"max_nights":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Nights"},"smart_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Smart Instructions","description":"Smart Send: free-text instructions about when this template should NOT send, applied by an AI gate at fire time (e.g. \"if the guest already told us their arrival time, don't ask again\"). Max 2000 characters. Blank clears it and disables the gate for this template."},"audience":{"anyOf":[{"type":"string","enum":["guests","owners"]},{"type":"null"}],"title":"Audience","description":"Which reservations this rule applies to: 'guests' (every booking channel except owner stays), 'owners' (owner-channel stays only). Omit or null for all eligible reservations. Reservations the PMS marks as having no guest-messaging channel (no_conversation=true — e.g. iCal calendar mirrors) are excluded from 'guests' and unfiltered rules; 'owners' rules remain eligible, since messaging the owner directly is the point of that filter. Deterministic, applied at creation, on template edits (queued rows on now-excluded reservations are cancelled), and re-checked at fire time."}},"type":"object","required":["type","title","message"],"title":"MessageTemplateCreateExternal","examples":[{"is_enabled":true,"listing_ids":["8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1"],"message":"Welcome! Check-in code is 4827.","time_offset_minutes":-120,"title":"Check-in welcome","type":"check_in"}]},"MessageTemplateExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"type":"string","title":"Type","description":"One of: booking_confirmed, check_in, checkout, recurring_weekly."},"title":{"type":"string","title":"Title"},"message":{"type":"string","title":"Message"},"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids"},"tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Tag Ids","description":"Listing tags (groups) the template applies to: every listing carrying one of them when a reservation is scheduled, on top of listing_ids. Requires the workspace's group-scope rollout."},"is_enabled":{"type":"boolean","title":"Is Enabled","default":true},"time_offset_minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Offset Minutes","description":"Signed minutes offset from the event time: NEGATIVE fires BEFORE the event (e.g. -120 = two hours before check-in), positive after, 0 at the event. Applies to booking_confirmed / check_in / checkout (recurring_weekly uses day_of_week + time_of_day instead)."},"day_of_week":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Day Of Week"},"time_of_day":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Of Day"},"send_if_past_due":{"type":"boolean","title":"Send If Past Due","description":"For check_in / checkout templates, a reservation booked AFTER the computed send time is silently skipped unless this is true — in which case the message is sent immediately (or after past_due_delay_minutes). Only affects reservations booked going forward, not the bulk apply-to-existing pass.","default":false},"past_due_delay_minutes":{"type":"integer","title":"Past Due Delay Minutes","default":0},"min_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Nights"},"max_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Nights"},"smart_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Smart Instructions","description":"Smart Send: free-text instructions about when this template should NOT send, applied by an AI gate at fire time (e.g. \"if the guest already told us their arrival time, don't ask again\"). Max 2000 characters. Blank clears it and disables the gate for this template."},"audience":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience","description":"Which reservations this rule applies to: 'guests' (every booking channel except owner stays), 'owners' (owner-channel stays only). Omit or null for all eligible reservations. Reservations the PMS marks as having no guest-messaging channel (no_conversation=true — e.g. iCal calendar mirrors) are excluded from 'guests' and unfiltered rules; 'owners' rules remain eligible, since messaging the owner directly is the point of that filter. Deterministic, applied at creation, on template edits (queued rows on now-excluded reservations are cancelled), and re-checked at fire time."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","type","title","message"],"title":"MessageTemplateExternal","description":"Account-wide message template."},"MessageTemplateListResponse":{"properties":{"templates":{"items":{"$ref":"#/components/schemas/MessageTemplateExternal"},"type":"array","title":"Templates"}},"type":"object","required":["templates"],"title":"MessageTemplateListResponse"},"MessageTemplateUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Title"},"message":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Message"},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids"},"tag_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Tag Ids","description":"Listing tags (groups) the template applies to: every listing carrying one of them when a reservation is scheduled, on top of listing_ids. Requires the workspace's group-scope rollout. Omit to keep, [] to remove."},"is_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Enabled"},"time_offset_minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Offset Minutes","description":"Signed minutes offset from the event time: NEGATIVE fires BEFORE the event (e.g. -120 = two hours before check-in), positive after, 0 at the event. Applies to booking_confirmed / check_in / checkout (recurring_weekly uses day_of_week + time_of_day instead)."},"day_of_week":{"anyOf":[{"type":"integer","maximum":6.0,"minimum":0.0},{"type":"null"}],"title":"Day Of Week"},"time_of_day":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Of Day"},"send_if_past_due":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Send If Past Due","description":"For check_in / checkout templates, a reservation booked AFTER the computed send time is silently skipped unless this is true — in which case the message is sent immediately (or after past_due_delay_minutes). Only affects reservations booked going forward, not the bulk apply-to-existing pass."},"past_due_delay_minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Past Due Delay Minutes"},"min_nights":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Min Nights"},"max_nights":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Nights"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"smart_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Smart Instructions","description":"Smart Send: free-text instructions about when this template should NOT send, applied by an AI gate at fire time (e.g. \"if the guest already told us their arrival time, don't ask again\"). Max 2000 characters. Blank clears it and disables the gate for this template."},"audience":{"anyOf":[{"type":"string","enum":["guests","owners"]},{"type":"null"}],"title":"Audience","description":"Which reservations this rule applies to: 'guests' (every booking channel except owner stays), 'owners' (owner-channel stays only). Omit or null for all eligible reservations. Reservations the PMS marks as having no guest-messaging channel (no_conversation=true — e.g. iCal calendar mirrors) are excluded from 'guests' and unfiltered rules; 'owners' rules remain eligible, since messaging the owner directly is the point of that filter. Deterministic, applied at creation, on template edits (queued rows on now-excluded reservations are cancelled), and re-checked at fire time."}},"type":"object","title":"MessageTemplateUpdateExternal","examples":[{"is_enabled":false}]},"MessageTotalExternal":{"properties":{"total":{"type":"integer","title":"Total"},"period_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period Start"},"period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period End"}},"type":"object","required":["total"],"title":"MessageTotalExternal"},"MinBaseMaxResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min"},"base":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Base"},"max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"}},"type":"object","required":["listing_id"],"title":"MinBaseMaxResponse"},"MinBaseMaxUpdateRequest":{"properties":{"min":{"type":"number","minimum":0.0,"title":"Min"},"base":{"type":"number","minimum":0.0,"title":"Base"},"max":{"type":"number","minimum":0.0,"title":"Max"}},"additionalProperties":false,"type":"object","required":["min","base","max"],"title":"MinBaseMaxUpdateRequest","description":"Body for PUT ``/listings/{listing_id}/pricing/min-base-max``.\n\nPriceLabs requires min <= base <= max. Validation enforced by both the\nschema and the SDK."},"MoveSectionScopeExternal":{"properties":{"guidebook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Guidebook Id"},"listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Tag Id"}},"additionalProperties":false,"type":"object","title":"MoveSectionScopeExternal","description":"Move a section between guidebook-scoped and tag-scoped (exactly one)."},"MuteRequestExternal":{"properties":{"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until","description":"When the mute ends (ISO-8601). Omit to mute until unmuted."}},"additionalProperties":false,"type":"object","title":"MuteRequestExternal","description":"Mute an item for the calling member."},"MyStaySectionOrderExternal":{"properties":{"section_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Section Ids"}},"additionalProperties":false,"type":"object","required":["section_ids"],"title":"MyStaySectionOrderExternal"},"NeighborhoodResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"pricelabs_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pricelabs Listing Id"},"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["listing_id","data"],"title":"NeighborhoodResponse","description":"Raw neighborhood-data payload from PriceLabs.\n\nThe PriceLabs neighborhood endpoint returns a large nested object whose\nschema is not stable; we relay it as a dict on ``data`` so clients get\nthe freshest shape without a round-trip release to update Pydantic."},"NightlyRateExternal":{"properties":{"date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date","description":"The night this rate applies to.","examples":["2026-06-15"]},"rate":{"type":"number","title":"Rate","description":"Accommodation rate for this night, in the reservation currency."}},"type":"object","required":["rate"],"title":"NightlyRateExternal","description":"A single night's accommodation rate, when the reservation stores one."},"NotificationSettingsUpdateExternal":{"properties":{"cleaning_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/CleaningNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Cleaning Preferences"},"task_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/TaskNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Task Preferences"},"message_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/MessageNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Message Preferences"},"reservation_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/ReservationNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Reservation Preferences"},"ai_employee_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/AIEmployeeNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Ai Employee Preferences"},"autopilot_nudge_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/AutopilotNudgeNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Autopilot Nudge Preferences"},"autopilot_booking_preferences":{"anyOf":[{"items":{"$ref":"#/components/schemas/AutopilotBookingNotificationScope-Input"},"type":"array"},{"type":"null"}],"title":"Autopilot Booking Preferences"},"ai_employee_cadence":{"anyOf":[{"$ref":"#/components/schemas/AIEmployeeCadence"},{"type":"null"}]},"following_cadence":{"anyOf":[{"$ref":"#/components/schemas/FollowingCadence"},{"type":"null"}]},"unfollow_when_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Unfollow When Done"},"cleaning_reminders_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cleaning Reminders Enabled"},"cleaning_needs_attention_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cleaning Needs Attention Enabled"},"cleaning_guest_checkout_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cleaning Guest Checkout Enabled"},"task_reminders_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Task Reminders Enabled"},"task_needs_attention_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Task Needs Attention Enabled"},"channel_preferences":{"anyOf":[{"additionalProperties":{"additionalProperties":{"type":"boolean"},"type":"object"},"type":"object"},{"type":"null"}],"title":"Channel Preferences"},"message_channel_preferences":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Message Channel Preferences"}},"additionalProperties":false,"type":"object","title":"NotificationSettingsUpdateExternal","description":"Partial update to the acting user's notification preferences.\n\nScope arrays REPLACE wholesale (an empty list silences that category);\n``channel_preferences`` and ``message_channel_preferences`` merge per key,\nso categories and channels omitted from the payload keep their stored\nvalues."},"OAuth2ClientRegistrationRequest":{"properties":{"client_name":{"type":"string","title":"Client Name"},"redirect_uris":{"items":{"type":"string"},"type":"array","title":"Redirect Uris"},"grant_types":{"items":{"type":"string"},"type":"array","title":"Grant Types","default":["authorization_code","refresh_token"]},"response_types":{"items":{"type":"string"},"type":"array","title":"Response Types","default":["code"]},"token_endpoint_auth_method":{"type":"string","title":"Token Endpoint Auth Method","default":"client_secret_post"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"},"software_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Software Id"}},"type":"object","required":["client_name","redirect_uris"],"title":"OAuth2ClientRegistrationRequest","description":"RFC 7591 Dynamic Client Registration request."},"OAuth2ProtectedResourceMetadata":{"properties":{"resource":{"type":"string","title":"Resource"},"authorization_servers":{"items":{"type":"string"},"type":"array","title":"Authorization Servers"},"scopes_supported":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Scopes Supported"},"bearer_methods_supported":{"items":{"type":"string"},"type":"array","title":"Bearer Methods Supported","default":["header"]}},"type":"object","required":["resource","authorization_servers"],"title":"OAuth2ProtectedResourceMetadata","description":"RFC 9728 Protected Resource Metadata."},"OAuth2ServerMetadata":{"properties":{"issuer":{"type":"string","title":"Issuer"},"authorization_endpoint":{"type":"string","title":"Authorization Endpoint"},"token_endpoint":{"type":"string","title":"Token Endpoint"},"revocation_endpoint":{"type":"string","title":"Revocation Endpoint"},"registration_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registration Endpoint"},"scopes_supported":{"items":{"type":"string"},"type":"array","title":"Scopes Supported"},"response_types_supported":{"items":{"type":"string"},"type":"array","title":"Response Types Supported","default":["code"]},"grant_types_supported":{"items":{"type":"string"},"type":"array","title":"Grant Types Supported","default":["authorization_code","refresh_token"]},"code_challenge_methods_supported":{"items":{"type":"string"},"type":"array","title":"Code Challenge Methods Supported","default":["S256"]},"token_endpoint_auth_methods_supported":{"items":{"type":"string"},"type":"array","title":"Token Endpoint Auth Methods Supported","default":["none","client_secret_post","client_secret_basic"]},"client_id_metadata_document_supported":{"type":"boolean","title":"Client Id Metadata Document Supported","default":true}},"type":"object","required":["issuer","authorization_endpoint","token_endpoint","revocation_endpoint","scopes_supported"],"title":"OAuth2ServerMetadata"},"OccupancyResponseExternal":{"properties":{"listings":{"items":{"$ref":"#/components/schemas/ListingOccupancyExternal"},"type":"array","title":"Listings"},"aggregate":{"additionalProperties":{"type":"number"},"type":"object","title":"Aggregate"}},"type":"object","required":["listings","aggregate"],"title":"OccupancyResponseExternal"},"OffsetPage_DepartmentExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DepartmentExternal"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records across all pages."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"offset":{"type":"integer","title":"Offset","description":"Zero-based index of the first item in this page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."}},"type":"object","required":["items","total","limit","offset","has_more"],"title":"OffsetPage[DepartmentExternal]"},"OffsetPage_GuidebookExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GuidebookExternal"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records across all pages."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"offset":{"type":"integer","title":"Offset","description":"Zero-based index of the first item in this page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."}},"type":"object","required":["items","total","limit","offset","has_more"],"title":"OffsetPage[GuidebookExternal]"},"OffsetPage_OwnerExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/OwnerExternal"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records across all pages."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"offset":{"type":"integer","title":"Offset","description":"Zero-based index of the first item in this page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."}},"type":"object","required":["items","total","limit","offset","has_more"],"title":"OffsetPage[OwnerExternal]"},"OffsetPage_OwnerStatementExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/OwnerStatementExternal"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records across all pages."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"offset":{"type":"integer","title":"Offset","description":"Zero-based index of the first item in this page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."}},"type":"object","required":["items","total","limit","offset","has_more"],"title":"OffsetPage[OwnerStatementExternal]"},"OffsetPage_WorkflowExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WorkflowExternal"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records across all pages."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"offset":{"type":"integer","title":"Offset","description":"Zero-based index of the first item in this page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."}},"type":"object","required":["items","total","limit","offset","has_more"],"title":"OffsetPage[WorkflowExternal]"},"OpportunityCreateExternal":{"properties":{"pipeline_id":{"type":"string","format":"uuid","title":"Pipeline Id"},"stage_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Stage Id"},"title":{"type":"string","minLength":1,"title":"Title"},"primary_contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Primary Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"value_amount":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Value Amount"},"value_currency":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Value Currency"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","required":["pipeline_id","title"],"title":"OpportunityCreateExternal"},"OpportunityExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"pipeline_id":{"type":"string","format":"uuid","title":"Pipeline Id"},"stage_id":{"type":"string","format":"uuid","title":"Stage Id"},"position":{"type":"integer","title":"Position"},"primary_contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Primary Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"title":{"type":"string","title":"Title"},"value_amount":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Value Amount"},"value_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value Currency"},"status":{"$ref":"#/components/schemas/OpportunityStatus"},"closed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Closed At"},"lost_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lost Reason"},"next_action_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Action At"},"custom_fields":{"additionalProperties":true,"type":"object","title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"archived_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Archived At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","pipeline_id","stage_id","position","title","status","created_at","updated_at"],"title":"OpportunityExternal"},"OpportunityMoveExternal":{"properties":{"stage_id":{"type":"string","format":"uuid","title":"Stage Id"},"position":{"type":"integer","minimum":0.0,"title":"Position"}},"additionalProperties":false,"type":"object","required":["stage_id","position"],"title":"OpportunityMoveExternal","description":"Move a card to a stage + position.\n\nEntering a stage whose ``kind`` is won/lost stamps the opportunity's\n``status`` + ``closed_at`` (and clears them on a move back to an open\nstage) — never inferred from the stage name."},"OpportunityStatus":{"type":"string","enum":["open","won","lost"],"title":"OpportunityStatus","description":"Open/won/lost lifecycle status of an opportunity card."},"OpportunityUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Title"},"primary_contact_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Primary Contact Id"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"value_amount":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Value Amount"},"value_currency":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Value Currency"},"lost_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lost Reason"},"next_action_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Action At"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","title":"OpportunityUpdateExternal"},"OpsActionFileRequest":{"properties":{"action_type":{"type":"string","title":"Action Type","description":"Allowlisted privileged action kind (OpsActionType)."},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id","description":"Support conversation the ask came from."},"account_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Account Id","description":"Customer account. Optional when conversation_id is given (resolved from the thread)."},"feedback_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Feedback Id","description":"Linked customer_feedback row."},"requested_by_user_id":{"type":"string","format":"uuid","title":"Requested By User Id","description":"Verified requester (must be an ADMIN of the account)."},"target_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target User Id"},"requested_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Value"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"},"card_posted":{"type":"boolean","title":"Card Posted","description":"Whether the caller already posted the operator notification for this filing.","default":false}},"type":"object","required":["action_type","requested_by_user_id"],"title":"OpsActionFileRequest"},"OpsActionFileResponse":{"properties":{"filed":{"type":"boolean","title":"Filed"},"created":{"type":"boolean","title":"Created"},"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status"},"filed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filed At"}},"type":"object","required":["filed","created","id","status","filed_at"],"title":"OpsActionFileResponse"},"OwnerCreateExternal":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"email":{"type":"string","minLength":1,"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state_province":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State Province"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"tax_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Id"},"commission_rate":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Commission Rate"},"commission_type":{"anyOf":[{"$ref":"#/components/schemas/CommissionType"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids","description":"Optional listing assignments on creation. The caller's API key must have access to every listing in the list."}},"type":"object","required":["name","email"],"title":"OwnerCreateExternal","description":"Create a new owner record on the account.","examples":[{"commission_rate":0.2,"commission_type":"percentage","email":"jane@owners.example","name":"Jane Owner","phone":"+1-555-0100"}]},"OwnerExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state_province":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State Province"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"commission_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Commission Rate"},"commission_type":{"anyOf":[{"$ref":"#/components/schemas/CommissionType"},{"type":"null"}]},"status":{"$ref":"#/components/schemas/OwnerStatus"},"has_app_access":{"type":"boolean","title":"Has App Access"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids","description":"Listings currently assigned to this owner. Populated on read so callers can verify the result of ``listing_ids`` passed on create/update."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","email","phone","company_name","address_line1","address_line2","city","state_province","postal_code","country","commission_rate","commission_type","status","has_app_access","notes","created_at","updated_at"],"title":"OwnerExternal"},"OwnerStatementCreateExternal":{"properties":{"title":{"type":"string","minLength":1,"title":"Title"},"status":{"$ref":"#/components/schemas/OwnerStatementStatus","default":"draft"},"owner_id":{"type":"string","format":"uuid","title":"Owner Id"},"from_date":{"type":"string","format":"date","title":"From Date"},"to_date":{"type":"string","format":"date","title":"To Date"},"rental_activity_display_type":{"$ref":"#/components/schemas/RentalActivityDisplayType","default":"per_reservation"},"property_owner_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Name"},"property_owner_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Email"},"property_owner_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Phone"},"property_owner_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Address"},"property_owner_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Tax Number"},"property_manager_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Name"},"property_manager_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Email"},"property_manager_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Phone"},"property_manager_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Address"},"property_manager_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Tax Number"},"logo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"invoice_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Number"}},"type":"object","required":["title","owner_id","from_date","to_date"],"title":"OwnerStatementCreateExternal","description":"Create a new owner statement covering ``[from_date, to_date]``.","examples":[{"from_date":"2026-04-01","owner_id":"01JQXYZ1234567890ABCDEFGHIJ","title":"April 2026","to_date":"2026-04-30"}]},"OwnerStatementExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"status":{"$ref":"#/components/schemas/OwnerStatementStatus"},"owner_id":{"type":"string","format":"uuid","title":"Owner Id"},"from_date":{"type":"string","format":"date","title":"From Date"},"to_date":{"type":"string","format":"date","title":"To Date"},"created_by_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By Id"},"rental_activity_display_type":{"$ref":"#/components/schemas/RentalActivityDisplayType"},"property_owner_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Name"},"property_owner_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Email"},"property_owner_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Phone"},"property_owner_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Address"},"property_owner_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Tax Number"},"property_manager_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Name"},"property_manager_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Email"},"property_manager_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Phone"},"property_manager_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Address"},"property_manager_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Tax Number"},"logo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"invoice_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Number"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","title","status","owner_id","from_date","to_date","rental_activity_display_type","created_at","updated_at"],"title":"OwnerStatementExternal","description":"An owner statement (period summary of rental + expense activity)."},"OwnerStatementStatus":{"type":"string","enum":["draft","published","archived"],"title":"OwnerStatementStatus"},"OwnerStatementUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"status":{"anyOf":[{"$ref":"#/components/schemas/OwnerStatementStatus"},{"type":"null"}]},"owner_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner Id"},"from_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"From Date"},"to_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"To Date"},"rental_activity_display_type":{"anyOf":[{"$ref":"#/components/schemas/RentalActivityDisplayType"},{"type":"null"}]},"property_owner_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Name"},"property_owner_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Email"},"property_owner_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Phone"},"property_owner_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Address"},"property_owner_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Owner Tax Number"},"property_manager_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Name"},"property_manager_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Email"},"property_manager_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Phone"},"property_manager_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Address"},"property_manager_tax_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Manager Tax Number"},"logo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"invoice_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Number"}},"type":"object","title":"OwnerStatementUpdateExternal","description":"Update an existing owner statement. All fields optional.\n\nThe five DB-required fields (``title``, ``status``, ``owner_id``,\n``from_date``, ``to_date``, ``rental_activity_display_type``) are\ntyped ``T | None`` so callers can omit them on PATCH (Pydantic\n``exclude_unset`` distinguishes \"missing\" from \"explicit null\"), but\nnone may be set to ``null`` — all are ``NOT NULL`` on\n``OwnerStatement``. The ``_reject_null_for_required_fields``\nvalidator turns the explicit-null case into a 422 instead of a\nNOT-NULL ``IntegrityError`` 500. Mirrors the same guard on\n``OwnerUpdateExternal``."},"OwnerStatus":{"type":"string","enum":["active","suspended","archived"],"title":"OwnerStatus","description":"Enum for owner statuses"},"OwnerUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state_province":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State Province"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"tax_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Id"},"commission_rate":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Commission Rate"},"commission_type":{"anyOf":[{"$ref":"#/components/schemas/CommissionType"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"status":{"anyOf":[{"$ref":"#/components/schemas/OwnerStatus"},{"type":"null"}]},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids"}},"type":"object","title":"OwnerUpdateExternal","description":"Update an existing owner. All fields optional; only provided fields are written.\n\n``name`` and ``email`` are typed as ``str | None`` so callers can omit\nthem on PATCH (Pydantic distinguishes \"missing\" from \"explicit null\"\nvia ``exclude_unset``), but neither field may be set to an explicit\n``null`` value — both are ``NOT NULL`` on ``Owner``. The\n``_reject_null_for_required_fields`` validator turns\n``{\"name\": null}`` / ``{\"email\": null}`` into a 422 instead of a\nNOT-NULL ``IntegrityError`` 500 at commit time."},"Page_CleaningExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CleaningExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[CleaningExternal]"},"Page_ContactExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/api_public__schemas__contacts__ContactExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ContactExternal]"},"Page_ConversationExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ConversationExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ConversationExternal]"},"Page_ConversationMessageExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ConversationMessageExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ConversationMessageExternal]"},"Page_DocumentExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DocumentExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[DocumentExternal]"},"Page_ExpenseExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ExpenseExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ExpenseExternal]"},"Page_GuestExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GuestExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[GuestExternal]"},"Page_ListingExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ListingExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ListingExternal]"},"Page_MemoryExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/MemoryExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[MemoryExternal]"},"Page_ReservationExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ReservationExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ReservationExternal]"},"Page_ReviewExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ReviewExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[ReviewExternal]"},"Page_TaskExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TaskExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[TaskExternal]"},"Page_UpsellOfferExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/UpsellOfferExternal"},"type":"array","title":"Items","description":"The page of results."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned per page."},"has_more":{"type":"boolean","title":"Has More","description":"True when more records remain beyond this page."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Offset mode only: total matching records across all pages."},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset","description":"Offset mode only: zero-based index of the first item."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor mode only: opaque cursor for the next page, or null on the final page."}},"type":"object","required":["items","limit","has_more"],"title":"Page[UpsellOfferExternal]"},"Paginated_DriveItemExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DriveItemExternal"},"type":"array","title":"Items"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"has_more":{"type":"boolean","title":"Has More"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total"}},"type":"object","required":["items","limit","offset","has_more"],"title":"Paginated[DriveItemExternal]"},"Paginated_SheetExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SheetExternal"},"type":"array","title":"Items"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"has_more":{"type":"boolean","title":"Has More"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total"}},"type":"object","required":["items","limit","offset","has_more"],"title":"Paginated[SheetExternal]"},"Paginated_SheetRowExternal_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SheetRowExternal"},"type":"array","title":"Items"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"has_more":{"type":"boolean","title":"Has More"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total"}},"type":"object","required":["items","limit","offset","has_more"],"title":"Paginated[SheetRowExternal]"},"PatchIngestedConversationExternal":{"properties":{"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id","description":"Attach the conversation to this listing."},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id","description":"Link a booking in this workspace (for example the one your booking engine just made from this inquiry). The conversation's listing follows the booking's."}},"additionalProperties":false,"type":"object","title":"PatchIngestedConversationExternal","examples":[{"reservation_id":"9fa4c218-fd7a-4aa1-a17c-728ec0eb74b5"}]},"PaymentStatus":{"type":"string","enum":["paid","unpaid"],"title":"PaymentStatus","description":"Enum for expense payment status"},"PaymentType":{"type":"string","enum":["manual","stripe"],"title":"PaymentType","description":"Enum for payment type - how the expense is paid"},"PinMoveScopeExternal":{"properties":{"target_guidebook_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Guidebook Id"},"target_listing_tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Listing Tag Id"}},"additionalProperties":false,"type":"object","title":"PinMoveScopeExternal","description":"Move a pin between guidebook scope and tag scope (exactly one).\n\nMirrors the XOR validator on ``MoveSectionScopeExternal`` so callers get\na clean Pydantic 422 instead of the service layer raising ``ValueError``."},"PinReorderItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"position":{"type":"integer","title":"Position"}},"type":"object","required":["id","position"],"title":"PinReorderItemExternal"},"PinUpdateExternal":{"properties":{"category":{"anyOf":[{"$ref":"#/components/schemas/PlacePinCategory"},{"type":"null"}]},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position"},"host_note_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Note Override"}},"additionalProperties":false,"type":"object","title":"PinUpdateExternal","description":"Update-pin payload — only fields present in the body are applied."},"PipelineCreateExternal":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"stages":{"anyOf":[{"items":{"$ref":"#/components/schemas/StageInputExternal"},"type":"array"},{"type":"null"}],"title":"Stages"}},"additionalProperties":false,"type":"object","required":["name"],"title":"PipelineCreateExternal"},"PipelineExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"position":{"type":"integer","title":"Position"},"archived_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Archived At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"stages":{"items":{"$ref":"#/components/schemas/StageExternal"},"type":"array","title":"Stages"}},"type":"object","required":["id","name","position","created_at","updated_at"],"title":"PipelineExternal"},"PipelineFromTemplateExternal":{"properties":{"template_key":{"type":"string","minLength":1,"title":"Template Key"}},"additionalProperties":false,"type":"object","required":["template_key"],"title":"PipelineFromTemplateExternal"},"PipelineStageKind":{"type":"string","enum":["open","won","lost"],"title":"PipelineStageKind","description":"Terminal-state classification of a pipeline stage.\n\nWon/Lost is driven off the stage's ``kind`` — never inferred from the\nstage name. When an opportunity enters a ``won``/``lost`` stage the\nservice sets ``opportunities.status`` + ``closed_at`` accordingly."},"PipelineUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"}},"additionalProperties":false,"type":"object","title":"PipelineUpdateExternal"},"PlaceAutocompleteResponseExternal":{"properties":{"results":{"items":{"$ref":"#/components/schemas/PlaceAutocompleteResultExternal"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"PlaceAutocompleteResponseExternal"},"PlaceAutocompleteResultExternal":{"properties":{"google_place_id":{"type":"string","title":"Google Place Id"},"primary_text":{"type":"string","title":"Primary Text"},"secondary_text":{"type":"string","title":"Secondary Text"},"full_text":{"type":"string","title":"Full Text"}},"type":"object","required":["google_place_id","primary_text","secondary_text","full_text"],"title":"PlaceAutocompleteResultExternal"},"PlaceCreateExternal":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Longitude"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"website_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website Url"},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Phone"},"google_place_id":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Google Place Id"},"listing_tag_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Tag Ids"}},"additionalProperties":false,"type":"object","required":["name"],"title":"PlaceCreateExternal","description":"Create-place payload."},"PlaceDetailsRequestExternal":{"properties":{"google_place_id":{"type":"string","maxLength":255,"minLength":1,"title":"Google Place Id"},"session_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Token"}},"type":"object","required":["google_place_id"],"title":"PlaceDetailsRequestExternal"},"PlaceDetailsResponseExternal":{"properties":{"google_place_id":{"type":"string","title":"Google Place Id"},"name":{"type":"string","title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"website_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website Url"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"}},"type":"object","required":["google_place_id","name","address","latitude","longitude","website_url","phone"],"title":"PlaceDetailsResponseExternal"},"PlaceExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"name":{"type":"string","title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"website_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website Url"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"google_place_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Google Place Id"},"listing_tag_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Tag Ids"},"place_id_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Place Id Refreshed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","account_id","name","created_at","updated_at"],"title":"PlaceExternal","description":"Full response shape for a place — includes the place's listing-tag IDs\nlooked up at serialization time."},"PlacePhotoContentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/heic"],"title":"PlacePhotoContentType","description":"Allowed Content-Type values for the place-photo presigned upload.\n\nConstrained to image MIME types so an authenticated client can't ask\nus to sign a PUT for ``text/html`` and serve that out of our public-read\nbucket. Mirrors the internal ``PlacePhotoContentType``."},"PlacePhotoUrlRequestExternal":{"properties":{"content_type":{"$ref":"#/components/schemas/PlacePhotoContentType"}},"type":"object","required":["content_type"],"title":"PlacePhotoUrlRequestExternal"},"PlacePhotoUrlResponseExternal":{"properties":{"presigned_url":{"type":"string","title":"Presigned Url"}},"type":"object","required":["presigned_url"],"title":"PlacePhotoUrlResponseExternal"},"PlacePinCategory":{"type":"string","enum":["food","coffee","activity","grocery","transit","nightlife","other"],"title":"PlacePinCategory"},"PlaceTagAssociationCreateExternal":{"properties":{"listing_tag_id":{"type":"string","format":"uuid","title":"Listing Tag Id"}},"type":"object","required":["listing_tag_id"],"title":"PlaceTagAssociationCreateExternal"},"PlaceTagInfoExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","name"],"title":"PlaceTagInfoExternal"},"PlaceUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"latitude":{"anyOf":[{"type":"number","maximum":90.0,"minimum":-90.0},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number","maximum":180.0,"minimum":-180.0},{"type":"null"}],"title":"Longitude"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"website_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website Url"},"phone":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Phone"},"listing_tag_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Tag Ids"}},"additionalProperties":false,"type":"object","title":"PlaceUpdateExternal","description":"Update-place payload — only fields present in the request body are\napplied. Pass an explicit ``null`` to clear a nullable field."},"PriceLabsCandidate":{"properties":{"pl_listing_id":{"type":"string","title":"Pl Listing Id"},"pl_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Name"},"pms":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pms"},"pl_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Min"},"pl_base":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Base"},"pl_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Max"},"confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence"},"reasons":{"items":{"$ref":"#/components/schemas/PriceLabsCandidateReason"},"type":"array","title":"Reasons"}},"type":"object","required":["pl_listing_id","confidence","reasons"],"title":"PriceLabsCandidate","description":"One PriceLabs candidate listing for the Pairing Sheet.\n\n``confidence`` is the sum of weighted reason scores in ``reasons``;\nsurfaced as a single number for ranking + UI display."},"PriceLabsCandidateReason":{"properties":{"kind":{"type":"string","enum":["name_match","geo_match","bedroom_match","exact_id_match","pms_match","city_match","channel_id_match","paused_in_pricelabs"],"title":"Kind"},"description":{"type":"string","title":"Description"},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"Weighted contribution of this signal to overall confidence (0..1)."},"raw_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Raw Score","description":"Unweighted signal strength in 0..1 (FE uses this for display)."}},"type":"object","required":["kind","description","score","raw_score"],"title":"PriceLabsCandidateReason","description":"One scored signal that contributed to a candidate's confidence.\n\n``kind`` is the machine-readable label the frontend uses to pick a\nlocalized template. ``description`` is a plain-English fallback the\nserver fills in so non-FE consumers (MCP tools, API debugging) get a\nusable string without a translation table.\n\n``raw_score`` is the unweighted strength of the signal in ``[0, 1]``\n(e.g. raw name similarity, ``1.0`` for boolean signals like\n``pms_match``). The frontend uses this for display interpolation\n(``\"Name {{score}}% similar\"``) so it doesn't have to parse\n``description`` text or hardcode a copy of the backend's weight\nconstants. ``score`` is still the weighted contribution to overall\n``confidence`` (``raw_score * weight``)."},"PriceLabsConnectionCreateRequest":{"properties":{"api_key":{"type":"string","maxLength":512,"minLength":8,"title":"Api Key","description":"PriceLabs Customer API key."}},"additionalProperties":false,"type":"object","required":["api_key"],"title":"PriceLabsConnectionCreateRequest","description":"Body for ``POST /connections/pricelabs``.\n\nThe Connect Card sends a freshly-pasted API key. The service validates\nit with a test call before encrypting + persisting."},"PriceLabsConnectionCreatedResponse":{"properties":{"connection_id":{"type":"string","format":"uuid","title":"Connection Id"},"api_key_last4":{"type":"string","title":"Api Key Last4"},"listings_in_pricelabs":{"type":"integer","title":"Listings In Pricelabs"}},"type":"object","required":["connection_id","api_key_last4","listings_in_pricelabs"],"title":"PriceLabsConnectionCreatedResponse","description":"Result of a successful connection create."},"PriceLabsListingDetailResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"found":{"type":"boolean","title":"Found"},"pl_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Listing Id"},"pl_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Name"},"pl_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Min"},"pl_base":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Base"},"pl_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Max"},"push_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Push Enabled"},"is_hidden":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Hidden"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"}},"type":"object","required":["listing_id","found"],"title":"PriceLabsListingDetailResponse","description":"``GET /listings/{listing_id}/pricelabs``."},"PriceLabsManualLinkRequest":{"properties":{"pricelabs_listing_id":{"type":"string","maxLength":255,"minLength":1,"title":"Pricelabs Listing Id"}},"additionalProperties":false,"type":"object","required":["pricelabs_listing_id"],"title":"PriceLabsManualLinkRequest"},"PriceLabsManualLinkResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"pricelabs_listing_id":{"type":"string","title":"Pricelabs Listing Id"}},"type":"object","required":["listing_id","pricelabs_listing_id"],"title":"PriceLabsManualLinkResponse"},"PriceLabsMappingPlOnlyRow":{"properties":{"pl_listing_id":{"type":"string","title":"Pl Listing Id"},"pl_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Name"},"pms":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pms"}},"type":"object","required":["pl_listing_id"],"title":"PriceLabsMappingPlOnlyRow","description":"A PriceLabs listing with no ProhostAI counterpart."},"PriceLabsMappingPriceLabsBlock":{"properties":{"found":{"type":"boolean","title":"Found"},"pl_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Listing Id"},"pl_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pl Name"},"pl_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Min"},"pl_base":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Base"},"pl_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pl Max"},"push_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Push Enabled"},"is_hidden":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Hidden"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"}},"type":"object","required":["found"],"title":"PriceLabsMappingPriceLabsBlock","description":"PriceLabs-side metadata for a single mapping row.\n\n``None`` at the parent level (``mapping.pricelabs is None``) when PriceLabs\ndoes not have a corresponding listing — ``found=False`` here is reserved\nfor the fuzzy-match-needs-attention case where we identified a candidate\nbut didn't auto-link."},"PriceLabsMappingResponse":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/PriceLabsMappingRow"},"type":"array","title":"Rows"},"pl_only":{"items":{"$ref":"#/components/schemas/PriceLabsMappingPlOnlyRow"},"type":"array","title":"Pl Only"}},"type":"object","required":["rows","pl_only"],"title":"PriceLabsMappingResponse"},"PriceLabsMappingRow":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"listing_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listing Title"},"pms_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pms Source"},"pms_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pms Listing Id"},"pricelabs":{"anyOf":[{"$ref":"#/components/schemas/PriceLabsMappingPriceLabsBlock"},{"type":"null"}]},"eligibility":{"type":"string","enum":["auto_matched","needs_attention","ineligible_no_pms"],"title":"Eligibility"},"confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence","description":"1.0 for auto-match (PMS id equal), weighted score for fuzzy match, 0.0 otherwise."},"suggestion":{"anyOf":[{"$ref":"#/components/schemas/PriceLabsCandidate"},{"type":"null"}],"description":"Best-guess PriceLabs match for a NOT-yet-linked ('needs attention') row, computed by the same scorer the candidates modal uses. Present only when its confidence is >= 0.60 and the PL listing isn't already claimed by another row (1-to-1 invariant). Additive/optional — older clients ignore it."}},"type":"object","required":["listing_id","eligibility","confidence"],"title":"PriceLabsMappingRow","description":"One row in the mapping table — a ProhostAI listing with its optional\nPriceLabs counterpart."},"PriceLabsStatusResponse":{"properties":{"connected":{"type":"boolean","title":"Connected"},"last_test_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Test At"},"last_test_ok":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Last Test Ok"},"api_key_last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Last4","description":"Last 4 characters of the connected API key (display-only)."},"default_pms":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Pms","description":"The ``pms`` value that PriceLabs requires on every call. Resolved from the account's PMS connection (e.g. ``hostaway``, ``guesty``)."}},"type":"object","required":["connected"],"title":"PriceLabsStatusResponse","description":"Result of ``GET /integrations/pricelabs/status``."},"PriceLabsTestConnectionResponse":{"properties":{"ok":{"type":"boolean","title":"Ok"},"listings_in_pricelabs":{"type":"integer","title":"Listings In Pricelabs","default":0},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["ok"],"title":"PriceLabsTestConnectionResponse","description":"Result of ``POST /integrations/pricelabs/test-connection``."},"PricingOverride":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"min_stay":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Stay"},"max_stay":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Stay"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"update_children":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Update Children"}},"type":"object","required":["date"],"title":"PricingOverride","description":"A single date-specific override (DSO) row from PriceLabs.\n\nThe PriceLabs DSO schema is permissive; we expose the commonly-used\nfields and pass through anything else via the ``extra`` dict on the\nupsert payload."},"PricingOverrideDeleteItem":{"properties":{"date":{"type":"string","format":"date","title":"Date"}},"additionalProperties":false,"type":"object","required":["date"],"title":"PricingOverrideDeleteItem"},"PricingOverrideDeleteRequest":{"properties":{"overrides":{"items":{"$ref":"#/components/schemas/PricingOverrideDeleteItem"},"type":"array","maxItems":365,"minItems":1,"title":"Overrides"},"update_children":{"type":"boolean","title":"Update Children","default":false}},"additionalProperties":false,"type":"object","required":["overrides"],"title":"PricingOverrideDeleteRequest"},"PricingOverrideDeleteResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"deleted":{"type":"integer","title":"Deleted"},"pricelabs_response":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricelabs Response"}},"type":"object","required":["listing_id","deleted"],"title":"PricingOverrideDeleteResponse"},"PricingOverrideUpsertItem":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"price":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Price"},"min_stay":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Min Stay"},"max_stay":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Stay","description":"Deprecated compatibility field; accepted but ignored on override upserts.","deprecated":true},"reason":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Reason"}},"additionalProperties":false,"type":"object","required":["date"],"title":"PricingOverrideUpsertItem","description":"One override-upsert item.\n\n``extra=\"forbid\"`` so a typo doesn't get silently dropped by Pydantic.\n``max_stay`` is accepted for backwards compatibility with the previous\nwire schema, but PriceLabs' upsert contract does not support writing it."},"PricingOverrideUpsertRequest":{"properties":{"overrides":{"items":{"$ref":"#/components/schemas/PricingOverrideUpsertItem"},"type":"array","maxItems":365,"minItems":1,"title":"Overrides"},"update_children":{"type":"boolean","title":"Update Children","default":false}},"additionalProperties":false,"type":"object","required":["overrides"],"title":"PricingOverrideUpsertRequest"},"PricingOverrideUpsertResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"accepted":{"type":"integer","title":"Accepted"},"pricelabs_response":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Pricelabs Response"}},"type":"object","required":["listing_id","accepted"],"title":"PricingOverrideUpsertResponse"},"PricingOverridesResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"pricelabs_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pricelabs Listing Id"},"overrides":{"items":{"$ref":"#/components/schemas/PricingOverride"},"type":"array","title":"Overrides"}},"type":"object","required":["listing_id","overrides"],"title":"PricingOverridesResponse"},"PricingRecommendationDay":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"min_stay":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Stay"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"occupancy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Occupancy"}},"type":"object","required":["date"],"title":"PricingRecommendationDay"},"PricingRecommendationsResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"pricelabs_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pricelabs Listing Id"},"days":{"items":{"$ref":"#/components/schemas/PricingRecommendationDay"},"type":"array","title":"Days"}},"type":"object","required":["listing_id","days"],"title":"PricingRecommendationsResponse"},"QuietHours":{"properties":{"start":{"type":"string","title":"Start"},"end":{"type":"string","title":"End"}},"additionalProperties":false,"type":"object","required":["start","end"],"title":"QuietHours","description":"A daily do-not-disturb window in the user's own local wall clock.\n\n``start`` and ``end`` are zero-padded 24-hour ``HH:MM`` strings. ``start``\nis inclusive, ``end`` exclusive, and an OVERNIGHT window (``start > end``,\ne.g. 22:00 → 07:00) is valid and expected. ``start == end`` is rejected as\nambiguous.\n\nSuppresses only the interruptive channels (push / SMS / Slack DM) — email\nis exempt, and escalations bypass the window entirely."},"QuotaWindowReport":{"properties":{"kind":{"type":"string","maxLength":32,"minLength":1,"title":"Kind"},"usedPercent":{"type":"number","title":"Usedpercent"},"resetsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resetsat"},"modelLabel":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Modellabel"}},"type":"object","required":["kind","usedPercent"],"title":"QuotaWindowReport","description":"One capacity window: ``session`` (5 h), ``weekly``, ``weekly_model`` or a newer kind."},"RatePlan":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"price_multiplier":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price Multiplier"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"extra":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extra"}},"type":"object","title":"RatePlan","description":"One rate plan from PriceLabs."},"RatePlansResponse":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"pricelabs_listing_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pricelabs Listing Id"},"rate_plans":{"items":{"$ref":"#/components/schemas/RatePlan"},"type":"array","title":"Rate Plans"}},"type":"object","required":["listing_id","rate_plans"],"title":"RatePlansResponse"},"RecurringCleaningOccupancyCondition":{"type":"string","enum":["always","occupied_only","occupied_only_excluding_arrival","vacant_only"],"title":"RecurringCleaningOccupancyCondition","description":"Whether a recurring cleaning should run on occupied or vacant dates."},"RecurringTaskCreateExternal":{"properties":{"title":{"type":"string","minLength":1,"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority","description":"Task priority (high, medium, low, no_priority)"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Task category (e.g. maintenance, cleanliness, plumbing)"},"listing_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Listing Ids","description":"Listings this schedule covers — each occurrence day mints one task per listing. Omit for an account-wide schedule (one task per occurrence, no listing)."},"assignee_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Assignee Ids","description":"Users to assign on every generated task. Each must be a member of the authenticated account."},"cost":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Cost","description":"Expected cost per generated task"},"currency":{"anyOf":[{"type":"string","maxLength":3,"minLength":3},{"type":"null"}],"title":"Currency","description":"ISO-4217 currency for `cost`. Omit to use the listing's currency when the schedule covers exactly one listing, else the account's currency"},"duration_unit":{"type":"string","title":"Duration Unit","description":"Cadence unit: daily, weekly, monthly, or yearly"},"recurrence_interval":{"type":"integer","minimum":1.0,"title":"Recurrence Interval","description":"Every N units (2 + weekly = every 2 weeks)","default":1},"first_recurring_date":{"type":"string","format":"date","title":"First Recurring Date","description":"First occurrence day (YYYY-MM-DD)"},"due_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Due Time","description":"Optional local time-of-day for generated tasks' due dates; omit for date-only"},"days_of_week":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Days Of Week","description":"Weekly-only day set of lowercase weekday names (monday..sunday). 'Every weekday' = weekly + monday..friday."},"ends_on":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Ends On","description":"Inclusive end date; mutually exclusive with ends_after_occurrences"},"ends_after_occurrences":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Ends After Occurrences","description":"Total occurrence days before the schedule ends; mutually exclusive with ends_on"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA timezone anchoring occurrence days (fallback: listing, then account owner)"},"occupancy_condition":{"$ref":"#/components/schemas/RecurringCleaningOccupancyCondition","description":"Which listing-days keep an occurrence, as for recurring cleanings: always (default), occupied_only, occupied_only_excluding_arrival (occupied, not the arrival day) or vacant_only. A day that does not match is skipped, not moved. Ignored without listings. A condition other than always creates tasks only 30 days ahead, and booking changes re-check them","default":"always"},"subtask_template_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":100},{"type":"null"}],"title":"Subtask Template Ids","description":"Section (checklist) template ids attached to the schedule — every generated task gets one checklist per template, in this order. Each must be a shared template of the authenticated account."}},"type":"object","required":["title","duration_unit","first_recurring_date"],"title":"RecurringTaskCreateExternal","description":"Body for creating a recurring-task schedule.\n\nSchedule semantics: ``duration_unit`` + ``recurrence_interval`` is the\ncadence (\"every 2 weeks\"). ``days_of_week`` (weekly only) emits one\noccurrence per selected day — \"every weekday\" is ``weekly`` +\n``monday..friday``, never ``daily``. ``ends_on`` and\n``ends_after_occurrences`` are mutually exclusive; omit both for a schedule\nwith no end. Rule violations reject with 422.","examples":[{"category":"maintenance","duration_unit":"monthly","first_recurring_date":"2026-10-01","priority":"medium","recurrence_interval":3,"title":"Replace HVAC filters"},{"days_of_week":["monday","thursday"],"due_time":"08:00:00","duration_unit":"weekly","first_recurring_date":"2026-09-07","timezone":"America/Los_Angeles","title":"Trash day prep"}]},"RecurringTaskCreateResultExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"listing_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Listing Ids"},"assignee_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Assignee Ids"},"cost":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Cost"},"currency":{"type":"string","title":"Currency","default":"USD"},"duration_unit":{"type":"string","title":"Duration Unit"},"recurrence_interval":{"type":"integer","title":"Recurrence Interval"},"first_recurring_date":{"type":"string","format":"date","title":"First Recurring Date"},"due_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Due Time"},"days_of_week":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Days Of Week"},"ends_on":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Ends On"},"ends_after_occurrences":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ends After Occurrences"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"subtask_template_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Subtask Template Ids","description":"Section (checklist) templates every generated task receives, in order"},"is_active":{"type":"boolean","title":"Is Active","default":true},"occupancy_condition":{"$ref":"#/components/schemas/RecurringCleaningOccupancyCondition","description":"Which listing-days keep an occurrence (always, occupied_only, occupied_only_excluding_arrival, vacant_only)","default":"always"},"next_occurrence":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Next Occurrence","description":"Next occurrence day the generator will materialize, if any"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"already_exists":{"type":"boolean","title":"Already Exists","default":false},"tasks_generated":{"type":"integer","title":"Tasks Generated","description":"Task instances pre-generated for the rolling window","default":0}},"type":"object","required":["id","title","duration_unit","recurrence_interval","first_recurring_date"],"title":"RecurringTaskCreateResultExternal","description":"Create response: the definition plus find-or-create provenance.\n\n``already_exists=True`` means an active schedule with the same normalized\ntitle already covered every requested listing, so that one was returned\n(status 200) instead of minting a duplicate (status 201)."},"ReferenceMedia":{"properties":{"url":{"type":"string","maxLength":2048,"minLength":1,"title":"Url"},"kind":{"type":"string","const":"photo","title":"Kind","default":"photo"}},"type":"object","required":["url"],"title":"ReferenceMedia","description":"One stored / returned reference-media entry (one element of the JSONB list)."},"ReferenceVideo":{"properties":{"url":{"type":"string","title":"Url"},"provider":{"type":"string","enum":["loom","youtube","vimeo"],"title":"Provider"},"embed_url":{"type":"string","title":"Embed Url"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds"}},"type":"object","required":["url","provider","embed_url"],"title":"ReferenceVideo","description":"The stored / returned shape of a reference video (one JSONB document)."},"RelatedListingSummaryExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"internal_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Internal Title"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"}},"type":"object","required":["id","title"],"title":"RelatedListingSummaryExternal","description":"Compact summary for a related (parent/child) listing."},"RentalActivityDisplayType":{"type":"string","enum":["per_reservation","per_listing"],"title":"RentalActivityDisplayType"},"RentalActivityListing":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"listing_name":{"type":"string","title":"Listing Name"},"total_payout":{"type":"number","title":"Total Payout"},"num_reservations":{"type":"integer","title":"Num Reservations"},"total_nights":{"type":"integer","title":"Total Nights"},"commission":{"type":"number","title":"Commission"},"owner_payout":{"type":"number","title":"Owner Payout"},"waterfall":{"anyOf":[{"$ref":"#/components/schemas/RentalActivityWaterfall"},{"type":"null"}]},"gift_voucher_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gift Voucher Amount"}},"type":"object","required":["listing_id","listing_name","total_payout","num_reservations","total_nights","commission","owner_payout"],"title":"RentalActivityListing"},"RentalActivityReservation":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"guest_name":{"type":"string","title":"Guest Name"},"check_in_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Check In Date"},"num_nights":{"type":"integer","title":"Num Nights"},"channel":{"type":"string","title":"Channel"},"total_payout":{"type":"number","title":"Total Payout"},"commission":{"type":"number","title":"Commission"},"owner_payout":{"type":"number","title":"Owner Payout"},"excluded_fee_total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Excluded Fee Total"},"total_tax":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Tax"},"waterfall":{"anyOf":[{"$ref":"#/components/schemas/RentalActivityWaterfall"},{"type":"null"}]},"gift_voucher_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gift Voucher Amount"}},"type":"object","required":["id","guest_name","check_in_date","num_nights","channel","total_payout","commission","owner_payout"],"title":"RentalActivityReservation"},"RentalActivityResponse":{"properties":{"reservations":{"items":{"$ref":"#/components/schemas/RentalActivityReservation"},"type":"array","title":"Reservations"},"reservations_total":{"type":"number","title":"Reservations Total"},"listings":{"items":{"$ref":"#/components/schemas/RentalActivityListing"},"type":"array","title":"Listings"},"listings_total":{"type":"number","title":"Listings Total"},"reservations_total_tax":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Reservations Total Tax"},"waterfall_total":{"anyOf":[{"$ref":"#/components/schemas/RentalActivityWaterfall"},{"type":"null"}]},"collected_by_manager_gift_card_total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Collected By Manager Gift Card Total"}},"type":"object","required":["reservations","reservations_total","listings","listings_total"],"title":"RentalActivityResponse"},"RentalActivityWaterfall":{"properties":{"gross_total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gross Total"},"accommodation_fare":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Accommodation Fare"},"cleaning_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cleaning Fee"},"pet_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pet Fee"},"other_fees":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Other Fees"},"discounts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Discounts"},"taxes_total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Taxes Total"},"guest_channel_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Guest Channel Fee"},"host_channel_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Host Channel Fee"},"payment_processing_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Payment Processing Fee"},"host_cancellation_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Host Cancellation Fee"}},"type":"object","title":"RentalActivityWaterfall","description":"Gross-to-net breakdown for one reservation, listing group, or statement.\n\nThe public mirror of :class:`shared.owners.waterfall.ReservationWaterfall`,\nwhich ``build_commission_rows`` already computes for every row — the app's\nstatement table, PDF and CSV render it, so omitting it here left the API\nand MCP surfaces unable to reproduce a statement they can otherwise read.\n\n``None`` means \"no line item of this category exists\", which is distinct\nfrom ``0.0`` (\"charged, and it came to zero\") — an Airbnb-direct booking\ncarries no payment-processing fee at all, so clients should render \"no\ndata\" rather than a misleading zero. Amounts are magnitudes: ``taxes_total``,\n``guest_channel_fee``, ``host_channel_fee``, ``payment_processing_fee`` and\n``host_cancellation_fee`` are subtracted from ``gross_total`` to arrive at\nthe row's ``total_payout``; ``discounts`` is already subtracted inside\n``gross_total``."},"ReorderExternal":{"properties":{"ordered_ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Ordered Ids"}},"additionalProperties":false,"type":"object","required":["ordered_ids"],"title":"ReorderExternal","description":"Reorder a set of sibling rows — ``ordered_ids`` is the new full order."},"ReservationCancelExternal":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason","description":"Recorded on the booking's conversation timeline; never sent to the guest."}},"additionalProperties":false,"type":"object","title":"ReservationCancelExternal","description":"Cancel a ProhostAI booking."},"ReservationChannelIdStr":{"type":"string","enum":["airbnb","vrbo","direct","owner","unknown","bookingcom","expedia","marriott","gds","google","other","partner","manual","ical"],"title":"ReservationChannelIdStr","description":"Client-facing enum: changes require mobile release coordination.\n\nString version of ReservationChannelId for JSON serialization."},"ReservationCreateExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"external_id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"External Id","description":"Your own id for this booking. Stored as the booking's `channel_reservation_id` (its confirmation code) and unique in the workspace: a second create with the same id answers 409 `reservation_exists` with the existing `reservation_id`. Cannot be changed later.","examples":["BK-48213"]},"channel":{"type":"string","enum":["direct","owner"],"title":"Channel","description":"`direct` for a guest booking taken off-platform, `owner` for an owner stay."},"check_in":{"type":"string","format":"date","title":"Check In","description":"Arrival date, in the listing's own timezone."},"check_out":{"type":"string","format":"date","title":"Check Out","description":"Departure date, in the listing's own timezone."},"check_in_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time","description":"Listing-local arrival time (HH:MM); the listing's check-in time when omitted."},"check_out_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check Out Time","description":"Listing-local departure time (HH:MM); the listing's check-out time when omitted."},"guest":{"$ref":"#/components/schemas/ReservationGuestDetailsExternal"},"guests":{"$ref":"#/components/schemas/ReservationPartyExternal"},"booked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Booked At","description":"When the guest booked; now when omitted."},"currency":{"anyOf":[{"type":"string","maxLength":3,"minLength":3},{"type":"null"}],"title":"Currency","description":"ISO 4217. Must match the listing's currency; the listing's currency when omitted."},"invoice_items":{"items":{"$ref":"#/components/schemas/ReservationInvoiceItemExternal"},"type":"array","maxItems":50,"title":"Invoice Items","description":"The price, line by line. Omitted: a $0 stay."},"scheduled_messages":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Scheduled Messages","description":"Whether the workspace's message templates schedule messages for this booking. Omitted: on for `direct`, off for `owner` — what the app's create dialog does."},"upsells_visible":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Upsells Visible","description":"Show or hide upsells to this guest. Omitted: the workspace default."},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"allow_overlap":{"type":"boolean","title":"Allow Overlap","description":"Create the booking even when another confirmed booking holds some of these nights (answered with an `overlap_allowed` warning instead of 409 `dates_unavailable`).","default":false},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id","description":"A conversation started through `POST /v1/conversations` (the inquiry this booking came from). The booking is linked to it instead of getting a new conversation of its own. Needs the `conversations:ingest` scope as well."}},"additionalProperties":false,"type":"object","required":["listing_id","channel","check_in","check_out"],"title":"ReservationCreateExternal","description":"Create a confirmed ProhostAI booking (a direct booking or an owner stay).","examples":[{"channel":"direct","check_in":"2026-11-20","check_out":"2026-11-23","external_id":"BK-48213","guest":{"email":"alex.rivera@example.com","first_name":"Alex","last_name":"Rivera"},"guests":{"adults":2},"invoice_items":[{"amount":450.0,"type":"accommodation_fare"},{"amount":80.0,"type":"cleaning_fee"}],"listing_id":"aaaaaaaa-bbbb-4ccc-8ddd-eeeeffff0000"}]},"ReservationCreatedExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","examples":["01JQXYZ1234567890ABCDEFGHIJ"]},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"guest_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Guest Id"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Reservation source, e.g. hostaway, airbnb, guesty."},"source_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Id","description":"Numeric reservation source ID."},"channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel","description":"Booking channel the guest booked through, e.g. airbnb, vrbo, bookingcom, expedia, direct, manual. Distinct from `source`, which names the PMS/integration the reservation synced from (a Hostfully-synced Airbnb booking has source=hostfully, channel=airbnb)."},"source_reservation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Reservation Id","description":"OTA/PMS reservation identifier."},"source_conversation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Conversation Id","description":"OTA/PMS conversation/thread identifier."},"channel_reservation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Reservation Id","description":"Booking-channel confirmation code when available."},"guest_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest First Name","examples":["John"]},"guest_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Last Name","examples":["Doe"]},"guest_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Email"},"guest_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Phone"},"guest_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Address"},"guest_city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest City"},"guest_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Country"},"guest_postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Postal Code"},"check_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check In At","examples":["2026-06-15T15:00:00Z"]},"check_out_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check Out At","examples":["2026-06-20T11:00:00Z"]},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Reservation status","examples":["confirmed"]},"status_detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Detail","description":"Sub-status, e.g. inquiry_expired or inquiry_denied for an inquiry that is closed, inquiry_preapproved, awaiting_payment. Null when there is none.","examples":["inquiry_expired"]},"num_adults":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Adults"},"num_children":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Children"},"num_infants":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Infants"},"num_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Nights"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","examples":["USD"]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id"},"warnings":{"items":{"$ref":"#/components/schemas/ReservationWarningExternal"},"type":"array","title":"Warnings"}},"type":"object","required":["id","listing_id","guest_id","guest_email","guest_phone","num_adults","num_children","num_infants","num_nights","created_at","updated_at"],"title":"ReservationCreatedExternal","description":"The created booking, its guest conversation, and any warnings."},"ReservationExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","examples":["01JQXYZ1234567890ABCDEFGHIJ"]},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"guest_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Guest Id"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Reservation source, e.g. hostaway, airbnb, guesty."},"source_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Id","description":"Numeric reservation source ID."},"channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel","description":"Booking channel the guest booked through, e.g. airbnb, vrbo, bookingcom, expedia, direct, manual. Distinct from `source`, which names the PMS/integration the reservation synced from (a Hostfully-synced Airbnb booking has source=hostfully, channel=airbnb)."},"source_reservation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Reservation Id","description":"OTA/PMS reservation identifier."},"source_conversation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Conversation Id","description":"OTA/PMS conversation/thread identifier."},"channel_reservation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Reservation Id","description":"Booking-channel confirmation code when available."},"guest_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest First Name","examples":["John"]},"guest_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Last Name","examples":["Doe"]},"guest_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Email"},"guest_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Phone"},"guest_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Address"},"guest_city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest City"},"guest_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Country"},"guest_postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Postal Code"},"check_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check In At","examples":["2026-06-15T15:00:00Z"]},"check_out_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check Out At","examples":["2026-06-20T11:00:00Z"]},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Reservation status","examples":["confirmed"]},"status_detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Detail","description":"Sub-status, e.g. inquiry_expired or inquiry_denied for an inquiry that is closed, inquiry_preapproved, awaiting_payment. Null when there is none.","examples":["inquiry_expired"]},"num_adults":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Adults"},"num_children":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Children"},"num_infants":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Infants"},"num_nights":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Nights"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","examples":["USD"]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","listing_id","guest_id","guest_email","guest_phone","num_adults","num_children","num_infants","num_nights","created_at","updated_at"],"title":"ReservationExternal"},"ReservationFinancialsExternal":{"properties":{"reservation_id":{"type":"string","format":"uuid","title":"Reservation Id"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"ISO 4217 currency for all amounts.","examples":["USD"]},"guest_paid_total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Guest Paid Total","description":"Total the guest paid across fare, fees, and taxes."},"accommodation_fare":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Accommodation Fare","description":"Nightly accommodation total (before fees/taxes)."},"cleaning_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cleaning Fee","description":"Cleaning fee charged to the guest."},"service_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Service Fee","description":"Channel/booking service fee charged to the guest."},"pet_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pet Fee","description":"Pet fee charged to the guest."},"other_fees":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Other Fees","description":"Other extra charges not covered by the named fees."},"taxes":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Taxes","description":"Total taxes (lodging/occupancy/sales)."},"discounts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Discounts","description":"Total discounts applied."},"refunds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Refunds","description":"Total refunds issued."},"host_fees":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Host Fees","description":"Host-side fees deducted from the payout (channel/processing)."},"host_payout":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Host Payout","description":"Net amount paid out to the host."},"per_night_rates":{"anyOf":[{"items":{"$ref":"#/components/schemas/NightlyRateExternal"},"type":"array"},{"type":"null"}],"title":"Per Night Rates","description":"Per-night accommodation rates when available."}},"type":"object","required":["reservation_id"],"title":"ReservationFinancialsExternal","description":"Per-reservation money breakdown.\n\nEach amount is expressed in ``currency``. A ``null`` amount means the\nreservation carries no line item for that category (e.g. a direct booking\nimported without an invoice, or an OTA that never synced fees) — it is not a\ncharged zero. ``guest_paid_total`` and ``host_payout`` are ``null`` only when\nthe reservation has no financial line items at all."},"ReservationGuestDetailsExternal":{"properties":{"first_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"First Name","examples":["Alex"]},"last_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Last Name","examples":["Rivera"]},"email":{"anyOf":[{"type":"string","maxLength":320},{"type":"null"}],"title":"Email","description":"Template scheduled messages reach the guest at this address; without it they cannot be delivered.","examples":["alex.rivera@example.com"]},"phone":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Phone","examples":["+15551234567"]},"address":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Address"},"city":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"City"},"country":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Country"},"postal_code":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Postal Code"}},"additionalProperties":false,"type":"object","title":"ReservationGuestDetailsExternal","description":"The booking's guest. ``first_name`` is required unless the booking is an owner stay."},"ReservationInvoiceItemExternal":{"properties":{"type":{"$ref":"#/components/schemas/InvoiceItemTypeName"},"amount":{"type":"number","exclusiveMinimum":0.0,"title":"Amount","description":"Positive; a discount is subtracted from the total by its type."},"host_remitted":{"type":"boolean","title":"Host Remitted","description":"Tax lines only: the tax is paid out to the host to remit, so deposit matching expects it.","default":false}},"additionalProperties":false,"type":"object","required":["type","amount"],"title":"ReservationInvoiceItemExternal","description":"One price line, in the listing's currency."},"ReservationNotificationScope-Input":{"type":"string","enum":["all","created","updated","cancelled"],"title":"ReservationNotificationScope","description":"Scopes for reservation notifications - can be combined additively"},"ReservationNotificationScope-Output":{"type":"string","title":"ReservationNotificationScope","description":"Scopes for reservation notifications - can be combined additively","x-extensible-enum":["all","created","updated","cancelled"]},"ReservationPartyExternal":{"properties":{"adults":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Adults","default":1},"children":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Children","default":0},"infants":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Infants","default":0},"pets":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Pets","default":0}},"additionalProperties":false,"type":"object","title":"ReservationPartyExternal","description":"Who is staying."},"ReservationPartyUpdateExternal":{"properties":{"adults":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Adults"},"children":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Children"},"infants":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Infants"},"pets":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Pets"}},"additionalProperties":false,"type":"object","title":"ReservationPartyUpdateExternal","description":"Who is staying; omitted counts keep their value."},"ReservationSourceName":{"type":"string","enum":["hostaway","airbnb","ownerrez","hospitable","guesty","prohost","ical","hostfully","hostex","lodgify","beds24","apaleo","cloudbeds","track","hostify","avaibook","rentalwise","rentalsunited","uplisting","mews","smoobu","smily","tokeet","fantasticstay","channex","host_tools","resly","opera","your_rentals","vrbo_web","repull"],"title":"ReservationSourceName"},"ReservationSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"guest_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Name"},"listing_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listing Title"},"check_in_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check In At"},"check_out_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Check Out At"}},"type":"object","required":["id","guest_name","listing_title","check_in_at","check_out_at"],"title":"ReservationSummary"},"ReservationUpdateExternal":{"properties":{"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields","description":"Replaces the entire ``custom_fields`` dict on the reservation. For partial updates use the batch custom-fields endpoints."},"guest_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest First Name"},"guest_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Last Name"},"guest_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Email"},"guest_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Phone"},"guest_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Address"},"guest_city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest City"},"guest_country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Country"},"guest_postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Guest Postal Code"},"check_in":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Check In","description":"New arrival date, listing-local. ProhostAI bookings only."},"check_out":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Check Out","description":"New departure date, listing-local. ProhostAI bookings only."},"check_in_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check In Time","description":"New listing-local arrival time. ProhostAI bookings only."},"check_out_time":{"anyOf":[{"type":"string","format":"time"},{"type":"null"}],"title":"Check Out Time","description":"New listing-local departure time. ProhostAI bookings only."},"guests":{"anyOf":[{"$ref":"#/components/schemas/ReservationPartyUpdateExternal"},{"type":"null"}],"description":"ProhostAI bookings only."},"invoice_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/ReservationInvoiceItemExternal"},"type":"array","maxItems":50},{"type":"null"}],"title":"Invoice Items","description":"Replaces every price line; `[]` clears them, omitted keeps them. ProhostAI bookings only."},"allow_overlap":{"type":"boolean","title":"Allow Overlap","description":"Move the stay even when another confirmed booking holds some of the new nights.","default":false}},"type":"object","title":"ReservationUpdateExternal","description":"Update a reservation via the public API.\n\n``custom_fields`` and the guest's contact details are writable on any\nreservation. The stay itself — dates, times, party, price lines — is\nwritable only on a booking ProhostAI owns (created in ProhostAI); a\nchannel's booking must change on that channel. No status change here:\ncancel through ``POST /v1/reservations/{id}/cancel``.\n\nMirrors the writable subset of ``src/reservations/schemas.py::ReservationUpdate``\nthat maps onto real columns on ``Reservation``: ``custom_fields`` plus\ncontact-person details. The reservation model has no free-form ``notes``\ncolumn (only ``ai_notes`` JSONB which we don't expose) — narrative notes\nbelong on the reservation's conversation thread, not the reservation row.\nAll fields are optional — only provided fields are updated (PUT semantics\nhere are partial-replace, matching the internal ``PUT /reservations/v2``\nendpoint which uses ``OptionalField`` to distinguish \"not provided\" from\n\"set to null\").","examples":[{"custom_fields":{"door_code":"1234"},"guest_phone":"+1-555-0100"}]},"ReservationWarningExternal":{"properties":{"code":{"type":"string","title":"Code","description":"`no_guest_email`, `dates_blocked`, `not_blocked_on_channel`, `over_capacity` or `overlap_allowed`."},"message":{"type":"string","title":"Message"}},"type":"object","required":["code","message"],"title":"ReservationWarningExternal","description":"Something the caller should know about a booking that was created anyway."},"ResolvedCustomFieldEntryExternal":{"properties":{"value":{"title":"Value"},"source":{"type":"string","enum":["account","tag","source","listing"],"title":"Source"},"tag_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag Name"},"tag_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tag Id"}},"type":"object","required":["value","source"],"title":"ResolvedCustomFieldEntryExternal","description":"A merged custom field with provenance for the editor preview pane."},"ResolvedCustomFieldsExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"values":{"additionalProperties":true,"type":"object","title":"Values"},"provenance":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/ResolvedCustomFieldEntryExternal"},"type":"object"},{"type":"null"}],"title":"Provenance"}},"type":"object","required":["listing_id","values"],"title":"ResolvedCustomFieldsExternal","description":"Response for ``GET /listings/{id}/custom-fields/resolved``.\n\n``values`` is the flat key→value dict callers render against. ``provenance``\nis populated only when ``?with_provenance=true`` is set, surfacing which\nscope each value came from for shadowing UI."},"ResponseTimeExternal":{"properties":{"median_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Seconds"},"p75_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P75 Seconds"},"period_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period Start"},"period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period End"}},"type":"object","required":["median_seconds"],"title":"ResponseTimeExternal"},"ReviewAnalyticsExternal":{"properties":{"total_reviews":{"type":"integer","title":"Total Reviews"},"average_rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average Rating"},"reviews_by_week":{"items":{"$ref":"#/components/schemas/WeeklyReviewCountExternal"},"type":"array","title":"Reviews By Week"},"rating_trend":{"items":{"$ref":"#/components/schemas/DailyRatingTrendExternal"},"type":"array","title":"Rating Trend"},"review_rate_percent":{"type":"number","title":"Review Rate Percent"},"total_checkouts":{"type":"integer","title":"Total Checkouts"},"checkouts_with_review":{"type":"integer","title":"Checkouts With Review"},"checkouts_without_review":{"type":"integer","title":"Checkouts Without Review"},"pending_review_count":{"type":"integer","title":"Pending Review Count"}},"type":"object","required":["total_reviews","average_rating","reviews_by_week","rating_trend","review_rate_percent","total_checkouts","checkouts_with_review","checkouts_without_review","pending_review_count"],"title":"ReviewAnalyticsExternal"},"ReviewCategoryRating":{"properties":{"category":{"type":"string","title":"Category"},"rating":{"type":"number","title":"Rating"},"max_rating":{"type":"integer","title":"Max Rating"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment"}},"type":"object","required":["category","rating","max_rating"],"title":"ReviewCategoryRating"},"ReviewCreateExternal":{"properties":{"rating":{"type":"number","minimum":1.0,"title":"Rating","description":"Overall rating: 1-10 for Booking.com, else 1-5"},"public_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Review"},"private_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Review"},"reviewer_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Reviewer Name"},"published_at":{"type":"string","format":"date-time","title":"Published At"},"host_response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Response"},"host_response_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Host Response At"},"rating_value":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Value"},"rating_cleanliness":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Cleanliness"},"rating_communication":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Communication"},"rating_location":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Location"},"rating_checkin":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Checkin"},"rating_accuracy":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Accuracy"},"rating_facilities":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Facilities"},"rating_staff":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Staff"},"rating_services":{"anyOf":[{"type":"number","minimum":1.0},{"type":"null"}],"title":"Rating Services"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"channel":{"$ref":"#/components/schemas/ReservationChannelIdStr"},"source_name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Source Name","description":"The site it came from, for channel other: TripAdvisor..."},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"confirmation_code":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Confirmation Code"},"external_id":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"External Id","description":"Your id for the review; a second create with it is refused"},"run_automations":{"type":"boolean","title":"Run Automations","description":"Handle it as a new review: send the review.received webhook, detect tasks in its text (published in the last 30 days) and fire your review workflows (published in the last 7). Leave off when uploading past reviews.","default":false}},"type":"object","required":["rating","published_at","listing_id","channel"],"title":"ReviewCreateExternal","description":"A new hand-added review, and whether to handle it as one that just came in."},"ReviewExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"stars":{"type":"integer","title":"Stars"},"rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rating"},"public_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Review"},"private_review":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Review"},"reviewer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reviewer Name"},"host_response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Response"},"host_response_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Host Response At"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"external_channel":{"anyOf":[{"$ref":"#/components/schemas/ReservationChannelIdStr"},{"type":"null"}]},"external_source_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Source Name"},"category_ratings":{"items":{"$ref":"#/components/schemas/ReviewCategoryRating"},"type":"array","title":"Category Ratings","default":[]}},"type":"object","required":["id","listing_id","reservation_id","stars","rating","public_review","private_review","published_at","created_at","updated_at"],"title":"ReviewExternal"},"ReviseSuggestionExternal":{"properties":{"instruction":{"type":"string","maxLength":2000,"minLength":1,"title":"Instruction"}},"type":"object","required":["instruction"],"title":"ReviseSuggestionExternal","description":"Body for requesting a rewrite of an existing suggestion.","examples":[{"instruction":"Make it shorter and friendlier."}]},"SavedReplyCreateExternal":{"properties":{"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title"},"message":{"type":"string","minLength":1,"title":"Message"},"category":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Category"},"shortcut":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Shortcut"}},"type":"object","required":["title","message"],"title":"SavedReplyCreateExternal","examples":[{"message":"Welcome! Let me know if you need anything.","shortcut":"/welcome","title":"Welcome"}]},"SavedReplyExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"message":{"type":"string","title":"Message"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"shortcut":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shortcut"},"sort_order":{"type":"integer","title":"Sort Order","default":0},"usage_count":{"type":"integer","title":"Usage Count","default":0},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","title","message"],"title":"SavedReplyExternal","description":"Account-wide canned message."},"SavedReplyListResponse":{"properties":{"saved_replies":{"items":{"$ref":"#/components/schemas/SavedReplyExternal"},"type":"array","title":"Saved Replies"}},"type":"object","required":["saved_replies"],"title":"SavedReplyListResponse"},"SavedReplyUpdateExternal":{"properties":{"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title"},"message":{"type":"string","minLength":1,"title":"Message"},"sort_order":{"type":"integer","title":"Sort Order"},"category":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Category"},"shortcut":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Shortcut"}},"type":"object","title":"SavedReplyUpdateExternal"},"ScheduleMessageExternal":{"properties":{"reservation_id":{"type":"string","format":"uuid","title":"Reservation Id","description":"Reservation the scheduled message is associated with"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id","description":"Listing the scheduled message is associated with"},"message":{"type":"string","minLength":1,"title":"Message","description":"Message body to send at ``scheduled_at``"},"scheduled_at":{"type":"string","format":"date-time","title":"Scheduled At","description":"When to send the message. Must be in the future (UTC)."}},"type":"object","required":["reservation_id","listing_id","message","scheduled_at"],"title":"ScheduleMessageExternal","description":"Request body for scheduling a message via the external REST API.","examples":[{"listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","message":"Reminder: check-in is today at 3pm. Let me know if you need anything!","reservation_id":"9fa4c218-fd7a-4aa1-a17c-728ec0eb74b5","scheduled_at":"2026-04-20T15:00:00Z"}]},"ScheduledMessageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id","description":"Reservation the scheduled message is associated with (null for reservationless rows)"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id","description":"Listing the scheduled message is associated with (null for listingless rows)"},"message":{"type":"string","title":"Message"},"status":{"type":"string","title":"Status","description":"Scheduled message status","examples":["scheduled","cancelled","sent"]},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Origin of the scheduled message. ``null`` for legacy rows that predate the source column.","examples":["api","mcp"]},"scheduled_at":{"type":"string","format":"date-time","title":"Scheduled At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","conversation_id","message","status","scheduled_at","created_at"],"title":"ScheduledMessageResponse","description":"Response for a scheduled-message create / cancel.","examples":[{"conversation_id":"c2d3e4f5-a6b7-4890-b123-4567890abcde","created_at":"2026-04-18T12:00:00Z","id":"e6a7b8c9-d0e1-4234-9567-890abcdef123","listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","message":"Reminder: check-in is today at 3pm.","reservation_id":"9fa4c218-fd7a-4aa1-a17c-728ec0eb74b5","scheduled_at":"2026-04-20T15:00:00Z","source":"api","status":"scheduled"}]},"ScheduledMessageUpdateExternal":{"properties":{"message":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Message","description":"New message body."},"scheduled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled At","description":"New send time (must remain in the future)."}},"type":"object","title":"ScheduledMessageUpdateExternal","description":"Patch body for editing a scheduled message that hasn't been sent yet.","examples":[{"message":"Updated reminder body.","scheduled_at":"2026-04-20T16:00:00Z"}]},"ScopeFollowRequestExternal":{"properties":{"who":{"type":"string","title":"Who","description":"`me` (the member the credential acts for) or the user id of a workspace member or AI employee. Acting for someone else needs a write scope for what the scope holds.","default":"me"},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level","description":"`all` (default) or `important` — status changes, completion, @mentions, overdue and issues."}},"additionalProperties":false,"type":"object","title":"ScopeFollowRequestExternal","description":"Follow a whole listing, department or recurring series for the calling member or for someone else."},"ScopeFollowStateExternal":{"properties":{"scope_type":{"type":"string","enum":["listing","department","recurring_task"],"title":"Scope Type"},"scope_id":{"type":"string","format":"uuid","title":"Scope Id"},"title":{"type":"string","title":"Title"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id","description":"The listing the scope is tied to, if any."},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id","description":"Whose follow `following` / `level` describe — null for an account-level key without `who`."},"following":{"type":"boolean","title":"Following","default":false},"level":{"anyOf":[{"type":"string","enum":["all","important"]},{"type":"null"}],"title":"Level"},"followers":{"items":{"$ref":"#/components/schemas/ScopeFollowerExternal"},"type":"array","title":"Followers","description":"Oldest follow first; at most 50."},"count":{"type":"integer","title":"Count","description":"How many people and AI employees follow the scope."}},"type":"object","required":["scope_type","scope_id","title","followers","count"],"title":"ScopeFollowStateExternal","description":"A scope, one person's follow of it, and everyone who follows it."},"ScopeFollowerExternal":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"is_ai_employee":{"type":"boolean","title":"Is Ai Employee","default":false},"level":{"type":"string","enum":["all","important"],"title":"Level"},"followed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Followed At"},"added_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Added By User Id","description":"Who added this follower, when it wasn't themselves."}},"type":"object","required":["user_id","level"],"title":"ScopeFollowerExternal","description":"One follower of a scope."},"SendAgentDMRequest":{"properties":{"message":{"type":"string","maxLength":10000,"minLength":1,"title":"Message"}},"type":"object","required":["message"],"title":"SendAgentDMRequest","examples":[{"message":"Which reservations check in tomorrow, and are any missing door codes?"}]},"SendAgentDMResponse":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"message_id":{"type":"string","format":"uuid","title":"Message Id"},"status":{"type":"string","title":"Status","description":"'sent' once the message is committed to the thread."},"run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Run Id","description":"The dispatched agent run, or null when a dispatch guard (credit budget, agent-chain depth, billing gate, in-flight dedup) suppressed the run. The reply arrives asynchronously in the DM thread — poll GET .../dm/messages or subscribe to the message.team_chat webhook event."},"dispatch_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dispatch Error","description":"Null normally. 'dispatch_enqueue_failed' when the message was delivered to the thread but the agent-run enqueue failed after a retry (queue outage) — no reply will arrive for THIS message; send a fresh message to retry."}},"type":"object","required":["conversation_id","message_id","status"],"title":"SendAgentDMResponse"},"SendMessageExternal":{"properties":{"message":{"type":"string","title":"Message"},"reply_to_message_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reply To Message Id","description":"Reply inside a team-chat thread instead of the main channel. Must reference a message in THIS conversation that has not been deleted (422 otherwise). The thread this lands in is computed server-side from the target — a reply chain always flattens to one root — so quote the message you are actually answering and the placement follows. Omit for an ordinary send."},"sender_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Sender Name","description":"Post as a named bot instead of as the human this API key belongs to. The name becomes the message's displayed author (with its own avatar, if you have set one), and the 'via API' pill is dropped — there is no human to disambiguate from. Reusing a name reuses the same bot identity, so 'Deploy bot' is one author across every message rather than a new one per send.\n\n**Team-chat conversations only** — a guest must never see a message from an identity that isn't yours, so this is ignored on guest channels.\n\nDistinct from the internal-note endpoint's `source_name`, which is audit provenance and does NOT change the displayed author."},"ai_agent_run_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Ai Agent Run Id","description":"For a paired AI employee: the agent run this message is part of — the `run_id` of the `agent.run_requested` event (it arrives in `reply_instructions.body_extra`). The message is recorded as written by that run. The run must be one this credential was handed (422 `ai_agent_run_not_found` otherwise). On a heartbeat run, a team-chat post into a thread another run of the same employee is answering, or has just answered, is refused with 409 `reply_race_held`. Omit it and the send behaves as it always has."}},"type":"object","required":["message"],"title":"SendMessageExternal","examples":[{"message":"Hi Sarah! Welcome — check-in is at 3pm. The keypad code is 4827."},{"message":"Maria confirmed — she'll be there by 11am.","reply_to_message_id":"b1c2d3e4-f5a6-4789-a012-3456789abcde"}]},"SendMessageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"type":"string","title":"Status","description":"Delivery status","examples":["pending"]},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"message":{"type":"string","title":"Message"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","status","conversation_id","message","created_at"],"title":"SendMessageResponse","examples":[{"conversation_id":"c2d3e4f5-a6b7-4890-b123-4567890abcde","created_at":"2026-04-12T14:31:00Z","id":"d3e4f5a6-b7c8-4901-8234-567890abcdef","message":"Hi Sarah! Welcome — check-in is at 3pm.","status":"sent"}]},"SheetColumn":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"type":{"$ref":"#/components/schemas/SheetColumnType"},"options":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"$ref":"#/components/schemas/SheetColumnObjectOptions"},{"type":"null"}],"title":"Options"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"wrap":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Wrap"},"option_colors":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/SheetOptionColor"},"type":"object"},{"type":"null"}],"title":"Option Colors"},"formula":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formula"}},"type":"object","required":["id","name","type"],"title":"SheetColumn"},"SheetColumnAggregate":{"type":"string","title":"SheetColumnAggregate","description":"Per-column summary aggregate rendered in the sheet totals row.\n\nPersisted in a column's ``options.aggregate`` bag (see\n``shared_types.drive_sheets.SheetColumn``). ``sum`` / ``avg`` are only\nmeaningful on numeric/currency columns; ``min`` / ``max`` work on any\norderable numeric column; ``count`` (row count) and ``filled`` (share of\nnon-empty cells) apply to any column type; ``checked`` (share of ticked\nboxes) only to ``boolean`` columns. A cleared aggregate is stored as the\nabsence of the key, never as a member here.","x-extensible-enum":["sum","avg","min","max","count","filled","checked"]},"SheetColumnObjectOptions":{"properties":{"target_drive_item_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Drive Item Id"},"aggregate":{"anyOf":[{"$ref":"#/components/schemas/SheetColumnAggregate"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SheetColumnObjectOptions","description":"Typed object-shaped column ``options`` bag.\n\nCarries the ``reference`` column's target and/or the totals-row\n``aggregate``. Kept as one typed model (rather than ``dict[str, Any]``) so\ngenerated OpenAPI types and mobile consumers get a real contract instead of\nan opaque map. ``extra=\"allow\"`` preserves any forward-compat keys a newer\nclient writes, so an old backend round-trips them untouched."},"SheetColumnType":{"type":"string","enum":["text","number","date","datetime","boolean","select","multi_select","url","email","phone","currency","reference","formula"],"title":"SheetColumnType","description":"Supported column types for a DriveSheet."},"SheetExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"drive_item_id":{"type":"string","format":"uuid","title":"Drive Item Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"schema":{"$ref":"#/components/schemas/SheetSchema"},"row_count":{"type":"integer","title":"Row Count"},"last_edited_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Last Edited By"},"last_edited_at":{"type":"string","format":"date-time","title":"Last Edited At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","drive_item_id","account_id","schema","row_count","last_edited_at","created_at","updated_at"],"title":"SheetExternal"},"SheetOptionColor":{"type":"string","enum":["gray","blue","green","yellow","orange","red","purple","indigo"],"title":"SheetOptionColor","description":"Display colour of one select / multi_select option.\n\nPersisted in a column's ``option_colors`` map (option name → colour, see\n``shared_types.drive_sheets.SheetColumn``). Display-only: the web app maps\neach name to its own palette, and an option without an entry falls back\nto the app's colour-by-position."},"SheetQueryRequest":{"properties":{"filter":{"additionalProperties":true,"type":"object","title":"Filter"},"sort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"},"limit":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Limit","default":50},"offset":{"type":"integer","minimum":0.0,"title":"Offset","default":0}},"type":"object","title":"SheetQueryRequest","description":"Simple filter DSL for sheet rows.\n\n``filter`` is a dict of ``column_id -> value`` — rows whose data matches\nevery column in the filter are returned. ``sort`` is an optional\n``column_id`` prefixed with ``-`` for descending (e.g. ``-created_at``)."},"SheetRowCreateRequest":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data"},"row_order":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Row Order"}},"type":"object","title":"SheetRowCreateRequest"},"SheetRowExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"sheet_id":{"type":"string","format":"uuid","title":"Sheet Id"},"row_order":{"type":"number","title":"Row Order"},"data":{"additionalProperties":true,"type":"object","title":"Data"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","sheet_id","row_order","data","created_at","updated_at"],"title":"SheetRowExternal"},"SheetRowUpdateRequest":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data"},"row_order":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Row Order"}},"type":"object","title":"SheetRowUpdateRequest"},"SheetSchema":{"properties":{"columns":{"items":{"$ref":"#/components/schemas/SheetColumn"},"type":"array","title":"Columns"}},"type":"object","title":"SheetSchema"},"SimplePage_ScheduledMessageResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ScheduledMessageResponse"},"type":"array","title":"Items","description":"The page of results."},"total":{"type":"integer","title":"Total","description":"Total number of matching records."},"limit":{"type":"integer","title":"Limit","description":"Maximum number of items returned."}},"type":"object","required":["items","total","limit"],"title":"SimplePage[ScheduledMessageResponse]"},"SkillExternal":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"enabled":{"type":"boolean","title":"Enabled"},"is_builtin":{"type":"boolean","title":"Is Builtin"},"is_customized":{"type":"boolean","title":"Is Customized"},"use_count":{"type":"integer","title":"Use Count"},"body":{"type":"string","title":"Body"}},"type":"object","required":["key","name","description","enabled","is_builtin","is_customized","use_count","body"],"title":"SkillExternal"},"SkillListResponse":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"skills":{"items":{"$ref":"#/components/schemas/SkillSummaryExternal"},"type":"array","title":"Skills"}},"type":"object","required":["enabled","skills"],"title":"SkillListResponse"},"SkillSummaryExternal":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"enabled":{"type":"boolean","title":"Enabled"},"is_builtin":{"type":"boolean","title":"Is Builtin"},"is_customized":{"type":"boolean","title":"Is Customized"},"use_count":{"type":"integer","title":"Use Count"}},"type":"object","required":["key","name","description","enabled","is_builtin","is_customized","use_count"],"title":"SkillSummaryExternal"},"SpaceExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"visibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility"},"created":{"type":"boolean","title":"Created","description":"`false` when an OPEN space with this name already existed and was returned untouched. Creation is idempotent on name for open spaces, so a retried call cannot fork a second channel; private spaces never dedup."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","created"],"title":"SpaceExternal","description":"A created — or reused — Inbox Space."},"StageCreateExternal":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"kind":{"$ref":"#/components/schemas/PipelineStageKind","default":"open"}},"additionalProperties":false,"type":"object","required":["name"],"title":"StageCreateExternal"},"StageExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"pipeline_id":{"type":"string","format":"uuid","title":"Pipeline Id"},"name":{"type":"string","title":"Name"},"position":{"type":"integer","title":"Position"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"kind":{"$ref":"#/components/schemas/PipelineStageKind"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","pipeline_id","name","position","kind","created_at","updated_at"],"title":"StageExternal"},"StageInputExternal":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"kind":{"$ref":"#/components/schemas/PipelineStageKind","default":"open"}},"additionalProperties":false,"type":"object","required":["name"],"title":"StageInputExternal"},"StageUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"kind":{"anyOf":[{"$ref":"#/components/schemas/PipelineStageKind"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"StageUpdateExternal"},"StatementExpense":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"listing_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Listing Name"},"category_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category Name"},"name":{"type":"string","title":"Name"},"amount":{"type":"number","minimum":0.0,"title":"Amount"},"date":{"type":"string","format":"date","title":"Date"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["id","listing_id","listing_name","category_name","name","amount","date","description"],"title":"StatementExpense"},"SuggestionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"message_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Message Id"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Generated draft body."},"edited_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Edited Message","description":"Host-edited override of the draft body."},"autopilot_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Autopilot Status"},"autopilot_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Autopilot Category"},"autopilot_confidence_overall":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Autopilot Confidence Overall"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","message_id","created_at","updated_at"],"title":"SuggestionExternal","description":"AI suggestion / draft for a guest reply."},"SuggestionsListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SuggestionExternal"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"SuggestionsListResponse"},"TagPinCreateExternal":{"properties":{"place_id":{"type":"string","format":"uuid","title":"Place Id"},"category":{"$ref":"#/components/schemas/PlacePinCategory"},"listing_tag_id":{"type":"string","format":"uuid","title":"Listing Tag Id"},"host_note_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Note Override"},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position"}},"additionalProperties":false,"type":"object","required":["place_id","category","listing_tag_id"],"title":"TagPinCreateExternal","description":"Used by ``POST /tag-pins`` (no guidebook in the URL — tag id in body)."},"TagPinGroupExternal":{"properties":{"tag":{"$ref":"#/components/schemas/PlaceTagInfoExternal"},"pins":{"items":{"$ref":"#/components/schemas/GuidebookPlacePinExternal"},"type":"array","title":"Pins"}},"type":"object","required":["tag","pins"],"title":"TagPinGroupExternal","description":"Tag-scoped pins inherited by a guidebook through its listing's tags."},"TagPinReorderExternal":{"properties":{"listing_tag_id":{"type":"string","format":"uuid","title":"Listing Tag Id"},"pins":{"items":{"$ref":"#/components/schemas/PinReorderItemExternal"},"type":"array","title":"Pins"}},"additionalProperties":false,"type":"object","required":["listing_tag_id"],"title":"TagPinReorderExternal","description":"Reorder pins within a single listing-tag scope."},"TagSectionCreateExternal":{"properties":{"listing_tag_id":{"type":"string","format":"uuid","title":"Listing Tag Id"},"title":{"type":"string","maxLength":255,"minLength":1,"title":"Title"},"content":{"type":"string","title":"Content","default":""},"section_type":{"$ref":"#/components/schemas/GuidebookSectionType","default":"text"},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position"},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"}},"additionalProperties":false,"type":"object","required":["listing_tag_id","title"],"title":"TagSectionCreateExternal","description":"Create a tag-scoped section. ``listing_tag_id`` lives in the body since\ntag-sections aren't nested under a guidebook in the URL."},"TagSectionReorderExternal":{"properties":{"listing_tag_id":{"type":"string","format":"uuid","title":"Listing Tag Id"},"sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionReorderItemExternal"},"type":"array","title":"Sections"}},"additionalProperties":false,"type":"object","required":["listing_tag_id"],"title":"TagSectionReorderExternal"},"TagSectionUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"section_type":{"anyOf":[{"$ref":"#/components/schemas/GuidebookSectionType"},{"type":"null"}]},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Id"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"unlock_before_checkin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unlock Before Checkin"}},"additionalProperties":false,"type":"object","title":"TagSectionUpdateExternal"},"TagSectionsListResponseExternal":{"properties":{"sections":{"items":{"$ref":"#/components/schemas/GuidebookSectionExternal"},"type":"array","title":"Sections"}},"type":"object","title":"TagSectionsListResponseExternal","description":"Response for ``GET /guidebooks/tag-sections`` — every tag-scoped section that\nrenders through the tag (primary tag or additional-tag link), roots first."},"TaskAlertDefaultsSettings":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"timed_minutes_before":{"items":{"type":"integer"},"type":"array","title":"Timed Minutes Before"},"all_day":{"type":"string","enum":["summary","none"],"title":"All Day","default":"summary"},"summary_enabled":{"type":"boolean","title":"Summary Enabled","default":true},"summary_time":{"type":"string","title":"Summary Time","default":"08:00"},"live_activity":{"$ref":"#/components/schemas/TaskAlertLiveActivity"}},"type":"object","title":"TaskAlertDefaultsSettings","description":"A user's task alert defaults as the settings API returns them (every key filled)."},"TaskAlertLiveActivity":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"lead_minutes":{"type":"integer","title":"Lead Minutes","default":60}},"type":"object","title":"TaskAlertLiveActivity","description":"The task-day Live Activity part of :class:`TaskAlertDefaultsSettings`."},"TaskBulkCreateErrorExternal":{"properties":{"index":{"type":"integer","title":"Index","description":"0-based index of the rejected entry in the request's `tasks` array"},"error":{"type":"string","title":"Error"}},"type":"object","required":["index","error"],"title":"TaskBulkCreateErrorExternal","description":"A single rejected entry, addressed by its index in the request array."},"TaskBulkCreateExternal":{"properties":{"tasks":{"items":{"$ref":"#/components/schemas/TaskBulkCreateItemExternal"},"type":"array","maxItems":100,"minItems":1,"title":"Tasks"}},"type":"object","required":["tasks"],"title":"TaskBulkCreateExternal","examples":[{"tasks":[{"category":"maintenance","checklists":[{"items":[{"title":"Strip old grout"},{"title":"Reseal"}],"title":"Steps"}],"priority":"high","title":"Regrout the primary shower"},{"category":"restocking","title":"Replace the entry mat"}]}]},"TaskBulkCreateItemExternal":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Initial status: a workflow state id, slug or name (case-insensitive), a category word (todo, in_progress, paused, blocked, in_review, completed, cancelled) or a legacy label. Omit to take the workspace's creation default.","examples":["open","parts-ordered"]},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Task category (e.g. maintenance, cleanliness, plumbing)"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"assignee_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Assignee Ids","description":"Users to assign. Each must be a member of the authenticated account."},"due_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due Date"},"media_reference":{"anyOf":[{"$ref":"#/components/schemas/TaskMediaReferenceInputExternal"},{"type":"null"}],"description":"Optional pointer to a moment in a video/audio attachment this task came from (e.g. a walkthrough video). See TaskMediaReferenceInputExternal."},"checklists":{"anyOf":[{"items":{"$ref":"#/components/schemas/TaskChecklistCreateExternal"},"type":"array"},{"type":"null"}],"title":"Checklists","description":"Checklist sections to create on this task, each with its own nested items. Created after the task, in the order given."}},"type":"object","required":["title"],"title":"TaskBulkCreateItemExternal","description":"One entry in a bulk create, optionally carrying its own checklists.\n\nNesting checklists here is what keeps the punch-list flow to one call\nrather than 1 + N: a client that turned a property walkthrough into \"57\ntasks, each with a few sub-steps\" would otherwise pay a round trip per\nchecklist.","examples":[{"description":"Guest reports water pooling under the sink cabinet.","priority":"high","title":"Fix leaking kitchen sink"}]},"TaskBulkCreateResultExternal":{"properties":{"created":{"items":{"$ref":"#/components/schemas/TaskExternal"},"type":"array","title":"Created"},"failed":{"items":{"$ref":"#/components/schemas/TaskBulkCreateErrorExternal"},"type":"array","title":"Failed"},"created_count":{"type":"integer","title":"Created Count"},"failed_count":{"type":"integer","title":"Failed Count"}},"type":"object","required":["created","failed","created_count","failed_count"],"title":"TaskBulkCreateResultExternal","description":"Partial-success result: every entry is independent.\n\n``created`` and ``failed`` together account for every submitted entry, so a\ncaller can retry exactly the failures by index without re-sending the\nsuccesses (which would duplicate them — bulk create is not idempotent\nper entry, only per whole request via ``Idempotency-Key``).","examples":[{"created":[],"created_count":0,"failed":[{"error":"Invalid category 'plummbing'","index":3}],"failed_count":1}]},"TaskChecklistCreateExternal":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"items":{"anyOf":[{"items":{"$ref":"#/components/schemas/TaskChecklistItemCreateExternal"},"type":"array"},{"type":"null"}],"title":"Items"}},"type":"object","required":["title"],"title":"TaskChecklistCreateExternal"},"TaskChecklistExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"task_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Task Id"},"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"type":"integer","title":"Order","default":0},"items":{"items":{"$ref":"#/components/schemas/TaskChecklistItemExternal"},"type":"array","title":"Items","default":[]},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","title"],"title":"TaskChecklistExternal"},"TaskChecklistFromTemplateExternal":{"properties":{"template_id":{"type":"string","format":"uuid","title":"Template Id"}},"type":"object","required":["template_id"],"title":"TaskChecklistFromTemplateExternal"},"TaskChecklistItemCreateExternal":{"properties":{"title":{"type":"string","title":"Title"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"}},"type":"object","required":["title"],"title":"TaskChecklistItemCreateExternal"},"TaskChecklistItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"order":{"type":"integer","title":"Order","default":0},"completed":{"type":"boolean","title":"Completed","default":false},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"reference_photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Photo Url"},"reference_media":{"anyOf":[{"items":{"$ref":"#/components/schemas/ReferenceMedia"},"type":"array"},{"type":"null"}],"title":"Reference Media"},"reference_video":{"anyOf":[{"$ref":"#/components/schemas/ReferenceVideo"},{"type":"null"}]},"photo_required":{"type":"boolean","title":"Photo Required","default":false},"photo_uploaded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Photo Uploaded At"}},"type":"object","required":["id","title"],"title":"TaskChecklistItemExternal"},"TaskChecklistReorderExternal":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TaskChecklistReorderItemExternal"},"type":"array","minItems":1,"title":"Items"}},"type":"object","required":["items"],"title":"TaskChecklistReorderExternal"},"TaskChecklistReorderItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"order":{"type":"integer","title":"Order"}},"type":"object","required":["id","order"],"title":"TaskChecklistReorderItemExternal"},"TaskChecklistUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"}},"type":"object","title":"TaskChecklistUpdateExternal"},"TaskCommentCreateExternal":{"properties":{"content":{"type":"string","maxLength":10000,"minLength":1,"title":"Content"}},"type":"object","required":["content"],"title":"TaskCommentCreateExternal"},"TaskCommentExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"task_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Task Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"content":{"type":"string","title":"Content"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","content"],"title":"TaskCommentExternal"},"TaskCreateExternal":{"properties":{"title":{"type":"string","title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Initial status: a workflow state id, slug or name (case-insensitive), a category word (todo, in_progress, paused, blocked, in_review, completed, cancelled) or a legacy label. Omit to take the workspace's creation default.","examples":["open","parts-ordered"]},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Task category (e.g. maintenance, cleanliness, plumbing)"},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"assignee_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Assignee Ids","description":"Users to assign. Each must be a member of the authenticated account."},"due_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due Date"},"media_reference":{"anyOf":[{"$ref":"#/components/schemas/TaskMediaReferenceInputExternal"},{"type":"null"}],"description":"Optional pointer to a moment in a video/audio attachment this task came from (e.g. a walkthrough video). See TaskMediaReferenceInputExternal."}},"type":"object","required":["title"],"title":"TaskCreateExternal","examples":[{"description":"Guest reports water pooling under the sink cabinet.","priority":"high","title":"Fix leaking kitchen sink"}]},"TaskExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Legacy status label (the system state's slug). Kept beside `workflow_state` through the deprecation window; read `workflow_state` for the workspace's own status.","examples":["open"]},"workflow_state":{"anyOf":[{"$ref":"#/components/schemas/TaskWorkflowStateExternal"},{"type":"null"}],"description":"The workspace's own status the task sits in (id, slug, name, category, color)."},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Task category","examples":["maintenance"]},"listing_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Listing Id"},"reservation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Reservation Id"},"assignee_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Assignee Ids","description":"Users assigned to the task"},"due_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due Date"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number","description":"Sequential task number within the workspace (never reused). Null until backfilled.","examples":[142]},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key","description":"Human-readable task key `<workspace prefix>-<number>`, e.g. `PRO-142`. Null until backfilled.","examples":["PRO-142"]},"actual_starts_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Starts At","description":"When the task's timer first started."},"actual_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Actual Ends At","description":"When the task was completed."},"calculated_duration_minutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Calculated Duration Minutes","description":"Billable duration in minutes, rounded up. Finalized on completion; while a session is open this still reflects the last close."},"work_sessions":{"anyOf":[{"items":{"$ref":"#/components/schemas/TaskWorkSessionExternal"},"type":"array"},{"type":"null"}],"title":"Work Sessions","description":"Every work interval recorded for this task, oldest first."},"kind":{"anyOf":[{"type":"string","enum":["ops","crm"]},{"type":"null"}],"title":"Kind","description":"`ops` for an operations task; `crm` for a CRM follow-up, which a key holding the CRM scope can open by id (lists return only `ops` tasks).","examples":["ops"]},"opportunity_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Opportunity Id","description":"The CRM opportunity a `crm` follow-up belongs to. Null for `ops` tasks."}},"type":"object","required":["id","title","description","priority","listing_id","reservation_id","due_date","created_at","updated_at"],"title":"TaskExternal","examples":[{"actual_starts_at":"2026-04-12T09:00:00Z","assignee_ids":["3f1c9a2e-77b4-4a1e-8f0b-2c9d4e5f6a7b"],"category":"plumbing","created_at":"2026-04-12T09:00:00Z","description":"Guest reports water pooling under the sink cabinet.","due_date":"2026-04-13T15:00:00Z","id":"6a4f7b3c-1d2e-4a5b-9c8d-1f2e3a4b5c6d","key":"PRO-142","listing_id":"8d4d8fb5-0f9f-47c2-9c3e-f8c6c2d8f2a1","number":142,"priority":"high","status":"open","title":"Fix leaking kitchen sink","updated_at":"2026-04-12T09:00:00Z","work_sessions":[{"id":"0f3a1c7e-91b2-4d6f-8a5c-2b7e9d1a4c3f","started_at":"2026-04-12T09:00:00Z"}],"workflow_state":{"category":"todo","id":"1d9b0a4e-3c2f-4b7a-9e8d-5f6a7b8c9d0e","name":"Open","slug":"open"}}]},"TaskMediaReferenceInputExternal":{"properties":{"attachment_id":{"type":"string","format":"uuid","title":"Attachment Id","description":"A video/audio task attachment in this account"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Display label for the moment"},"start_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Start Seconds","description":"Moment start, seconds into the media"},"end_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"End Seconds","description":"Moment end, seconds into the media"}},"type":"object","required":["attachment_id"],"title":"TaskMediaReferenceInputExternal","description":"Inline media-moment reference on a task create.\n\nPoints the new task at a moment in a video/audio task attachment — the\nwalkthrough-video flow: a client extracts tasks from a walkthrough and\nstamps each with where in the video it came from. The attachment must be\na video or audio attachment in the authenticated account; it may belong\nto a different task (the walkthrough video usually does)."},"TaskNotificationScope-Input":{"type":"string","enum":["all","assigned","commented","needs_attention","due_reminders","following"],"title":"TaskNotificationScope","description":"Scopes for task notifications - can be combined additively"},"TaskNotificationScope-Output":{"type":"string","title":"TaskNotificationScope","description":"Scopes for task notifications - can be combined additively","x-extensible-enum":["all","assigned","commented","needs_attention","due_reminders","following"]},"TaskPullRequestExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"repo":{"type":"string","title":"Repo"},"pr_number":{"type":"integer","title":"Pr Number"},"pr_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pr Url"},"pr_state":{"type":"string","title":"Pr State"},"head_sha":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Head Sha"},"merge_sha":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Merge Sha"},"merged_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Merged At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","repo","pr_number","pr_url","pr_state","head_sha","merge_sha","merged_at","created_at"],"title":"TaskPullRequestExternal","description":"A GitHub pull request linked to a task.","examples":[{"created_at":"2026-08-05T09:00:00Z","id":"2c8f5a1b-4e7d-4c3a-9b2f-0a1e2d3c4b5a","pr_number":11307,"pr_state":"open","pr_url":"https://github.com/ProhostAI/backend-service/pull/11307","repo":"ProhostAI/backend-service"}]},"TaskPullRequestLinkExternal":{"properties":{"repo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo","description":"owner/name, e.g. ProhostAI/backend-service"},"pr_number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pr Number","description":"Pull request number"},"pr_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pr Url","description":"Full GitHub pull request URL"}},"type":"object","title":"TaskPullRequestLinkExternal","description":"Body for attaching a GitHub pull request to a task.\n\nSupply `pr_url` on its own, or `repo` plus `pr_number`. Supplying both is\nallowed as long as they agree.\n\n`pr_state` is deliberately not accepted: a merged pull request completes\nits task, so letting a client assert the state would let any caller close\ntasks it never merged. State is written only by the GitHub integration.","examples":[{"pr_url":"https://github.com/ProhostAI/backend-service/pull/11307"},{"pr_number":11307,"repo":"ProhostAI/backend-service"}]},"TaskUpdateExternal":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"A workflow state id, slug or name (case-insensitive — see GET /v1/tasks/workflow-states), a category word (todo, in_progress, paused, blocked, in_review, completed, cancelled; lands on the workspace's default status of that category) or a legacy label (open, in_progress, completed, in_review, need_to_pay, waiting_on_guest, waiting_on_vendor, waiting_on_owner, later, cancelled).","examples":["completed","parts-ordered"]},"priority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priority"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Task category (e.g. maintenance, cleanliness, plumbing)"},"assignee_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Assignee Ids","description":"Replaces the whole assignee set. Send [] to unassign everyone; omit the field to leave assignees untouched. Each id must be a member of the authenticated account."},"due_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due Date"}},"type":"object","title":"TaskUpdateExternal","examples":[{"status":"completed"},{"priority":"low","title":"Replaced — low priority"},{"assignee_ids":["3f1c9a2e-77b4-4a1e-8f0b-2c9d4e5f6a7b"],"category":"plumbing"}]},"TaskWorkSessionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At"},"duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Seconds","description":"Cached on close; null while the session is still running."}},"type":"object","required":["id","started_at"],"title":"TaskWorkSessionExternal","description":"One contiguous ``start → pause | complete`` interval on a task.\n\nBillable duration is the sum of ``duration_seconds`` across a task's\nsessions. A session with ``ended_at`` null is still running.","examples":[{"duration_seconds":5400,"ended_at":"2026-04-12T10:30:00Z","id":"0f3a1c7e-91b2-4d6f-8a5c-2b7e9d1a4c3f","started_at":"2026-04-12T09:00:00Z"}]},"TaskWorkflowStateExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"slug":{"type":"string","title":"Slug","description":"Stable identifier; accepted as `status` on writes","examples":["parts-ordered"]},"name":{"type":"string","title":"Name","description":"Display name","examples":["Parts ordered"]},"category":{"type":"string","title":"Category","description":"One of todo, in_progress, paused, blocked, in_review, completed, cancelled","examples":["in_progress"]},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color","description":"Hex colour chosen in the workflow editor","examples":["#f59e0b"]}},"type":"object","required":["id","slug","name","category"],"title":"TaskWorkflowStateExternal","description":"The workspace's own status a task sits in — beside the legacy ``status`` label."},"TaskWorkflowStateListItemExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"slug":{"type":"string","title":"Slug","description":"Stable identifier; accepted as `status` on writes","examples":["parts-ordered"]},"name":{"type":"string","title":"Name","description":"Display name","examples":["Parts ordered"]},"category":{"type":"string","title":"Category","description":"One of todo, in_progress, paused, blocked, in_review, completed, cancelled","examples":["in_progress"]},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color","description":"Hex colour chosen in the workflow editor","examples":["#f59e0b"]},"is_system":{"type":"boolean","title":"Is System","description":"Seeded with the workspace (a legacy status's twin)"},"is_terminal":{"type":"boolean","title":"Is Terminal","description":"Tasks here are done (completed / cancelled categories)"},"display_order":{"type":"integer","title":"Display Order","description":"Position within the category"}},"type":"object","required":["id","slug","name","category","is_system","is_terminal","display_order"],"title":"TaskWorkflowStateListItemExternal","description":"One state in ``GET /v1/tasks/workflow-states``: the embedded shape plus the editor fields."},"TaskWorkflowStatesExternal":{"properties":{"states":{"items":{"$ref":"#/components/schemas/TaskWorkflowStateListItemExternal"},"type":"array","title":"States"},"categories":{"items":{"type":"string"},"type":"array","title":"Categories","description":"The seven categories, in display order"},"required_categories":{"items":{"type":"string"},"type":"array","title":"Required Categories","description":"Categories every workspace keeps at least one active state in"},"creation_default_state_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Creation Default State Id","description":"Where a task created without a `status` lands"}},"type":"object","required":["states","categories","required_categories"],"title":"TaskWorkflowStatesExternal"},"TeamChatContextExternal":{"properties":{"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"channel":{"type":"string","title":"Channel","description":"Always `internal` — the endpoint refuses every other channel."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Custom thread name, when the team chat has one."},"messages":{"items":{"$ref":"#/components/schemas/TeamChatMessageExternal"},"type":"array","title":"Messages","description":"Up to `limit` most-recent messages, returned in TRANSCRIPT ORDER (oldest first)."}},"type":"object","required":["conversation_id","channel"],"title":"TeamChatContextExternal","description":"An internal team-chat thread's recent transcript, oldest first."},"TeamChatMessageExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"sender_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Sender Id","description":"Member user who sent the message; null for system rows."},"sender_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender Type","description":"Human-readable sender type (e.g. `host`, `ai_agent`)."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","message","sent_at","created_at"],"title":"TeamChatMessageExternal","description":"One message in an internal team-chat transcript."},"TeamChatPushLevel":{"type":"string","enum":["all","dms_and_mentions","nothing"],"title":"TeamChatPushLevel","description":"Workspace-level team-chat push level (Slack's \"Notify me about\").\n\nStored as a plain string on ``user_notification_settings.team_chat_push_level``\n(CHECK-constrained to these values):\n\n* ``all`` — every message in every channel the user is in (the default).\n* ``dms_and_mentions`` — DMs, @mentions, replies and followed threads.\n* ``nothing`` — no team-chat push at all, DMs included. A per-channel\n  ``all`` / ``mentioned`` override still applies to that channel."},"TeamMemberExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Account-user role ID"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"role":{"type":"string","title":"Role","description":"Role: 'admin' or 'user'"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","user_id","email","first_name","last_name","role","created_at"],"title":"TeamMemberExternal"},"ToggleReactionExternal":{"properties":{"emoji":{"type":"string","maxLength":16,"minLength":1,"title":"Emoji"}},"type":"object","required":["emoji"],"title":"ToggleReactionExternal","description":"Body for toggling an emoji reaction on a message.","examples":[{"emoji":"🎉"}]},"ToggleReactionExternalResponse":{"properties":{"action":{"type":"string","title":"Action","description":"One of `added`, `removed`."},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emoji","description":"The emoji that was added; ``null`` after removal."}},"type":"object","required":["action"],"title":"ToggleReactionExternalResponse","description":"Response for toggling a reaction — mirrors the internal v2 API shape."},"TokenTotalDay":{"properties":{"day":{"type":"string","format":"date","title":"Day"},"accountKey":{"type":"string","format":"uuid","title":"Accountkey"},"runtime":{"type":"string","enum":["claude_code","codex"],"title":"Runtime"},"model":{"type":"string","maxLength":100,"minLength":1,"title":"Model"},"project":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Project"},"inputTokens":{"type":"integer","maximum":10000000000000.0,"minimum":0.0,"title":"Inputtokens","default":0},"cachedInputTokens":{"type":"integer","maximum":10000000000000.0,"minimum":0.0,"title":"Cachedinputtokens","default":0},"cacheWriteTokens":{"type":"integer","maximum":10000000000000.0,"minimum":0.0,"title":"Cachewritetokens","default":0},"outputTokens":{"type":"integer","maximum":10000000000000.0,"minimum":0.0,"title":"Outputtokens","default":0}},"type":"object","required":["day","accountKey","runtime","model"],"title":"TokenTotalDay","description":"One day's aggregate for one account, model and project. Never prompt text."},"TokenTotalPair":{"properties":{"day":{"type":"string","format":"date","title":"Day"},"accountKey":{"type":"string","format":"uuid","title":"Accountkey"}},"type":"object","required":["day","accountKey"],"title":"TokenTotalPair","description":"One account's day, named whole by a token-totals body (``completeDays``)."},"TokenTotalsAccepted":{"properties":{"accepted":{"type":"integer","title":"Accepted"},"acceptedAccountKeys":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Acceptedaccountkeys"},"skipped":{"items":{"$ref":"#/components/schemas/UsageSkipped"},"type":"array","title":"Skipped"},"replacedDays":{"type":"integer","title":"Replaceddays","default":0}},"type":"object","required":["accepted"],"title":"TokenTotalsAccepted","description":"Response for ``POST /v1/usage/token-totals``.\n\n``replacedDays`` counts the ``completeDays`` pairs replaced whole (an\naccepted account, a day in range). Its presence tells a client the server\ndeletes rows a complete day no longer carries — an older server omits it."},"TokenTotalsReport":{"properties":{"machineId":{"type":"string","format":"uuid","title":"Machineid"},"machine":{"type":"string","maxLength":120,"minLength":1,"title":"Machine"},"days":{"items":{"$ref":"#/components/schemas/TokenTotalDay"},"type":"array","maxItems":2000,"title":"Days"},"completeDays":{"items":{"$ref":"#/components/schemas/TokenTotalPair"},"type":"array","maxItems":2000,"title":"Completedays"}},"type":"object","required":["machineId","machine","days"],"title":"TokenTotalsReport","description":"``POST /v1/usage/token-totals``.\n\n``complete_days`` lists the (day, account) pairs this body carries in full:\nthe server deletes the machine's other rows for each before storing\n``days``, so a project or model the day no longer has stops counting. A\nbody without it (CLI 0.10.1 and older) only replaces the rows it carries."},"UpdateAIEmployeeTriggerRequest":{"properties":{"trigger_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trigger Type"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What this trigger is for; injected into the prompt of every run it fires. Create already accepts this — without it here a description could be set once and never corrected."},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"cooldown_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cooldown Seconds"},"trigger_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Trigger Config","description":"Replaces the stored configuration when sent. Trigger configuration. A 'schedule' trigger requires {'schedule': {'frequency', 'time', 'timezone', ...}}. Any trigger accepts 'conditions' (list of {field, op, value} pre-filters on the event), 'relevance_screen' (bool) and 'skill_key' (a skill run on every fire). 'listing_ids' limits a listing-bound trigger to those listings; it is rejected (422) on triggers whose events have no listing (GitHub, calls, calendar, email, Slack, webhook, outbound, Airbnb support, recruiting, workflow_chain, gift card)."}},"type":"object","title":"UpdateAIEmployeeTriggerRequest","description":"Patch an existing agent trigger. Only supplied fields are written."},"UpgradeOptionType":{"type":"string","enum":["reservation_wide","quantity","date_range"],"title":"UpgradeOptionType","description":"Type of upgrade option for reservation upgrades."},"UpgradePricingType":{"type":"string","enum":["flat_rate","per_hour","gap_night_percent","multi_item"],"title":"UpgradePricingType"},"UpgradeType":{"type":"string","enum":["check_in","check_out","per_reservation","date_based","quantity_based"],"title":"UpgradeType"},"UpsellOfferExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"listing_id":{"type":"string","format":"uuid","title":"Listing Id"},"reservation_id":{"type":"string","format":"uuid","title":"Reservation Id"},"type":{"$ref":"#/components/schemas/UpsellType"},"status":{"$ref":"#/components/schemas/UpsellStatus"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"discount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Discount"},"sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sent At"},"converted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Converted At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"converted":{"type":"boolean","title":"Converted","readOnly":true}},"type":"object","required":["id","listing_id","reservation_id","type","status","start_date","end_date","price","discount","sent_at","created_at","updated_at","converted"],"title":"UpsellOfferExternal"},"UpsellStatus":{"type":"string","enum":["accepted","declined","sent","not_sent","skipped","paused","failed"],"title":"UpsellStatus"},"UpsellType":{"type":"string","enum":["early_checkin","late_checkout","extra_service","reservation_extension"],"title":"UpsellType"},"UpsellUpgradeExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"slug":{"type":"string","title":"Slug"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"upgrade_type":{"$ref":"#/components/schemas/UpgradeType"},"enabled":{"type":"boolean","title":"Enabled"},"pricing_type":{"$ref":"#/components/schemas/UpgradePricingType"},"price":{"type":"number","title":"Price"},"currency":{"type":"string","title":"Currency"},"fixed_hours":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fixed Hours"},"discount_percent":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Discount Percent"},"max_hours_offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Hours Offset"},"unlock_before_checkin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unlock Before Checkin"},"unlocks_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Unlocks At"},"locked":{"type":"boolean","title":"Locked","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","title","slug","description","upgrade_type","enabled","pricing_type","price","currency","fixed_hours","created_at","updated_at"],"title":"UpsellUpgradeExternal"},"UpsellUpgradeListingExternal":{"properties":{"listing_id":{"type":"string","format":"uuid","title":"Listing Id"}},"type":"object","required":["listing_id"],"title":"UpsellUpgradeListingExternal"},"UpsellUpgradeWithListingsExternal":{"properties":{"upgrade":{"$ref":"#/components/schemas/UpsellUpgradeExternal"},"listings":{"items":{"$ref":"#/components/schemas/UpsellUpgradeListingExternal"},"type":"array","title":"Listings"}},"type":"object","required":["upgrade","listings"],"title":"UpsellUpgradeWithListingsExternal"},"UsageAccepted":{"properties":{"accepted":{"type":"integer","title":"Accepted"},"acceptedAccountKeys":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Acceptedaccountkeys"},"skipped":{"items":{"$ref":"#/components/schemas/UsageSkipped"},"type":"array","title":"Skipped"}},"type":"object","required":["accepted"],"title":"UsageAccepted","description":"Response for every write: how many items were stored (0 when throttled), and which.\n\n``accepted`` counts stored items (accounts for reports, day rows for token\ntotals). ``acceptedAccountKeys`` lists each account key with at least one\nstored item; ``skipped`` lists each refused account key once with its\nreason. Both are additive — older clients read ``accepted`` alone."},"UsageEndpointSummary":{"properties":{"path":{"type":"string","title":"Path"},"method":{"type":"string","title":"Method"},"count":{"type":"integer","title":"Count"},"avg_response_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Avg Response Ms"}},"type":"object","required":["path","method","count","avg_response_ms"],"title":"UsageEndpointSummary"},"UsageReportAccount":{"properties":{"accountKey":{"type":"string","format":"uuid","title":"Accountkey"},"label":{"type":"string","maxLength":60,"minLength":1,"title":"Label"},"runtime":{"type":"string","enum":["claude_code","codex"],"title":"Runtime"},"billing":{"type":"string","enum":["subscription","api_key"],"title":"Billing","default":"subscription"},"planLabel":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Planlabel"},"authState":{"type":"string","title":"Authstate","default":"unknown"},"quotaWindows":{"items":{"$ref":"#/components/schemas/QuotaWindowReport"},"type":"array","maxItems":8,"title":"Quotawindows"},"observedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Observedat"}},"type":"object","required":["accountKey","label","runtime"],"title":"UsageReportAccount"},"UsageSeriesPoint":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"count":{"type":"integer","title":"Count"},"status_codes":{"$ref":"#/components/schemas/UsageStatusCounts"}},"type":"object","required":["date","count","status_codes"],"title":"UsageSeriesPoint","description":"A single day bucket in the usage time-series.\n\n``count`` is the total request count for the day (what the FE sparkline\nrenders). ``status_codes`` carries the same breakdown the range-level\n``status_counts`` does, but scoped to the day — handy for future per-day\nerror-rate views even though the current FE only reads ``count``."},"UsageSkipped":{"properties":{"accountKey":{"type":"string","format":"uuid","title":"Accountkey"},"reason":{"type":"string","enum":["not_owned","other_source","throttled","not_reported","out_of_range"],"title":"Reason"}},"type":"object","required":["accountKey","reason"],"title":"UsageSkipped","description":"An account a write did not store, and why.\n\n* ``not_owned`` — another member connected the account (or owns the row).\n* ``other_source`` — a different source (e.g. a desktop session vs the CLI)\n  wrote this machine's row for the account; only that source updates it.\n* ``throttled`` — this machine reported less than 30 s ago.\n* ``not_reported`` — token totals for an account this machine never\n  reported (POST the account in a usage report first).\n* ``out_of_range`` — token totals for a day too far in the past or future."},"UsageStatusCounts":{"properties":{"2xx":{"type":"integer","title":"2Xx","default":0},"4xx":{"type":"integer","title":"4Xx","default":0},"5xx":{"type":"integer","title":"5Xx","default":0},"429":{"type":"integer","title":"429","default":0}},"type":"object","title":"UsageStatusCounts","description":"2xx/4xx/5xx/429 counts for the queried window."},"UsageSummaryResponse":{"properties":{"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"},"endpoints":{"items":{"$ref":"#/components/schemas/UsageEndpointSummary"},"type":"array","title":"Endpoints"},"total_requests":{"type":"integer","title":"Total Requests"},"status_counts":{"$ref":"#/components/schemas/UsageStatusCounts"},"series":{"items":{"$ref":"#/components/schemas/UsageSeriesPoint"},"type":"array","title":"Series"}},"type":"object","required":["start_date","end_date","endpoints","total_requests"],"title":"UsageSummaryResponse"},"UserNotificationSettingsResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"account_id":{"type":"string","format":"uuid","title":"Account Id"},"cleaning_preferences":{"items":{"$ref":"#/components/schemas/CleaningNotificationScope-Output"},"type":"array","title":"Cleaning Preferences"},"task_preferences":{"items":{"$ref":"#/components/schemas/TaskNotificationScope-Output"},"type":"array","title":"Task Preferences"},"message_preferences":{"items":{"$ref":"#/components/schemas/MessageNotificationScope-Output"},"type":"array","title":"Message Preferences"},"reservation_preferences":{"items":{"$ref":"#/components/schemas/ReservationNotificationScope-Output"},"type":"array","title":"Reservation Preferences"},"ai_employee_preferences":{"items":{"$ref":"#/components/schemas/AIEmployeeNotificationScope-Output"},"type":"array","title":"Ai Employee Preferences"},"ai_employee_cadence":{"$ref":"#/components/schemas/AIEmployeeCadence"},"ai_task_cadence":{"anyOf":[{"$ref":"#/components/schemas/AITaskCadence"},{"type":"null"}]},"autopilot_nudge_preferences":{"items":{"$ref":"#/components/schemas/AutopilotNudgeNotificationScope-Output"},"type":"array","title":"Autopilot Nudge Preferences"},"autopilot_booking_preferences":{"items":{"$ref":"#/components/schemas/AutopilotBookingNotificationScope-Output"},"type":"array","title":"Autopilot Booking Preferences"},"cleaning_reminders_enabled":{"type":"boolean","title":"Cleaning Reminders Enabled","default":true},"cleaning_needs_attention_enabled":{"type":"boolean","title":"Cleaning Needs Attention Enabled","default":true},"cleaning_guest_checkout_enabled":{"type":"boolean","title":"Cleaning Guest Checkout Enabled","default":false},"task_reminders_enabled":{"type":"boolean","title":"Task Reminders Enabled","default":false},"task_needs_attention_enabled":{"type":"boolean","title":"Task Needs Attention Enabled","default":true},"meeting_starting_enabled":{"type":"boolean","title":"Meeting Starting Enabled","default":true},"channel_preferences":{"additionalProperties":{"additionalProperties":{"type":"boolean"},"type":"object"},"type":"object","title":"Channel Preferences"},"message_channel_preferences":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Message Channel Preferences"},"escalation_reachability":{"$ref":"#/components/schemas/EscalationReachability"},"category_enabled":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Category Enabled"},"quiet_hours":{"anyOf":[{"$ref":"#/components/schemas/QuietHours"},{"type":"null"}]},"quiet_hours_vip_user_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Quiet Hours Vip User Ids"},"timezone_auto":{"type":"boolean","title":"Timezone Auto","default":true},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"team_chat_email_enabled":{"type":"boolean","title":"Team Chat Email Enabled","default":false},"has_channel_customizations":{"type":"boolean","title":"Has Channel Customizations","default":true},"following_cadence":{"anyOf":[{"$ref":"#/components/schemas/FollowingCadence"},{"type":"null"}]},"unfollow_when_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Unfollow When Done"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"team_chat_push_level":{"$ref":"#/components/schemas/TeamChatPushLevel","default":"all"},"team_chat_notification_model_enabled":{"type":"boolean","title":"Team Chat Notification Model Enabled","default":true},"connected_team_mentions":{"$ref":"#/components/schemas/ConnectedTeamMentions","default":"notify"},"has_connected_teams":{"type":"boolean","title":"Has Connected Teams","default":false},"escalation_ladder_available":{"type":"boolean","title":"Escalation Ladder Available","default":false},"live_activity_preferences":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Live Activity Preferences"},"task_alert_defaults":{"$ref":"#/components/schemas/TaskAlertDefaultsSettings"},"arrivals_scope_tag_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Arrivals Scope Tag Ids"},"arrivals_buzz":{"$ref":"#/components/schemas/ArrivalsBuzz","default":"urgent"},"arrivals_available":{"type":"boolean","title":"Arrivals Available","default":false}},"type":"object","required":["id","user_id","account_id","cleaning_preferences","task_preferences","message_preferences","reservation_preferences","ai_employee_preferences","ai_employee_cadence","autopilot_nudge_preferences","autopilot_booking_preferences","channel_preferences","message_channel_preferences","escalation_reachability","category_enabled","created_at","updated_at"],"title":"UserNotificationSettingsResponse","description":"User notification settings response.\n\n``channel_preferences`` is always the full category × channel matrix\n(stored overrides merged over defaults by the model's hybrid property),\nso clients never need to know the server-side defaults."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookDeliveryExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"event_type":{"type":"string","title":"Event Type"},"status":{"type":"string","title":"Status"},"response_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Response Status"},"attempts":{"type":"integer","title":"Attempts"},"delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","event_type","status","response_status","attempts","delivered_at","created_at"],"title":"WebhookDeliveryExternal","examples":[{"attempts":1,"created_at":"2026-04-12T09:00:00Z","delivered_at":"2026-04-12T09:00:01Z","event_type":"reservation.created","id":"f6a7b8c9-d0e1-4234-8567-890abcdef123","response_status":200,"status":"delivered"}]},"WebhookSubscriptionCreate":{"properties":{"url":{"type":"string","title":"Url","description":"Delivery URL (must be HTTPS)","examples":["https://example.com/webhook"]},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"Event types to subscribe to","examples":[["reservation.created","message.received"]]},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Human-readable description"}},"type":"object","required":["url","events"],"title":"WebhookSubscriptionCreate","examples":[{"description":"Sync new bookings into our CRM","events":["reservation.created"],"url":"https://example.com/hooks/prohost"}]},"WebhookSubscriptionCreated":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"url":{"type":"string","title":"Url"},"events":{"items":{"type":"string"},"type":"array","title":"Events"},"is_active":{"type":"boolean","title":"Is Active"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"connected_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connected From"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"secret":{"type":"string","title":"Secret","description":"HMAC-SHA256 signing secret. Store securely — it will not be shown again."}},"type":"object","required":["id","url","events","is_active","description","created_at","updated_at","secret"],"title":"WebhookSubscriptionCreated","description":"Returned only on creation — includes the signing secret (shown once).","examples":[{"created_at":"2026-04-12T09:00:00Z","description":"Sync new bookings into our CRM","events":["reservation.created"],"id":"e5f6a7b8-c9d0-4123-8456-7890abcdef12","is_active":true,"secret":"whsec_abc123xyz...","updated_at":"2026-04-12T09:00:00Z","url":"https://example.com/hooks/prohost"}]},"WebhookSubscriptionExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"url":{"type":"string","title":"Url"},"events":{"items":{"type":"string"},"type":"array","title":"Events"},"is_active":{"type":"boolean","title":"Is Active"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"connected_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connected From"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","url","events","is_active","description","created_at","updated_at"],"title":"WebhookSubscriptionExternal","examples":[{"created_at":"2026-04-12T09:00:00Z","description":"Sync new bookings into our CRM","events":["reservation.created","message.received"],"id":"e5f6a7b8-c9d0-4123-8456-7890abcdef12","is_active":true,"updated_at":"2026-04-12T09:00:00Z","url":"https://example.com/hooks/prohost"}]},"WebhookSubscriptionUpdate":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"New delivery URL (must be HTTPS)"},"events":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Events","description":"Replacement event-type list"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active","description":"Enable/disable the subscription"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Human-readable description (pass null to clear)"}},"type":"object","title":"WebhookSubscriptionUpdate","description":"PATCH body for ``PATCH /v1/webhooks/{id}``.\n\nEvery field is optional — only fields present in the request are changed\n(the router uses ``model_dump(exclude_unset=True)`` so ``description`` can be\ncleared by explicitly passing ``null``). A new ``url`` is re-validated\n(HTTPS + SSRF guard) exactly like create.","examples":[{"events":["reservation.created","reservation.cancelled"],"is_active":true,"url":"https://example.com/hooks/prohost-v2"}]},"WebhookTestRequest":{"properties":{"url":{"type":"string","title":"Url","description":"URL to send a test webhook to","examples":["https://example.com/webhook"]},"event_type":{"type":"string","title":"Event Type","description":"Event type for the test payload","default":"webhook.verification"}},"type":"object","required":["url"],"title":"WebhookTestRequest","examples":[{"event_type":"webhook.verification","url":"https://example.com/hooks/prohost"}]},"WeeklyReviewCountExternal":{"properties":{"week_start":{"type":"string","format":"date-time","title":"Week Start"},"count":{"type":"integer","title":"Count"},"average_rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average Rating"}},"type":"object","required":["week_start","count"],"title":"WeeklyReviewCountExternal"},"WhatsNewStory":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"edition_tag":{"type":"string","title":"Edition Tag"},"published_at":{"type":"string","format":"date-time","title":"Published At"},"category":{"type":"string","title":"Category"},"surface":{"type":"string","title":"Surface"},"headline":{"type":"string","title":"Headline"},"body_md":{"type":"string","title":"Body Md"},"media_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Media Url"},"deep_link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deep Link"},"is_marquee":{"type":"boolean","title":"Is Marquee"},"workspace_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Workspace Types"},"language":{"type":"string","title":"Language","examples":["en-US"]}},"type":"object","required":["id","edition_tag","published_at","category","surface","headline","body_md","is_marquee","language"],"title":"WhatsNewStory","description":"One published What's New story, its copy in the served locale."},"WhatsNewStoryList":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WhatsNewStory"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"WhatsNewStoryList","description":"A page of published stories, newest first."},"WorkflowExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"enabled":{"type":"boolean","title":"Enabled"},"trigger_type":{"type":"string","title":"Trigger Type"},"trigger_config":{"additionalProperties":true,"type":"object","title":"Trigger Config"},"steps":{"items":{"$ref":"#/components/schemas/WorkflowStepExternal"},"type":"array","title":"Steps","default":[]},"run_count":{"type":"integer","title":"Run Count"},"last_run_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Run At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","enabled","trigger_type","trigger_config","run_count","created_at","updated_at"],"title":"WorkflowExternal"},"WorkflowStepExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"order":{"type":"integer","title":"Order"},"instruction":{"type":"string","title":"Instruction"},"tool_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Name"},"skill_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skill Key"},"delay_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delay Seconds"}},"type":"object","required":["id","order","instruction"],"title":"WorkflowStepExternal"},"_Patch":{"properties":{"ai_muted":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ai Muted"},"is_done":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Done"},"is_starred":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Starred"},"needs_follow_up":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Needs Follow Up"},"autopilot_disabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autopilot Disabled"},"assignee_user_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Assignee User Ids","description":"Who owns these conversations. FULL-ARRAY REPLACE — the ids you pass become the assignee list, so send the complete set; `[]` unassigns everyone. Every id must be a member of the account (AI employees included). Omit the field to leave assignment untouched.","examples":[["b1c2d3e4-a5b6-4789-a012-3456789abcde"]]}},"type":"object","title":"_Patch"},"api_public__schemas__contacts__ContactCreateExternal":{"properties":{"first_name":{"type":"string","title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["first_name"],"title":"ContactCreateExternal"},"api_public__schemas__contacts__ContactExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"first_name":{"type":"string","title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","first_name","created_at","updated_at"],"title":"ContactExternal"},"api_public__schemas__contacts__ContactUpdateExternal":{"properties":{"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"company":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields","description":"Replaces the entire ``custom_fields`` dict on the contact. For partial updates use the batch custom-fields endpoints."}},"type":"object","title":"ContactUpdateExternal","description":"Update an existing contact. All fields optional; only provided fields are written.","examples":[{"company":"Acme Plumbing","phone":"+1-555-0100","role":"plumber"}]},"api_public__schemas__crm__ContactCreateExternal":{"properties":{"name":{"type":"string","minLength":1,"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"type":{"$ref":"#/components/schemas/ContactType","default":"lead"},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","required":["name"],"title":"ContactCreateExternal"},"api_public__schemas__crm__ContactExternal":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"type":{"$ref":"#/components/schemas/ContactType"},"custom_fields":{"additionalProperties":true,"type":"object","title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"},"archived_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Archived At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","type","created_at","updated_at"],"title":"ContactExternal"},"api_public__schemas__crm__ContactUpdateExternal":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"company_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Company Id"},"type":{"anyOf":[{"$ref":"#/components/schemas/ContactType"},{"type":"null"}]},"custom_fields":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Custom Fields"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id"}},"additionalProperties":false,"type":"object","title":"ContactUpdateExternal"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Scoped API key. Create one in your ProhostAI dashboard (Settings → API Keys) and send it in the `X-API-Key` header on every request. An OAuth 2.1 bearer token (see the /oauth/* flow) is also accepted on the same endpoints."}}},"security":[{"ApiKeyAuth":[]},{"HTTPBearer":[]}]}