Every committed billing run produces client timesheet documents: an HTML version, a PDF, and a CSV, either one combined document per client or one per project depending on the client's timesheet layout. This recipe fetches them for an accounting or archiving system.
Who may download
The token sees the documents its owner may download in the app:
| Owner | Documents |
|---|---|
| Owner or Admin | All |
| Workspace user with a client-wide document grant | That client's documents, plus project documents of projects they manage |
| Project manager without a grant | Project-scoped documents of their projects |
| Billing contact (client user) with a full login | Their own client's documents |
| Anyone else | None |
A project-scoped token is further limited to its named projects and never receives combined (client-wide) documents. The list's scope field (all, client, projects, none) tells you which rule applied.
1. List documents
curl "https://saq.no/api/w/acme/documents?clientId=01924c3e-0000-7000-8000-000000000007" \
-H "Authorization: Bearer saq_YOUR_TOKEN"
Both query parameters are optional: clientId narrows to one client, runId to one billing run. Response:
{
"scope": "all",
"documents": [
{
"id": "01924c3e-0000-7000-8000-000000000040",
"runId": "01924c3e-0000-7000-8000-000000000041",
"number": "ACME-2026-09-001",
"scope": "combined",
"projectId": null,
"projectName": null,
"clientId": "01924c3e-0000-7000-8000-000000000007",
"clientName": "Acme AS",
"periodStart": "2026-08-01",
"format": "pdf",
"version": 1,
"locale": "nb",
"checksum": "3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"bytes": 48213,
"voided": false,
"redacted": false,
"createdAt": "2026-09-02T07:30:00.000Z",
"deliveries": [
{
"email": "invoices@acme.example",
"state": "sent",
"detail": null,
"attemptedAt": "2026-09-02T07:31:00.000Z"
}
]
}
]
}
Each format is its own document with its own id; filter on format (html, pdf, csv) and skip documents with voided: true. checksum lets you verify a stored copy; deliveries shows the emails SAQ sent to the client's billing recipients.
2. Download
curl -L "https://saq.no/api/w/acme/documents/01924c3e-0000-7000-8000-000000000040/download" \
-H "Authorization: Bearer saq_YOUR_TOKEN" \
-o ACME-2026-09-001.pdf
The response streams the bytes with Content-Type application/pdf, text/csv; charset=utf-8, or text/html; charset=utf-8, and a Content-Disposition of attachment; filename="<number>.<format>" (inline for HTML). A document the owner may not download answers 404 not_found.
3. Through MCP
The MCP tool get_timesheet does both steps. Without arguments (or with clientId) it returns the same list as above. With documentId it returns the document's metadata and its content: encoding: "base64" with the PDF bytes, or encoding: "utf-8" with the HTML or CSV text.
{
"name": "get_timesheet",
"arguments": { "documentId": "01924c3e-0000-7000-8000-000000000040" }
}
Notes
- Documents are immutable. A redaction or a voided run produces a new version or marks the document
voided; re-list rather than caching ids forever. - The CSV holds the same lines as the PDF: date, category, ticket, billing description, hours, rate, amount, and outcome (charged, covered by a time bank, or free), followed by the bank ledger.
- The PDF format exists only when the deployment produces PDFs; HTML and CSV are always produced.