{"openapi":"3.1.0","info":{"title":"Mavo API","version":"1","description":"Read and write household data with an API key. Authenticate every request with the `x-api-key` header. Keys are scoped to a single family."},"servers":[{"url":"https://mavolife.com"}],"security":[{"apiKey":[]}],"tags":[{"name":"Collections","description":"Create and manage household collections."},{"name":"Entries","description":"Add and edit entries inside a collection."},{"name":"Calendar","description":"Manage family calendar events, external feeds, and share links."},{"name":"Plans","description":"Manage family plans: linked calendar events, notes, date polls, and the public share page."},{"name":"People","description":"Manage household people."},{"name":"Notifications","description":"Send notifications and manage notification routines."},{"name":"Webhooks","description":"Manage outbound webhook destinations."},{"name":"Context","description":"Search household context."},{"name":"External info","description":"Look up weather and public web content."}],"paths":{"/api/v1/families/{familySlug}/trackers":{"get":{"operationId":"listCollections","tags":["Collections"],"summary":"List collections","description":"Returns every collection in the family, built-in and custom.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"trackers":[{"key":"meals","name":"Meals","description":"What’s for dinner.","fields":[]}]},"schema":{"properties":{"trackers":{"items":{"properties":{"key":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"fields":{"items":{},"type":"array"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"The family’s collections."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createCollection","tags":["Collections"],"summary":"Create a collection","description":"Creates a custom collection with the given fields.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTracker"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"tracker":{"key":"chores","name":"Chores","fields":[]}},"schema":{"properties":{"tracker":{"properties":{"key":{"type":"string"},"name":{"type":"string"},"fields":{"items":{},"type":"array"}},"type":"object"}},"type":"object"}}},"description":"The created collection."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/trackers/{collectionKey}":{"patch":{"operationId":"updateCollection","tags":["Collections"],"summary":"Update a collection","description":"Updates a custom collection. Send only the fields you want to change.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTracker"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"tracker":{"key":"chores","name":"Weekly chores"}},"schema":{"properties":{"tracker":{"properties":{"key":{"type":"string"},"name":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The updated collection."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteCollection","tags":["Collections"],"summary":"Delete a collection","description":"Deletes a custom collection and its entries. Built-in collections cannot be deleted.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"tracker":{"key":"chores","name":"Weekly chores"}},"schema":{"properties":{"tracker":{"properties":{"key":{"type":"string"},"name":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The deleted collection."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/trackers/{collectionKey}/entries":{"get":{"operationId":"listCollectionEntries","tags":["Entries"],"summary":"List entries","description":"Returns entries in a collection, optionally narrowed by text, status, or result count.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}},{"description":"Case-insensitive text to match against entry titles and data.","in":"query","name":"query","required":false,"schema":{"type":"string"}},{"description":"Only return entries with this status.","in":"query","name":"status","required":false,"schema":{"enum":["active","done","archived"],"type":"string"}},{"description":"Maximum number of matching entries to return.","in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":50,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"entries":[{"id":"ent_123","title":"Taco night","data":{"day":"2026-06-09","status":"Planned"}}]},"schema":{"properties":{"entries":{"items":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"data":{"properties":{"day":{"type":"string"},"status":{"type":"string"}},"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"The collection’s entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createCollectionEntry","tags":["Entries"],"summary":"Create an entry","description":"Adds an entry to a collection. `title` is the entry’s display label; collection-specific fields go in `data`.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTrackerEntry"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"entry":{"id":"ent_123","title":"Taco night","data":{"day":"2026-06-09","status":"Planned"}}},"schema":{"properties":{"entry":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"data":{"properties":{"day":{"type":"string"},"status":{"type":"string"}},"type":"object"}},"type":"object"}},"type":"object"}}},"description":"The created entry."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/trackers/{collectionKey}/entries/{entryId}":{"patch":{"operationId":"updateCollectionEntry","tags":["Entries"],"summary":"Update an entry","description":"Updates an entry. Send only the fields you want to change. `title` renames the entry; collection-specific fields go in `data`.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}},{"description":"Identifier of the entry within the collection.","in":"path","name":"entryId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTrackerEntry"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"entry":{"id":"ent_123","title":"Taco night","status":"done"}},"schema":{"properties":{"entry":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The updated entry."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteCollectionEntry","tags":["Entries"],"summary":"Delete an entry","description":"Removes an entry from a collection by id. No request body is needed; the deleted entry is returned for confirmation.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}},{"description":"Identifier of the entry within the collection.","in":"path","name":"entryId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"entry":{"id":"ent_123","title":"Taco night"}},"schema":{"properties":{"entry":{"properties":{"id":{"type":"string"},"title":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The deleted entry."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/trackers/{collectionKey}/entries/batch":{"post":{"operationId":"createCollectionEntries","tags":["Entries"],"summary":"Create entries","description":"Adds multiple entries to a collection in one request.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionItems"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"count":2,"entries":[{"id":"ent_123","title":"Taco night"}],"ok":true},"schema":{"properties":{"count":{"type":"integer"},"entries":{"items":{"properties":{"id":{"type":"string"},"title":{"type":"string"}},"type":"object"},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The created entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"patch":{"operationId":"updateCollectionEntries","tags":["Entries"],"summary":"Update entries","description":"Updates multiple entries in a collection in one request.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionItems"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"count":2,"entries":[{"id":"ent_123","title":"Taco night","status":"done"}],"ok":true},"schema":{"properties":{"count":{"type":"integer"},"entries":{"items":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"}},"type":"object"},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The updated entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteCollectionEntries","tags":["Entries"],"summary":"Delete entries","description":"Deletes multiple entries from a collection in one request. Pass entry ids only; titles are returned in the response for confirmation.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Key of the collection, e.g. \"meals\".","in":"path","name":"collectionKey","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCollectionItems"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"count":2,"entries":[{"id":"ent_123","title":"Taco night"}],"ok":true},"schema":{"properties":{"count":{"type":"integer"},"entries":{"items":{"properties":{"id":{"type":"string"},"title":{"type":"string"}},"type":"object"},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deleted entries."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/events":{"get":{"operationId":"listCalendarEvents","tags":["Calendar"],"summary":"List calendar events","description":"Returns family calendar events, optionally narrowed by date window, text, status, or result count. When both date boundaries are supplied, repeating series are expanded into concrete occurrences inside the window.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Only include events on or after this date (YYYY-MM-DD). With `to`, repeating series expand into dated occurrences inside the window.","in":"query","name":"from","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only include events on or before this date (YYYY-MM-DD).","in":"query","name":"to","required":false,"schema":{"format":"date","type":"string"}},{"description":"Case-insensitive text to match against event titles and data.","in":"query","name":"query","required":false,"schema":{"type":"string"}},{"description":"Only return events with this status.","in":"query","name":"status","required":false,"schema":{"enum":["active","done","archived"],"type":"string"}},{"description":"Set true to leave out events that already finished in the household's time zone. Expanded repeating occurrences are evaluated independently.","in":"query","name":"excludeEnded","required":false,"schema":{"type":"boolean"}},{"description":"Maximum number of matching events to return.","in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":50,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"events":[{"id":"ent_123","title":"Soccer practice","data":{"date":"2026-07-01","time":"17:00"}}],"ok":true},"schema":{"properties":{"events":{"items":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"data":{"properties":{"date":{"type":"string"},"time":{"type":"string"}},"type":"object"}},"type":"object"},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The matching calendar events."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createCalendarEvent","tags":["Calendar"],"summary":"Create calendar event","description":"Adds an event to the family calendar.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCalendarEvent"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"entryId":"ent_123","ok":true,"title":"Soccer practice"},"schema":{"properties":{"entryId":{"type":"string"},"ok":{"type":"boolean"},"title":{"type":"string"}},"type":"object"}}},"description":"The created calendar event."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/events/{eventId}":{"patch":{"operationId":"updateCalendarEvent","tags":["Calendar"],"summary":"Update calendar event","description":"Updates one family calendar event.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the calendar event.","in":"path","name":"eventId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCalendarEvent"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"event":{"id":"ent_123","title":"Soccer practice","data":{"date":"2026-07-01"}},"ok":true},"schema":{"properties":{"event":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"data":{"properties":{"date":{"type":"string"}},"type":"object"}},"type":"object"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The updated calendar event."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteCalendarEvent","tags":["Calendar"],"summary":"Delete calendar event","description":"Deletes a calendar event series by default, or one occurrence when both occurrence query parameters are provided.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the calendar event.","in":"path","name":"eventId","required":true,"schema":{"type":"string"}},{"description":"Use `occurrence` to delete one date in a repeating series. Defaults to the entire series.","in":"query","name":"editScope","required":false,"schema":{"enum":["occurrence","series"],"type":"string"}},{"description":"Original occurrence date (YYYY-MM-DD). Required when `editScope=occurrence`.","in":"query","name":"occurrenceDate","required":false,"schema":{"format":"date","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"event":{"id":"ent_123","title":"Soccer practice"},"ok":true},"schema":{"properties":{"event":{"properties":{"id":{"type":"string"},"title":{"type":"string"}},"type":"object"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deleted calendar event."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/context":{"get":{"operationId":"searchHouseholdContext","tags":["Context"],"summary":"Search household context","description":"Searches household collections, members, and upcoming calendar items. Use the optional `query` query parameter to narrow results.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Text to match across household collections, people, and calendar items.","in":"query","name":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"query":"soccer","results":[]},"schema":{"properties":{"ok":{"type":"boolean"},"query":{"type":"string"},"results":{"items":{},"type":"array"}},"type":"object"}}},"description":"The household context summary."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/families/{familySlug}/notifications":{"get":{"operationId":"listRecentNotifications","tags":["Notifications"],"summary":"List recent notifications","description":"Returns recent household notifications. Supports an optional `sinceMinutes` query parameter.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Only include notifications newer than this many minutes.","in":"query","name":"sinceMinutes","required":false,"schema":{"maximum":43200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"notifications":[{"title":"Practice moved","body":"Field changed."}]},"schema":{"properties":{"notifications":{"items":{"properties":{"title":{"type":"string"},"body":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"Recent notifications."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"sendNotification","tags":["Notifications"],"summary":"Send notification","description":"Sends a household notification.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendNotification"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"delivered":1,"ok":true,"suppressed":0},"schema":{"properties":{"delivered":{"type":"integer"},"ok":{"type":"boolean"},"suppressed":{"type":"integer"}},"type":"object"}}},"description":"The delivery result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/checks":{"post":{"operationId":"scheduleEventCheck","tags":["Notifications"],"summary":"Schedule event check","description":"Schedules a background check ahead of a calendar event.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleCheck"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"eventId":"ent_123","leadHours":14,"ok":true},"schema":{"properties":{"eventId":{"type":"string"},"leadHours":{"type":"integer"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The scheduled check."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/people":{"get":{"operationId":"listPeople","tags":["People"],"summary":"List people","description":"Returns household people.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"people":[{"id":"person_123","name":"Maya","role":"child"}]},"schema":{"properties":{"ok":{"type":"boolean"},"people":{"items":{"properties":{"id":{"type":"string"},"name":{"type":"string"},"role":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"The household people."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createPerson","tags":["People"],"summary":"Create person","description":"Adds a household person profile.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHouseholdPerson"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"person":{"id":"person_123","displayName":"Maya"}},"schema":{"properties":{"ok":{"type":"boolean"},"person":{"properties":{"id":{"type":"string"},"displayName":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The created person."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/people/{personId}":{"patch":{"operationId":"updatePerson","tags":["People"],"summary":"Update person","description":"Updates a household person profile.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the household person.","in":"path","name":"personId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHouseholdPerson"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"person":{"id":"person_123","displayName":"Maya"}},"schema":{"properties":{"ok":{"type":"boolean"},"person":{"properties":{"id":{"type":"string"},"displayName":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The updated person."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deletePerson","tags":["People"],"summary":"Delete person","description":"Removes a household person profile from active household views.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the household person.","in":"path","name":"personId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"personId":"person_123"},"schema":{"properties":{"ok":{"type":"boolean"},"personId":{"type":"string"}},"type":"object"}}},"description":"The deleted person."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/webhook-destinations":{"get":{"operationId":"listWebhookDestinations","tags":["Webhooks"],"summary":"List webhook destinations","description":"Returns outbound webhook destinations, delivery history, available events, and usage.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"destinations":[],"events":["tracker.entry.created"],"ok":true},"schema":{"properties":{"destinations":{"items":{},"type":"array"},"events":{"items":{"type":"string"},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The webhook destinations."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createWebhookDestination","tags":["Webhooks"],"summary":"Create webhook destination","description":"Creates an outbound webhook destination. The signing secret is returned once.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookDestination"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"destination":{"id":"whd_123","name":"Zapier","url":"https://example.com/webhook"},"ok":true,"signingSecret":"whsec_..."},"schema":{"properties":{"destination":{"properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"}},"type":"object"},"ok":{"type":"boolean"},"signingSecret":{"type":"string"}},"type":"object"}}},"description":"The created webhook destination."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/webhook-destinations/{destinationId}":{"patch":{"operationId":"updateWebhookDestination","tags":["Webhooks"],"summary":"Update webhook destination","description":"Updates an outbound webhook destination or rotates its signing secret.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the webhook destination.","in":"path","name":"destinationId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookDestination"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"destination":{"id":"whd_123","name":"Zapier"},"ok":true},"schema":{"properties":{"destination":{"properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The updated webhook destination."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteWebhookDestination","tags":["Webhooks"],"summary":"Delete webhook destination","description":"Deletes an outbound webhook destination.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the webhook destination.","in":"path","name":"destinationId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/webhook-destinations/{destinationId}/test":{"post":{"operationId":"testWebhookDestination","tags":["Webhooks"],"summary":"Test webhook destination","description":"Sends a test delivery to a webhook destination.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the webhook destination.","in":"path","name":"destinationId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The test delivery result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/notification-preferences":{"get":{"operationId":"getNotificationPreferences","tags":["Notifications"],"summary":"Get notification preferences","description":"Returns household notification preferences.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"preferences":{}},"schema":{"properties":{"ok":{"type":"boolean"},"preferences":{"properties":{},"type":"object"}},"type":"object"}}},"description":"The notification preferences."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"setNotificationPreference","tags":["Notifications"],"summary":"Set notification preference","description":"Updates one household notification preference.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetNotificationPreference"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"preferences":{}},"schema":{"properties":{"ok":{"type":"boolean"},"preferences":{"properties":{},"type":"object"}},"type":"object"}}},"description":"The updated notification preferences."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/notification-routines":{"get":{"operationId":"listNotificationRoutines","tags":["Notifications"],"summary":"List notification routines","description":"Returns household notification routines.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"routines":[]},"schema":{"properties":{"ok":{"type":"boolean"},"routines":{"items":{},"type":"array"}},"type":"object"}}},"description":"The notification routines."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createNotificationRoutine","tags":["Notifications"],"summary":"Create notification routine","description":"Creates a household notification routine.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationRoutine"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"routine":{"id":"trg_123"}},"schema":{"properties":{"ok":{"type":"boolean"},"routine":{"properties":{"id":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The notification routine."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/notification-routines/{triggerId}":{"patch":{"operationId":"updateNotificationRoutine","tags":["Notifications"],"summary":"Update notification routine","description":"Updates a household notification routine.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the notification routine.","in":"path","name":"triggerId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationRoutine"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"routine":{"id":"trg_123"}},"schema":{"properties":{"ok":{"type":"boolean"},"routine":{"properties":{"id":{"type":"string"}},"type":"object"}},"type":"object"}}},"description":"The notification routine."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteNotificationRoutine","tags":["Notifications"],"summary":"Delete notification routine","description":"Deletes a household notification routine.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the notification routine.","in":"path","name":"triggerId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/weather":{"get":{"operationId":"getWeather","tags":["External info"],"summary":"Check weather","description":"Looks up weather for a location. Send `location`, and optionally `date` and `time`, as query parameters.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Place to look up, such as a venue, city, or postal code.","in":"query","name":"location","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Date to focus on (YYYY-MM-DD). Defaults to the soonest available day.","in":"query","name":"date","required":false,"schema":{"format":"date","type":"string"}},{"description":"Local time to focus on (HH:mm).","in":"query","name":"time","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The weather lookup result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/families/{familySlug}/web/search":{"get":{"operationId":"searchWeb","tags":["External info"],"summary":"Search web","description":"Searches the public web. Send `query`, and optionally `numResults`, as query parameters.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"What to search the public web for.","in":"query","name":"query","required":true,"schema":{"minLength":1,"type":"string"}},{"description":"Number of search results to return.","in":"query","name":"numResults","required":false,"schema":{"default":5,"maximum":10,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"results":[{"title":"Example","url":"https://example.com"}]},"schema":{"properties":{"ok":{"type":"boolean"},"results":{"items":{"properties":{"title":{"type":"string"},"url":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"The web search results."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/families/{familySlug}/web/page":{"get":{"operationId":"readWebPage","tags":["External info"],"summary":"Read web page","description":"Reads the main text of a public web page. Send `url` as a query parameter.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Public HTTP or HTTPS URL to read.","in":"query","name":"url","required":true,"schema":{"format":"uri","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"text":"Readable page content...","url":"https://example.com"},"schema":{"properties":{"ok":{"type":"boolean"},"text":{"type":"string"},"url":{"type":"string"}},"type":"object"}}},"description":"The readable page content."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/families/{familySlug}/calendar/external":{"get":{"operationId":"listExternalCalendars","tags":["Calendar"],"summary":"List external calendars","description":"Returns linked external calendar feeds.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"feeds":[],"ok":true},"schema":{"properties":{"feeds":{"items":{},"type":"array"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The external calendars."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createExternalCalendar","tags":["Calendar"],"summary":"Create external calendar","description":"Links an external ICS calendar feed and syncs its events.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarExternalFeed"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"eventCount":12,"ok":true},"schema":{"properties":{"eventCount":{"type":"integer"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The linked external calendar."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/external/probe":{"post":{"operationId":"probeExternalCalendar","tags":["Calendar"],"summary":"Probe external calendar","description":"Checks whether an external ICS calendar URL can be read.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadWebPage"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The probe result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/external/{sourceId}":{"patch":{"operationId":"updateExternalCalendar","tags":["Calendar"],"summary":"Update external calendar","description":"Updates notes about a linked external calendar feed.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the external calendar feed.","in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalCalendar"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The update result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteExternalCalendar","tags":["Calendar"],"summary":"Delete external calendar","description":"Removes a linked external calendar feed and its synced calendar.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the external calendar feed.","in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/external/{sourceId}/refresh":{"post":{"operationId":"refreshExternalCalendar","tags":["Calendar"],"summary":"Refresh external calendar","description":"Requests a refresh for a linked external calendar feed.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the external calendar feed.","in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The refresh request result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/shares":{"get":{"operationId":"listCalendarShares","tags":["Calendar"],"summary":"List calendar shares","description":"Returns household calendar share links.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"shares":[]},"schema":{"properties":{"ok":{"type":"boolean"},"shares":{"items":{},"type":"array"}},"type":"object"}}},"description":"The calendar shares."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createCalendarShare","tags":["Calendar"],"summary":"Create calendar share","description":"Creates a calendar share link. The plaintext share token is returned once.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarShare"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"share":{"id":"share_123","name":"Soccer calendar"},"token":"share-token"},"schema":{"properties":{"ok":{"type":"boolean"},"share":{"properties":{"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"token":{"type":"string"}},"type":"object"}}},"description":"The calendar share."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/calendar/shares/{shareId}":{"delete":{"operationId":"deleteCalendarShare","tags":["Calendar"],"summary":"Revoke calendar share","description":"Revokes a calendar share link.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the calendar share link.","in":"path","name":"shareId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The revocation result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans":{"get":{"operationId":"listPlans","tags":["Plans"],"summary":"List plans","description":"Returns the household plans with each plan's derived date range, phase, event count, and share state.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"plans":[{"archived":false,"eventCount":3,"phase":"upcoming","planId":"plan_123","shareEnabled":false,"shareUrl":null,"title":"Spring break in Tahoe","when":"Mar 21–28"}]},"schema":{"properties":{"ok":{"type":"boolean"},"plans":{"items":{"properties":{"archived":{"type":"boolean"},"eventCount":{"type":"integer"},"phase":{"type":"string"},"planId":{"type":"string"},"shareEnabled":{"type":"boolean"},"shareUrl":{"type":["null"]},"title":{"type":"string"},"when":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"The plans."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createPlan","tags":["Plans"],"summary":"Create plan","description":"Creates a plan: a named thing the family is planning that gathers calendar events, notes, and date polls in one place.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlan"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"planId":"plan_123","title":"Spring break in Tahoe"},"schema":{"properties":{"ok":{"type":"boolean"},"planId":{"type":"string"},"title":{"type":"string"}},"type":"object"}}},"description":"The created plan."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}":{"get":{"operationId":"getPlan","tags":["Plans"],"summary":"Get plan","description":"Returns one plan in full: description, linked calendar events, notes, and polls with vote counts.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"archived":false,"events":[{"eventId":"event_123","location":"Tahoe City","showDetailsOnShare":true,"showLocationOnShare":true,"timing":{"date":"2026-03-21","endDate":"2026-03-28","kind":"all-day"},"title":"Cabin week"}],"notes":[{"author":"Dana","body":"Cabin gate code is 4415.","noteId":"note_123","onSharedPage":false}],"ok":true,"phase":"upcoming","planId":"plan_123","polls":[{"options":[{"date":"2026-03-21","endDate":null,"endTime":null,"label":"Mar 21 weekend","optionId":"option_123","time":"3:30 PM","votes":3}],"pollId":"poll_123","question":"Which weekend works?","settledOptionId":null,"status":"open"}],"prose":"A week at the cabin with the cousins.","shareUrl":null,"title":"Spring break in Tahoe","when":"Mar 21–28"},"schema":{"properties":{"archived":{"type":"boolean"},"events":{"items":{"properties":{"eventId":{"type":"string"},"location":{"type":"string"},"showDetailsOnShare":{"type":"boolean"},"showLocationOnShare":{"type":"boolean"},"timing":{"properties":{"date":{"type":"string"},"endDate":{"type":"string"},"kind":{"type":"string"}},"type":"object"},"title":{"type":"string"}},"type":"object"},"type":"array"},"notes":{"items":{"properties":{"author":{"type":"string"},"body":{"type":"string"},"noteId":{"type":"string"},"onSharedPage":{"type":"boolean"}},"type":"object"},"type":"array"},"ok":{"type":"boolean"},"phase":{"type":"string"},"planId":{"type":"string"},"polls":{"items":{"properties":{"options":{"items":{"properties":{"date":{"type":"string"},"endDate":{"type":["null"]},"endTime":{"type":["null"]},"label":{"type":"string"},"optionId":{"type":"string"},"time":{"type":"string"},"votes":{"type":"integer"}},"type":"object"},"type":"array"},"pollId":{"type":"string"},"question":{"type":"string"},"settledOptionId":{"type":["null"]},"status":{"type":"string"}},"type":"object"},"type":"array"},"prose":{"type":"string"},"shareUrl":{"type":["null"]},"title":{"type":"string"},"when":{"type":"string"}},"type":"object"}}},"description":"The plan."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updatePlan","tags":["Plans"],"summary":"Update plan","description":"Renames a plan, rewrites its description, or archives it. Pass at least one of title, prose, or archived.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlan"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"archived":false,"ok":true,"planId":"plan_123","title":"Spring break in Tahoe"},"schema":{"properties":{"archived":{"type":"boolean"},"ok":{"type":"boolean"},"planId":{"type":"string"},"title":{"type":"string"}},"type":"object"}}},"description":"The update result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deletePlan","tags":["Plans"],"summary":"Delete plan","description":"Deletes a plan along with its notes, polls, and share link. Linked calendar events stay on the calendar.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/events":{"post":{"operationId":"linkPlanEvent","tags":["Plans"],"summary":"Link plan event","description":"Points the plan at an existing calendar event. Nothing is copied; the plan derives its dates from the events it points at.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPlanEvent"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"eventId":"event_123","ok":true,"planId":"plan_123"},"schema":{"properties":{"eventId":{"type":"string"},"ok":{"type":"boolean"},"planId":{"type":"string"}},"type":"object"}}},"description":"The link result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/events/{eventId}":{"delete":{"operationId":"unlinkPlanEvent","tags":["Plans"],"summary":"Unlink plan event","description":"Removes the plan's pointer to a calendar event. The event stays on the calendar.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the calendar event.","in":"path","name":"eventId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"eventId":"event_123","ok":true,"planId":"plan_123"},"schema":{"properties":{"eventId":{"type":"string"},"ok":{"type":"boolean"},"planId":{"type":"string"}},"type":"object"}}},"description":"The unlink result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/notes":{"post":{"operationId":"addPlanNote","tags":["Plans"],"summary":"Add plan note","description":"Adds a note to the plan. Notes stay family-only unless showOnSharedPage is true.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddPlanNote"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"noteId":"note_123","ok":true},"schema":{"properties":{"noteId":{"type":"string"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The created note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/notes/{noteId}":{"patch":{"operationId":"updatePlanNote","tags":["Plans"],"summary":"Update plan note","description":"Rewrites a note, or changes whether it shows on the plan's share link. The note keeps its author and its place in the plan.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan note.","in":"path","name":"noteId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlanNote"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"noteId":"note_123","ok":true,"onSharedPage":false},"schema":{"properties":{"noteId":{"type":"string"},"ok":{"type":"boolean"},"onSharedPage":{"type":"boolean"}},"type":"object"}}},"description":"The updated note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deletePlanNote","tags":["Plans"],"summary":"Delete plan note","description":"Deletes a plan note.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan note.","in":"path","name":"noteId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls":{"post":{"operationId":"createPlanPoll","tags":["Plans"],"summary":"Create plan poll","description":"Opens a poll on the plan, like which weekend works. Options can be dated, label-only, or both.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanPoll"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"pollId":"poll_123"},"schema":{"properties":{"ok":{"type":"boolean"},"pollId":{"type":"string"}},"type":"object"}}},"description":"The created poll."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}":{"patch":{"operationId":"updatePlanPoll","tags":["Plans"],"summary":"Update plan poll","description":"Rewords the question a poll is asking. The options and every vote already cast stay as they are. Only works while the poll is open.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlanPoll"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"pollId":"poll_123"},"schema":{"properties":{"ok":{"type":"boolean"},"pollId":{"type":"string"}},"type":"object"}}},"description":"The updated poll."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deletePlanPoll","tags":["Plans"],"summary":"Delete plan poll","description":"Deletes a plan poll and its votes.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true},"schema":{"properties":{"ok":{"type":"boolean"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}/options":{"post":{"operationId":"addPlanPollOption","tags":["Plans"],"summary":"Add plan poll option","description":"Adds one more choice to an open poll, for when a possibility turns up after the question went out. Votes already cast are untouched. Twelve options is the ceiling.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanPollOption"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"ok":true,"optionId":"option_456"},"schema":{"properties":{"ok":{"type":"boolean"},"optionId":{"type":"string"}},"type":"object"}}},"description":"The created option."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}/options/{optionId}":{"patch":{"operationId":"updatePlanPollOption","tags":["Plans"],"summary":"Update plan poll option","description":"Rewrites an option on an open poll: its wording, its day, its time. The option keeps its identity, so the votes cast for it stay attached. Fields left out are cleared, so send the option as it should end up.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the option within the poll.","in":"path","name":"optionId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanPollOption"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"optionId":"option_123"},"schema":{"properties":{"ok":{"type":"boolean"},"optionId":{"type":"string"}},"type":"object"}}},"description":"The updated option."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deletePlanPollOption","tags":["Plans"],"summary":"Delete plan poll option","description":"Removes one choice from an open poll. Any votes cast for that option go with it, so reword it instead when the choice is still on the table in some form.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the option within the poll.","in":"path","name":"optionId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"optionId":"option_123"},"schema":{"properties":{"ok":{"type":"boolean"},"optionId":{"type":"string"}},"type":"object"}}},"description":"The deletion result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}/vote":{"post":{"operationId":"votePlanPoll","tags":["Plans"],"summary":"Vote on plan poll","description":"Casts the calling person's vote on an open poll. One vote per person: voting again moves it to the new option. There is no way to vote on someone else's behalf.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VotePlanPoll"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"optionId":"option_123","pollId":"poll_123"},"schema":{"properties":{"ok":{"type":"boolean"},"optionId":{"type":"string"},"pollId":{"type":"string"}},"type":"object"}}},"description":"The vote result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"clearPlanPollVote","tags":["Plans"],"summary":"Clear plan poll vote","description":"Takes the calling person's own vote back off an open poll, leaving them with no answer. Other people's votes are untouched.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"pollId":"poll_123"},"schema":{"properties":{"ok":{"type":"boolean"},"pollId":{"type":"string"}},"type":"object"}}},"description":"The cleared vote."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}/settle":{"post":{"operationId":"settlePlanPoll","tags":["Plans"],"summary":"Settle plan poll","description":"Closes a poll on the chosen option. A dated option is written to the family calendar as a real event and linked onto the plan.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettlePlanPoll"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"addedToCalendar":true,"eventId":"event_456","ok":true},"schema":{"properties":{"addedToCalendar":{"type":"boolean"},"eventId":{"type":"string"},"ok":{"type":"boolean"}},"type":"object"}}},"description":"The settle result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/polls/{pollId}/reopen":{"post":{"operationId":"reopenPlanPoll","tags":["Plans"],"summary":"Reopen plan poll","description":"Puts a settled poll back to open. Anything settling created goes with it: a calendar event written from the winning option is removed and unlinked from the plan. Votes already cast stay.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan poll.","in":"path","name":"pollId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"removedEventId":"event_456","removedFromCalendar":true},"schema":{"properties":{"ok":{"type":"boolean"},"removedEventId":{"type":"string"},"removedFromCalendar":{"type":"boolean"}},"type":"object"}}},"description":"The reopen result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/v1/families/{familySlug}/plans/{planId}/share":{"post":{"operationId":"setPlanSharing","tags":["Plans"],"summary":"Set plan sharing","description":"Turns the plan's public share link on or off. The link shows the live plan to whoever has it, no account needed.","parameters":[{"description":"Slug of the family (household) to act on.","in":"path","name":"familySlug","required":true,"schema":{"type":"string"}},{"description":"Identifier of the plan.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPlanSharing"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"enabled":true,"ok":true,"shareUrl":"https://mavolife.com/share/plan/abc123"},"schema":{"properties":{"enabled":{"type":"boolean"},"ok":{"type":"boolean"},"shareUrl":{"type":"string"}},"type":"object"}}},"description":"The sharing state."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}}},"components":{"responses":{"BadRequest":{"content":{"application/json":{"example":{"error":"Invalid request."},"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The request did not match the API contract."},"Unauthorized":{"content":{"application/json":{"example":{"error":"Authentication required."},"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The API key is missing or invalid."},"Forbidden":{"content":{"application/json":{"example":{"error":"This API key does not have access."},"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The API key cannot perform this operation."},"NotFound":{"content":{"application/json":{"example":{"error":"Resource not found."},"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The requested family resource was not found."},"Conflict":{"content":{"application/json":{"example":{"error":"The requested change conflicts with an existing resource."},"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The requested change conflicts with the current resource state."}},"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"A family-scoped API key. Generate one in Settings → Developer."}},"schemas":{"ApiError":{"type":"object","properties":{"error":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}}},"required":["error"]},"CreateTracker":{"type":"object","properties":{"category":{"description":"Set to calendar only when creating another household calendar; omit for ordinary collections.","type":"string","const":"calendar"},"color":{"description":"Optional display color for a calendar collection.","type":"string","enum":["sage","blue","clay","plum","gold"]},"description":{"description":"Optional short explanation of what the collection tracks.","type":"string"},"fields":{"default":[],"description":"Structured fields shared by items in this collection.","type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"description":"Stable camelCase or snake_case field key used in collection item data."},"label":{"type":"string","minLength":1,"description":"Short family-facing label shown for this field."},"options":{"description":"Allowed values when type is select; omit for other field types.","type":"array","items":{"type":"string"}},"type":{"default":"text","description":"How values in this field should be entered and displayed.","type":"string","enum":["date","number","person","select","text","textarea"]}},"required":["key","label"]}},"name":{"type":"string","minLength":1,"description":"Family-facing collection or calendar name."}},"required":["name"]},"UpdateTracker":{"type":"object","properties":{"color":{"description":"Replacement display color for a calendar collection.","type":"string","enum":["sage","blue","clay","plum","gold"]},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Replacement description; null removes the current description."},"fields":{"description":"Complete replacement list of structured fields.","type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"description":"Stable camelCase or snake_case field key used in collection item data."},"label":{"type":"string","minLength":1,"description":"Short family-facing label shown for this field."},"options":{"description":"Allowed values when type is select; omit for other field types.","type":"array","items":{"type":"string"}},"type":{"default":"text","description":"How values in this field should be entered and displayed.","type":"string","enum":["date","number","person","select","text","textarea"]}},"required":["key","label"]}},"name":{"description":"Replacement family-facing name.","type":"string","minLength":1}}},"CreateTrackerEntry":{"type":"object","properties":{"data":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Collection-specific fields for this entry. Only fields defined by the collection are saved."},"title":{"type":"string","minLength":1,"description":"Human-readable entry label. This is stored separately from collection-specific data fields and is returned in entry responses."}},"required":["title"]},"UpdateTrackerEntry":{"type":"object","properties":{"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Collection-specific fields for this entry. Only fields defined by the collection are saved."},"status":{"type":"string","enum":["active","archived","done"]},"title":{"type":"string","minLength":1,"description":"Human-readable entry label. This is stored separately from collection-specific data fields and is returned in entry responses."}}},"CreateCollectionItems":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"data":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"title":{"type":"string","minLength":1}},"required":["title"]}}},"required":["items"]},"UpdateCollectionItems":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"entryId":{"type":"string","minLength":1},"status":{"type":"string","enum":["active","done","archived"]},"title":{"type":"string","minLength":1}},"required":["entryId"]}}},"required":["items"]},"DeleteCollectionItems":{"type":"object","properties":{"entryIds":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","minLength":1}}},"required":["entryIds"]},"AddCalendarEvent":{"type":"object","properties":{"allDay":{"type":"boolean"},"assignee":{"type":"string"},"attendance":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","enum":["going","maybe","out"]}},"calendarKey":{"type":"string"},"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Required event date in YYYY-MM-DD format."},"durationMinutes":{"type":"integer","minimum":15,"maximum":1440},"endDate":{"type":"string","description":"Inclusive ISO end date for multi-day events."},"endTime":{"type":"string","description":"Local event end time when known."},"everyoneAttendance":{"type":"string","enum":["going","maybe","out"]},"note":{"type":"string"},"ownerPersonId":{"type":"string"},"responsibilityRequired":{"description":"False means the household explicitly decided this event needs no responsible person. Omit it when responsibility is still undecided.","type":"boolean"},"responsiblePersonIds":{"type":"array","items":{"type":"string","minLength":1}},"reminders":{"type":"array","items":{"type":"object","properties":{"audience":{"default":"household","description":"Who should receive the reminder: the whole household, responsible people, people marked going, or the explicit people list.","type":"string","enum":["household","responsible","going","people"]},"channels":{"default":["in_app"],"description":"Delivery channels for this reminder.","type":"array","items":{"type":"string","enum":["in_app","email","push","sms"]}},"mode":{"default":"plain","description":"plain sends the saved reminder; mavo allows a contextual reminder generated at send time.","type":"string","enum":["plain","mavo"]},"offsetMinutes":{"type":"integer","minimum":0,"maximum":20160,"description":"How many minutes before the event start to send the reminder; 0 means at the start."},"recipientPersonIds":{"default":[],"description":"Household person ids to notify when audience is people; otherwise leave empty.","type":"array","items":{"type":"string","minLength":1}}},"required":["offsetMinutes"]}},"repeatDays":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"repeatFrequency":{"type":"string","enum":["none","daily","weekdays","weekends","weekly","monthly","yearly","custom"]},"repeatInterval":{"type":"integer","minimum":1,"maximum":52},"time":{"type":"string"},"title":{"type":"string","minLength":1},"travelPlan":{"anyOf":[{"type":"object","properties":{"arriveEarlyMinutes":{"default":0,"description":"Extra minutes to arrive before the event starts.","type":"integer","minimum":0,"maximum":720},"baseTravelMinutes":{"type":"integer","minimum":1,"maximum":1440,"description":"Expected travel time in minutes before any live traffic adjustment."},"origin":{"type":"string","minLength":1,"maxLength":240,"description":"Specific starting place for the trip, such as Home or a street address."}},"required":["baseTravelMinutes","origin"]},{"type":"null"}]},"where":{"type":"string"}},"required":["date","title"]},"UpdateCalendarEvent":{"type":"object","properties":{"allDay":{"type":"boolean"},"assignee":{"type":"string"},"attendance":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","enum":["going","maybe","out"]}},"calendarKey":{"type":"string"},"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Required event date in YYYY-MM-DD format."},"durationMinutes":{"type":"integer","minimum":15,"maximum":1440},"endDate":{"type":"string","description":"Inclusive ISO end date for multi-day events."},"endTime":{"type":"string","description":"Local event end time when known."},"everyoneAttendance":{"type":"string","enum":["going","maybe","out"]},"note":{"type":"string"},"ownerPersonId":{"type":"string"},"responsibilityRequired":{"description":"False means the household explicitly decided this event needs no responsible person. Omit it when responsibility is still undecided.","type":"boolean"},"responsiblePersonIds":{"type":"array","items":{"type":"string","minLength":1}},"reminders":{"type":"array","items":{"type":"object","properties":{"audience":{"default":"household","description":"Who should receive the reminder: the whole household, responsible people, people marked going, or the explicit people list.","type":"string","enum":["household","responsible","going","people"]},"channels":{"default":["in_app"],"description":"Delivery channels for this reminder.","type":"array","items":{"type":"string","enum":["in_app","email","push","sms"]}},"mode":{"default":"plain","description":"plain sends the saved reminder; mavo allows a contextual reminder generated at send time.","type":"string","enum":["plain","mavo"]},"offsetMinutes":{"type":"integer","minimum":0,"maximum":20160,"description":"How many minutes before the event start to send the reminder; 0 means at the start."},"recipientPersonIds":{"default":[],"description":"Household person ids to notify when audience is people; otherwise leave empty.","type":"array","items":{"type":"string","minLength":1}}},"required":["offsetMinutes"]}},"repeatDays":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"repeatFrequency":{"type":"string","enum":["none","daily","weekdays","weekends","weekly","monthly","yearly","custom"]},"repeatInterval":{"type":"integer","minimum":1,"maximum":52},"time":{"type":"string"},"title":{"type":"string","minLength":1},"travelPlan":{"anyOf":[{"type":"object","properties":{"arriveEarlyMinutes":{"default":0,"description":"Extra minutes to arrive before the event starts.","type":"integer","minimum":0,"maximum":720},"baseTravelMinutes":{"type":"integer","minimum":1,"maximum":1440,"description":"Expected travel time in minutes before any live traffic adjustment."},"origin":{"type":"string","minLength":1,"maxLength":240,"description":"Specific starting place for the trip, such as Home or a street address."}},"required":["baseTravelMinutes","origin"]},{"type":"null"}]},"where":{"type":"string"},"clearAttendance":{"type":"boolean"},"clearTravelPlan":{"type":"boolean"},"editScope":{"type":"string","enum":["occurrence","series"]},"occurrenceDate":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"status":{"type":"string","enum":["active","done","archived"]}}},"SendNotification":{"type":"object","properties":{"body":{"default":"","type":"string"},"channels":{"type":"array","items":{"type":"string","enum":["in_app","email","push","sms"]}},"title":{"type":"string","minLength":1}},"required":["title"]},"ScheduleCheck":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string","enum":["in_app","email","push","sms"]}},"eventId":{"type":"string","minLength":1},"leadHours":{"type":"number","minimum":0.5,"maximum":336},"task":{"type":"string","minLength":1}},"required":["eventId","leadHours","task"]},"CreateHouseholdPerson":{"type":"object","properties":{"familiarName":{"type":"string"},"kind":{"default":"adult","type":"string","enum":["adult","child","helper","caregiver","other"]},"name":{"type":"string","minLength":1}},"required":["name"]},"UpdateHouseholdPerson":{"type":"object","properties":{"familiarName":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["adult","child","helper","caregiver","other"]},"name":{"type":"string","minLength":1}}},"CreateWebhookDestination":{"type":"object","properties":{"enabled":{"type":"boolean"},"eventTypes":{"minItems":1,"type":"array","items":{"type":"string","enum":["collection.created","collection.updated","collection.deleted","tracker.entry.created","tracker.entry.updated","tracker.entry.deleted","calendar.event.created","calendar.event.updated","calendar.event.deleted","calendar.check.created","external_calendar.created","external_calendar.updated","external_calendar.refresh_requested","external_calendar.deleted","calendar_share.created","calendar_share.deleted","plan.created","plan.updated","plan.deleted","plan.event.linked","plan.event.unlinked","plan.note.created","plan.note.updated","plan.note.deleted","plan.poll.created","plan.poll.deleted","plan.poll.settled","plan.poll.reopened","plan.poll.vote.cast","plan.share.enabled","plan.share.disabled","person.created","person.updated","person.deleted","notification.sent","notification_preference.updated","notification_routine.created","notification_routine.updated","notification_routine.deleted","webhook_destination.created","webhook_destination.updated","webhook_destination.deleted"]}},"name":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","format":"uri"}},"required":["eventTypes","name","url"]},"UpdateWebhookDestination":{"type":"object","properties":{"enabled":{"type":"boolean"},"eventTypes":{"minItems":1,"type":"array","items":{"type":"string","enum":["collection.created","collection.updated","collection.deleted","tracker.entry.created","tracker.entry.updated","tracker.entry.deleted","calendar.event.created","calendar.event.updated","calendar.event.deleted","calendar.check.created","external_calendar.created","external_calendar.updated","external_calendar.refresh_requested","external_calendar.deleted","calendar_share.created","calendar_share.deleted","plan.created","plan.updated","plan.deleted","plan.event.linked","plan.event.unlinked","plan.note.created","plan.note.updated","plan.note.deleted","plan.poll.created","plan.poll.deleted","plan.poll.settled","plan.poll.reopened","plan.poll.vote.cast","plan.share.enabled","plan.share.disabled","person.created","person.updated","person.deleted","notification.sent","notification_preference.updated","notification_routine.created","notification_routine.updated","notification_routine.deleted","webhook_destination.created","webhook_destination.updated","webhook_destination.deleted"]}},"name":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","format":"uri"},"rotateSecret":{"type":"boolean"}}},"SetNotificationPreference":{"type":"object","properties":{"channel":{"type":"string","enum":["email","push"]},"eventKind":{"type":"string","enum":["reminder","coverage_alert","follow_up_nudge","digest","intake_update"]},"isEnabled":{"type":"boolean"}},"required":["channel","eventKind","isEnabled"]},"NotificationRoutine":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string","enum":["in_app","email","push","sms"]}},"cron":{"type":"string","minLength":1},"intent":{"type":"string","enum":["briefing","reminder","digest"]},"isEnabled":{"type":"boolean"},"mode":{"type":"string","enum":["plain","mavo"]},"timezone":{"type":"string"}}},"SearchWeb":{"type":"object","properties":{"numResults":{"default":5,"type":"integer","minimum":1,"maximum":10},"query":{"type":"string","minLength":1}},"required":["query"]},"ReadWebPage":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]},"CalendarExternalFeed":{"type":"object","properties":{"color":{"type":"string"},"hint":{"type":"string","maxLength":280},"name":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["name","url"]},"UpdateExternalCalendar":{"type":"object","properties":{"hint":{"type":"string","maxLength":280}}},"CalendarShare":{"type":"object","properties":{"categories":{"default":[],"type":"array","items":{"type":"string"}},"eventIds":{"default":[],"type":"array","items":{"type":"string"}},"name":{"type":"string","minLength":1,"maxLength":120},"personIds":{"default":[],"type":"array","items":{"type":"string"}},"sourceIds":{"default":[],"type":"array","items":{"type":"string"}}},"required":["name"]},"CreatePlan":{"type":"object","properties":{"prose":{"description":"A few plain sentences about what the plan covers.","type":"string","maxLength":20000},"title":{"type":"string","minLength":1,"maxLength":200,"description":"Name of the specific thing being planned, e.g. \"Spring break in Tahoe\"."}},"required":["title"]},"UpdatePlan":{"type":"object","properties":{"archived":{"description":"True archives the plan once it has run its course; false brings it back. Linked calendar events stay either way.","type":"boolean"},"prose":{"description":"Replacement description. Null clears it. Omit to leave unchanged.","anyOf":[{"type":"string","maxLength":20000},{"type":"null"}]},"title":{"description":"Replacement name. Omit to leave unchanged.","type":"string","minLength":1,"maxLength":200}}},"LinkPlanEvent":{"type":"object","properties":{"eventId":{"type":"string","minLength":1,"description":"Identifier of the calendar event to link. Nothing is copied; the plan points at the event."}},"required":["eventId"]},"AddPlanNote":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000,"description":"The note itself: context that is not an event, like a gate code or pack list."},"showOnSharedPage":{"description":"True shows this note on the public share page. Notes stay family-only by default.","type":"boolean"}},"required":["body"]},"UpdatePlanNote":{"type":"object","properties":{"body":{"description":"Replacement text for the note. Omit to leave the wording alone.","type":"string","minLength":1,"maxLength":4000},"showOnSharedPage":{"description":"True puts this note on the plan's share link, false keeps it family-only. Omit to leave it as it is.","type":"boolean"}}},"CreatePlanPoll":{"type":"object","properties":{"options":{"minItems":2,"maxItems":12,"type":"array","items":{"type":"object","properties":{"date":{"description":"Proposed date when this option is a date choice. The winning dated option can land on the calendar at settle time.","type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endDate":{"description":"Inclusive proposed end date for multi-day options.","type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endTime":{"description":"Proposed local end time, like \"4:30 PM\".","type":"string","maxLength":20},"label":{"description":"What the option says. Optional when a date is given.","type":"string","minLength":1,"maxLength":120},"time":{"description":"Proposed local start time, like \"3:30 PM\".","type":"string","maxLength":20}}},"description":"Two to twelve choices. Each option needs a label or a date."},"question":{"type":"string","minLength":1,"maxLength":300,"description":"The question being decided, e.g. \"Which weekend works for the trip?\"."}},"required":["options","question"]},"UpdatePlanPoll":{"type":"object","properties":{"question":{"type":"string","minLength":1,"maxLength":300,"description":"Replacement wording for the question."}},"required":["question"]},"PlanPollOption":{"type":"object","properties":{"date":{"description":"Proposed date when this option is a date choice. The winning dated option can land on the calendar at settle time.","type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endDate":{"description":"Inclusive proposed end date for multi-day options.","type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endTime":{"description":"Proposed local end time, like \"4:30 PM\".","type":"string","maxLength":20},"label":{"description":"What the option says. Optional when a date is given.","type":"string","minLength":1,"maxLength":120},"time":{"description":"Proposed local start time, like \"3:30 PM\".","type":"string","maxLength":20}}},"VotePlanPoll":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Identifier of the option to vote for."}},"required":["optionId"]},"SettlePlanPoll":{"type":"object","properties":{"optionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Identifier of the option the family is going with."}},"required":["optionId"]},"SetPlanSharing":{"type":"object","properties":{"enabled":{"type":"boolean","description":"True turns the public share link on; false turns it off. The same address comes back when re-enabled."}},"required":["enabled"]}}}}