Product Pricing Guides Templates Contact

TeamPilot API v1

Updated 8 July 2026

The TeamPilot API is a read-only REST API scoped to a single workspace. Use it to pull people, shifts, timesheets, time-off and tasks into payroll, BI or your own tools, and subscribe to webhooks to react to events as they happen.

Base URL

Every request goes to your own workspace subdomain, under /api/v1:

https://your-workspace.teampilot.app/api/v1

A token minted in one workspace is valid only for that workspace. There is no cross-workspace endpoint.

Authentication

Create a token under Settings -> API & webhooks. Send it as a bearer token:

Authorization: Bearer 42|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tokens carry the read ability. Pay figures (hourly_rate_pence, payroll_number) are only returned to tokens that also hold the people:pay ability, which you opt into when you create the token.

The API requires a plan that includes API access. Requests on a plan without it receive 403 forbidden.

Pagination

List endpoints are cursor-paginated:

{
  "data": [ ... ],
  "meta": { "next_cursor": "eyJpZCI6NDJ9", "per_page": 50 }
}

Pass ?cursor=<next_cursor> to fetch the next page and ?per_page=<n> to size it (default 50, maximum 100). When next_cursor is null you have reached the end.

Filtering

  • updated_since=<ISO8601> returns only records changed on or after that instant. Use it to poll for changes cheaply.
  • /shifts defaults to the current week and accepts status=<status>.

Endpoints

Method Path Returns
GET /people Workspace members, including archived
GET /people/{id} A single person
GET /shifts Scheduled shifts (current week by default)
GET /time-entries Clock-in/out timesheet entries
GET /leave-requests Time-off requests
GET /tasks Tasks

All money is returned in integer pence with a _pence suffix; all times are ISO 8601 in UTC.

Errors

Errors use a consistent envelope:

{ "error": { "code": "validation_failed", "message": "The given data was invalid.", "fields": { "per_page": ["..."] } } }
Status Code
401 unauthenticated
403 forbidden / account_suspended
404 not_found
422 validation_failed
429 rate_limited
500 server_error

Rate limits

Requests are limited to 60 per minute per token. Over the limit you receive 429 rate_limited with a Retry-After header.

Webhooks

Add an https endpoint under Settings -> API & webhooks and subscribe it to events. When an event fires we POST a JSON envelope:

{
  "id": "018f...",
  "event": "shift.published",
  "created_at": "2026-07-08T12:00:00Z",
  "data": { ... }
}

Headers on each delivery:

  • X-TeamPilot-Event the event name
  • X-TeamPilot-Delivery a unique id for this delivery
  • X-TeamPilot-Signature an HMAC-SHA256 of the raw request body, keyed with your endpoint's signing secret

Verifying the signature

Compute the HMAC over the exact bytes you received and compare, in constant time, to the header:

$expected = hash_hmac('sha256', $rawBody, $signingSecret);
if (! hash_equals($expected, $request->header('X-TeamPilot-Signature'))) {
    abort(400);
}

Respond with any 2xx to acknowledge. Non-2xx responses are retried with backoff; persistently failing deliveries can be replayed from the webhook's delivery history.

Events

Event Fires when
shift.published A shift is published to the schedule
timesheet.approved A timesheet entry is approved
leave.approved A time-off request is approved
person.joined A person accepts an invitation and joins

See it with your own team

Set up takes minutes: add your people, build a week and publish. Free for 14 days on every paid plan, free forever for small teams.

No credit card required.