Read your venue's published rota, timesheets and wage tracker hours from your own dashboard, spreadsheet script or BI tool. Read-only, version 1.
The venue's Owner makes keys in Resto: Settings → API keys → + New key. Choose a name, what the key may read (Schedule, Timesheets, Wage tracker) and when it expires (1 year by default).
Later the Owner can change what an existing key may read, rename it or extend it (Edit access): the key stays the same and the dashboard gets the new access at once.
The key is shown once. Resto keeps only a fingerprint of it, so copy it straight away. If it is lost or leaked, revoke it in the same place and make a new one: a revoked key stops working at once.
Base address: https://getresto.app/api/v1. Send the key in the Authorization header (or in X-Api-Key).
curl -H "Authorization: Bearer rk_live_…" \ "https://getresto.app/api/v1/shifts?from=2026-11-02&to=2026-11-08"
Every answer is JSON. Dates are YYYY-MM-DD in the venue's own calendar; shift times are the venue's local clock time (2026-11-02T17:00); clock-in times are UTC (2026-11-02T16:58:00.000Z).
The venue's name and time zone, its departments, roles and zones — to turn the ids in the other answers into names. Any key.
{ "venue": { "name": "Echo Bistro", "timezone": "Europe/London" },
"departments": [ { "id": "floor", "name": "Floor" }, … ],
"roles": [ { "id": "server", "name": "Server", "department": "floor" }, … ],
"zones": [ { "id": "zT", "name": "Terrace" } ] }
The team: id, name, main role, all roles, departments, and whether the person is still on the team today. Any key. No dates, email, phone, pay or other personal details.
{ "employees": [ { "id": "e2", "name": "Bob Bar", "mainRole": "bartender", "roles": ["bartender", "server"],
"departments": ["bar", "floor"], "active": true } ] }
Key with Schedule. Every published working shift in the period (at most 62 days) — exactly what the team sees in their own rota: shifts typed or generated and approved, and shifts that come from a person's weekly pattern. Drafts and weeks (or departments) that are not published are not included. Days off, holidays and sick days are never included.
{ "from": "2026-10-19", "to": "2026-10-25", "shifts": [
{ "employeeId": "e2", "employeeName": "Bob Bar", "date": "2026-10-20", "text": "7pm-3am",
"start": "2026-10-20T19:00", "end": "2026-10-21T03:00", "minutes": 480, "approx": false,
"role": "bartender", "department": "bar", "zone": null, "zoneName": null, "source": "pattern" } ] }
| Field | Meaning |
|---|---|
text | The shift as written on the rota. |
start, end, minutes | Local times and length. null when the text is not a time range. |
approx | true for AM / MID / PM shifts: the times are the venue's usual hours for that part of the day. |
source | saved (on the rota) or pattern (the person's weekly pattern). |
Key with Timesheets. Clock-ins and clock-outs in the period (at most 62 days), one row per shift worked. No location is ever included.
{ "from": "2026-10-19", "to": "2026-10-25", "timesheets": [
{ "id": "e1__2026-10-19", "employeeId": "e1", "employeeName": "Ann Server", "date": "2026-10-19", "shift": 1,
"clockIn": "2026-10-19T07:58:00.000Z", "clockOut": "2026-10-19T16:04:00.000Z", "minutes": 486,
"open": false, "department": "floor", "confirmation": "confirmed", "confirmed": true } ] }
| Field | Meaning |
|---|---|
shift | 1 for the first shift of that day, 2, 3… for a split shift. |
open | Clocked in, not clocked out yet. |
minutes | Clock-out minus clock-in; null when open or longer than 24 hours (check it in Resto). |
confirmation | confirmed: the department's manager confirmed that week in Resto and nothing has changed since. changed: confirmed, but a clock-in or clock-out of that department's week was added, removed or edited afterwards — check it again. none: not confirmed yet. confirmed (true/false) is the same as confirmation = "confirmed". |
Key with Wage tracker. One Monday-to-Sunday week (week is its Monday), the same figures as Resto's Wage tracker screen for a manager without Payroll: hours only, never pounds. Per department and per day:
{ "weekStart": "2026-11-02", "weekEnd": "2026-11-08", "today": "2026-11-04", "nearPct": 90,
"departments": [ { "id": "floor", "name": "Floor", "light": "over",
"budgetMinutes": 1800, "forecastMinutes": 2880, "projectedMinutes": 2895, "draftMinutes": 0, "lastYearMinutes": 2100,
"headroomMinutes": -1095, "unpublished": true, "notClockedDays": 1,
"days": [ { "date": "2026-11-02", "forecastMinutes": 480, "projectedMinutes": 495 }, … ] } ],
"totals": { "light": "over", "budgetMinutes": 3000, "projectedMinutes": 3315, … },
"cutList": { "contractsChecked": false, "departments": [ { "id": "floor", "toBudgetMinutes": 1095,
"suggested": { "count": 3, "minutes": 1440, "reachesTarget": true },
"shifts": [ { "employeeId": "e1", "employeeName": "Ann Server", "date": "2026-11-07", "text": "AM", "minutes": 480, "draft": false,
"published": false, "need": "none", "suggested": true, "flags": [ … ] } ] } ] } }
| Field | Meaning |
|---|---|
forecastMinutes | The week as it stands on the rota — published shifts and drafts, like the screen. draftMinutes says how much of it is drafts; unpublished: true means the department's week is not published yet. |
projectedMinutes | Actual so far plus the rest of the week: past days count what was clocked, today the larger of rota and clocked, later days the rota. |
light | ok / near (from nearPct% of the budget) / over / no_budget. |
budgetMinutes, lastYearMinutes | The hours budget and last year's hours as typed in the Wage tracker (the week's own figure, else the standing one). null when not set. |
cutList | "What could be cut" for departments near or over budget: shifts after today that could come out, best first, with a suggested set. need: gap (taking it out leaves a template or event slot empty), none, unknown. Contracts are not checked here (no pay data leaves Resto): check guaranteed hours before cutting. It names people and their shifts, drafts included. |
| Status | Code | When |
|---|---|---|
| 400 | bad_range | from / to missing or not dates, to before from, or more than 62 days. |
| 400 | bad_week | /wage: week missing or not a Monday. |
| 401 | invalid_key | No key, a wrong key, or a key that was revoked or has expired. |
| 403 | scope | The key was not given that kind of data. |
| 404 | unknown_endpoint | Any other address. |
| 429 | rate_limited | More than 120 calls a minute with one key. Wait the seconds in the Retry-After header. |
| 502 | upstream | A temporary problem on our side. Try again shortly. |
{ "error": { "code": "invalid_key", "message": "The API key is missing, wrong, revoked or expired." } }
A key reads only its own venue. Calls are counted per minute (endpoint, result, number of calls and rows — no addresses, no contents) and kept 90 days; the Owner sees them under API keys → Activity.