Spruce Integration Guide

Interacting with the Spruce Public API for integration with external systems

Integration Guide

Here's how Spruce's Public API supports keeping Spruce and an external system (EMR, CRM, PMS, scheduling, billing, etc.) in sync. At a high level, there are three pieces:

  1. Push contact demographics into Spruce (if missing) using the REST Contact endpoints so every record in your system has a corresponding Spruce contact your team can message.
  2. Link each Spruce contact back to the external record with Integration Links so staff can round-trip between systems and your sync job can match records deterministically.
  3. Subscribe to Spruce Webhooks to receive near-real-time notifications when demographics change in Spruce or when conversation activity happens, then write those back to your system.

Full API reference: https://developer.sprucehealth.com/reference/overview

All endpoints below live under the production REST API at https://api.sprucehealth.com/v1.

Authentication

All Public API calls use HTTP Basic or Bearer auth with a base64-encoded credential pair:

Authorization: Bearer <base64(access_id:secret_key)>

Access IDs and secret keys are issued per organization. Customers can request API access at https://sprucehealth.com/spruce-api. A method of secure exchange for these secrets with integration partners can be discussed with us as part of the integration development process.

Syncing Contact Demographics into Spruce

Initial backfill and ongoing create

Create a Spruce contact for each record that doesn't already exist in Spruce with POST /v1/contacts. You can pass an s-idempotency-key header (≤255 chars) to make retries safe — we recommend a stable value derived from the record ID in your system.

Minimum requirement: at least one of givenName, familyName, phoneNumbers, faxNumbers, or emailAddresses.

Example request body:

{
  "category": "patient",
  "givenName": "Joe",
  "middleName": "William",
  "familyName": "Smith",
  "dateOfBirth": "2000-01-30",
  "gender": "male",
  "phoneNumbers":   [{ "value": "+12225550000",    "label": "Mobile" }],
  "emailAddresses": [{ "value": "[email protected]", "label": "Home"   }]
}

The response returns the full contact, including the Spruce contact id (entity_…) you should persist against the external record.

Updating demographics

PATCH /v1/contacts/{contactId} accepts the same fields. Omitted fields are unchanged; empty strings or empty arrays clear a field. Use this when a record's phone number, address, name, etc. change in your system.

Deletion

DELETE /v1/contacts/{contactId}. Honor the canDelete flag on the contact before calling — contacts involved in active conversations typically aren't deletable.

Search / Lookup

POST /v1/contacts/search supports free-text and structured filters (name, phone, email, tags, category, gender, account status, and — see below — integration link). Useful for reconciliation jobs or when webhook events reference a contact you haven't seen before.

Tags and custom fields

This is the best place to stamp metadata from the external system (MRN, insurance, primary care provider, account number, etc.) so your team sees it alongside the conversation.

Linking Spruce Contacts to the External System

Use Integration Links to associate a Spruce contact with its record in the external system. This gives staff a deep link from the Spruce UI back to the external system and gives your webhook consumer a canonical external ID to resolve back to the source record.

Looking up a Spruce contact by external ID

Once integration links are in place, you can find the Spruce contact for a given external record directly by passing an integrationIDFilter to POST /v1/contacts/search:

{
  "structured": {
    "integrationIDFilter": [
      {
        "integrationIDs": [
          { "integrationLinkType": "custom", "id": "ext_patient_12345" }
        ],
        "match": "any"
      }
    ]
  }
}

The contact payload (including webhook payloads) echoes integrationLinks back to you, so when you receive a contact.updated or conversation.created event you can resolve the Spruce contact directly to the external record without an extra call.

Receiving Change Notifications via Webhooks

Spruce Webhooks push events to a URL you own when contacts, conversations, or messages change. This is the mechanism for detecting demographic changes and conversation activity.

Event types most relevant to a bidirectional integration

  • Contact (demographics): contact.created, contact.updated, contact.deleted, contact.mergeddata.object is the full Contact resource, same shape as the REST API (so integrationLinks are available on the payload).
  • Conversation (thread metadata): conversation.created, conversation.updated, conversation.deleteddata.object includes associatedContactIds, externalParticipants, tags, archived, assignedToMemberId.
  • Conversation item (messages, notes, calls, attachments): conversationItem.created, conversationItem.updated, conversationItem.deleted, conversationItem.restoreddata.object embeds the parent conversation, so you rarely need a follow-up GET.

Recommended End-to-End Architecture

  1. Bootstrap: one-time backfill — for each active record in the external system, POST /v1/contacts for contacts that don't already exist, then POST /v1/contacts/{id}/integrationlinks with type=custom and the external record URL. Persist the Spruce contact id on your side (optional if you rely on integrationIDFilter for lookups).
  2. Outbound sync (external system → Spruce): when the external system emits a demographic change, PATCH the corresponding Spruce contact. Use a stable idempotency key derived from the external change id.
  3. Inbound sync (Spruce → external system): register one webhook endpoint per environment. On each event:
    • Verify the X-Spruce-Signature header (see the webhooks overview linked above).
    • Ack with 2XX immediately; enqueue for async processing.
    • Resolve the external record via the Integration Link on the contact payload (or via associatedContactIds + integrationIDFilter for conversation events).
    • Apply the demographic change, or record the conversation activity in the external system (e.g. as a communication note, task, or timeline entry).