openapi: 3.0.3 info: title: Spruce Public API description: >- The Spruce Public API connects a Spruce Health organization to internal tools, electronic health records (EHRs), practice management systems, and other external systems so practices can automate workflows, sync data, and receive real-time events. It is a RESTful API over HTTPS with a base URL of https://api.sprucehealth.com/v1 and Bearer token authentication (Authorization: Bearer ); tokens are generated by administrators from the "API Access" section of Settings after Spruce Support enables API access for the organization (API access is part of the Communicator plan). Grounding note: the base URL and Bearer auth are confirmed from the Spruce developer documentation, and the following paths are confirmed directly from the API reference: GET /contacts, GET /conversations, POST /conversations/{conversationId}/messages, GET /webhooks/endpoints, POST /webhooks/endpoints, and GET /internalendpoints. The remaining paths and all request/response schemas are honestly MODELED from the published operation catalog (developer.sprucehealth.com/llms.txt) and documented behavior; exact request/response bodies should be reconciled against the live reference and the machine-readable OpenAPI Spruce publishes. version: '1.0' contact: name: Spruce Health url: https://developer.sprucehealth.com x-endpointsModeled: true servers: - url: https://api.sprucehealth.com/v1 description: Spruce Public API security: - bearerAuth: [] tags: - name: Contacts description: Contacts (patients and other parties) in a Spruce organization. - name: Conversations description: Conversations (message threads) in a Spruce organization. - name: Messages description: Conversation items, messages, media, endpoints, and scheduled messages. - name: Webhooks description: Webhook endpoints for real-time contact / conversation events. paths: /contacts: get: operationId: listContacts tags: - Contacts summary: List contacts description: Lists all contacts available to a given organization. Confirmed path. parameters: - name: pageSize in: query schema: type: integer format: int32 minimum: 1 maximum: 200 - name: paginationToken in: query schema: type: string responses: '200': description: A list of contacts. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Contact' '403': $ref: '#/components/responses/Forbidden' post: operationId: createContact tags: - Contacts summary: Create a contact description: Creates a new contact in the organization. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Contact' responses: '200': description: The created contact. content: application/json: schema: $ref: '#/components/schemas/Contact' '403': $ref: '#/components/responses/Forbidden' /contacts/search: get: operationId: searchContacts tags: - Contacts summary: Search contacts description: Search contacts by name, phone, email, or other fields. Modeled. parameters: - name: query in: query schema: type: string responses: '200': description: Matching contacts. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Contact' /contacts/{contactId}: parameters: - name: contactId in: path required: true schema: type: string get: operationId: contact tags: - Contacts summary: Get a contact description: Retrieves a single contact by ID. Modeled. responses: '200': description: The requested contact. content: application/json: schema: $ref: '#/components/schemas/Contact' '403': $ref: '#/components/responses/Forbidden' patch: operationId: updateContact tags: - Contacts summary: Update a contact description: Updates fields on an existing contact. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Contact' responses: '200': description: The updated contact. content: application/json: schema: $ref: '#/components/schemas/Contact' delete: operationId: deleteContact tags: - Contacts summary: Delete a contact description: Deletes a contact from the organization. Modeled. responses: '204': description: Contact deleted. /contacts/{contactId}/conversations: parameters: - name: contactId in: path required: true schema: type: string get: operationId: contactConversations tags: - Contacts summary: List a contact's conversations description: Lists the conversations associated with a contact. Modeled. responses: '200': description: Conversations for the contact. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Conversation' /contacts/{contactId}/integration-links: parameters: - name: contactId in: path required: true schema: type: string get: operationId: contactIntegrationLinks tags: - Contacts summary: List a contact's integration links description: Lists links between a contact and external systems (EHR/PM). Modeled. responses: '200': description: Integration links for the contact. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/IntegrationLink' post: operationId: createContactIntegrationLink tags: - Contacts summary: Create a contact integration link description: Links a contact to a record in an external system. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IntegrationLink' responses: '200': description: The created integration link. content: application/json: schema: $ref: '#/components/schemas/IntegrationLink' /contacts/fields: get: operationId: contactFields tags: - Contacts summary: List contact custom fields description: Lists the custom fields defined for contacts. Modeled. responses: '200': description: Contact fields. content: application/json: schema: type: object properties: data: type: array items: type: object post: operationId: createContactField tags: - Contacts summary: Create a contact custom field description: Creates a new custom field for contacts. Modeled. requestBody: required: true content: application/json: schema: type: object responses: '200': description: The created contact field. /contacts/tags: get: operationId: contactTags tags: - Contacts summary: List contact tags description: Lists the tags that can be applied to contacts. Modeled. responses: '200': description: Contact tags. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Tag' post: operationId: createContactTag tags: - Contacts summary: Create a contact tag description: Creates a new contact tag. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Tag' responses: '200': description: The created contact tag. /conversations: get: operationId: listConversations tags: - Conversations summary: List conversations description: Lists conversations in the organization. Confirmed path and parameters. parameters: - name: pageSize in: query schema: type: integer format: int32 minimum: 1 maximum: 200 description: How many conversations to return at one time (max 200). - name: paginationToken in: query schema: type: string description: Token to fetch subsequent pages; cannot be combined with startFrom. - name: orderBy in: query required: true schema: type: string enum: - created - last_message description: Order results by creation time or last message. - name: startFrom in: query schema: type: string format: date-time description: Only return conversations whose ordering field value is at or after this RFC 3339 timestamp. responses: '200': description: A list of conversations. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Conversation' '403': $ref: '#/components/responses/Forbidden' post: operationId: createConversation tags: - Conversations summary: Create a conversation description: Creates a new conversation. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Conversation' responses: '200': description: The created conversation. content: application/json: schema: $ref: '#/components/schemas/Conversation' /conversations/{conversationId}: parameters: - name: conversationId in: path required: true schema: type: string get: operationId: conversation tags: - Conversations summary: Get a conversation description: Retrieves a single conversation by ID. Modeled. responses: '200': description: The requested conversation. content: application/json: schema: $ref: '#/components/schemas/Conversation' patch: operationId: updateConversation tags: - Conversations summary: Update a conversation description: Updates an existing conversation. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Conversation' responses: '200': description: The updated conversation. content: application/json: schema: $ref: '#/components/schemas/Conversation' /conversations/tags: get: operationId: conversationTags tags: - Conversations summary: List conversation tags description: Lists the tags that can be applied to conversations. Modeled. responses: '200': description: Conversation tags. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Tag' post: operationId: createConversationTag tags: - Conversations summary: Create a conversation tag description: Creates a new conversation tag. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Tag' responses: '200': description: The created conversation tag. /conversations/{conversationId}/messages: parameters: - name: conversationId in: path required: true schema: type: string post: operationId: postConversationMessage tags: - Messages summary: Post a message to a conversation description: Posts a new message into a conversation. Confirmed path. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MessageCreate' responses: '200': description: The created conversation item (message). content: application/json: schema: $ref: '#/components/schemas/ConversationItem' '403': $ref: '#/components/responses/Forbidden' /conversations/{conversationId}/items: parameters: - name: conversationId in: path required: true schema: type: string get: operationId: conversationItems tags: - Messages summary: List conversation items description: Lists the items (messages, calls, faxes, events) in a conversation. Modeled. responses: '200': description: Conversation items. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ConversationItem' /conversations/{conversationId}/items/{itemId}: parameters: - name: conversationId in: path required: true schema: type: string - name: itemId in: path required: true schema: type: string get: operationId: conversationItem tags: - Messages summary: Get a conversation item description: Gets a conversation item for a given id. Modeled path (operation confirmed). responses: '200': description: The conversation item. content: application/json: schema: $ref: '#/components/schemas/ConversationItem' delete: operationId: deleteConversationItem tags: - Messages summary: Delete a conversation item description: Deletes a conversation item. Modeled. responses: '204': description: Item deleted. /internalendpoints: get: operationId: internalEndpoints tags: - Messages summary: List internal endpoints description: Lists all internal endpoints (phone lines / addresses) an organization can communicate with. Confirmed path. responses: '200': description: Internal endpoints. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Endpoint' /internalendpoints/{endpointId}/messages: parameters: - name: endpointId in: path required: true schema: type: string post: operationId: postMessageFromEndpoint tags: - Messages summary: Send a message from an internal endpoint description: Sends a message (e.g. SMS/secure) from a given internal endpoint. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MessageCreate' responses: '200': description: The created conversation item. content: application/json: schema: $ref: '#/components/schemas/ConversationItem' /proxy-calls: post: operationId: postCreateProxyCall tags: - Messages summary: Create a proxy call description: Creates a proxy (bridge) call between a member and a contact. Modeled. requestBody: required: true content: application/json: schema: type: object responses: '200': description: The created proxy call. /media: post: operationId: uploadMedia tags: - Messages summary: Upload media description: Uploads media for use as a message attachment. Modeled. requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary responses: '200': description: The uploaded media reference. /scheduled-messages: get: operationId: listScheduledMessages tags: - Messages summary: List scheduled messages description: Lists scheduled messages for the organization. Modeled. responses: '200': description: Scheduled messages. content: application/json: schema: type: object properties: data: type: array items: type: object /conversations/{conversationId}/scheduled-messages: parameters: - name: conversationId in: path required: true schema: type: string get: operationId: listConversationScheduledMessages tags: - Messages summary: List a conversation's scheduled messages description: Lists scheduled messages for a conversation. Modeled. responses: '200': description: Scheduled messages for the conversation. content: application/json: schema: type: object properties: data: type: array items: type: object post: operationId: scheduleConversationMessage tags: - Messages summary: Schedule a message in a conversation description: Schedules a message to be sent in a conversation at a future time. Modeled. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MessageCreate' responses: '200': description: The scheduled message. /scheduled-messages/{scheduledMessageId}: parameters: - name: scheduledMessageId in: path required: true schema: type: string delete: operationId: deleteScheduledMessage tags: - Messages summary: Delete a scheduled message description: Deletes a scheduled message before it is sent. Modeled. responses: '204': description: Scheduled message deleted. /saved-messages: get: operationId: listSavedMessages tags: - Messages summary: List saved messages description: Lists saved (canned/template) messages for the organization. Modeled. responses: '200': description: Saved messages. content: application/json: schema: type: object properties: data: type: array items: type: object /webhooks/endpoints: get: operationId: listWebhookEndpoints tags: - Webhooks summary: List webhook endpoints description: Lists the endpoints an organization has registered for webhooks (secret keys are not returned). Confirmed path. responses: '200': description: Webhook endpoints. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/WebhookEndpoint' post: operationId: createWebhookEndpoint tags: - Webhooks summary: Create a webhook endpoint description: >- Registers a new HTTPS webhook endpoint with a name and destination URL. The response includes a signing secret used to verify event signatures; the endpoint must respond 2XX within 5 seconds. Confirmed path. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookEndpointCreate' responses: '200': description: The created webhook endpoint, including its signing secret. content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' '403': $ref: '#/components/responses/Forbidden' /webhooks/endpoints/{endpointId}: parameters: - name: endpointId in: path required: true schema: type: string get: operationId: webhookEndpoint tags: - Webhooks summary: Get a webhook endpoint description: Retrieves a webhook endpoint by ID. Modeled. responses: '200': description: The webhook endpoint. content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' delete: operationId: deleteWebhookEndpoint tags: - Webhooks summary: Delete a webhook endpoint description: Deletes a webhook endpoint. Modeled. responses: '204': description: Webhook endpoint deleted. /webhooks/endpoints/{endpointId}/events: parameters: - name: endpointId in: path required: true schema: type: string get: operationId: listWebhookEndpointEvents tags: - Webhooks summary: List a webhook endpoint's events description: Lists the events delivered (or attempted) for a webhook endpoint. Modeled. responses: '200': description: Webhook endpoint events. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/WebhookEvent' /webhooks/endpoints/{endpointId}/paused: parameters: - name: endpointId in: path required: true schema: type: string put: operationId: modifyWebhookEndpointPaused tags: - Webhooks summary: Pause or resume a webhook endpoint description: Pauses or resumes dispatch of events to a webhook endpoint. Modeled. requestBody: required: true content: application/json: schema: type: object properties: paused: type: boolean responses: '200': description: The updated webhook endpoint. content: application/json: schema: $ref: '#/components/schemas/WebhookEndpoint' components: securitySchemes: bearerAuth: type: http scheme: bearer description: Organization API token generated in Settings after Spruce Support enables API access. responses: Forbidden: description: Missing, incorrect, or disabled API token. content: application/json: schema: type: object properties: error: type: string schemas: Contact: type: object properties: id: type: string displayName: type: string firstName: type: string lastName: type: string phones: type: array items: type: object properties: value: type: string label: type: string emails: type: array items: type: object properties: value: type: string label: type: string tags: type: array items: type: string IntegrationLink: type: object properties: id: type: string externalId: type: string system: type: string Tag: type: object properties: id: type: string name: type: string color: type: string Conversation: type: object properties: id: type: string title: type: string createdAt: type: string format: date-time lastMessageAt: type: string format: date-time tags: type: array items: type: string ConversationItem: type: object properties: id: type: string conversationId: type: string type: type: string description: Item type, e.g. message, call, fax, or secure conversation event. body: type: string createdAt: type: string format: date-time MessageCreate: type: object properties: body: type: string mediaIds: type: array items: type: string Endpoint: type: object properties: id: type: string displayName: type: string type: type: string value: type: string WebhookEndpointCreate: type: object required: - name - url properties: name: type: string url: type: string format: uri events: type: array items: type: string WebhookEndpoint: type: object properties: id: type: string name: type: string url: type: string format: uri secret: type: string description: Signing secret, returned only on creation. paused: type: boolean events: type: array items: type: string WebhookEvent: type: object properties: id: type: string type: type: string description: e.g. contact.created, conversation.updated, conversationItem.created. createdAt: type: string format: date-time deliveryStatus: type: string