Developer platform
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
API keys are scoped per organisation, expire after 365 days, and can be rotated without downtime.
curl https://api.careloop.com/v1/residents \
-H "Authorization: Bearer cl_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Accept: application/json"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();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 plansread:staff · staff directory, roles, certsread:incidents · incidents, falls, body mapwrite:visits · create / update visit recordsadmin · 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.
JSON in, JSON out. Predictable HTTP verbs, standard error envelopes.
# 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 }
}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", … }# 422 Unprocessable Entity
{
"error": {
"code": "validation_failed",
"message": "ends_at must be after starts_at",
"fields": { "ends_at": "must_be_after_starts_at" }
}
}Subscribe to events; we POST a signed JSON payload to your URL within seconds.
Currently emitted events
incident.critical— any incident logged with severity=criticalincident.created— new incident of any severityfall.logged— an entry added to the falls registercert.expiring— a certification will expire in 30 dayscert.expired— a certification has expiredcourse.completed— a staff member completed a courseresident.admitted— new resident moves inresident.discharged— resident discharged or deceasedvisit.confirmed— staff confirmed a scheduled visitvisit.no_show— staff did not show up to a visitkiosk.visitor.signed_in— a visitor signed in at receptionfamily.message.sent— family member sent a note via the portalPOST 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_…"
}
}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));
}# 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.First-party packages for the languages you actually ship in.
Node / TypeScript
npm install @careloop/sdkBetaPython
pip install careloopBetaRuby
gem install careloopPlannedPostman collection
One-click import from /developersAvailableOpenAPI 3.1 spec
GET /v1/openapi.jsonAvailableZapier
careloop.com/zapierQ3 2026Same 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.
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