Resto← Back to the app

Resto API

Read your venue's published rota, timesheets and wage tracker hours from your own dashboard, spreadsheet script or BI tool. Read-only, version 1.

1. Get a key

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.

Treat a key like a password. Keep it on a server or in your tool's secret settings, not in a web page that other people can open.

2. Call the API

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).

3. Endpoints

GET/venue

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" } ] }

GET/employees

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 } ] }

GET/shifts?from=YYYY-MM-DD&to=YYYY-MM-DD

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" } ] }
FieldMeaning
textThe shift as written on the rota.
start, end, minutesLocal times and length. null when the text is not a time range.
approxtrue for AM / MID / PM shifts: the times are the venue's usual hours for that part of the day.
sourcesaved (on the rota) or pattern (the person's weekly pattern).

GET/timesheets?from=YYYY-MM-DD&to=YYYY-MM-DD

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 } ] }
FieldMeaning
shift1 for the first shift of that day, 2, 3… for a split shift.
openClocked in, not clocked out yet.
minutesClock-out minus clock-in; null when open or longer than 24 hours (check it in Resto).
confirmationconfirmed: 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".

GET/wage?week=YYYY-MM-DD

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": [ … ] } ] } ] } }
FieldMeaning
forecastMinutesThe 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.
projectedMinutesActual 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.
lightok / near (from nearPct% of the budget) / over / no_budget.
budgetMinutes, lastYearMinutesThe 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.

4. Errors and limits

StatusCodeWhen
400bad_rangefrom / to missing or not dates, to before from, or more than 62 days.
400bad_week/wage: week missing or not a Monday.
401invalid_keyNo key, a wrong key, or a key that was revoked or has expired.
403scopeThe key was not given that kind of data.
404unknown_endpointAny other address.
429rate_limitedMore than 120 calls a minute with one key. Wait the seconds in the Retry-After header.
502upstreamA 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.