Build on Syncurio

Programmatic access to your rostering, workforce, governance, task, budget and reporting data. Plug payroll integrations, BI dashboards, time-clock devices and bespoke tooling straight into the system that runs your homes.

Get started →

Get started in three steps

1

Issue an API key

Sign in, open Settings → Integrations from the profile menu, and create a key scoped to what your integration needs. Issue a separate key per integration so scopes and rate limits stay isolated.

2

Send your first request

Pass the key in the X-Api-Key header, and call your base URL — shown under Settings → Integrations (it differs by environment). Every endpoint requires the relevant scope grant.

3

Explore the reference

Browse and try every endpoint in the interactive Scalar reference, linked from Settings → Integrations in your dashboard. Opening it there points “Try it” at your own environment, so calls work with your key.

Three ways in, one key

Public API

Live records for integration partners: read the current state of shifts, audits, findings and tasks, and make changes the way staff do in the app.

Base path
/public/v1
Paging
pageNumber / pageSize (50, max 200)
Rate limit
1,000 requests / hour per key
47 endpoints — browse the reference ↓

Reporting API

Flat, denormalised datasets for BI tools such as Power BI, Tableau and Looker, and for data warehouses.

Base path
/reporting/v1
Paging
Cursor — pass nextCursor back unchanged
Rate limit
200 requests / hour per key
9 datasets — browse the reference ↓

MCP server

The same endpoints as tools for AI assistants — Claude Desktop, Claude Code, Cursor and other MCP clients.

Install
npx @syncurio/mcp
Writes
Off unless you turn them on
Limits
Your key's scopes and rate limits
Set it up ↓

Endpoint reference

Every integration starts with GET/public/v1/homes (home:read): the home ids every other call takes. The full request and response schemas, with “Try it”, are in the interactive reference linked from Settings → Integrations.

Shifts, the people and agencies who can work them, and the rules changes are checked against.

Read

GET/public/v1/rostering/shiftsShifts for a home over up to 92 days, with assignmentsrostering:read
GET/public/v1/rostering/shifts/{id}One shiftrostering:read
GET/public/v1/rostering/employeesCurrent employees at a home, with their rolesrostering:read
GET/public/v1/rostering/rolesThe staffing role catalogue, with departmentsrostering:read
GET/public/v1/rostering/absencesHoliday and leave overlapping a date rangerostering:read
GET/public/v1/rostering/agenciesAgencies attached to a home and the roles they supplyrostering:read
GET/public/v1/rostering/unitsA home's floors or wingsrostering:read
GET/public/v1/rostering/settingsRostering rules: rest time, consecutive hours, holidayrostering:read
GET/public/v1/rostering/templatesSaved week patterns for a homerostering:read
GET/public/v1/rostering/templates/{id}A week pattern, day by dayrostering:read
GET/public/v1/rostering/missed-shiftsAssigned shifts nobody clocked in forrostering:read
GET/public/v1/rostering/unscheduledTime clocked without a rostered shiftrostering:read

Make changes

POST/public/v1/rostering/shiftsCreate up to 100 shifts, all checked firstrostering:write
PUT/public/v1/rostering/shifts/{id}Change a shift's date, times, role or unitrostering:write
POST/public/v1/rostering/shifts/{id}/edit-checkCheck a change against the rules without savingrostering:write
PUT/public/v1/rostering/shifts/{id}/assignmentAssign an employee or agencyrostering:write
DELETE/public/v1/rostering/shifts/{id}/assignmentUnassign a shiftrostering:write
DELETE/public/v1/rostering/shifts/{id}Cancel a future shift (permanent)rostering:write
POST/public/v1/rostering/shifts/publishPublish a week — emails affected staffrostering:publish

Audits and their answers, the findings they raise and the action plans that fix them.

Read

