Spruce Health · AsyncAPI Specification
Spruce Health Webhooks
Version
View Spec
View on GitHub
HealthcareHIPAACommunicationsSecure MessagingTelehealthPatient EngagementContactsConversationsMessagingSMSVoiceVoIPFaxVideoWebhookSchedulingTranscriptionEHR IntegrationComplianceAsyncAPIWebhooksEvents
AsyncAPI Specification
generated: '2026-08-15'
method: searched
source: https://developer.sprucehealth.com/docs/webhooks-overview.md
docs: https://developer.sprucehealth.com/docs/webhooks-overview
provider: Spruce Health
providerId: spruce-health
type: Webhooks
description: >-
Spruce Health's event surface is outbound HTTPS webhooks. Spruce POSTs a signed event
envelope to endpoints an organization registers through the Public API. This is the
full published event catalog, its delivery contract and its signature scheme, read
from the Spruce Webhooks Overview (last updated by Spruce 2026-07-31).
asyncapi_published: false
asyncapi_note: >-
Spruce publishes no AsyncAPI document. /asyncapi.yaml on the docs host returns 404 and
no event schema file appears in the ReadMe registry alongside the OpenAPI. The events
below are transcribed from the provider's own documentation and worked example
payloads; no AsyncAPI has been authored on Spruce's behalf, because a generated one
would assert a machine-readable contract the provider does not actually serve.
probe:
url: https://developer.sprucehealth.com/asyncapi.yaml
http_status: 404
fetched: '2026-08-15'
model:
direction: outbound
transport: HTTPS POST
websocket: false
websocket_note: >-
No ws:// or wss:// surface is documented anywhere in Spruce's developer materials.
Real-time delivery is server-to-endpoint HTTP, not a bidirectional socket.
scope: >-
All events published to an endpoint are scoped to the context of their owning
organization.
registration:
operation: CreateWebhookEndpoint
path: POST /webhooks/endpoints
reference: https://developer.sprucehealth.com/reference/createwebhookendpoint
note: >-
The create response returns a signing secret. It is returned ONCE, at creation -
subsequent listings never return it.
management:
list: GET /webhooks/endpoints
get: GET /webhooks/endpoints/{endpointId}
delete: DELETE /webhooks/endpoints/{endpointId}
pause_resume: POST /webhooks/endpoints/{endpointId}/paused
delivery_log: GET /webhooks/endpoints/{endpointId}/events
delivery_log_retention: 30 days, returned 20 at a time with a pagination token
envelope:
fields:
- name: object
value: event
description: Constant discriminator identifying the payload as an event envelope.
- name: type
description: The event type, e.g. contact.created.
- name: eventTime
format: RFC 3339 UTC
description: When the event occurred.
- name: data.object
description: >-
The full current state of the affected resource, itself carrying an `object` field
naming its type (contact, conversation, conversationItem, scheduledMessage).
example_shape: |
{
"object": "event",
"type": "contact.created",
"eventTime": "2024-05-15T00:00:00Z",
"data": { "object": { "object": "contact", "id": "entity_...", ... } }
}
note: >-
The envelope carries the whole resource, not a delta, so a consumer does not need a
follow-up GET to apply the change.
events:
- type: contact.created
resource: contact
description: Occurs when a new contact is created.
- type: contact.updated
resource: contact
description: Occurs when a contact is modified.
- type: contact.deleted
resource: contact
description: Occurs when a contact is deleted.
- type: contact.merged
resource: contact
description: Occurs when contacts are merged.
added: '2026-04-15'
note: >-
Spruce's own event table describes this as "Occurs when contacts are deleted",
which reads as a copy error against the event name and the worked merge example.
Announced on the changelog 2026-04-15 as "New webhook event: contact.merged".
- type: conversation.created
resource: conversation
description: Occurs when a new conversation is created.
- type: conversation.updated
resource: conversation
description: Occurs when a conversation is modified.
- type: conversation.deleted
resource: conversation
description: Occurs when a conversation is deleted.
- type: conversationItem.created
resource: conversationItem
description: Occurs when a new conversation item is created.
correlates_with:
- PostConversationMessage (requestID)
- PostMessageFromEndpoint (RequestID)
- CreateConversation (postMessageRequestId)
- type: conversationItem.updated
resource: conversationItem
description: Occurs when a conversation item is modified.
- type: conversationItem.deleted
resource: conversationItem
description: Occurs when a conversation item is deleted.
correlates_with:
- DeleteConversationItem (requestId)
- type: conversationItem.restored
resource: conversationItem
description: Occurs when a conversation item is restored.
note: >-
Deletion is a soft delete that leaves a restorable placeholder, which is why a
restore is an event in its own right.
- type: scheduledMessage.created
resource: scheduledMessage
description: Occurs when a message is scheduled.
added: '2026-07-31'
- type: scheduledMessage.updated
resource: scheduledMessage
description: Occurs when a scheduled message is modified.
added: '2026-07-31'
- type: scheduledMessage.deleted
resource: scheduledMessage
description: Occurs when a scheduled message is deleted before it was sent.
added: '2026-07-31'
- type: scheduledMessage.sent
resource: scheduledMessage
description: Occurs when a scheduled message reaches its send time and is posted.
added: '2026-07-31'
event_count: 15
delivery:
scheme_required: https
scheme_note: Spruce will only send events to endpoints that support HTTPS.
ack_status: 2XX
ack_window_seconds: 5
ordering:
sent_in_order: true
delivered_in_order: false
note: >-
Events are sent in the order they occur, but may not arrive in that order.
Consumers must be able to handle out-of-order events - eventTime is the field to
order on.
retry:
interval_minutes: 2
max_attempts: 10
trigger: any non-2XX response, or no response within the 5-second window
rate_limit:
events_per_minute: 1000
scope: per endpoint
behavior: >-
If the limit is exceeded, events resume sending after the rate limit window has
passed.
signature:
header: X-Spruce-Signature
algorithm: HMAC-SHA256
encoding: base64
secret_issued: at endpoint creation, returned once and never again
verification: >-
Base64-decode the X-Spruce-Signature header, HMAC-SHA256 the raw request body with
the endpoint secret, and compare the two in constant time. Spruce publishes a Go
reference implementation using hmac.Equal in the Webhooks Overview.
consumer_guidance:
mapping_items_to_contacts: >-
A conversationItem event carries the conversation id; pass it to GET
/conversations/{conversationId} to resolve the containing thread. For conversations
with unsaved or multiple matching contacts, the rawValue of the externalParticipant
endpoint can be passed to POST /contacts/search to resolve candidate contacts.
polling_alternative: >-
Where webhooks are not an option, ListConversations with orderBy=last_message plus
startFrom is the documented polling pattern for detecting new activity.
access:
gated: true
note: >-
Webhooks are only reachable through the Public API, so they inherit its gate - the
Communicator plan plus API access enabled by Spruce Support.
request_form: https://sprucehealth.com/spruce-api
maintainers:
- FN: Kin Lane
email: kin@apievangelist.com