{"openapi":"3.1.0","info":{"title":"Elsewhere Ventures API","version":"2026-05-05.3","description":"Machine-readable endpoints for public itineraries and trusted bot integrations."},"servers":[{"url":"https://app.elsewhereventures.com"}],"components":{"securitySchemes":{"BotApiKey":{"type":"http","scheme":"bearer","bearerFormat":"BOT_API_KEY"},"ClientApiKey":{"type":"http","scheme":"bearer","bearerFormat":"CLIENT_API_KEY"}},"schemas":{"HealthResponse":{"type":"object","required":["ok","timestamp"],"properties":{"ok":{"type":"boolean"},"timestamp":{"type":"string","format":"date-time"}},"example":{"ok":true,"timestamp":"2026-03-05T19:21:53.000Z"}},"CapabilitiesResponse":{"type":"object","required":["schemaVersion","docs","auth","mcp","endpoints"],"properties":{"schemaVersion":{"type":"string"},"docs":{"type":"object","required":["openapi","llms","llmsFull","mcp"],"properties":{"openapi":{"type":"string","format":"uri"},"llms":{"type":"string","format":"uri"},"llmsFull":{"type":"string","format":"uri"},"mcp":{"type":"string","format":"uri"}}},"auth":{"type":"object","required":["botApiKeyHeader","alternativeBotApiKeyHeader","managedKeysUiPath","keySources","mcpKeyHeader","mcpManagedKeysUiPath"],"properties":{"botApiKeyHeader":{"type":"string"},"alternativeBotApiKeyHeader":{"type":"string"},"managedKeysUiPath":{"type":"string"},"keySources":{"type":"array","items":{"type":"string"}},"mcpKeyHeader":{"type":"string"},"mcpManagedKeysUiPath":{"type":"string"}}},"mcp":{"type":"object","required":["endpoint","transport","readOnly","toolCount"],"properties":{"endpoint":{"type":"string","format":"uri"},"transport":{"type":"string"},"readOnly":{"type":"boolean"},"toolCount":{"type":"integer"}}},"endpoints":{"type":"array","items":{"type":"object","required":["path","methods","auth","cache"],"properties":{"path":{"type":"string"},"methods":{"type":"array","items":{"type":"string","enum":["GET","POST","PUT","DELETE"]}},"auth":{"type":"string","enum":["none","bearer","session"]},"scopes":{"type":"array","items":{"type":"string"}},"cache":{"type":"string"},"notes":{"type":"string"}}}}},"example":{"schemaVersion":"2026-05-05.3","docs":{"openapi":"https://app.elsewhereventures.com/api/openapi","llms":"https://app.elsewhereventures.com/llms.txt","llmsFull":"https://app.elsewhereventures.com/llms-full.txt","mcp":"https://app.elsewhereventures.com/api/v1/mcp"},"auth":{"botApiKeyHeader":"Authorization: Bearer <BOT_API_KEY>","alternativeBotApiKeyHeader":"X-API-Key: <BOT_API_KEY>","managedKeysUiPath":"/settings","keySources":["managed key","BOT_API_KEYS env"],"mcpKeyHeader":"Authorization: Bearer <CLIENT_API_KEY>","mcpManagedKeysUiPath":"/clients/{clientId}"},"mcp":{"endpoint":"https://app.elsewhereventures.com/api/v1/mcp","transport":"streamable-http","readOnly":true,"toolCount":17},"endpoints":[{"path":"/api/health","methods":["GET"],"auth":"none","cache":"no-store, max-age=0"},{"path":"/api/v1/bot/events","methods":["GET"],"auth":"bearer","scopes":["events.read","events.*"],"cache":"private, max-age=15, stale-while-revalidate=30"}]}},"BotWhoAmIResponse":{"type":"object","required":["schemaVersion","requestId","bot"],"properties":{"schemaVersion":{"type":"string"},"requestId":{"type":"string"},"bot":{"type":"object","required":["name","source","scopes"],"properties":{"name":{"type":"string"},"source":{"type":"string","enum":["env","db"]},"advisorId":{"type":"string","nullable":true},"keyId":{"type":"string","nullable":true},"scopes":{"type":"array","items":{"type":"string"}}}}},"example":{"schemaVersion":"2026-05-05.3","requestId":"req_01HZY7M90V6WQ0RF6A7M2Q7X0N","bot":{"name":"Zapier Sync","source":"db","advisorId":"advisor_123","keyId":"bak_456","scopes":["events.read","export.read"]}}},"McpDiscoveryResponse":{"type":"object","required":["schemaVersion","name","version","endpoint","transport","authentication","readOnly","toolCount","tools","documentation","configurationExample"],"properties":{"schemaVersion":{"type":"string"},"name":{"type":"string"},"version":{"type":"string"},"endpoint":{"type":"string","format":"uri"},"transport":{"type":"string"},"authentication":{"type":"object","required":["type","header","tokenKind","managedKeysUiPath"],"properties":{"type":{"type":"string"},"header":{"type":"string"},"tokenKind":{"type":"string"},"managedKeysUiPath":{"type":"string"}}},"readOnly":{"type":"boolean"},"toolCount":{"type":"integer"},"tools":{"type":"array","items":{"type":"string"}},"documentation":{"type":"object","required":["openapi","capabilities","llms","llmsFull"],"properties":{"openapi":{"type":"string","format":"uri"},"capabilities":{"type":"string","format":"uri"},"llms":{"type":"string","format":"uri"},"llmsFull":{"type":"string","format":"uri"}}},"configurationExample":{"type":"object","required":["claudeDesktop"],"properties":{"claudeDesktop":{"type":"string"}}}},"example":{"schemaVersion":"2026-05-05.3","name":"elsewhere-ventures","version":"2.1.0","endpoint":"https://app.elsewhereventures.com/api/v1/mcp","transport":"streamable-http","authentication":{"type":"bearer","header":"Authorization: Bearer <CLIENT_API_KEY>","tokenKind":"client_api_key","managedKeysUiPath":"/clients/{clientId}"},"readOnly":true,"toolCount":17,"tools":["whoami","list_trips","trip_details","trip_itinerary","list_invoices","list_contacts","trip_countdown","trip_summary","search_trips","payment_history","travel_stats","trip_compare","list_gifts","get_gift","create_gift","redeem_gift","extend_gift"],"documentation":{"openapi":"https://app.elsewhereventures.com/api/openapi","capabilities":"https://app.elsewhereventures.com/api/v1/capabilities","llms":"https://app.elsewhereventures.com/llms.txt","llmsFull":"https://app.elsewhereventures.com/llms-full.txt"},"configurationExample":{"claudeDesktop":"{\n  \"mcpServers\": {\n    \"elsewhere-ventures\": {\n      \"url\": \"https://app.elsewhereventures.com/api/v1/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer <CLIENT_API_KEY>\"\n      }\n    }\n  }\n}"}}},"ApiError":{"type":"object","required":["code","message","retryable","requestId"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"},"requestId":{"type":"string"}},"example":{"code":"INVALID_QUERY","message":"Query parameter \"cursor\" is invalid.","retryable":false,"requestId":"req_01HZY7M90V6WQ0RF6A7M2Q7X0N"}},"EventFeedResponse":{"type":"object","required":["schemaVersion","requestId","since","generatedAt","count","hasMore","nextCursor","links","events"],"properties":{"schemaVersion":{"type":"string"},"requestId":{"type":"string"},"since":{"type":"string","format":"date-time"},"generatedAt":{"type":"string","format":"date-time"},"count":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true},"links":{"type":"object","properties":{"self":{"type":"string","format":"uri"},"next":{"type":"string","format":"uri","nullable":true}}},"events":{"type":"array","items":{"type":"object","required":["id","type","occurredAt","tripId"],"properties":{"id":{"type":"string","description":"Composite event ID: {type}:{entityId}:{timestamp}"},"type":{"type":"string","enum":["trip.updated","expense.changed","payment.changed","points.changed","commission.changed"]},"occurredAt":{"type":"string","format":"date-time"},"tripId":{"type":"string"},"tripCode":{"type":"string"},"tripName":{"type":"string"},"status":{"type":"string"},"advisorId":{"type":"string"},"expenseId":{"type":"string"},"expenseCode":{"type":"string"},"paymentId":{"type":"string"},"paymentCode":{"type":"string"},"pointsId":{"type":"string"},"pointsCode":{"type":"string"},"commissionId":{"type":"string"},"commissionCode":{"type":"string"},"amount":{"type":"number","description":"Monetary amount (expense/payment events)"},"currency":{"type":"string"},"pointsUsed":{"type":"integer","description":"Points quantity (points events)"},"program":{"type":"string","description":"Loyalty program name (points events)"}},"description":"Event fields vary by type. Only tripId and type are present on all events."}}},"example":{"schemaVersion":"2026-05-05.3","requestId":"req_01HZY7M90V6WQ0RF6A7M2Q7X0N","since":"2026-03-05T00:00:00.000Z","generatedAt":"2026-03-05T19:21:53.000Z","count":1,"hasMore":false,"nextCursor":null,"links":{"self":"https://app.elsewhereventures.com/api/v1/bot/events?since=2026-03-05T00%3A00%3A00.000Z&limit=1","next":null},"events":[{"id":"expense.changed:exp_123:2026-03-05T16:40:00.000Z","type":"expense.changed","occurredAt":"2026-03-05T16:40:00.000Z","tripId":"trip_123","expenseId":"exp_123","expenseCode":"EXP-0012","amount":420.75,"currency":"USD"}]}},"TripsExportResponse":{"type":"object","required":["schemaVersion","requestId","generatedAt","count","hasMore","nextCursor","links","trips"],"properties":{"schemaVersion":{"type":"string"},"requestId":{"type":"string"},"generatedAt":{"type":"string","format":"date-time"},"count":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true},"links":{"type":"object","properties":{"self":{"type":"string","format":"uri"},"next":{"type":"string","format":"uri","nullable":true}}},"trips":{"type":"array","items":{"type":"object","required":["id","tripCode","tripName","advisorId","primaryClientId","status","startDate","endDate","updatedAt","counts"],"properties":{"id":{"type":"string"},"tripCode":{"type":"string"},"tripLabel":{"type":"string","nullable":true},"tripName":{"type":"string"},"tripMode":{"type":"string","enum":["broadcast","hosted"],"description":"broadcast = group event (shared link), hosted = guest management enabled"},"advisorId":{"type":"string"},"primaryClientId":{"type":"string"},"status":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"counts":{"type":"object","properties":{"itineraryItems":{"type":"integer"},"expenses":{"type":"integer"},"points":{"type":"integer"},"payments":{"type":"integer"},"commissions":{"type":"integer"},"additionalClients":{"type":"integer"}}},"splitClients":{"type":"array","items":{"type":"object","properties":{"clientId":{"type":"string"},"splitPercent":{"type":"number"}}}}}}}},"example":{"schemaVersion":"2026-05-05.3","requestId":"req_01HZY7M90V6WQ0RF6A7M2Q7X0N","generatedAt":"2026-03-05T19:21:53.000Z","count":1,"hasMore":false,"nextCursor":null,"links":{"self":"https://app.elsewhereventures.com/api/v1/bot/export/trips?limit=1","next":null},"trips":[{"id":"trip_123","tripCode":"3.6.26-B2","tripLabel":"NYC Birthday","tripName":"New York Weekender","advisorId":"advisor_123","primaryClientId":"client_123","status":"In Progress","startDate":"2026-03-06T00:00:00.000Z","endDate":"2026-03-11T00:00:00.000Z","updatedAt":"2026-03-05T17:10:00.000Z","counts":{"itineraryItems":18,"expenses":24,"points":2,"payments":3,"commissions":4,"additionalClients":1},"splitClients":[{"clientId":"client_456","splitPercent":0.4}]}]}},"GuestRsvpRequest":{"type":"object","required":["tripItemId","clientContactId","response"],"properties":{"tripItemId":{"type":"string","description":"ID of the optional trip item to RSVP for."},"clientContactId":{"type":"string","description":"Client contact ID for the responding guest."},"response":{"type":"string","enum":["yes","no","maybe"],"description":"Guest's RSVP response."}}},"GuestRsvpResponse":{"type":"object","required":["success","response"],"properties":{"success":{"type":"boolean"},"response":{"type":"string","enum":["yes","no","maybe"]}}},"GuestPreferencesRequest":{"type":"object","required":["clientContactId"],"properties":{"clientContactId":{"type":"string","description":"Client contact ID to update."},"dietaryRestrictions":{"type":"string","nullable":true,"description":"Dietary restrictions or requirements."},"notes":{"type":"string","nullable":true,"description":"Additional preferences or notes for the trip."}}},"GuestPreferencesResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}},"GuestIntakeRequest":{"type":"object","required":["firstName","lastName","email"],"properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string","nullable":true},"dietaryRestrictions":{"type":"string","nullable":true},"passportNumber":{"type":"string","nullable":true},"passportExpiry":{"type":"string","nullable":true,"description":"Passport expiry date string submitted by the guest."},"nationality":{"type":"string","nullable":true},"dateOfBirth":{"type":"string","nullable":true,"description":"Date of birth string submitted by the guest."},"knownTraveler":{"type":"string","nullable":true},"globalEntry":{"type":"string","nullable":true},"loyaltyPrograms":{"type":"string","nullable":true},"customAnswers":{"type":"object","additionalProperties":{"type":"string"},"nullable":true}}},"GuestIntakeResponse":{"type":"object","required":["success","clientContactId"],"properties":{"success":{"type":"boolean"},"clientContactId":{"type":"string"}}},"TripPoll":{"type":"object","required":["id","type","prompt","status"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["choice","text","slot_signup"],"description":"Poll answer type. choice = single option, text = free response, slot_signup = option + HH:MM time within a configured window."},"prompt":{"type":"string"},"status":{"type":"string","enum":["active","closed"]},"options":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Choice/slot_signup options offered to guests."},"linkUrl":{"type":"string","format":"uri","nullable":true,"description":"Optional reference link (e.g., menu PDF) shown to guests as a button."},"linkLabel":{"type":"string","nullable":true,"maxLength":80,"description":"Display label for the reference link button."},"slotWindow":{"type":"object","nullable":true,"description":"Configured time window for slot_signup polls. Required when type=slot_signup.","required":["start","end","stepMinutes"],"properties":{"start":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$","description":"Window start (HH:MM, 24h)."},"end":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$","description":"Window end (HH:MM, 24h)."},"stepMinutes":{"type":"integer","enum":[5,10,15,20,30,60],"description":"Spacing between selectable slots."}}}}},"TripPollResponse":{"type":"object","required":["id","pollId","respondedAt"],"properties":{"id":{"type":"string"},"pollId":{"type":"string"},"answer":{"type":"string","nullable":true},"answerOption":{"type":"string","nullable":true,"description":"Selected option for slot_signup polls."},"answerTime":{"type":"string","nullable":true,"pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$","description":"Selected HH:MM time for slot_signup polls."},"respondedAt":{"type":"string","format":"date-time"}}},"GuestPollRespondRequest":{"type":"object","description":"Body for choice/text polls: { answer, tripId? }. Body for slot_signup polls: { option, time, tripId? }. tripId is required on the personal-token endpoint and ignored on the broadcast endpoint.","properties":{"answer":{"type":"string","nullable":true,"description":"Choice option (must match an offered option) or text response."},"option":{"type":"string","nullable":true,"description":"Selected option for slot_signup polls."},"time":{"type":"string","nullable":true,"pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$","description":"Selected HH:MM time for slot_signup polls."},"tripId":{"type":"string","nullable":true}}},"GuestPollRespondResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"},"response":{"$ref":"#/components/schemas/TripPollResponse"}}},"DeleteMutationData":{"type":"object","required":["id","deleted"],"properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"example":{"id":"trip_123","deleted":true}},"TripClientSplitRequest":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string"},"splitPercent":{"type":"number","minimum":0,"maximum":100,"description":"Client share percentage in whole-number form. Use all 0 values to request equal split behavior."}},"example":{"clientId":"client_456","splitPercent":40}},"TripMutationData":{"type":"object","required":["id","tripCode","tripName"],"properties":{"id":{"type":"string"},"tripCode":{"type":"string"},"tripName":{"type":"string"},"tripMode":{"type":"string","enum":["broadcast","hosted"]},"status":{"type":"string","enum":["Planned","In Progress","Complete","Cancelled"]}},"example":{"id":"trip_123","tripCode":"TR-000123","tripName":"New York Weekender","tripMode":"broadcast","status":"Planned"}},"TripCreateRequest":{"type":"object","required":["clientId","tripName","startDate","endDate"],"properties":{"clientId":{"type":"string"},"tripClients":{"type":"array","items":{"$ref":"#/components/schemas/TripClientSplitRequest"},"description":"Optional participant list for split trips. The primary client will be injected automatically if omitted."},"tripName":{"type":"string"},"tripMode":{"type":"string","enum":["broadcast","hosted"],"description":"broadcast (group event) or hosted (guest management). Defaults to broadcast."},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"feePlan":{"type":"string","enum":["Percent","Flat","Mixed","None"]},"feePercent":{"type":"number","minimum":0,"maximum":100},"feeFlat":{"type":"number","minimum":0},"feeMinimum":{"type":"number","minimum":0},"status":{"type":"string","enum":["Planned","In Progress","Complete","Cancelled"]},"tripLabel":{"type":"string"},"location":{"type":"string"},"notes":{"type":"string"}}},"TripUpdateRequest":{"type":"object","properties":{"clientId":{"type":"string"},"tripClients":{"type":"array","items":{"$ref":"#/components/schemas/TripClientSplitRequest"},"description":"Optional participant list for split trips. When supplied, all existing trip-client rows are replaced."},"tripName":{"type":"string"},"tripMode":{"type":"string","enum":["broadcast","hosted"],"description":"Can only upgrade from broadcast to hosted, not downgrade."},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"feePlan":{"type":"string","enum":["Percent","Flat","Mixed","None"]},"feePercent":{"type":"number","minimum":0,"maximum":100},"feeFlat":{"type":"number","minimum":0},"feeMinimum":{"type":"number","minimum":0},"status":{"type":"string","enum":["Planned","In Progress","Complete","Cancelled"]},"tripLabel":{"type":"string"},"location":{"type":"string"},"notes":{"type":"string"}}},"ExpenseMutationData":{"type":"object","required":["id","expenseCode"],"properties":{"id":{"type":"string"},"expenseCode":{"type":"string"}},"example":{"id":"exp_123","expenseCode":"E-0042"}},"ExpenseCreateRequest":{"type":"object","required":["tripId","date","vendor","category","amount"],"properties":{"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string","enum":["Flight","Hotel","Villa","Car","Tour/Guide","Food","Activities","Insurance","Visa/Entry","Misc","Transportation","Private Transfer","Rail","Yacht","Charter / Aviation","Incidentals","Gratuities","Tips","Dining","Nightclub/Bar","Spa/Wellness","Shopping","Event Tickets","Security","Medical","Concierge","Taxes/Fees"]},"description":{"type":"string"},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"amount":{"type":"number","exclusiveMinimum":0},"paidBy":{"type":"string","enum":["Client","Advisor","Split"]},"ultimatelyResponsible":{"type":"string","enum":["Client","Advisor","Split"]},"clientPercent":{"type":"number","minimum":0,"maximum":100},"assignments":{"type":"array","description":"Optional per-client allocation. Pass one entry per client with a relative weight (defaults to 1). Weights are normalized at read time — [1,1,1] means equal thirds, [2,1,1] means 50/25/25. Omit or pass an empty array to fall back to the trip's primary client (for Client) or trip-level split percentages (for Split).","items":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string"},"weight":{"type":"number","exclusiveMinimum":0,"default":1}}}},"retailAmount":{"type":"number","minimum":0},"notes":{"type":"string"},"isCommissionable":{"type":"boolean"},"commissionType":{"type":"string","enum":["percent","flat"],"nullable":true},"commissionValue":{"type":"number","minimum":0}}},"ExpenseUpdateRequest":{"type":"object","properties":{"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string","enum":["Flight","Hotel","Villa","Car","Tour/Guide","Food","Activities","Insurance","Visa/Entry","Misc","Transportation","Private Transfer","Rail","Yacht","Charter / Aviation","Incidentals","Gratuities","Tips","Dining","Nightclub/Bar","Spa/Wellness","Shopping","Event Tickets","Security","Medical","Concierge","Taxes/Fees"]},"description":{"type":"string"},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"amount":{"type":"number","exclusiveMinimum":0},"paidBy":{"type":"string","enum":["Client","Advisor","Split"]},"ultimatelyResponsible":{"type":"string","enum":["Client","Advisor","Split"]},"clientPercent":{"type":"number","minimum":0,"maximum":100},"assignments":{"type":"array","description":"Optional per-client allocation. Pass one entry per client with a relative weight (defaults to 1). Weights are normalized at read time — [1,1,1] means equal thirds, [2,1,1] means 50/25/25. Omit or pass an empty array to fall back to the trip's primary client (for Client) or trip-level split percentages (for Split).","items":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string"},"weight":{"type":"number","exclusiveMinimum":0,"default":1}}}},"retailAmount":{"type":"number","minimum":0,"nullable":true},"notes":{"type":"string"},"isCommissionable":{"type":"boolean"},"commissionType":{"type":"string","enum":["percent","flat"],"nullable":true},"commissionValue":{"type":"number","minimum":0,"nullable":true}}},"BulkExpenseItemRequest":{"type":"object","required":["date","vendor","category","amount"],"properties":{"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string","enum":["Flight","Hotel","Villa","Car","Tour/Guide","Food","Activities","Insurance","Visa/Entry","Misc","Transportation","Private Transfer","Rail","Yacht","Charter / Aviation","Incidentals","Gratuities","Tips","Dining","Nightclub/Bar","Spa/Wellness","Shopping","Event Tickets","Security","Medical","Concierge","Taxes/Fees"]},"description":{"type":"string"},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"amount":{"type":"number","exclusiveMinimum":0},"paidBy":{"type":"string","enum":["Client","Advisor","Split"]},"ultimatelyResponsible":{"type":"string","enum":["Client","Advisor","Split"]},"clientPercent":{"type":"number","minimum":0,"maximum":100},"assignments":{"type":"array","description":"Optional per-client allocation. Pass one entry per client with a relative weight (defaults to 1). Weights are normalized at read time — [1,1,1] means equal thirds, [2,1,1] means 50/25/25. Omit or pass an empty array to fall back to the trip's primary client (for Client) or trip-level split percentages (for Split).","items":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string"},"weight":{"type":"number","exclusiveMinimum":0,"default":1}}}},"retailAmount":{"type":"number","minimum":0},"notes":{"type":"string"},"isCommissionable":{"type":"boolean"},"commissionType":{"type":"string","enum":["percent","flat"],"nullable":true},"commissionValue":{"type":"number","minimum":0}}},"BulkExpenseCreateRequest":{"type":"object","required":["tripId","expenses"],"properties":{"tripId":{"type":"string"},"expenses":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/BulkExpenseItemRequest"}}}},"BulkExpenseMutationData":{"type":"object","required":["created","count"],"properties":{"created":{"type":"array","items":{"$ref":"#/components/schemas/ExpenseMutationData"}},"count":{"type":"integer"}},"example":{"created":[{"id":"exp_123","expenseCode":"E-0042"},{"id":"exp_124","expenseCode":"E-0043"}],"count":2}},"PaymentMutationData":{"type":"object","required":["id","paymentCode"],"properties":{"id":{"type":"string"},"paymentCode":{"type":"string"}},"example":{"id":"pay_123","paymentCode":"P-0102"}},"PaymentCreateRequest":{"type":"object","required":["tripId","date","amount","payer"],"properties":{"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"method":{"type":"string","enum":["ACH","Wire","Zelle","Credit Card","Cash","Check","Other"]},"type":{"type":"string","enum":["Deposit","Reimbursement","Fee","Final","Refund/Chargeback","Other"]},"payer":{"type":"string"},"clientId":{"type":"string","nullable":true},"notes":{"type":"string"}}},"PaymentUpdateRequest":{"type":"object","properties":{"date":{"type":"string","format":"date-time"},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"method":{"type":"string","enum":["ACH","Wire","Zelle","Credit Card","Cash","Check","Other"]},"type":{"type":"string","enum":["Deposit","Reimbursement","Fee","Final","Refund/Chargeback","Other"]},"payer":{"type":"string"},"clientId":{"type":"string","nullable":true},"notes":{"type":"string"}}},"BulkPaymentItemRequest":{"type":"object","required":["date","amount","payer"],"properties":{"date":{"type":"string","format":"date-time"},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"method":{"type":"string","enum":["ACH","Wire","Zelle","Credit Card","Cash","Check","Other"]},"type":{"type":"string","enum":["Deposit","Reimbursement","Fee","Final","Refund/Chargeback","Other"]},"payer":{"type":"string"},"clientId":{"type":"string","nullable":true},"notes":{"type":"string"}}},"BulkPaymentCreateRequest":{"type":"object","required":["tripId","payments"],"properties":{"tripId":{"type":"string"},"payments":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/BulkPaymentItemRequest"}}}},"BulkPaymentMutationData":{"type":"object","required":["created","count"],"properties":{"created":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMutationData"}},"count":{"type":"integer"}},"example":{"created":[{"id":"pay_123","paymentCode":"P-0102"},{"id":"pay_124","paymentCode":"P-0103"}],"count":2}},"CommissionMutationData":{"type":"object","required":["id","commissionCode"],"properties":{"id":{"type":"string"},"commissionCode":{"type":"string"}},"example":{"id":"com_123","commissionCode":"C-0007"}},"CommissionCreateRequest":{"type":"object","required":["tripId","date","vendor","category","commissionBaseAmt","commissionRate"],"properties":{"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string"},"description":{"type":"string"},"commissionBaseAmt":{"type":"number","exclusiveMinimum":0},"commissionRate":{"type":"number","minimum":0,"maximum":100},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"status":{"type":"string","enum":["Expected","Invoiced","Received","Not Applicable"]},"expectedPayDate":{"type":"string","format":"date-time"},"receivedDate":{"type":"string","format":"date-time"},"notes":{"type":"string"}}},"CommissionUpdateRequest":{"type":"object","properties":{"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string"},"description":{"type":"string"},"commissionBaseAmt":{"type":"number","exclusiveMinimum":0},"commissionRate":{"type":"number","minimum":0,"maximum":100},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"status":{"type":"string","enum":["Expected","Invoiced","Received","Not Applicable"]},"expectedPayDate":{"type":"string","format":"date-time","nullable":true},"receivedDate":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string"}}},"PointsMutationData":{"type":"object","required":["id","pointsCode"],"properties":{"id":{"type":"string"},"pointsCode":{"type":"string"}},"example":{"id":"pts_123","pointsCode":"PT-0015"}},"PointsCreateRequest":{"type":"object","required":["tripId","date","program","pointsUsed"],"properties":{"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"program":{"type":"string"},"pointsUsed":{"type":"integer","minimum":1},"taxesAndFees":{"type":"number","minimum":0},"retailCashPrice":{"type":"number","minimum":0},"description":{"type":"string"}}},"PointsUpdateRequest":{"type":"object","properties":{"date":{"type":"string","format":"date-time"},"program":{"type":"string"},"pointsUsed":{"type":"integer","minimum":1},"taxesAndFees":{"type":"number","minimum":0},"retailCashPrice":{"type":"number","minimum":0,"nullable":true},"description":{"type":"string"}}},"TripListItem":{"type":"object","required":["id","tripCode","tripName","status","startDate","endDate","createdAt"],"properties":{"id":{"type":"string"},"tripCode":{"type":"string"},"tripLabel":{"type":"string","nullable":true},"tripName":{"type":"string"},"primaryClientId":{"type":"string"},"status":{"type":"string","enum":["Planned","In Progress","Complete","Cancelled"]},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"feePlan":{"type":"string","enum":["Percent","Flat","Mixed","None"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ExpenseListItem":{"type":"object","required":["id","expenseCode","tripId","date","vendor","category","amount","currency"],"properties":{"id":{"type":"string"},"expenseCode":{"type":"string"},"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string","enum":["Flight","Hotel","Villa","Car","Tour/Guide","Food","Activities","Insurance","Visa/Entry","Misc","Transportation","Private Transfer","Rail","Yacht","Charter / Aviation","Incidentals","Gratuities","Tips","Dining","Nightclub/Bar","Spa/Wellness","Shopping","Event Tickets","Security","Medical","Concierge","Taxes/Fees"]},"description":{"type":"string","nullable":true},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"amount":{"type":"number"},"paidBy":{"type":"string","enum":["Client","Advisor","Split"]},"ultimatelyResponsible":{"type":"string","enum":["Client","Advisor","Split"]},"clientPercent":{"type":"number"},"assignments":{"type":"array","description":"Optional per-client allocation. Pass one entry per client with a relative weight (defaults to 1). Weights are normalized at read time — [1,1,1] means equal thirds, [2,1,1] means 50/25/25. Omit or pass an empty array to fall back to the trip's primary client (for Client) or trip-level split percentages (for Split).","items":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string"},"weight":{"type":"number","exclusiveMinimum":0,"default":1}}}},"isCommissionable":{"type":"boolean"}}},"PaymentListItem":{"type":"object","required":["id","paymentCode","tripId","date","amount","currency"],"properties":{"id":{"type":"string"},"paymentCode":{"type":"string"},"tripId":{"type":"string"},"clientId":{"type":"string"},"date":{"type":"string","format":"date-time"},"amount":{"type":"number"},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"method":{"type":"string","enum":["ACH","Wire","Zelle","Credit Card","Cash","Check","Other"]},"type":{"type":"string","enum":["Deposit","Reimbursement","Fee","Final","Refund/Chargeback","Other"]},"payer":{"type":"string"},"notes":{"type":"string","nullable":true}}},"CommissionListItem":{"type":"object","required":["id","commissionCode","tripId","date","vendor","commissionBaseAmt","commissionRate"],"properties":{"id":{"type":"string"},"commissionCode":{"type":"string"},"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"vendor":{"type":"string"},"category":{"type":"string"},"description":{"type":"string","nullable":true},"commissionBaseAmt":{"type":"number"},"commissionRate":{"type":"number"},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"status":{"type":"string","enum":["Expected","Invoiced","Received","Not Applicable"]},"expectedPayDate":{"type":"string","format":"date-time","nullable":true},"receivedDate":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true}}},"PointsListItem":{"type":"object","required":["id","pointsCode","tripId","date","program","pointsUsed"],"properties":{"id":{"type":"string"},"pointsCode":{"type":"string"},"tripId":{"type":"string"},"date":{"type":"string","format":"date-time"},"program":{"type":"string"},"pointsUsed":{"type":"integer"},"taxesAndFees":{"type":"number","nullable":true},"retailCashPrice":{"type":"number","nullable":true},"notes":{"type":"string","nullable":true}}},"GiftListItem":{"type":"object","required":["id","code","status","type","currency","expiresAt","createdAt"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string","enum":["CREATED","DELIVERED","REDEEMED","TRIP_LINKED","CELEBRATED","NEEDS_ATTENTION"]},"type":{"type":"string","enum":["FIXED","OPEN_ENDED"]},"amount":{"type":"number","nullable":true},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"revealAmount":{"type":"boolean"},"trustedGift":{"type":"boolean"},"gifterId":{"type":"string"},"gifterName":{"type":"string"},"recipientName":{"type":"string","nullable":true},"recipientEmail":{"type":"string","nullable":true},"recipientPhone":{"type":"string","nullable":true},"recipientClientId":{"type":"string","nullable":true},"tripId":{"type":"string","nullable":true},"expiresAt":{"type":"string","format":"date-time"},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"redeemedAt":{"type":"string","format":"date-time","nullable":true},"celebrationSentAt":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"GiftDetailData":{"type":"object","required":["id","code","status","type","currency","gifterId","gifterName","expiresAt","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string","enum":["CREATED","DELIVERED","REDEEMED","TRIP_LINKED","CELEBRATED","NEEDS_ATTENTION"]},"type":{"type":"string","enum":["FIXED","OPEN_ENDED"]},"amount":{"type":"number","nullable":true},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"revealAmount":{"type":"boolean"},"trustedGift":{"type":"boolean"},"customCode":{"type":"boolean"},"gifterId":{"type":"string"},"gifterName":{"type":"string"},"recipientName":{"type":"string","nullable":true},"recipientEmail":{"type":"string","nullable":true},"recipientPhone":{"type":"string","nullable":true},"recipientClientId":{"type":"string","nullable":true},"recipientClientName":{"type":"string","nullable":true},"tripId":{"type":"string","nullable":true},"expiresAt":{"type":"string","format":"date-time"},"extendedAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"redeemedAt":{"type":"string","format":"date-time","nullable":true},"celebrationSentAt":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"GiftCreateRequest":{"type":"object","required":["gifterId","type"],"properties":{"gifterId":{"type":"string"},"recipientName":{"type":"string"},"type":{"type":"string","enum":["FIXED","OPEN_ENDED"]},"amount":{"type":"number","exclusiveMinimum":0,"nullable":true},"currency":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY","CHF","MXN","BRL","NZD","SGD","HKD","THB","INR","AED","ZAR","SEK","NOK","DKK","ILS"]},"revealAmount":{"type":"boolean"},"trustedGift":{"type":"boolean"},"customCode":{"type":"string"},"notes":{"type":"string"}}},"GiftCreateData":{"type":"object","required":["id","code"],"properties":{"id":{"type":"string"},"code":{"type":"string"}}},"GiftUpdateRequest":{"type":"object","properties":{"status":{"type":"string","enum":["CREATED","DELIVERED","REDEEMED","TRIP_LINKED","CELEBRATED","NEEDS_ATTENTION"]},"recipientName":{"type":"string"},"recipientEmail":{"type":"string","format":"email","nullable":true},"recipientPhone":{"type":"string","nullable":true},"tripId":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"expiresAt":{"type":"string","format":"date-time"}}},"GiftMutationData":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"GiftRedeemRequest":{"type":"object","properties":{"recipientName":{"type":"string"},"recipientEmail":{"type":"string","format":"email"},"recipientPhone":{"type":"string"},"notes":{"type":"string"}}},"GiftRedeemData":{"type":"object","required":["id","code","status"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string","enum":["REDEEMED"]}}},"GiftCelebrateRequest":{"type":"object","properties":{"destination":{"type":"string"}}},"GiftCelebrateData":{"type":"object","required":["id","code","status","celebrationSentAt","destination"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string","enum":["CELEBRATED"]},"celebrationSentAt":{"type":"string","format":"date-time"},"destination":{"type":"string"}}},"WebhookEndpointListItem":{"type":"object","required":["id","url","secretPreview","events","active","createdAt","counts","latestDelivery"],"properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"secretPreview":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"counts":{"type":"object","required":["delivered","pending","failed","paused"],"properties":{"delivered":{"type":"integer"},"pending":{"type":"integer"},"failed":{"type":"integer"},"paused":{"type":"integer"}}},"latestDelivery":{"oneOf":[{"type":"object","required":["status","createdAt","lastHttpStatus"],"properties":{"status":{"type":"string","enum":["pending","delivered","failed","paused"]},"createdAt":{"type":"string","format":"date-time"},"lastHttpStatus":{"type":"integer","nullable":true}}},{"type":"null"}]}}},"WebhookListData":{"type":"object","required":["endpoints","stats"],"properties":{"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointListItem"}},"stats":{"type":"object","required":["activeEndpoints","pendingCount","failedCount"],"properties":{"activeEndpoints":{"type":"integer"},"pendingCount":{"type":"integer"},"failedCount":{"type":"integer"}}}}},"WebhookCreateRequest":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","minItems":1,"items":{"type":"string"}}}},"WebhookCreateData":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpointListItem"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string"}}}]},"WebhookUpdateRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","minItems":1,"items":{"type":"string"}},"active":{"type":"boolean"}},"minProperties":1},"WebhookDeliveryListItem":{"type":"object","required":["id","endpointId","endpointUrl","endpointActive","event","status","attemptCount","createdAt"],"properties":{"id":{"type":"string"},"endpointId":{"type":"string","nullable":true},"endpointUrl":{"type":"string","format":"uri"},"endpointActive":{"type":"boolean"},"event":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed","paused"]},"attemptCount":{"type":"integer"},"lastHttpStatus":{"type":"integer","nullable":true},"lastError":{"type":"string","nullable":true},"nextAttemptAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"responseSnippet":{"type":"string","nullable":true}}},"WebhookDeliveriesData":{"type":"object","required":["deliveries"],"properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryListItem"}}}},"WebhookReplayData":{"type":"object","required":["sourceDeliveryId","replayDeliveryId","status","nextAttemptAt"],"properties":{"sourceDeliveryId":{"type":"string"},"replayDeliveryId":{"type":"string"},"status":{"type":"string","enum":["delivered","retrying","failed","paused","skipped","missing"]},"nextAttemptAt":{"type":"string","format":"date-time","nullable":true}}},"ClientApiKeyListItem":{"type":"object","required":["id","name","createdAt","lastUsedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true}}},"ClientApiKeyListData":{"type":"object","required":["clientId","keys"],"properties":{"clientId":{"type":"string"},"keys":{"type":"array","items":{"$ref":"#/components/schemas/ClientApiKeyListItem"}}}},"ClientApiKeyCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"ClientApiKeyCreateData":{"type":"object","required":["id","name","apiKey","createdAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"apiKey":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"ClientApiKeyRevokeData":{"type":"object","required":["id","revoked"],"properties":{"id":{"type":"string"},"revoked":{"type":"boolean","const":true}}}}},"paths":{"/api/health":{"get":{"summary":"Health check","responses":{"200":{"description":"Service healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/capabilities":{"get":{"summary":"Machine-readable API capabilities and auth model","responses":{"200":{"description":"Capabilities payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilitiesResponse"}}}},"304":{"description":"Not modified"}}}},"/api/v1/public/trips/{shareToken}/itinerary":{"get":{"summary":"Public shared itinerary (read-only)","parameters":[{"in":"path","name":"shareToken","required":true,"schema":{"type":"string"}},{"in":"header","name":"If-None-Match","required":false,"schema":{"type":"string"}},{"in":"header","name":"Origin","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Itinerary payload"},"304":{"description":"Not modified"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/public/trips/{shareToken}/rsvp":{"post":{"summary":"Guest RSVP for an optional trip activity","description":"Unauthenticated endpoint gated by share token. Allows a named guest to RSVP for an optional itinerary item.","parameters":[{"in":"path","name":"shareToken","required":true,"schema":{"type":"string"},"description":"Trip share token."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestRsvpRequest"}}}},"responses":{"200":{"description":"RSVP recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestRsvpResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/public/trips/{shareToken}/guest-preferences":{"post":{"summary":"Submit guest dietary and preference notes","description":"Unauthenticated endpoint gated by share token. Allows a named guest to submit dietary restrictions and personalization notes for the trip.","parameters":[{"in":"path","name":"shareToken","required":true,"schema":{"type":"string"},"description":"Trip share token."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPreferencesRequest"}}}},"responses":{"200":{"description":"Preferences saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPreferencesResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/public/trips/{shareToken}/intake":{"post":{"summary":"Submit guest intake details","description":"Unauthenticated endpoint gated by share token. Creates or updates a client contact and stores any configured custom intake answers for the trip.","parameters":[{"in":"path","name":"shareToken","required":true,"schema":{"type":"string"},"description":"Trip share token."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestIntakeRequest"}}}},"responses":{"200":{"description":"Guest intake saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestIntakeResponse"}}}},"400":{"description":"Invalid request body or share token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/public/guests/{personalToken}/polls/{pollId}/respond":{"post":{"summary":"Submit a guest poll response (personal share link)","description":"Unauthenticated endpoint gated by the guest's personal share token. Polls support three answer types: choice (single option), text (free response), and slot_signup (option + HH:MM time within a configured window). Polls may carry an optional reference link (linkUrl + linkLabel) shown to guests as a button. Rate limited at 30 requests per 10 minutes per token + IP.","parameters":[{"in":"path","name":"personalToken","required":true,"schema":{"type":"string"},"description":"Guest personal share token."},{"in":"path","name":"pollId","required":true,"schema":{"type":"string"},"description":"Poll identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPollRespondRequest"}}}},"responses":{"200":{"description":"Poll response recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPollRespondResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No matching active contact for this token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Poll is closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/public/trips/{shareToken}/polls/{pollId}/respond":{"post":{"summary":"Submit a guest poll response (broadcast share link)","description":"Unauthenticated endpoint gated by the broadcast share token. Caller must have the intake_guest_<shareToken> cookie set (granted on intake completion). Same poll types and link semantics as the personal-token endpoint.","parameters":[{"in":"path","name":"shareToken","required":true,"schema":{"type":"string"},"description":"Trip share token."},{"in":"path","name":"pollId","required":true,"schema":{"type":"string"},"description":"Poll identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPollRespondRequest"}}}},"responses":{"200":{"description":"Poll response recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuestPollRespondResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid intake_guest cookie","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Poll is closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/host/trips/{tripId}/polls/{pollId}/responses.csv":{"get":{"summary":"Download poll responses as CSV","description":"Returns poll responses as a UTF-8 CSV file. Authenticated session required (advisor owner, admin, attached client, or host contact). Columns vary by poll type: slot_signup → Name, Email, Treatment, Time, Responded At; choice/text → Name, Email, Answer, Responded At.","parameters":[{"in":"path","name":"tripId","required":true,"schema":{"type":"string"},"description":"Trip identifier."},{"in":"path","name":"pollId","required":true,"schema":{"type":"string"},"description":"Poll identifier."}],"responses":{"200":{"description":"CSV file (UTF-8)","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"description":"Not authorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or poll not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/events":{"get":{"summary":"Bot event feed for trip/accounting changes (120 req/60s rate limit)","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"since","required":false,"schema":{"type":"string","format":"date-time"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event feed payload","headers":{"Link":{"description":"Pagination links (rel=\"self\", rel=\"next\" when more results exist).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventFeedResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/export/trips":{"get":{"summary":"Bot-safe trips export (60 req/60s rate limit)","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"updatedSince","required":false,"schema":{"type":"string","format":"date-time"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000}},{"in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trips export payload","headers":{"Link":{"description":"Pagination links (rel=\"self\", rel=\"next\" when more results exist).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TripsExportResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/whoami":{"get":{"summary":"Resolve bot identity and granted scopes","security":[{"BotApiKey":[]}],"responses":{"200":{"description":"Bot identity payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotWhoAmIResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/mcp":{"get":{"summary":"MCP discovery metadata","description":"Returns discovery metadata and a ready-to-paste configuration example for client-scoped read-only MCP access.","responses":{"200":{"description":"MCP discovery payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDiscoveryResponse"}}}}}},"post":{"summary":"Streamable HTTP MCP transport","description":"JSON-RPC 2.0 endpoint for read-only client MCP sessions. Authenticate with a client-issued bearer token. Request and response bodies follow the Model Context Protocol streamable HTTP specification.","security":[{"ClientApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"JSON-RPC request envelope (single request or batch) per the MCP streamable HTTP transport."}}}},"responses":{"200":{"description":"JSON-RPC response envelope","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing or invalid MCP token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal MCP server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/stream":{"get":{"summary":"SSE real-time event stream","description":"Server-Sent Events stream for real-time audit log events. Supports auto-reconnect via ?since= cursor. Max 2 concurrent connections per token.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"since","required":false,"schema":{"type":"string","format":"date-time"},"description":"ISO8601 datetime cursor to resume from."}],"responses":{"200":{"description":"SSE event stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited or max concurrent streams exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/trips/{id}/insights":{"get":{"summary":"Trip intelligence insights","description":"Returns payment alerts, completeness checks, timeline warnings, and accounting observations for a trip.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Trip identifier."}],"responses":{"200":{"description":"Insights payload","content":{"application/json":{"schema":{"type":"object","required":["tripId","tripCode","tripName","insights","generatedAt"],"properties":{"tripId":{"type":"string"},"tripCode":{"type":"string"},"tripName":{"type":"string"},"insights":{"type":"array","items":{"type":"object","required":["severity","category","message"],"properties":{"severity":{"type":"string","enum":["info","warning","critical"]},"category":{"type":"string","enum":["payment","completeness","timeline","accounting"]},"message":{"type":"string"},"data":{"type":"object"}}}},"generatedAt":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/query":{"post":{"summary":"Natural language query","description":"Accepts a natural language question and returns structured answers about balances, spending, upcoming trips, and payments.","security":[{"BotApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Query result","content":{"application/json":{"schema":{"type":"object","required":["question","answer","data","intent","confidence"],"properties":{"question":{"type":"string"},"answer":{"type":"string"},"data":{"type":"object","nullable":true},"intent":{"type":"string","enum":["spend","balance","upcoming","payments","count","unknown"]},"confidence":{"type":"string","enum":["high","medium","ambiguous","none"]}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/trips/{id}/actions":{"get":{"summary":"Next-action suggestions for a trip","description":"Returns prioritized action suggestions: payment reminders, missing data, status updates. Actions marked advisory=true are suggestions only.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Trip identifier."}],"responses":{"200":{"description":"Actions payload","content":{"application/json":{"schema":{"type":"object","required":["tripId","tripCode","tripName","actions","generatedAt"],"properties":{"tripId":{"type":"string"},"tripCode":{"type":"string"},"tripName":{"type":"string"},"actions":{"type":"array","items":{"type":"object","required":["priority","action","reason"],"properties":{"priority":{"type":"string","enum":["critical","high","medium","low"]},"action":{"type":"string"},"reason":{"type":"string"},"advisory":{"type":"boolean"},"endpoint":{"type":"string"},"method":{"type":"string"},"payload":{"type":"object"}}}},"generatedAt":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/trips":{"get":{"summary":"List trips","description":"List trips with cursor-based (recommended) or offset pagination. Requires one of: trips.read, trips.*, or *. Cursor pagination is safe during concurrent mutations.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination. Returns records with IDs before this cursor. Recommended over offset pagination for concurrent-safe iteration."},{"in":"query","name":"page","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number for offset pagination (backward compatibility). Ignored when cursor is provided."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":25},"description":"Maximum number of records to return."},{"in":"query","name":"tripId","required":false,"schema":{"type":"string"},"description":"Filter results to a specific trip."}],"responses":{"200":{"description":"Paginated list of trips.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TripListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a trip","description":"Requires one of: mutations.trips, mutations.*, or *. Supports optional tripClients rows for split trips; all 0 splitPercent values are treated as equal split.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TripCreateRequest"}}}},"responses":{"201":{"description":"Trip created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TripMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Primary client or one of the split-trip clients was not found on this advisor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/trips/{id}":{"put":{"summary":"Update a trip","description":"Requires one of: mutations.trips, mutations.*, or *. Supports updating the primary client and replacing split-trip participant rows.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Trip identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TripUpdateRequest"}}}},"responses":{"200":{"description":"Trip updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TripMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete a trip","description":"Requires one of: mutations.trips, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Trip identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Trip soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/expenses":{"get":{"summary":"List expenses","description":"List expenses with cursor-based (recommended) or offset pagination. Requires one of: trips.read, trips.*, or *. Cursor pagination is safe during concurrent mutations.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination. Returns records with IDs before this cursor. Recommended over offset pagination for concurrent-safe iteration."},{"in":"query","name":"page","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number for offset pagination (backward compatibility). Ignored when cursor is provided."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":25},"description":"Maximum number of records to return."},{"in":"query","name":"tripId","required":false,"schema":{"type":"string"},"description":"Filter results to a specific trip."}],"responses":{"200":{"description":"Paginated list of expenses.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExpenseListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create an expense","description":"Requires one of: mutations.expenses, mutations.*, or *. Supports multi-client `assignments: [{clientId, weight}]` for split allocation across clients on a shared trip.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseCreateRequest"}}}},"responses":{"201":{"description":"Expense created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ExpenseMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or assigned client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/expenses/{id}":{"put":{"summary":"Update an expense","description":"Requires one of: mutations.expenses, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Expense identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseUpdateRequest"}}}},"responses":{"200":{"description":"Expense updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ExpenseMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Expense or assigned client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete an expense","description":"Requires one of: mutations.expenses, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Expense identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Expense soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Expense not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/expenses/bulk":{"post":{"summary":"Bulk-create expenses","description":"Requires one of: mutations.bulk, mutations.*, or *. Accepts up to 50 expenses per request.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExpenseCreateRequest"}}}},"responses":{"201":{"description":"Expenses created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BulkExpenseMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or assigned client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/payments":{"get":{"summary":"List payments","description":"List payments with cursor-based (recommended) or offset pagination. Requires one of: trips.read, trips.*, or *. Cursor pagination is safe during concurrent mutations.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination. Returns records with IDs before this cursor. Recommended over offset pagination for concurrent-safe iteration."},{"in":"query","name":"page","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number for offset pagination (backward compatibility). Ignored when cursor is provided."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":25},"description":"Maximum number of records to return."},{"in":"query","name":"tripId","required":false,"schema":{"type":"string"},"description":"Filter results to a specific trip."}],"responses":{"200":{"description":"Paginated list of payments.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a payment","description":"Requires one of: mutations.payments, mutations.*, or *. Supports clientId for shared-trip attribution.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCreateRequest"}}}},"responses":{"201":{"description":"Payment created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/PaymentMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/payments/{id}":{"put":{"summary":"Update a payment","description":"Requires one of: mutations.payments, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Payment identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentUpdateRequest"}}}},"responses":{"200":{"description":"Payment updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/PaymentMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Payment or client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete a payment","description":"Requires one of: mutations.payments, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Payment identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Payment soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Payment not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/payments/bulk":{"post":{"summary":"Bulk-create payments","description":"Requires one of: mutations.bulk, mutations.*, or *. Accepts up to 50 payments per request.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPaymentCreateRequest"}}}},"responses":{"201":{"description":"Payments created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BulkPaymentMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip or client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/commissions":{"get":{"summary":"List commissions","description":"List commissions with cursor-based (recommended) or offset pagination. Requires one of: trips.read, trips.*, or *. Cursor pagination is safe during concurrent mutations.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination. Returns records with IDs before this cursor. Recommended over offset pagination for concurrent-safe iteration."},{"in":"query","name":"page","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number for offset pagination (backward compatibility). Ignored when cursor is provided."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":25},"description":"Maximum number of records to return."},{"in":"query","name":"tripId","required":false,"schema":{"type":"string"},"description":"Filter results to a specific trip."}],"responses":{"200":{"description":"Paginated list of commissions.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CommissionListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a commission entry","description":"Requires one of: mutations.commissions, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommissionCreateRequest"}}}},"responses":{"201":{"description":"Commission created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/CommissionMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/commissions/{id}":{"put":{"summary":"Update a commission entry","description":"Requires one of: mutations.commissions, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Commission identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommissionUpdateRequest"}}}},"responses":{"200":{"description":"Commission updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/CommissionMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Commission not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete a commission entry","description":"Requires one of: mutations.commissions, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Commission identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Commission soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Commission not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/points":{"get":{"summary":"List points entries","description":"List points entries with cursor-based (recommended) or offset pagination. Requires one of: trips.read, trips.*, or *. Cursor pagination is safe during concurrent mutations.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination. Returns records with IDs before this cursor. Recommended over offset pagination for concurrent-safe iteration."},{"in":"query","name":"page","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number for offset pagination (backward compatibility). Ignored when cursor is provided."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":25},"description":"Maximum number of records to return."},{"in":"query","name":"tripId","required":false,"schema":{"type":"string"},"description":"Filter results to a specific trip."}],"responses":{"200":{"description":"Paginated list of points entries.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PointsListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a points entry","description":"Requires one of: mutations.points, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointsCreateRequest"}}}},"responses":{"201":{"description":"Points entry created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/PointsMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Trip not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/points/{id}":{"put":{"summary":"Update a points entry","description":"Requires one of: mutations.points, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Points entry identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PointsUpdateRequest"}}}},"responses":{"200":{"description":"Points entry updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/PointsMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Points entry not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete a points entry","description":"Requires one of: mutations.points, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Points entry identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Points entry soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Points entry not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/gifts":{"get":{"summary":"List gifts","description":"List gifts with cursor pagination. Supports optional status and gifterId filters.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"},"description":"Record ID cursor for keyset pagination."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Maximum number of gifts to return."},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["CREATED","DELIVERED","REDEEMED","TRIP_LINKED","CELEBRATED","NEEDS_ATTENTION"]},"description":"Filter gifts by status."},{"in":"query","name":"gifterId","required":false,"schema":{"type":"string"},"description":"Filter gifts to a single gifter client record."}],"responses":{"200":{"description":"Paginated list of gifts.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GiftListItem"}},"pagination":{"oneOf":[{"type":"object","required":["cursor","hasMore","count"],"properties":{"cursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"count":{"type":"integer"}},"description":"Cursor-based pagination (default)."},{"type":"object","required":["page","limit","total","totalPages"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"description":"Offset-based pagination (when ?page= is used)."}]}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Failed to list gifts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a gift","description":"Requires one of: mutations.gifts, mutations.*, or *. Creates a new gift code for a client.","security":[{"BotApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftCreateRequest"}}}},"responses":{"201":{"description":"Gift created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/GiftCreateData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gifter not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Gift code conflict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Failed to create gift.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/gifts/{id}":{"get":{"summary":"Get gift detail","description":"Resolve a single gift with recipient, trip, and delivery state details.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Gift identifier."}],"responses":{"200":{"description":"Gift detail.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/GiftDetailData"}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gift not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"put":{"summary":"Update a gift","description":"Requires one of: mutations.gifts, mutations.*, or *. Supports status, recipient fields, trip linkage, notes, and expiry updates.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Gift identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftUpdateRequest"}}}},"responses":{"200":{"description":"Gift updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/GiftMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gift or trip not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Soft-delete a gift","description":"Requires one of: mutations.gifts, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Gift identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Gift soft-deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gift not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/gifts/{id}/redeem":{"post":{"summary":"Redeem a gift","description":"Requires one of: mutations.gifts, mutations.*, or *. Marks a gift as redeemed and can capture recipient details.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Gift identifier."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftRedeemRequest"}}}},"responses":{"200":{"description":"Gift redeemed.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/GiftRedeemData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gift not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Gift is already in a terminal status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Failed to redeem gift.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/gifts/{id}/celebrate":{"post":{"summary":"Send gift celebration","description":"Requires one of: mutations.gifts, mutations.*, or *. Marks the celebration message as sent for a gift.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Gift identifier."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftCelebrateRequest"}}}},"responses":{"200":{"description":"Gift celebration sent.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/GiftCelebrateData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Gift not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Celebration has already been sent for this gift.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Failed to send celebration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/webhooks":{"get":{"summary":"List webhook endpoints","description":"List advisor-scoped webhook endpoints and queue stats. Requires one of: webhooks.read, webhooks.*, mutations.webhooks, mutations.*, or *.","security":[{"BotApiKey":[]}],"responses":{"200":{"description":"Webhook endpoint list.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookListData"}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a webhook endpoint","description":"Requires one of: mutations.webhooks, mutations.*, or *. Returns the raw signing secret exactly once.","security":[{"BotApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreateRequest"}}}},"responses":{"201":{"description":"Webhook endpoint created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookCreateData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/webhooks/{id}":{"put":{"summary":"Update a webhook endpoint","description":"Requires one of: mutations.webhooks, mutations.*, or *. Supports URL, event list, and active-state updates.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Webhook endpoint identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdateRequest"}}}},"responses":{"200":{"description":"Webhook endpoint updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookEndpointListItem"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Webhook endpoint not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"summary":"Delete a webhook endpoint","description":"Requires one of: mutations.webhooks, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Webhook endpoint identifier."},{"in":"query","name":"dryRun","required":false,"schema":{"type":"boolean"},"description":"When true, validate the request without persisting changes. Returns the same response shape as a real mutation."}],"responses":{"200":{"description":"Webhook endpoint deleted.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DeleteMutationData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Webhook endpoint not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/webhooks/deliveries":{"get":{"summary":"List webhook deliveries","description":"List recent webhook deliveries. Supports ?endpointId=<id>, ?status=<pending|delivered|failed|paused>, and ?limit=<n>.","security":[{"BotApiKey":[]}],"parameters":[{"in":"query","name":"endpointId","required":false,"schema":{"type":"string"},"description":"Filter deliveries to a single webhook endpoint."},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["pending","delivered","failed","paused"]},"description":"Filter deliveries by status."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":30},"description":"Maximum number of recent deliveries to return."}],"responses":{"200":{"description":"Webhook deliveries list.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookDeliveriesData"}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/webhooks/deliveries/{id}/replay":{"post":{"summary":"Replay a webhook delivery","description":"Requires one of: mutations.webhooks, mutations.*, or *. Creates a new delivery and immediately attempts dispatch.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Webhook delivery identifier."}],"responses":{"201":{"description":"Webhook delivery replayed.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookReplayData"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Webhook delivery not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Endpoint must be active before replay.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/clients/{clientId}/api-keys":{"get":{"summary":"List client MCP API keys","description":"List active client-scoped MCP API keys for a client record. Requires one of: client-api-keys.read, client-api-keys.*, mutations.client-api-keys, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"clientId","required":true,"schema":{"type":"string"},"description":"Client record identifier."}],"responses":{"200":{"description":"Client API key list.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ClientApiKeyListData"}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Create a client MCP API key","description":"Requires one of: mutations.client-api-keys, mutations.*, or *. Returns the raw token once.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"clientId","required":true,"schema":{"type":"string"},"description":"Client record identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientApiKeyCreateRequest"}}}},"responses":{"201":{"description":"Client API key created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ClientApiKeyCreateData"}}}}}},"400":{"description":"Invalid request payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Client not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/bot/clients/{clientId}/api-keys/{keyId}":{"delete":{"summary":"Revoke a client MCP API key","description":"Requires one of: mutations.client-api-keys, mutations.*, or *.","security":[{"BotApiKey":[]}],"parameters":[{"in":"path","name":"clientId","required":true,"schema":{"type":"string"},"description":"Client record identifier."},{"in":"path","name":"keyId","required":true,"schema":{"type":"string"},"description":"Client API key identifier."}],"responses":{"200":{"description":"Client API key revoked.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ClientApiKeyRevokeData"}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Forbidden.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"API key not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}}}