{"openapi": "3.0.3", "info": {"title": "Further Public API", "version": "1.0.0", "description": "Public API for integrating with Further \u2014 Senior Living and Behavioral Health lead automation, conversations, communities, and payments."}, "paths": {"/api/chat/leads/ingestion/zapier-webhook": {"post": {"operationId": "chat_leads_ingestion_zapier_webhook_create", "description": "Creates a lead in a Further community on behalf of an external system (Zapier, partner referral feeds, custom website forms, etc.) and dispatches it through the standard processing pipeline. Identify the target community with `community_id`, `community_url`, or `community_crm_code` (the first one provided wins). Optional flags can schedule a tour, enroll the lead in nurture campaigns, submit it to the configured CRM, and send the standard new-lead notification email to the community.", "summary": "Ingest a lead from an external system", "tags": ["Leads"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadIngestionZapierRequest"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/LeadIngestionZapierRequest"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/LeadIngestionZapierRequest"}}}}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"201": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadIngestionZapierResponse"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities": {"get": {"operationId": "v1_communities_list", "description": "Return a list of communities accessible to the caller. Supports filtering by community ID or name, and bulk retrieval of community data.", "summary": "Return Communities for an account", "parameters": [{"in": "query", "name": "id", "schema": {"type": "array", "items": {"type": "integer"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"in": "query", "name": "name", "schema": {"type": "array", "items": {"type": "string"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page", "required": false, "in": "query", "description": "A page number within the paginated result set.", "schema": {"type": "integer"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results to return per page.", "schema": {"type": "integer"}}, {"name": "search", "required": false, "in": "query", "description": "A search term.", "schema": {"type": "string"}}], "tags": ["Communities"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedPublicCommunityListList"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities/{community_id}/contact-info": {"get": {"operationId": "v1_communities_contact_info_retrieve", "description": "Returns the community's contact info: primary and secondary contact emails, phone numbers, and the contact's first name.", "summary": "Get community contact info", "parameters": [{"in": "path", "name": "community_id", "schema": {"type": "integer"}, "required": true}], "tags": ["Communities"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityContactInfo"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "put": {"operationId": "v1_communities_contact_info_update", "description": "Updates the community's contact info. Only the fields present in the request body are changed. `primary_sales_email` and `other_sales_emails` together replace the stored contact emails, with the primary email listed first; leads are announced to the primary email. Logs an audit entry.", "summary": "Update community contact info", "parameters": [{"in": "path", "name": "community_id", "schema": {"type": "integer"}, "required": true}], "tags": ["Communities"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityContactInfo"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PublicCommunityContactInfo"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PublicCommunityContactInfo"}}}}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityContactInfo"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities/{community_id}/survey-data": {"get": {"operationId": "v1_communities_survey_data_retrieve", "description": "Returns the survey data captured for a community. Two field shapes are returned: a senior-living payload for Senior Living organizations and a behavioral-health payload for Behavioral Health organizations. The shape is selected automatically based on the owning organization's `default_market_type`.", "summary": "Get a community's survey data", "parameters": [{"in": "path", "name": "community_id", "schema": {"type": "integer"}, "required": true}], "tags": ["Communities"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "put": {"operationId": "v1_communities_survey_data_update", "description": "Replaces the survey data captured for a community. The accepted field set follows the same senior-living vs. behavioral-health split as GET.", "summary": "Update a community's survey data", "parameters": [{"in": "path", "name": "community_id", "schema": {"type": "integer"}, "required": true}], "tags": ["Communities"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}}}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "patch": {"operationId": "v1_communities_survey_data_partial_update", "description": "Patches selected fields of the community's survey data. The accepted field set follows the same senior-living vs. behavioral-health split as GET.", "summary": "Partially update a community's survey data", "parameters": [{"in": "path", "name": "community_id", "schema": {"type": "integer"}, "required": true}], "tags": ["Communities"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PatchedCommunitySurveyData"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PatchedCommunitySurveyData"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PatchedCommunitySurveyData"}}}}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CommunitySurveyData"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities/groups": {"get": {"operationId": "v1_communities_groups_list", "description": "Returns the community groups owned by the calling user. Community groups are user-curated collections of communities used to organise dashboard navigation, so they are scoped to a single user and are only available to personal API keys. Organization API keys are rejected with 403 because a group may span communities across multiple organizations and is not meaningful at the organization level.", "summary": "List community groups", "parameters": [{"in": "query", "name": "community_id", "schema": {"type": "array", "items": {"type": "number"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"in": "query", "name": "community_name", "schema": {"type": "array", "items": {"type": "string"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"in": "query", "name": "name", "schema": {"type": "array", "items": {"type": "string"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page", "required": false, "in": "query", "description": "A page number within the paginated result set.", "schema": {"type": "integer"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results to return per page.", "schema": {"type": "integer"}}, {"name": "search", "required": false, "in": "query", "description": "A search term.", "schema": {"type": "string"}}], "tags": ["Community groups"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedPublicCommunityGroupList"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities/groups/{id}": {"get": {"operationId": "v1_communities_groups_retrieve", "description": "Returns a single community group, including the communities it contains. Community groups are user-scoped, so the group must be owned by the calling user. Organization API keys are rejected with 403 (see `GET /communities/groups` for the same reason).", "summary": "Get a community group", "parameters": [{"in": "path", "name": "id", "schema": {"type": "integer"}, "required": true}], "tags": ["Community groups"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityGroup"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/communities/pricing": {"get": {"operationId": "v1_communities_pricing_retrieve", "description": "Returns the configured pricing for a community: starting and ending costs across all care types, plus the per-care-type breakdown. The community is identified by exactly one of the query parameters `community_id`, `community_uuid`, or `community_url`.", "summary": "Get a community's pricing", "tags": ["Communities"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityPricing"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "put": {"operationId": "v1_communities_pricing_update", "description": "Updates the configured pricing for a community: starting/ending costs and the cost of each existing per-care-type row. The community is identified by `community_id` or `community_uuid` in the query string. PATCH is not supported on this resource.", "summary": "Update a community's pricing", "tags": ["Communities"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityPricing"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PublicCommunityPricing"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PublicCommunityPricing"}}}, "required": true}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCommunityPricing"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/community-events": {"get": {"operationId": "v1_community_events_list", "description": "Return a list of community events at communities the caller can access. Each event appears once, even if it runs at multiple communities \u2014 those communities are listed in the `communities` array.", "summary": "Return Community Events for an account", "parameters": [{"in": "query", "name": "active", "schema": {"type": "boolean"}, "description": "Active"}, {"in": "query", "name": "community_id", "schema": {"type": "array", "items": {"type": "integer"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page", "required": false, "in": "query", "description": "A page number within the paginated result set.", "schema": {"type": "integer"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results to return per page.", "schema": {"type": "integer"}}, {"name": "search", "required": false, "in": "query", "description": "A search term.", "schema": {"type": "string"}}], "tags": ["Events"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedPublicCommunityEventInstanceListList"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/conversations/leads/{id}": {"get": {"operationId": "v1_conversations_leads_retrieve", "description": "Returns the full conversation timeline for a single lead, ordered chronologically. Each item represents one event in the conversation (SMS, email, phone call, note, etc.); the shape of `data` varies by `message_type`. Designed for embedded messaging surfaces such as the Salesforce app.", "summary": "Get a lead's conversation timeline", "parameters": [{"in": "path", "name": "id", "schema": {"type": "integer"}, "required": true}], "tags": ["Conversations"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadConversationBriefResponse"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/conversations/leads/{id}/messages/check-new": {"post": {"operationId": "v1_conversations_leads_messages_check_new_create", "description": "Polling helper: given a reference message id and type, returns whether any newer messages exist for the lead. Used by embedded surfaces (Salesforce, etc.) that need to refresh the timeline without re-downloading it. When `same_type` is `true`, only messages on the same channel as `message_type` are considered.", "summary": "Check for new messages on a lead", "parameters": [{"in": "path", "name": "id", "schema": {"type": "integer"}, "required": true}], "tags": ["Conversations"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCheckNewMessagesRequest"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PublicCheckNewMessagesRequest"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PublicCheckNewMessagesRequest"}}}, "required": true}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicCheckNewMessagesResponse"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/conversations/leads/{id}/messages/send": {"post": {"operationId": "v1_conversations_leads_messages_send_create", "description": "Sends an SMS or email message to a lead from the community. The message is queued and delivered through the same pipeline as messages sent from the Further dashboard. Designed for use by embedded messaging surfaces (e.g. the Salesforce app) where an agent composes the message in the caller's UI.", "summary": "Send a message to a lead", "parameters": [{"in": "path", "name": "id", "schema": {"type": "integer"}, "required": true}], "tags": ["Conversations"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicLeadConversationSendRequest"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PublicLeadConversationSendRequest"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PublicLeadConversationSendRequest"}}}, "required": true}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"201": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicLeadConversationSendResponse"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/lead-report": {"put": {"operationId": "v1_lead_report_update", "description": "Reports that a lead has attended a tour or moved into a community. The lead can be identified by `lead_id`, `lead_hash_code`, or `external_lead_id` (CRM identifier). Reports flow into Further's qualification and CRM-sync pipelines.", "summary": "Report a tour or move-in for a lead", "tags": ["Leads"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadReport"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/LeadReport"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/LeadReport"}}}, "required": true}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadReport"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "patch": {"operationId": "v1_lead_report_partial_update", "description": "Same as PUT. Reports that a lead has attended a tour or moved into a community. The lead can be identified by `lead_id`, `lead_hash_code`, or `external_lead_id`.", "summary": "Report a tour or move-in for a lead", "tags": ["Leads"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PatchedLeadReport"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/PatchedLeadReport"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/PatchedLeadReport"}}}}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadReport"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/leads/": {"get": {"operationId": "v1_leads_list", "description": "Returns a paginated list of leads from communities the caller has access to. Supports search by name, email, and phone, plus filters from `LeadPublicAPIFilters`. Personal API keys return leads from the communities visible to the key owner; organization keys return every lead belonging to the calling organization.", "summary": "List leads", "parameters": [{"in": "query", "name": "community_id", "schema": {"type": "array", "items": {"type": "number"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"in": "query", "name": "end_date", "schema": {"type": "string", "format": "date"}}, {"in": "query", "name": "financially_unqualified", "schema": {"type": "boolean"}}, {"in": "query", "name": "group_id", "schema": {"type": "array", "items": {"type": "integer"}}, "description": "Multiple values may be separated by commas.", "explode": false, "style": "form"}, {"in": "query", "name": "move_in_date", "schema": {"type": "boolean"}}, {"name": "ordering", "required": false, "in": "query", "description": "Which field to use when ordering the results.", "schema": {"type": "string"}}, {"name": "page", "required": false, "in": "query", "description": "A page number within the paginated result set.", "schema": {"type": "integer"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results to return per page.", "schema": {"type": "integer"}}, {"in": "query", "name": "score_from", "schema": {"type": "integer"}}, {"in": "query", "name": "score_to", "schema": {"type": "integer"}}, {"name": "search", "required": false, "in": "query", "description": "A search term.", "schema": {"type": "string"}}, {"in": "query", "name": "start_date", "schema": {"type": "string", "format": "date"}}, {"in": "query", "name": "submitted_to_crm", "schema": {"type": "boolean"}}, {"in": "query", "name": "tour_scheduled", "schema": {"type": "boolean"}}, {"in": "query", "name": "updated_end_date", "schema": {"type": "string", "format": "date"}}, {"in": "query", "name": "updated_start_date", "schema": {"type": "string", "format": "date"}}], "tags": ["Leads"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedLeadList"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}, "post": {"operationId": "v1_leads_create", "description": "Creates a new lead from a partner integration and enrolls it into the standard Further processing pipeline (CRM sync, qualification, etc.). The `provider_profile` field must identify a Further community owned by the caller's organization.", "summary": "Create a lead", "tags": ["Leads"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateLead"}}, "application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/CreateLead"}}, "multipart/form-data": {"schema": {"$ref": "#/components/schemas/CreateLead"}}}, "required": true}, "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"201": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateLead"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/leads/{id}": {"get": {"operationId": "v1_leads_retrieve", "description": "Returns detailed information about a single lead, including channel and traffic source, score, captured URL parameters, and tour/move-in metadata. The lead must belong to a community the caller has access to.", "summary": "Get a lead", "parameters": [{"in": "path", "name": "id", "schema": {"type": "integer"}, "required": true}], "tags": ["Leads"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadDetails"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}, "/api/v1/visitors": {"get": {"operationId": "v1_visitors_list", "description": "Returns recent unique website visitors observed across the communities the caller has access to. Bot traffic is excluded. The optional `community_ids` query parameter (repeated or comma-separated) narrows results to a specific set of communities.", "summary": "List website visitors", "parameters": [{"name": "cursor", "required": false, "in": "query", "description": "The pagination cursor value.", "schema": {"type": "string"}}, {"name": "page_size", "required": false, "in": "query", "description": "Number of results to return per page.", "schema": {"type": "integer"}}], "tags": ["Visitors"], "security": [{"PersonalApiKey": []}, {"OrganizationApiKey": []}], "responses": {"200": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaginatedVisitorPublicDetailsList"}}}, "description": ""}, "401": {"description": "Missing or invalid API key."}, "403": {"description": "API key valid but lacks the required scope or permissions."}, "429": {"description": "Rate limit exceeded for this API key.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "minimum": 1}}}}}}}}, "components": {"schemas": {"BehavioralHealthSurveyData": {"type": "object", "properties": {"activities": {"type": "array", "items": {}, "nullable": true}, "activities_calendar_url": {"type": "string", "nullable": true}, "amenities": {"type": "array", "items": {}, "nullable": true}, "amenities_url": {"type": "string", "nullable": true}, "languages": {"type": "array", "items": {}, "nullable": true}, "pets": {"type": "string", "nullable": true}, "smoking": {"type": "array", "items": {}, "nullable": true}, "transportation": {"type": "array", "items": {}, "nullable": true}, "visiting_hours": {"type": "array", "items": {}, "nullable": true}, "number_residents": {"type": "integer", "nullable": true}, "men_women_separated": {"type": "boolean", "nullable": true}, "pets_policy": {"type": "array", "items": {}, "nullable": true}, "additional_information": {"type": "string", "nullable": true}, "acreditation": {"type": "array", "items": {}, "nullable": true}, "adults_children_separated": {"type": "boolean", "nullable": true}, "aftercare_program": {"type": "boolean", "nullable": true}, "after_hours_policy": {"type": "string", "nullable": true}, "age_policy": {"type": "string", "nullable": true}, "confidentiality_policy": {"type": "string", "nullable": true}, "detox_program": {"type": "boolean", "nullable": true}, "doctor_types": {"type": "array", "items": {}, "nullable": true}, "establishment_year": {"type": "integer", "nullable": true}, "family_counseling": {"type": "boolean", "nullable": true}, "family_support": {"type": "boolean", "nullable": true}, "inpatient_outpatient_rehab_diff": {"type": "string", "nullable": true}, "insurance_accepted": {"type": "array", "items": {}, "nullable": true}, "licensed_clinicians": {"type": "boolean", "nullable": true}, "medication_management": {"type": "boolean", "nullable": true}, "one_on_one_counseling_frequency": {"type": "string", "nullable": true}, "personal_devices_allowed": {"type": "boolean", "nullable": true}, "prescribe_medication": {"type": "boolean", "nullable": true}, "program_length": {"type": "string", "nullable": true}, "readmits_allowed": {"type": "boolean", "nullable": true}, "staff_to_patient_ratio": {"type": "string", "nullable": true}, "support_groups": {"type": "boolean", "nullable": true}, "threatment_options": {"type": "array", "items": {}, "nullable": true}, "trial_session": {"type": "boolean", "nullable": true}}, "required": ["acreditation", "activities", "activities_calendar_url", "additional_information", "adults_children_separated", "after_hours_policy", "aftercare_program", "age_policy", "amenities", "amenities_url", "confidentiality_policy", "detox_program", "doctor_types", "establishment_year", "family_counseling", "family_support", "inpatient_outpatient_rehab_diff", "insurance_accepted", "languages", "licensed_clinicians", "medication_management", "men_women_separated", "number_residents", "one_on_one_counseling_frequency", "personal_devices_allowed", "pets", "pets_policy", "prescribe_medication", "program_length", "readmits_allowed", "smoking", "staff_to_patient_ratio", "support_groups", "threatment_options", "transportation", "trial_session", "visiting_hours"]}, "CommunitySimpleInfo": {"type": "object", "properties": {"id": {"type": "integer", "description": "Community identifier."}, "name": {"type": "string", "description": "Community display name."}}, "required": ["id", "name"]}, "CommunitySurveyData": {"oneOf": [{"$ref": "#/components/schemas/SeniorLivingSurveyData"}, {"$ref": "#/components/schemas/BehavioralHealthSurveyData"}]}, "CreateLead": {"type": "object", "description": "A model serializer used for lead creation via public API, and consumed by the partner clients.", "properties": {"provider_profile": {"type": "integer", "description": "Identifier of the Further community the lead is interested in."}, "first_name": {"type": "string", "maxLength": 30}, "last_name": {"type": "string", "nullable": true, "maxLength": 150}, "email": {"type": "string", "format": "email", "description": "Lead email address. Either `email` or `phone` is required (community-dependent)."}, "phone": {"type": "string", "description": "Lead phone number in E.164 format. Either `email` or `phone` is required (community-dependent)."}, "timing": {"type": "string", "description": "Free-text move-in timing as captured from the source form (e.g. `3-6 months`)."}, "care_type": {"type": "string", "description": "Care level requested by the lead (e.g. `Independent Living`, `Assisted Living`)."}, "utm_source": {"type": "string", "description": "Marketing attribution: source (`utm_source` query parameter)."}, "utm_medium": {"type": "string", "description": "Marketing attribution: medium (`utm_medium` query parameter)."}, "utm_campaign": {"type": "string", "description": "Marketing attribution: campaign name (`utm_campaign` query parameter)."}}, "required": ["provider_profile"]}, "Lead": {"type": "object", "description": "Maps lead information when fetching list of lead entities. It serves for exposed APIs used by third-parties.\n\nNOTE: Part of the API documentation. Updates should be synchronized with api-docs.", "properties": {"lead_id": {"type": "integer", "description": "Internal Further lead identifier."}, "name": {"type": "string", "description": "Full name of the lead."}, "email": {"type": "string", "description": "Lead email address."}, "phone": {"type": "string", "description": "Lead phone number formatted for display."}, "date": {"type": "string", "format": "date-time", "description": "ISO-8601 timestamp when the lead was created."}, "financially_unqualified": {"type": "boolean", "description": "`true` if the lead was disqualified for financial reasons during qualification."}, "move_in_date": {"type": "string", "format": "date-time", "description": "Recorded move-in date, or `null` if none was set."}, "community_id": {"type": "integer", "description": "Identifier of the community the lead belongs to."}, "community_name": {"type": "string", "description": "Display name of the community."}, "channel_source": {"type": "string", "nullable": true, "readOnly": true, "description": "Originating channel. One of `chat_api`, `conversational_webform` (embedded VSA), `conversational_ivr` (voice VSA), `web_form_submit`, `static_webform`, `phone_call`, or `referral`."}, "lead_submitted": {"type": "boolean", "description": "`true` once the lead has completed the qualifying flow and been submitted."}, "device": {"type": "string", "nullable": true, "description": "Device classification of the originating visit (e.g. `desktop`, `mobile`).", "readOnly": true}, "traffic_source": {"type": "string", "nullable": true, "description": "Classified traffic source of the originating visit (e.g. `Direct`, `Google Ads`).", "readOnly": true}, "tours_count": {"type": "integer", "readOnly": true, "description": "Number of tours scheduled for this lead."}, "tour_date": {"type": "string", "format": "date-time", "description": "Start time of the most recently scheduled tour, or `null` if none."}, "tour_scheduled": {"type": "boolean", "readOnly": true, "description": "`true` if at least one tour has been scheduled."}, "tour_confirmed": {"type": "boolean", "description": "`true` if a scheduled tour has been confirmed."}, "visitor_uuid": {"type": "string", "nullable": true, "description": "Stable identifier of the originating website visitor, when known.", "readOnly": true}, "external_lead_id": {"type": "string", "description": "Lead identifier in the customer's CRM, when CRM sync is configured."}}, "required": ["channel_source", "community_id", "community_name", "date", "device", "email", "financially_unqualified", "lead_id", "lead_submitted", "move_in_date", "name", "phone", "tour_confirmed", "tour_scheduled", "tours_count", "traffic_source", "visitor_uuid"]}, "LeadConversationBriefItem": {"type": "object", "description": "A single item in the lead conversation timeline.\n\nThe `data` payload's shape depends on `message_type`; treat it as an opaque object\ncontaining message-type-specific fields (text, attachments, recording, transcript, etc.).", "properties": {"message_type": {"type": "string", "description": "Type of conversation event (e.g. `sms`, `email`, `call`, `note`)."}, "created_on": {"type": "string", "format": "date-time", "description": "ISO-8601 timestamp at which the event occurred."}, "data": {"type": "object", "additionalProperties": {}, "description": "Message-type-specific payload (text, attachments, recording URL, etc.)."}}, "required": ["created_on", "data", "message_type"]}, "LeadConversationBriefResponse": {"type": "object", "description": "Response body for the public lead-conversation endpoint.\n\nDeclares `conversation` as a typed list so drf-spectacular can introspect the response\nshape. The runtime payload is produced by `LeadConversationBriefSerializer`, which\nsynthesizes the polymorphic timeline from `conversations.get_lead_conversation(lead)`.", "properties": {"conversation": {"type": "array", "items": {"$ref": "#/components/schemas/LeadConversationBriefItem"}, "description": "Chronologically ordered list of conversation events for the lead."}}, "required": ["conversation"]}, "LeadDetails": {"type": "object", "description": "Map lead details information for the purpose of retrieving the information for a single lead instance.", "properties": {"id": {"type": "integer", "description": "Internal Further lead identifier."}, "external_lead_id": {"type": "string", "description": "Lead identifier in the customer's CRM, when CRM sync is configured."}, "name": {"type": "string", "description": "Full name of the lead."}, "email": {"type": "string", "description": "Lead email address."}, "phone": {"type": "string", "description": "Lead phone number."}, "hash_code": {"type": "string", "description": "Stable opaque identifier for the lead, safe for use in URLs."}, "channel_source": {"type": "string", "description": "Originating channel. One of `chat_api`, `conversational_webform` (embedded VSA), `conversational_ivr` (voice VSA), `web_form_submit`, `static_webform`, `phone_call`, or `referral`."}, "score": {"type": "integer", "description": "Lead score assigned by Further's qualification engine (0-100)."}, "move_in_date": {"type": "string", "format": "date-time", "description": "Recorded move-in date, or `null` if none was set."}, "tour_date": {"type": "string", "format": "date-time", "description": "Start time of the most recent tour, or `null` if none."}, "care_type": {"type": "string", "description": "Care level captured during the qualifying conversation (free text)."}, "visitor_uuid": {"type": "string", "format": "uuid", "description": "Stable identifier of the originating website visitor, when known."}, "url_parameters": {"type": "array", "items": {"type": "object", "additionalProperties": {}}, "readOnly": true, "description": "Query-string parameters captured at the originating visit, as `[{key, value}, \u2026]`."}, "traffic_source": {"type": "string", "description": "Classified traffic source of the originating visit (e.g. `Direct`, `Google Ads`)."}}, "required": ["care_type", "channel_source", "email", "hash_code", "id", "move_in_date", "name", "phone", "score", "url_parameters"]}, "LeadIngestionZapierRequest": {"type": "object", "description": "Request body for the lead-ingestion endpoint.\n\nIdentify the target community by exactly one of `community_id`, `community_url`, or\n`community_crm_code`. All other fields describe the lead and how Further should process it.", "properties": {"community_id": {"type": "integer", "description": "Identifier of the Further community the lead belongs to."}, "community_url": {"type": "string", "description": "URL of the community as configured in Further. Used as a fallback when `community_id` is omitted."}, "community_crm_code": {"type": "string", "description": "CRM location code for the community, useful when the calling system only has the code from its own CRM setup (e.g. Yardi)."}, "first_name": {"type": "string", "description": "Lead first name (truncated to 30 characters)."}, "last_name": {"type": "string", "description": "Lead last name (truncated to 150 characters)."}, "email": {"type": "string", "format": "email", "description": "Lead email address."}, "phone": {"type": "string", "description": "Lead phone number (free-form, up to 20 characters)."}, "lead_source": {"type": "string", "description": "Source label for the lead. Defaults to `zapier`. If provided, must match a registered source (e.g. `apfm`, `caring`)."}, "traffic_source": {"type": "string", "description": "Free-text traffic source label (e.g. `Google Ads`, `Facebook Ad`)."}, "external_lead_id": {"type": "string", "description": "Caller's identifier for the lead, recorded for cross-system correlation."}, "tour_booked": {"type": "boolean", "description": "If `true`, Further schedules a tour for the lead after creation."}, "tour_date": {"type": "string", "format": "date-time", "description": "Scheduled start time for the tour. Parsed in the community's timezone if no offset is supplied. Only meaningful when `tour_booked` is `true`."}, "nurture_lead": {"type": "boolean", "description": "If `true`, the lead is enrolled in nurture campaigns after creation."}, "submit_crm": {"type": "boolean", "description": "If `true`, Further submits the lead to the community's configured CRM after creation."}, "send_via_email": {"type": "boolean", "description": "If `true`, Further sends the standard new-lead notification email to the community."}}}, "LeadIngestionZapierResponse": {"type": "object", "properties": {"further_lead_id": {"type": "integer", "description": "Identifier of the newly created lead in Further."}, "external_lead_id": {"type": "string", "description": "Echoes the `external_lead_id` from the request, if one was provided."}, "community_code": {"type": "string", "description": "CRM location code of the community the lead was created in."}}, "required": ["community_code", "external_lead_id", "further_lead_id"]}, "LeadReport": {"type": "object", "properties": {"lead_status": {"enum": [null, "no-contact", "qualified", "financial", "no_response", "not-qualified", "tour", "move-in", "move-out", "duplicate", "not-looking-for", "qualified-closed", "bad-info", "other", "other-closed", ""], "description": "* `None` - None\n* `no-contact` - Could Not Make Contact\n* `qualified` - Qualified, Made Contact\n* `financial` - Not Financially Qualified\n* `no_response` - Reached Out (email/phone) - No Response Yet\n* `not-qualified` - Not Qualified - Other\n* `tour` - Scheduled Tour\n* `move-in` - Moved In\n* `move-out` - Moved Out\n* `duplicate` - Duplicate\n* `not-looking-for` - Looking for something else.\n* `qualified-closed` - Qualified, but closed lead\n* `bad-info` - Bad Contact Information\n* `other` - Other\n* `other-closed` - Other, Closed", "x-spec-enum-id": "71604178179b7a3e", "nullable": true}, "report_type": {"enum": ["tour", "move-in"], "type": "string", "x-spec-enum-id": "05e61e51ab1b37a9", "writeOnly": true, "description": "Event being reported. `tour` records that the lead attended a tour; `move_in` records a move-in.\n\n* `tour` - tour\n* `move-in` - move-in"}, "report_date": {"type": "string", "format": "date-time", "writeOnly": true, "nullable": true, "description": "ISO-8601 timestamp at which the event occurred. Defaults to the time of the request if omitted."}}, "required": ["report_type"]}, "PaginatedLeadList": {"type": "object", "required": ["count", "results"], "properties": {"count": {"type": "integer", "example": 123}, "next": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=4"}, "previous": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=2"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/Lead"}}}}, "PaginatedPublicCommunityEventInstanceListList": {"type": "object", "required": ["count", "results"], "properties": {"count": {"type": "integer", "example": 123}, "next": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=4"}, "previous": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=2"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/PublicCommunityEventInstanceList"}}}}, "PaginatedPublicCommunityGroupList": {"type": "object", "required": ["count", "results"], "properties": {"count": {"type": "integer", "example": 123}, "next": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=4"}, "previous": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=2"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/PublicCommunityGroup"}}}}, "PaginatedPublicCommunityListList": {"type": "object", "required": ["count", "results"], "properties": {"count": {"type": "integer", "example": 123}, "next": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=4"}, "previous": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?page=2"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/PublicCommunityList"}}}}, "PaginatedVisitorPublicDetailsList": {"type": "object", "required": ["results"], "properties": {"next": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?cursor=cD00ODY%3D\""}, "previous": {"type": "string", "nullable": true, "format": "uri", "example": "http://api.example.org/accounts/?cursor=cj0xJnA9NDg3"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/VisitorPublicDetails"}}}}, "PatchedBehavioralHealthSurveyData": {"type": "object", "properties": {"activities": {"type": "array", "items": {}, "nullable": true}, "activities_calendar_url": {"type": "string", "nullable": true}, "amenities": {"type": "array", "items": {}, "nullable": true}, "amenities_url": {"type": "string", "nullable": true}, "languages": {"type": "array", "items": {}, "nullable": true}, "pets": {"type": "string", "nullable": true}, "smoking": {"type": "array", "items": {}, "nullable": true}, "transportation": {"type": "array", "items": {}, "nullable": true}, "visiting_hours": {"type": "array", "items": {}, "nullable": true}, "number_residents": {"type": "integer", "nullable": true}, "men_women_separated": {"type": "boolean", "nullable": true}, "pets_policy": {"type": "array", "items": {}, "nullable": true}, "additional_information": {"type": "string", "nullable": true}, "acreditation": {"type": "array", "items": {}, "nullable": true}, "adults_children_separated": {"type": "boolean", "nullable": true}, "aftercare_program": {"type": "boolean", "nullable": true}, "after_hours_policy": {"type": "string", "nullable": true}, "age_policy": {"type": "string", "nullable": true}, "confidentiality_policy": {"type": "string", "nullable": true}, "detox_program": {"type": "boolean", "nullable": true}, "doctor_types": {"type": "array", "items": {}, "nullable": true}, "establishment_year": {"type": "integer", "nullable": true}, "family_counseling": {"type": "boolean", "nullable": true}, "family_support": {"type": "boolean", "nullable": true}, "inpatient_outpatient_rehab_diff": {"type": "string", "nullable": true}, "insurance_accepted": {"type": "array", "items": {}, "nullable": true}, "licensed_clinicians": {"type": "boolean", "nullable": true}, "medication_management": {"type": "boolean", "nullable": true}, "one_on_one_counseling_frequency": {"type": "string", "nullable": true}, "personal_devices_allowed": {"type": "boolean", "nullable": true}, "prescribe_medication": {"type": "boolean", "nullable": true}, "program_length": {"type": "string", "nullable": true}, "readmits_allowed": {"type": "boolean", "nullable": true}, "staff_to_patient_ratio": {"type": "string", "nullable": true}, "support_groups": {"type": "boolean", "nullable": true}, "threatment_options": {"type": "array", "items": {}, "nullable": true}, "trial_session": {"type": "boolean", "nullable": true}}}, "PatchedCommunitySurveyData": {"oneOf": [{"$ref": "#/components/schemas/PatchedSeniorLivingSurveyData"}, {"$ref": "#/components/schemas/PatchedBehavioralHealthSurveyData"}]}, "PatchedLeadReport": {"type": "object", "properties": {"lead_status": {"enum": [null, "no-contact", "qualified", "financial", "no_response", "not-qualified", "tour", "move-in", "move-out", "duplicate", "not-looking-for", "qualified-closed", "bad-info", "other", "other-closed", ""], "description": "* `None` - None\n* `no-contact` - Could Not Make Contact\n* `qualified` - Qualified, Made Contact\n* `financial` - Not Financially Qualified\n* `no_response` - Reached Out (email/phone) - No Response Yet\n* `not-qualified` - Not Qualified - Other\n* `tour` - Scheduled Tour\n* `move-in` - Moved In\n* `move-out` - Moved Out\n* `duplicate` - Duplicate\n* `not-looking-for` - Looking for something else.\n* `qualified-closed` - Qualified, but closed lead\n* `bad-info` - Bad Contact Information\n* `other` - Other\n* `other-closed` - Other, Closed", "x-spec-enum-id": "71604178179b7a3e", "nullable": true}, "report_type": {"enum": ["tour", "move-in"], "type": "string", "x-spec-enum-id": "05e61e51ab1b37a9", "writeOnly": true, "description": "Event being reported. `tour` records that the lead attended a tour; `move_in` records a move-in.\n\n* `tour` - tour\n* `move-in` - move-in"}, "report_date": {"type": "string", "format": "date-time", "writeOnly": true, "nullable": true, "description": "ISO-8601 timestamp at which the event occurred. Defaults to the time of the request if omitted."}}}, "PatchedSeniorLivingSurveyData": {"type": "object", "properties": {"activities": {"type": "array", "items": {}, "nullable": true}, "activities_calendar_url": {"type": "string", "nullable": true}, "adult_day_care": {"type": "boolean", "nullable": true}, "adult_day_care_hours": {"type": "string", "nullable": true}, "age_limit": {"type": "integer", "nullable": true}, "amenities": {"type": "array", "items": {}, "nullable": true}, "amenities_url": {"type": "string", "nullable": true}, "budget_assistance": {"type": "array", "items": {}, "nullable": true}, "car_allowed": {"type": "boolean", "nullable": true}, "care_types": {"type": "array", "items": {}, "nullable": true}, "cleaning_services": {"type": "array", "items": {}, "nullable": true}, "couples_allowed": {"type": "boolean", "nullable": true}, "dining_areas": {"type": "array", "items": {}, "nullable": true}, "entrance_fee": {"type": "integer", "nullable": true}, "entrance_fee_text": {"type": "string", "nullable": true}, "is_ccrc": {"type": "boolean", "readOnly": true}, "exercise_fitness": {"type": "array", "items": {}, "nullable": true}, "floorplans_url": {"type": "string", "nullable": true}, "hospice": {"type": "boolean", "nullable": true}, "images_url": {"type": "string", "nullable": true}, "included": {"type": "array", "items": {}, "nullable": true}, "jobs_url": {"type": "string", "nullable": true}, "languages": {"type": "array", "items": {}, "nullable": true}, "lease_term": {"type": "integer", "nullable": true}, "long_term_insurance": {"type": "boolean", "nullable": true}, "meals": {"type": "array", "items": {}, "nullable": true}, "parking": {"type": "boolean", "nullable": true}, "pets": {"type": "string", "nullable": true}, "physical_therapy": {"type": "string", "nullable": true}, "private_aides": {"type": "boolean", "nullable": true}, "respite_care": {"type": "boolean", "nullable": true}, "room_amenities": {"type": "array", "items": {}, "nullable": true}, "second_person_fee": {"type": "integer", "nullable": true}, "skilled_nursing": {"type": "boolean", "nullable": true}, "smoking": {"type": "array", "items": {}, "nullable": true}, "speech_therapy": {"type": "boolean", "nullable": true}, "transportation": {"type": "array", "items": {}, "nullable": true}, "vision_impaired": {"type": "boolean", "nullable": true}, "wheelchair": {"type": "string", "nullable": true}, "outdoor_areas": {"type": "array", "items": {}, "nullable": true}, "dietary_needs": {"type": "array", "items": {}, "nullable": true}, "religious_services": {"type": "array", "items": {}, "nullable": true}, "visiting_hours": {"type": "array", "items": {}, "nullable": true}, "security": {"type": "array", "items": {}, "nullable": true}, "services": {"type": "array", "items": {}, "nullable": true}, "room_types": {"type": "array", "items": {}, "nullable": true}, "number_residents": {"type": "integer", "nullable": true}, "men_women_separated": {"type": "boolean", "nullable": true}, "care_services": {"type": "array", "items": {}, "nullable": true}, "group_activities": {"type": "array", "items": {}, "nullable": true}, "outdoor_activities": {"type": "array", "items": {}, "nullable": true}, "pets_policy": {"type": "array", "items": {}, "nullable": true}, "additional_information": {"type": "string", "nullable": true}}}, "PublicCheckNewMessagesRequest": {"type": "object", "description": "Request body for `POST /api/v1/conversations/leads/{id}/messages/check-new`.", "properties": {"message_type": {"enum": ["email", "sms", null], "type": "string", "x-spec-enum-id": "a718e613965537ee", "nullable": true, "description": "Channel of the reference message. Pass `null` to check across all channels.\n\n* `email` - email\n* `sms` - sms"}, "message_id": {"type": "integer", "nullable": true, "description": "Identifier of the last message the caller has seen. Pass `null` to check from the beginning."}, "same_type": {"type": "boolean", "description": "If `true`, only count new messages whose channel matches `message_type`."}}, "required": ["message_id", "message_type"]}, "PublicCheckNewMessagesResponse": {"type": "object", "description": "Response body for `POST /api/v1/conversations/leads/{id}/messages/check-new`.", "properties": {"new_messages": {"type": "boolean", "description": "`true` if there are messages newer than the reference message; otherwise `false`."}}, "required": ["new_messages"]}, "PublicCommunityAddress": {"type": "object", "properties": {"address": {"type": "string", "nullable": true, "description": "Street address"}, "city": {"type": "string", "nullable": true, "description": "City name"}, "state": {"type": "string", "nullable": true, "description": "State or province"}, "zip": {"type": "string", "nullable": true, "description": "ZIP or postal code"}}, "required": ["address", "city", "state", "zip"]}, "PublicCommunityContactInfo": {"type": "object", "description": "A community's main point of contact: emails, phone numbers, and first name.", "properties": {"primary_sales_email": {"type": "string", "format": "email", "nullable": true, "description": "Primary contact email of the community. Leads are announced to this address.", "maxLength": 300}, "other_sales_emails": {"type": "array", "items": {"type": "string", "format": "email", "maxLength": 300}, "description": "Secondary contact emails of the community."}, "sales_phones": {"type": "array", "items": {"type": "string", "maxLength": 20}, "description": "Contact phone numbers of the community."}, "sales_first_name": {"type": "string", "nullable": true, "description": "First name of the community's primary contact.", "maxLength": 300}}}, "PublicCommunityEventCommunity": {"type": "object", "properties": {"community_event_id": {"type": "integer", "description": "ID of this community-specific event occurrence."}, "id": {"type": "integer", "description": "Community ID."}, "name": {"type": "string", "description": "Community name."}, "timezone": {"type": "string", "description": "IANA timezone identifier for the community."}, "local_start_date_time": {"type": "string", "format": "date-time", "description": "Start timestamp converted to this community's local timezone."}, "local_end_date_time": {"type": "string", "format": "date-time", "description": "End timestamp converted to this community's local timezone."}, "local_display_start_date": {"type": "string", "format": "date-time", "description": "Display-only start date converted to this community's local timezone."}, "local_display_end_date": {"type": "string", "format": "date-time", "description": "Display-only end date converted to this community's local timezone."}, "address": {"type": "string", "description": "Free-text street address where the event takes place at this community."}}, "required": ["address", "community_event_id", "id", "local_display_end_date", "local_display_start_date", "local_end_date_time", "local_start_date_time", "name", "timezone"]}, "PublicCommunityEventInstanceList": {"type": "object", "properties": {"event_instance_uuid": {"type": "string", "format": "uuid", "description": "Unique identifier for the event instance."}, "image": {"type": "string", "format": "uri", "nullable": true, "description": "URL to the event's image at the aspect ratio it was uploaded at, or `null` if none was uploaded. This is the whole photo rather than the cropped banner shown inside the Further assistant, so it suits any layout you render it in. Events last saved before we started keeping the whole photo return the cropped banner instead."}, "name": {"type": "string", "description": "Event name."}, "description": {"type": "string", "description": "Event description."}, "is_all_day": {"type": "boolean", "description": "`true` for all-day events, `false` for events with explicit start/end times."}, "communities": {"type": "array", "items": {"$ref": "#/components/schemas/PublicCommunityEventCommunity"}, "description": "Communities this event runs at, each with its own local start/end and display times."}}, "required": ["communities", "description", "event_instance_uuid", "image", "is_all_day", "name"]}, "PublicCommunityGroup": {"type": "object", "properties": {"id": {"type": "integer", "description": "Identifier of the community group."}, "name": {"type": "string", "description": "Display name of the community group."}, "color": {"type": "string", "description": "Hex color used to visually tag the group in the dashboard."}, "communities": {"type": "array", "items": {"$ref": "#/components/schemas/CommunitySimpleInfo"}}}, "required": ["color", "communities", "id", "name"]}, "PublicCommunityList": {"type": "object", "properties": {"id": {"type": "integer", "readOnly": true}, "community_uuid": {"type": "string", "format": "uuid", "description": "Unique identifier for the community"}, "name": {"type": "string", "maxLength": 511}, "url": {"type": "string", "format": "uri", "nullable": true, "maxLength": 200}, "facility_type": {"enum": ["nursing_home", "assisted_living", "continuing_care_retirement", "independent_living", "home_care", "multi_family", "partner", "substance_abuse", "mental_health", "eating_disorders", "medication_assisted_treatment", "outpatient"], "type": "string", "description": "* `nursing_home` - NURSING_HOME\n* `assisted_living` - ASSISTED_LIVING\n* `continuing_care_retirement` - CONTINUING_CARE_RETIREMENT\n* `independent_living` - INDEPENDENT_LIVING\n* `home_care` - HOME_CARE\n* `multi_family` - MULTI_FAMILY\n* `partner` - PARTNER\n* `substance_abuse` - SUBSTANCE_ABUSE\n* `mental_health` - MENTAL_HEALTH\n* `eating_disorders` - EATING_DISORDERS\n* `medication_assisted_treatment` - MEDICATION_ASSISTED_TREATMENT\n* `outpatient` - OUTPATIENT", "x-spec-enum-id": "dc602c7fe0a6af3f"}, "slug": {"type": "string", "maxLength": 50, "pattern": "^[-a-zA-Z0-9_]+$"}, "organization_id": {"type": "integer", "description": "Identifier for the organization that the community belongs to"}, "address": {"allOf": [{"$ref": "#/components/schemas/PublicCommunityAddress"}], "description": "Community address details"}}, "required": ["community_uuid", "facility_type", "id", "name", "organization_id", "slug"]}, "PublicCommunityPricing": {"type": "object", "properties": {"community_id": {"type": "integer", "readOnly": true, "description": "Identifier of the community."}, "starting_cost": {"type": "integer", "nullable": true, "description": "Lowest monthly cost across all care types (in dollars), or `null` if unset."}, "ending_cost": {"type": "integer", "nullable": true, "description": "Highest monthly cost across all care types (in dollars), or `null` if unset."}, "price_by_care_type": {"type": "array", "items": {"$ref": "#/components/schemas/PublicPriceList"}, "description": "Per-care-type pricing breakdown for this community."}}, "required": ["community_id", "ending_cost", "price_by_care_type", "starting_cost"]}, "PublicLeadConversationSendRequest": {"type": "object", "description": "Request body for `POST /api/v1/conversations/leads/{id}/messages/send`.", "properties": {"message_type": {"enum": ["email", "sms"], "type": "string", "x-spec-enum-id": "a718e613965537ee", "description": "Channel to send the message on. One of `sms` or `email`.\n\n* `email` - email\n* `sms` - sms"}, "text": {"type": "string", "description": "Message body. Plain text for SMS, HTML or plain text for email."}, "attachment": {"type": "string", "format": "uri", "description": "Optional file attachment (pdf, jpg, jpeg, gif, png)."}, "external_sender_user_id": {"type": "string", "description": "Identifier of the sending agent in the caller's system (e.g. Salesforce user id)."}}, "required": ["message_type", "text"]}, "PublicLeadConversationSendResponse": {"type": "object", "description": "Response body for `POST /api/v1/conversations/leads/{id}/messages/send`.", "properties": {"message_id": {"type": "integer", "description": "Identifier of the message that was created and queued for delivery."}, "message_type": {"enum": ["email", "sms"], "type": "string", "x-spec-enum-id": "a718e613965537ee", "description": "Channel the message was sent on (echoed from the request).\n\n* `email` - email\n* `sms` - sms"}}, "required": ["message_id", "message_type"]}, "PublicPriceList": {"type": "object", "properties": {"id": {"type": "integer", "description": "Identifier of the per-care-type price row."}, "name": {"type": "string", "readOnly": true, "description": "Care type name (e.g. `Independent Living`)."}, "cost": {"type": "integer", "maximum": 2147483647, "minimum": 0, "description": "Monthly cost for this care type (in dollars)."}}, "required": ["cost", "id", "name"]}, "SeniorLivingSurveyData": {"type": "object", "properties": {"activities": {"type": "array", "items": {}, "nullable": true}, "activities_calendar_url": {"type": "string", "nullable": true}, "adult_day_care": {"type": "boolean", "nullable": true}, "adult_day_care_hours": {"type": "string", "nullable": true}, "age_limit": {"type": "integer", "nullable": true}, "amenities": {"type": "array", "items": {}, "nullable": true}, "amenities_url": {"type": "string", "nullable": true}, "budget_assistance": {"type": "array", "items": {}, "nullable": true}, "car_allowed": {"type": "boolean", "nullable": true}, "care_types": {"type": "array", "items": {}, "nullable": true}, "cleaning_services": {"type": "array", "items": {}, "nullable": true}, "couples_allowed": {"type": "boolean", "nullable": true}, "dining_areas": {"type": "array", "items": {}, "nullable": true}, "entrance_fee": {"type": "integer", "nullable": true}, "entrance_fee_text": {"type": "string", "nullable": true}, "is_ccrc": {"type": "boolean", "readOnly": true}, "exercise_fitness": {"type": "array", "items": {}, "nullable": true}, "floorplans_url": {"type": "string", "nullable": true}, "hospice": {"type": "boolean", "nullable": true}, "images_url": {"type": "string", "nullable": true}, "included": {"type": "array", "items": {}, "nullable": true}, "jobs_url": {"type": "string", "nullable": true}, "languages": {"type": "array", "items": {}, "nullable": true}, "lease_term": {"type": "integer", "nullable": true}, "long_term_insurance": {"type": "boolean", "nullable": true}, "meals": {"type": "array", "items": {}, "nullable": true}, "parking": {"type": "boolean", "nullable": true}, "pets": {"type": "string", "nullable": true}, "physical_therapy": {"type": "string", "nullable": true}, "private_aides": {"type": "boolean", "nullable": true}, "respite_care": {"type": "boolean", "nullable": true}, "room_amenities": {"type": "array", "items": {}, "nullable": true}, "second_person_fee": {"type": "integer", "nullable": true}, "skilled_nursing": {"type": "boolean", "nullable": true}, "smoking": {"type": "array", "items": {}, "nullable": true}, "speech_therapy": {"type": "boolean", "nullable": true}, "transportation": {"type": "array", "items": {}, "nullable": true}, "vision_impaired": {"type": "boolean", "nullable": true}, "wheelchair": {"type": "string", "nullable": true}, "outdoor_areas": {"type": "array", "items": {}, "nullable": true}, "dietary_needs": {"type": "array", "items": {}, "nullable": true}, "religious_services": {"type": "array", "items": {}, "nullable": true}, "visiting_hours": {"type": "array", "items": {}, "nullable": true}, "security": {"type": "array", "items": {}, "nullable": true}, "services": {"type": "array", "items": {}, "nullable": true}, "room_types": {"type": "array", "items": {}, "nullable": true}, "number_residents": {"type": "integer", "nullable": true}, "men_women_separated": {"type": "boolean", "nullable": true}, "care_services": {"type": "array", "items": {}, "nullable": true}, "group_activities": {"type": "array", "items": {}, "nullable": true}, "outdoor_activities": {"type": "array", "items": {}, "nullable": true}, "pets_policy": {"type": "array", "items": {}, "nullable": true}, "additional_information": {"type": "string", "nullable": true}}, "required": ["activities", "activities_calendar_url", "additional_information", "adult_day_care", "adult_day_care_hours", "age_limit", "amenities", "amenities_url", "budget_assistance", "car_allowed", "care_services", "care_types", "cleaning_services", "couples_allowed", "dietary_needs", "dining_areas", "entrance_fee", "exercise_fitness", "floorplans_url", "group_activities", "hospice", "images_url", "included", "is_ccrc", "jobs_url", "languages", "lease_term", "long_term_insurance", "meals", "men_women_separated", "number_residents", "outdoor_activities", "outdoor_areas", "parking", "pets", "pets_policy", "physical_therapy", "private_aides", "religious_services", "respite_care", "room_amenities", "room_types", "second_person_fee", "security", "services", "skilled_nursing", "smoking", "speech_therapy", "transportation", "vision_impaired", "visiting_hours", "wheelchair"]}, "VisitorPublicDetails": {"type": "object", "properties": {"uuid": {"type": "string", "format": "uuid", "description": "Stable identifier for the website visitor. Survives across visits on the same browser."}, "timestamp": {"type": "string", "format": "date-time", "description": "ISO-8601 timestamp at which the visitor was first recorded."}, "community_id": {"type": "integer", "description": "Identifier of the community whose website the visitor landed on."}, "community_name": {"type": "string", "description": "Display name of the community."}, "referrer": {"type": "string", "description": "URL the visitor was referred from, or empty if not available."}, "traffic_source": {"type": "string", "description": "Classified traffic source (e.g. `Direct`, `Google Ads`, `Google SEO`, `Facebook Ad`)."}}, "required": ["community_id", "community_name", "referrer", "timestamp", "traffic_source", "uuid"]}}, "securitySchemes": {"OrganizationApiKey": {"type": "apiKey", "in": "header", "name": "Authorization", "description": "Organization API key issued on a per-organization basis. Pass as `Authorization: Org-Api-Key frth_org_\u2026`. Requires the scope declared by the endpoint (e.g. `events:read`) or the `api:read` umbrella scope."}, "PersonalApiKey": {"type": "apiKey", "in": "header", "name": "Authorization", "description": "Personal API key issued on a per-user basis. Pass as `Authorization: Api-Key frth_usr_\u2026`. Returns data scoped to the communities the key owner can access."}}}, "servers": [{"url": "https://api.talkfurther.com", "description": "Production (US)"}, {"url": "https://api.ca.talkfurther.com", "description": "Production (Canada)"}, {"url": "https://api.uk.talkfurther.com", "description": "Production (UK)"}], "tags": [{"name": "Getting Started", "description": "## Authentication\n\nAll Further `/api/v1/` endpoints require an API key sent in the standard `Authorization` HTTP header. Further supports **two** key types \u2014 pick the one that matches how the integration is owned.\n\n| | Personal API Key | Organization API Key |\n| --- | --- | --- |\n| **Key prefix** | `frth_usr_\u2026` | `frth_org_\u2026` |\n| **Header keyword** | `Api-Key` | `Org-Api-Key` |\n| **Scoped to** | A single user | An entire organization |\n| **Permissions** | The user's role | Explicit scopes on the key (e.g. `analytics:read`, `leads:write`) |\n| **Best for** | A person scripting against the API as themselves | Server-to-server integrations and shared automations |\n\n## Wire format\n\n**Personal API Key**\n\n```http\nAuthorization: Api-Key frth_usr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n**Organization API Key**\n\n```http\nAuthorization: Org-Api-Key frth_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\nThe header keyword (`Api-Key` / `Org-Api-Key`) is case-insensitive, but the key value itself is not. Send the entire key \u2014 including the `frth_usr_` / `frth_org_` prefix \u2014 exactly as it was issued.\n\n## Obtaining a key\n\n> **Organization API Keys are the recommended approach.** Personal API Keys exist for legacy reasons and are still required by some endpoints, but every endpoint will eventually support Organization API Keys, and new integrations should default to them.\n\n### Personal API Keys\n\nPersonal API Keys are issued by Further support \u2014 there is no self-service flow. Contact support to request one. Each key inherits the permissions of the user it belongs to and is invalidated if that user is deactivated.\n\nNote that, today, **most endpoints only support Personal API Keys.** Organization API Key support is being rolled out per endpoint and will eventually cover all `/api/v1/` routes.\n\n### Organization API Keys\n\nOrganization administrators create Organization API Keys self-service from the Further dashboard:\n\n**Dashboard \u2192 Settings \u2192 API Keys \u2192 New API Key**\n\nGive the key a descriptive name and select the scopes it should be granted. The full key value is shown **once** at creation \u2014 copy it immediately and store it somewhere safe (a password manager or secret store). Further does not retain the plaintext value and cannot recover it later; if you lose it, rotate the key.\n\n### Available scopes\n\nOrganization keys must declare the scopes they need at creation time. Scope-protected endpoints will reject keys missing the required scope.\n\n- **Umbrella:** `api:read`, `api:write`\n- **Domain:** `analytics:read`, `events:read`, `leads:read`, `leads:write`, `conversations:read`, `conversations:write`, `communities:read`, `communities:write`, `pricing:read`, `pricing:write`\n\n## Troubleshooting\n\n- **`401 Unauthorized`** \u2014 Check that the `Authorization` header is present and the keyword (`Api-Key` vs `Org-Api-Key`) matches the key's prefix. A `frth_org_\u2026` key sent with the `Api-Key` keyword will be rejected.\n- **`403 Forbidden` on an Organization key** \u2014 The key is valid but missing a required scope. Rotate the key with the additional scope, or use a key that already has it.\n- **The key stopped working** \u2014 Personal keys are invalidated when the owning user is deactivated. Organization keys are invalidated when the organization is deactivated, when the key expires, or when it is revoked or rotated.\n"}, {"name": "Rate limits", "description": "All Further `/api/v1/` endpoints are rate-limited to **300 requests per minute per API key**.\n\nWhen a key exceeds the limit, the server responds with `429 Too Many Requests` and a `Retry-After` header containing the number of seconds to wait before retrying. Clients should honour `Retry-After` rather than retrying immediately \u2014 a simple back-off loop that respects the header is sufficient.\n\nBatch reads where the API supports pagination, cache responses where appropriate, and prefer separate keys when running multiple integrations on the same account so one workload can't starve another.\n"}], "x-tagGroups": [{"name": "Guides", "tags": ["Getting Started", "Rate limits"]}, {"name": "API Reference", "tags": ["Communities", "Community groups", "Conversations", "Events", "Leads", "Visitors"]}]}