Developer platform

REST API, webhooks & integrations

Wire CareLoop into your finance system, telephony, BI tools or staff app. JSON, OAuth-style API keys, predictable HTTP, and event-driven webhooks for everything that happens in the platform.

Beta · contact us for an API key

Authentication

API keys are scoped per organisation, expire after 365 days, and can be rotated without downtime.

curl
curl https://api.careloop.com/v1/residents \
  -H "Authorization: Bearer cl_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Accept: application/json"
Node
const res = await fetch("https://api.careloop.com/v1/residents", {
  headers: {
    Authorization: `Bearer ${process.env.CARELOOP_API_KEY}`,
    Accept: "application/json",
  },
});
const { data } = await res.json();
Python
import requests
res = requests.get(
    "https://api.careloop.com/v1/residents",
    headers={
        "Authorization": f"Bearer {os.environ['CARELOOP_API_KEY']}",
        "Accept": "application/json",
    },
)
data = res.json()["data"]

Scopes

Each key has a comma-separated scope list:

  • read:residents · resident records, care plans
  • read:staff · staff directory, roles, certs
  • read:incidents · incidents, falls, body map
  • write:visits · create / update visit records
  • admin · everything (org owners only)

Rate limits

120 requests / minute per API key. Bursts up to 30 in any 5-second window. 429 with a Retry-After header when exceeded. Webhook deliveries don’t count.

REST endpoints

JSON in, JSON out. Predictable HTTP verbs, standard error envelopes.

MethodPathPurpose
GET/v1/residentsList residents (filterable, paginated)
GET/v1/residents/:idSingle resident with location, keyworker, contacts
PATCH/v1/residents/:idUpdate resident record
GET/v1/residents/:id/care-notesCare notes timeline
POST/v1/residents/:id/care-notesAdd a care note
GET/v1/staffStaff directory with role + cert summary
GET/v1/staff/:id/certificationsCertifications for a staff member
POST/v1/staff/:id/certificationsIssue or renew a certification
GET/v1/incidentsIncidents with severity, type, status filters
POST/v1/incidentsLog an incident
GET/v1/visitsScheduled and completed visits
POST/v1/visitsSchedule a new visit
PATCH/v1/visits/:idUpdate or cancel a visit
GET/v1/coursesTraining catalogue (system + your org)
GET/v1/audit-logAudit log (search + paginate)
List residents
# 200 OK
{
  "data": [
    {
      "id": "8e7b…",
      "full_name": "Margaret Wilson",
      "preferred_name": "Maggie",
      "room_number": "12",
      "date_of_birth": "1942-03-12",
      "status": "current",
      "dnar_status": "for_resus",
      "location": { "id": "1a…", "name": "Avery Park" }
    }
  ],
  "meta": { "total": 124, "page": 1, "page_size": 50 }
}
Create visit
POST /v1/visits
{
  "location_id": "1a…",
  "staff_user_id": "u1…",
  "visit_type": "personal_care",
  "starts_at": "2026-05-12T09:00:00Z",
  "ends_at":   "2026-05-12T10:00:00Z",
  "notes": "Prefers shower."
}

# 201 Created
{ "id": "v1…", "status": "scheduled", … }
Error envelope
# 422 Unprocessable Entity
{
  "error": {
    "code": "validation_failed",
    "message": "ends_at must be after starts_at",
    "fields": { "ends_at": "must_be_after_starts_at" }
  }
}

Webhooks

Subscribe to events; we POST a signed JSON payload to your URL within seconds.

Currently emitted events

incident.criticalany incident logged with severity=critical
incident.creatednew incident of any severity
fall.loggedan entry added to the falls register
cert.expiringa certification will expire in 30 days
cert.expireda certification has expired
course.completeda staff member completed a course
resident.admittednew resident moves in
resident.dischargedresident discharged or deceased
visit.confirmedstaff confirmed a scheduled visit
visit.no_showstaff did not show up to a visit
kiosk.visitor.signed_ina visitor signed in at reception
family.message.sentfamily member sent a note via the portal
Payload
POST https://example.com/your-webhook
Content-Type: application/json
X-CareLoop-Event: incident.critical
X-CareLoop-Signature: t=1747900800,v1=4f9e…
X-CareLoop-Delivery: dlv_5e1f…

{
  "id": "evt_…",
  "type": "incident.critical",
  "occurred_at": "2026-05-22T08:14:55Z",
  "organization_id": "org_…",
  "data": {
    "incident_id": "inc_…",
    "severity": "critical",
    "type": "fall",
    "resident_id": "res_…",
    "title": "Witnessed fall in lounge",
    "url": "https://app.careloop.com/incidents/inc_…"
  }
}
Verify signature (Node)
import crypto from "node:crypto";

function verify(req: Request, secret: string): boolean {
  const sig = req.headers.get("x-careloop-signature") || "";
  const m = sig.match(/t=(\d+),v1=([a-f0-9]+)/);
  if (!m) return false;
  const [, t, v] = m;
  const body = await req.text();
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${body}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v));
}
Retry policy
# Failed deliveries (non-2xx) are retried with exponential backoff:
#   1 min   →  5 min  →  30 min  →  2 hours  →  6 hours  →  give up
#
# Inspect failures and re-send manually from
#   /settings/integrations/webhooks
#
# Idempotency: every event has a stable id (evt_…). Use it to
# dedupe retries on your side.

SDKs & integrations

First-party packages for the languages you actually ship in.

Node / TypeScript

npm install @careloop/sdkBeta

Python

pip install careloopBeta

Ruby

gem install careloopPlanned

Postman collection

One-click import from /developersAvailable

OpenAPI 3.1 spec

GET /v1/openapi.jsonAvailable

Zapier

careloop.com/zapierQ3 2026

Security & compliance

Same controls as the app — UK-hosted, GDPR-compliant, audit-logged.

Tenant isolation

Every API call is scoped to the organisation owning the API key. RLS enforces this at the database layer — there is no path to cross-tenant data.

Encrypted in transit & at rest

TLS 1.3 only, HSTS preloaded, AES-256 at rest. Keys rotated quarterly.

Audit log

Every API request is written to the audit log with key id, IP and the resource touched. Searchable from the admin UI.

Ready to integrate?

We’re onboarding integration partners through a private beta. Tell us what you’re building — we’ll send you an API key and a Slack channel for direct support.

Request API access