Skip to main content

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
ScopeGrants
read:projectsList and read projects
read:documentsList and read document metadata + download links
read:workersList and read workers
read:certificationsList and read worker certifications
read:attendanceList 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

GET/api/v1/projects

List your account's projects. Cursor-paginated.

Auth: API key · scope read:projects

Response

{
  "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
}
GET/api/v1/projects/{projectId}

Get one project. Returns 404 for projects outside your account.

Auth: API key · scope read:projects

Response

{ "data": { "id": "…", "title": "…", … } }

Documents

GET/api/v1/projects/{projectId}/documents

List a project's documents (RAMS, CPP, site induction, emergency plan, toolbox talks, COSHH) with latest version info.

Auth: API key · scope read:documents

Response

{
  "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
}
GET/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.

Auth: API key · scope read:documents

Response

{
  "data": {
    "id": "…",
    "document_type": "RAMS",
    …,
    "pdf_download_url": "https://…(presigned, expires)…",
    "pdf_download_expires_in_seconds": 600
  }
}

Workers & certifications

GET/api/v1/workers

List your account's workers with their certifications embedded.

Auth: API key · scope read:workers

Response

{
  "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
}
GET/api/v1/certifications?expiring_before=2026-09-01

List certifications across all workers. Use expiring_before to pull everything that needs renewing by a date.

Auth: API key · scope read:certifications

Response

{
  "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

GET/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.

Auth: API key · scope read:attendance

Response

{
  "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 429 response includes a Retry-After header (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."
  }
}
StatusCodeMeaning
400invalid_requestBad query parameter or body
401unauthorizedMissing, invalid, revoked or expired API key
403forbiddenPlan or key scope does not allow this request
404not_foundResource missing — or not visible to your account
429rate_limitedRate limit exceeded — honour Retry-After
500internal_errorServer 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.

EventFires when
document.generatedA document PDF finished generating
document.signedA worker signed a document via a sign link
certificate.expiringA worker certification entered its expiry warning window
worker.checked_inSomeone checked in to a site
induction.acknowledgedA 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.

GET/api/zapier/projects

List your most recent projects. Used by Zapier as the 'New Project' polling trigger.

Auth: 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"
  }
]
POST/api/zapier/projects

Create a project. Used by Zapier as the 'Create Project' action.

Auth: 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": "…" }
GET/api/zapier/documents

List recently generated documents. Used by Zapier as the 'New Document Generated' polling trigger.

Auth: 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"
  }
]
POST/api/integrations/zapier/hooks

Subscribe a Zapier hook URL to an event (new_project, worker_added, document_generated). Called automatically by Zapier when a Zap is enabled.

Auth: X-API-Key (Zapier key)

Request Body

{ "event": "new_project", "hookUrl": "https://hooks.zapier.com/hooks/catch/…" }

Response

{ "id": "…" }
DELETE/api/integrations/zapier/hooks

Unsubscribe a hook by id. Called automatically by Zapier when a Zap is disabled.

Auth: 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]