GET/public/v1/governance/frameworksRegulatory frameworks and each home's regulatorgovernance:read
GET/public/v1/governance/audit-templatesAudit templatesgovernance:read
GET/public/v1/governance/audit-templates/{id}A template's questions and grade bandsgovernance:read
GET/public/v1/governance/audit-schedulesRecurring audits and when they're next duegovernance:read
GET/public/v1/governance/auditsAudits with status, grade and scoregovernance:read
GET/public/v1/governance/audits/{id}An audit with every answergovernance:read
GET/public/v1/governance/findingsFindings, filterable by severity and statusgovernance:read
GET/public/v1/governance/findings/{id}A finding with its tasks and observationsgovernance:read
GET/public/v1/governance/action-plansAction plans with task countsgovernance:read
GET/public/v1/governance/action-plans/{id}An action plan with its tasksgovernance:read
GET/public/v1/governance/evidence/{id}/urlA short-lived evidence download linkgovernance:evidence:read

Make changes

POST/public/v1/governance/findingsRaise a finding outside an auditgovernance:write
POST/public/v1/governance/findings/{id}/commentsComment on a findinggovernance:write
POST/public/v1/governance/findings/{id}/resolveResolve a findinggovernance:write

Tasks from every module — governance remediation, CRM follow-ups and general tasks — each tagged with its source.

Read

GET/public/v1/tasks/groupsTask groups with open and overdue countstasks:read
GET/public/v1/tasks/groups/{id}A task group and its taskstasks:read
GET/public/v1/tasks/itemsTasks, filterable by assignee, due date, statustasks:read
GET/public/v1/tasks/items/{id}A task with its commentstasks:read
GET/public/v1/tasks/assigneesWho tasks at a home can be assigned totasks:read

Make changes

POST/public/v1/tasks/itemsCreate a general tasktasks:write
PUT/public/v1/tasks/items/{id}Change priority, due date, progress or assigneetasks:write
POST/public/v1/tasks/items/{id}/completeComplete a tasktasks:write
POST/public/v1/tasks/items/{id}/cancelCancel a task, with a reasontasks:write
POST/public/v1/tasks/items/{id}/commentsComment or record progresstasks:write

Built for payroll and earned-wage-access partners.

Read

GET/public/v1/workforce/employeesCurrent employees with pay basis and ratesworkforce:read
GET/public/v1/workforce/timesheetsWorked timesheets with hours and payworkforce:read

A home's staffing budget. Contains pay rates.

Read

GET/public/v1/budget/homes/{homeId}Budgeted roles, rates, uplifts and shift patternsbudget:read

Flat, cursor-paginated datasets for BI tools. One row per record, nothing nested.

Rostering

GET/reporting/v1/rostering/shiftsOne row per shift, with clocked hoursreporting:rostering
GET/reporting/v1/rostering/employee-weekly-hoursScheduled hours per employee per weekreporting:rostering

Governance

GET/reporting/v1/governance/auditsOne row per auditreporting:governance
GET/reporting/v1/governance/audit-responsesOne row per answer, with readings against targetreporting:governance
GET/reporting/v1/governance/findingsOne row per finding, with recurrence and days openreporting:governance
GET/reporting/v1/governance/action-itemsOne row per remediation taskreporting:governance

Tasks

GET/reporting/v1/tasks/itemsOne row per task, from every modulereporting:tasks

Budget

GET/reporting/v1/budget/home-summaryBudget against occupancy and fees, per homereporting:budget
GET/reporting/v1/budget/weekly-comparisonBudgeted vs rostered vs worked, by role and weekreporting:budget

MCP server

Add Syncurio to your MCP client's config with your API key and base URL. Each tool calls one of the endpoints above, with the same scopes and rate limits.

{
  "mcpServers": {
    "syncurio": {
      "command": "npx",
      "args": ["-y", "@syncurio/mcp"],
      "env": {
        "SYNCURIO_API_KEY": "syn_live_…",
        "SYNCURIO_BASE_URL": "https://<your-syncurio-api-host>"
      }
    }
  }
}

SYNCURIO_ENABLE_WRITES

Set to true to add the tools that make changes (create shifts, complete tasks, raise findings and so on). They still need the key's write scopes. Each call carries its own Idempotency-Key, so a retried call is applied only once.

SYNCURIO_TOOLSETS

Load only the areas you need, e.g. governance,tasks. Choose from rostering, workforce, budget, governance, tasks, reporting. A shorter tool list helps the assistant pick the right tool.

The full tool list is on the npm package page.

Code examples

