API docs
The Site Book API
Read your compliance data over the REST API, receive signed webhooks, or connect 5,000+ apps via the Zapier integration.
Availability
- • REST API v1 + outbound webhooks: included with the Site Control plan.
- • Zapier integration: included with Pro and above.
Base URL: https://thesitebook.co.uk — HTTPS only, JSON responses. Machine-readable reference: OpenAPI 3.1 spec.
Authentication
Create an account-scoped API key in Settings → Integrations → API keys (account owners and admins). Keys are shown once, carry only the scopes you grant, and can be revoked at any time. Send the key on every request either way:
Authorization: Bearer sb_live_your_api_key_here # or X-API-Key: sb_live_your_api_key_here
| Scope | Grants |
|---|---|
read:projects | List and read projects |
read:documents | List and read document metadata + download links |
read:workers | List and read workers |
read:certifications | List and read worker certifications |
read:attendance | List site attendance (check-ins/check-outs) |
v1 is read-only by design — write scopes will be added as separate, opt-in scopes so existing keys never gain abilities silently.
Pagination
List endpoints return { "data": […], "next_cursor": "…" | null }. Pass ?limit= (1–100, default 25) and re-request with ?cursor=next_cursor until it comes back null.
REST API v1
Projects
/api/v1/projectsList your account's projects. Cursor-paginated.
API key · scope read:projectsResponse
{
"data": [
{
"id": "…",
"title": "Rear Extension — 14 Oak Lane",
"site_address": "14 Oak Lane, Manchester, M1 1AA",
"client_name": "Smith Developments Ltd",
"contractor_role": "PRINCIPAL_CONTRACTOR",
"status": "ACTIVE",
"created_at": "2026-07-01T09:30:00.000Z",
"updated_at": "2026-07-04T16:02:11.000Z"
}
],
"next_cursor": null
}/api/v1/projects/{projectId}Get one project. Returns 404 for projects outside your account.
API key · scope read:projectsResponse
{ "data": { "id": "…", "title": "…", … } }Documents
/api/v1/projects/{projectId}/documentsList a project's documents (RAMS, CPP, site induction, emergency plan, toolbox talks, COSHH) with latest version info.
API key · scope read:documentsResponse
{
"data": [
{
"id": "…",
"project_id": "…",
"document_type": "RAMS",
"status": "GENERATED",
"needs_review": false,
"latest_version_number": 3,
"latest_version_created_at": "2026-07-03T11:20:05.000Z",
"created_at": "2026-06-28T08:00:00.000Z",
"updated_at": "2026-07-03T11:20:05.000Z"
}
],
"next_cursor": null
}/api/v1/documents/{documentId}Get one document with a short-lived (10 minute) presigned download link for the latest generated PDF. Request a fresh link each time you need the file.
API key · scope read:documentsResponse
{
"data": {
"id": "…",
"document_type": "RAMS",
…,
"pdf_download_url": "https://…(presigned, expires)…",
"pdf_download_expires_in_seconds": 600
}
}Workers & certifications
/api/v1/workersList your account's workers with their certifications embedded.
API key · scope read:workersResponse
{
"data": [
{
"id": "…",
"name": "Jane Doe",
"role": "STAFF",
"company": null,
"email": null,
"phone": null,
"first_aid_trained": true,
"fire_warden_trained": false,
"certifications": [
{
"id": "…",
"worker_id": "…",
"worker_name": "Jane Doe",
"name": "CSCS Card",
"issued_at": null,
"expires_at": "2027-01-31T00:00:00.000Z",
"created_at": "2026-05-01T10:00:00.000Z"
}
],
"created_at": "2026-05-01T10:00:00.000Z",
"updated_at": "2026-06-20T09:12:00.000Z"
}
],
"next_cursor": null
}/api/v1/certifications?expiring_before=2026-09-01List certifications across all workers. Use expiring_before to pull everything that needs renewing by a date.
API key · scope read:certificationsResponse
{
"data": [
{
"id": "…",
"worker_id": "…",
"worker_name": "Jane Doe",
"name": "CSCS Card",
"issued_at": null,
"expires_at": "2026-08-14T00:00:00.000Z",
"created_at": "2026-05-01T10:00:00.000Z"
}
],
"next_cursor": null
}Site attendance
/api/v1/attendance?project_id=…&from=…&to=…List site check-ins/check-outs (contractor app, entrance QR, kiosk, dashboard). Filter by project and checked_in_at range.
API key · scope read:attendanceResponse
{
"data": [
{
"id": "…",
"project_id": "…",
"portal_user_id": "…",
"person_name": "Jane Doe",
"person_type": "contractor",
"company": "Doe Electrical Ltd",
"checked_in_at": "2026-07-04T07:02:33.000Z",
"checked_out_at": "2026-07-04T15:41:02.000Z",
"check_in_source": "site_qr"
}
],
"next_cursor": null
}Rate limits
- • REST API v1: 120 requests/minute per API key.
- • A
429response includes aRetry-Afterheader (seconds).
Error responses
v1 errors always use a stable machine-readable envelope:
{
"error": {
"code": "forbidden",
"message": "This API key does not have the 'read:attendance' scope."
}
}| Status | Code | Meaning |
|---|---|---|
400 | invalid_request | Bad query parameter or body |
401 | unauthorized | Missing, invalid, revoked or expired API key |
403 | forbidden | Plan or key scope does not allow this request |
404 | not_found | Resource missing — or not visible to your account |
429 | rate_limited | Rate limit exceeded — honour Retry-After |
500 | internal_error | Server error — contact support |
Webhooks
Receive signed, real-time events at your own HTTPS endpoints — configured in Settings → Integrations → Webhooks (Site Control). Failed deliveries are retried with increasing backoff — up to six attempts over roughly ten hours; every delivery is visible in the in-app delivery log.
| Event | Fires when |
|---|---|
document.generated | A document PDF finished generating |
document.signed | A worker signed a document via a sign link |
certificate.expiring | A worker certification entered its expiry warning window |
worker.checked_in | Someone checked in to a site |
induction.acknowledged | A worker acknowledged the site induction |
Delivery format
POST https://your-endpoint.example.com/webhooks
User-Agent: TheSiteBook-Webhooks/1.0
X-TSB-Event: worker.checked_in
X-TSB-Delivery-Id: <unique id — use for idempotency>
X-TSB-Signature: t=1751700000,v1=<hex HMAC-SHA256>
{
"id": "<delivery id>",
"event": "worker.checked_in",
"created_at": "2026-07-05T07:02:33.000Z",
"data": {
"project_id": "…",
"person_name": "Jane Doe",
"person_type": "contractor",
"source": "site_qr",
"checked_in_at": "2026-07-05T07:02:33.000Z",
"portal_user_id": "…"
}
}Verifying the signature (Node.js)
const crypto = require("crypto");
function verify(signatureHeader, rawBody, secret) {
const { t, v1 } = Object.fromEntries(
signatureHeader.split(",").map((part) => part.split("="))
);
const expected = crypto
.createHmac("sha256", secret) // your endpoint's whsec_… secret
.update(`${t}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex"));
}Respond with any 2xx within 5 seconds to acknowledge. Anything else (or a timeout) schedules a retry. Reject stale timestamps (e.g. older than 5 minutes) to prevent replay.
Zapier
The Zapier integration uses its own personal API key — generate it in Settings → Integrations → Zapier. Available events: new project, worker added, document generated.
/api/zapier/projectsList your most recent projects. Used by Zapier as the 'New Project' polling trigger.
X-API-Key (Zapier key)Response
[
{
"id": "…",
"name": "Rear Extension — 14 Oak Lane",
"address": "14 Oak Lane, Manchester, M1 1AA",
"client_name": "Smith Developments Ltd",
"created_at": "2026-07-04T09:30:00.000Z"
}
]/api/zapier/projectsCreate a project. Used by Zapier as the 'Create Project' action.
X-API-Key (Zapier key)Request Body
{
"name": "New Build — 5 Maple Close",
"address": "5 Maple Close, Leeds, LS1 1AB",
"client_name": "Jones Construction",
"scope_description": "Two-storey new build, 4 bed detached"
}Response
{ "id": "…", "name": "…", "address": "…", "client_name": "…", "created_at": "…" }/api/zapier/documentsList recently generated documents. Used by Zapier as the 'New Document Generated' polling trigger.
X-API-Key (Zapier key)Response
[
{
"id": "…",
"document_type": "RAMS",
"project_id": "…",
"project_name": "Rear Extension — 14 Oak Lane",
"created_at": "2026-07-04T09:45:00.000Z"
}
]/api/integrations/zapier/hooksSubscribe a Zapier hook URL to an event (new_project, worker_added, document_generated). Called automatically by Zapier when a Zap is enabled.
X-API-Key (Zapier key)Request Body
{ "event": "new_project", "hookUrl": "https://hooks.zapier.com/hooks/catch/…" }Response
{ "id": "…" }/api/integrations/zapier/hooksUnsubscribe a hook by id. Called automatically by Zapier when a Zap is disabled.
X-API-Key (Zapier key)Request Body
{ "id": "…" }Response
{ "success": true }Need help?
Contact us if you need assistance building an integration or have questions about the API.
[email protected]