Legal & compliance
Business Associate Agreement (BAA)
Required before any PHI scope works:
transcripts:read,
recordings:read, and (Phase 2) intake:write return 403 baa_required
until the BAA is executed. PHI flows both directions once granted, so your
own storage and access controls for transcripts, recordings, and patient
data must be HIPAA-appropriate. Start early — this is usually the
long pole.TCPA consent attestation
Outbound calls may only go to contacts with prior express consent to
be called at the submitted number. Under your partner agreement, that
attestation is yours: every contact you submit in a call request (and
every patient you push in Phase 2, via the required
consent field) is a
representation that consent exists and is current.Verify before go-live:- You capture and store consent (timestamp + method) in your system.
- Opt-outs and do-not-call flags in your system suppress submission — don’t submit and rely on us to filter.
- No purchased or third-party lists, ever.
Call recording consent rules
Calls are recorded and several US states require all-party consent.
The voice agent handles disclosure on GrowDental-placed calls, but if you
fetch recordings via the API, your downstream use (storage, playback,
sharing) must comply with the strictest state involved. If you are unsure,
limit recording access to internal QA.
Security
- API key lives in a secret manager; never in code, config files, logs, or client-side apps.
- All API calls originate from your servers over HTTPS.
- Webhook signing secret stored like the API key; captured at endpoint creation (it is shown once).
- Webhook receiver verifies
X-GrowDental-Signature(constant-time compare, 300 s timestamp tolerance) and rejects failures with a 4xx — see Receiving call outcomes. - A key-rotation runbook exists (who requests the new key, where it deploys, who confirms revocation).
Operational readiness
-
Idempotency-Keysent on every POST — especially call-request creation, where a blind retry can dial patients twice. - 429 handling honors
Retry-Afterforrate_limitedand pauses until tomorrow fordaily_cap_exceeded; 409 backpressure (queue_full,insufficient_minute_balance) pauses submission instead of hammering. - Webhook receiver responds 2xx in under 10 seconds (enqueue, then process) and de-duplicates on
X-GrowDental-Delivery-Id. - Alerting exists for webhook endpoint auto-disable (poll
GET /webhook-endpointsforstatus: "disabled"or alert on sustained delivery gaps). - Recording URLs from the 302 redirect are treated as ephemeral — fetched on demand, never persisted or shared.
- Transcript/summary text is stored under the same access controls as the rest of your PHI.
Integration sanity pass
-
GET /practicesreturns exactly the practices you expect, with the scopes you expect for each. - A test call request against your pilot practice completes end to end: contacts progress to terminal states,
call.completedevents arrive and verify, theexternal_refyou submitted per contact round-trips (echoed asexternal_refonGET /call-requests/{id}contact progress and ascontact_external_refoncall.completedevents), and the request’scountsreconcile with the contacts you submitted. - Ungranted-practice behavior confirmed: unknown practice IDs return
404and your code treats that as “not granted”, not as a retryable error. - Your handling tolerates new enum values (outcomes and event types can grow without a version bump).