List today's shifts — curl
curl "$SYN_BASE/public/v1/rostering/shifts?homeId=1&from=2026-04-30&to=2026-04-30" \
     -H "X-Api-Key: $SYN_KEY"
List today's shifts — JavaScript (fetch)
const res = await fetch(
  `${process.env.SYN_BASE}/public/v1/rostering/shifts?homeId=1&from=2026-04-30&to=2026-04-30`,
  { headers: { 'X-Api-Key': process.env.SYN_KEY } }
);
const { items, totalCount } = await res.json();
console.log(`Found ${totalCount} shift(s)`);
List today's shifts — C# (HttpClient)
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("SYN_KEY"));
var baseUrl = Environment.GetEnvironmentVariable("SYN_BASE");

var response = await http.GetAsync(
    $"{baseUrl}/public/v1/rostering/shifts" +
    "?homeId=1&from=2026-04-30&to=2026-04-30");
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Pull worked timesheets for payroll — curl
curl "$SYN_BASE/public/v1/workforce/timesheets?from=2026-04-01&to=2026-04-30" \
     -H "X-Api-Key: $SYN_KEY"
Pull approved paid holiday for payroll (one row per day) — curl
curl "$SYN_BASE/public/v1/workforce/holidays?from=2026-04-01&to=2026-04-30" \
     -H "X-Api-Key: $SYN_KEY"
Create a task, safely retryable — curl
curl -X POST "$SYN_BASE/public/v1/tasks/items" \
     -H "X-Api-Key: $SYN_KEY" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"homeId": 1, "title": "Order more gloves", "priority": "High"}'
Stream a reporting dataset with cursor pagination — curl
# First page
curl "$SYN_BASE/reporting/v1/rostering/shifts?homeId=1&from=2026-01-01&to=2026-03-31&pageSize=500" \
     -H "X-Api-Key: $SYN_KEY"

# Continue with the nextCursor from the previous response
curl "$SYN_BASE/reporting/v1/rostering/shifts?homeId=1&from=2026-01-01&to=2026-03-31&pageSize=500&cursor=$NEXT" \
     -H "X-Api-Key: $SYN_KEY"

Authentication & rate limits

Base URL

Your base URL depends on your Syncurio environment and is shown under Settings → Integrations. The examples below use $SYN_BASE as a stand-in — set it once with export SYN_BASE="https://<your-syncurio-api-host>".

X-Api-Key header

Every request must carry the key issued from the dashboard. Keys are scoped — grant only what an integration needs, and issue a separate key per integration:

Read

Make changes

Reporting

A key whose required modules aren't subscribed by your organisation can't be issued, and existing keys are revoked at request time if a module is later unsubscribed.

Staff-level governance records (staff audits and findings) are only included when a key also has governance:staff:read. Evidence files need governance:evidence:read.

Making changes

A key with a write scope acts as the person who created it. Changes are recorded against their name, and they must still be an active user with the matching permission in Syncurio — if they leave or lose the permission, the key's writes stop (with 403) while its reads carry on. Every rostering and governance rule applies, exactly as in the app; a change that breaks one is rejected with 400 and a code naming the rule.

Send an Idempotency-Key header (any unique string, such as a UUID) with every change. It's required when creating records. If a request is retried with the same key and body you get the original response back, marked Idempotent-Replayed: true, instead of a duplicate; the same key with a different body is a 409. Keys are remembered for 24 hours.

Rate limits

Each key has its own hourly budget. The defaults are 1,000 requests / hour on the public API and 200 requests / hour on the reporting API (sized for periodic BI pulls rather than interactive use).

The 1,001st (or 201st) request in an hour returns 429 Too Many Requests with a Retry-After header. Need higher limits for an integration? Get in touch.

Versioning & deprecation

The base paths are /public/v1 and /reporting/v1. We commit to backwards-compatible changes within v1. When an endpoint is deprecated we publish at least six months notice via the standard Sunset and Deprecation response headers, plus a banner in the API reference.

Webhooks

Real-time event notifications are on the roadmap for a future release. In the meantime the reporting API supports incremental pulls via cursor pagination. Want to be told when webhooks ship? Drop us a line.