Skip to main content

clockster

Official Python SDK for the Clockster Company API.

Server-to-server client for a company's employees, structure, schedules, attendance, tasks and documents. Typed from the API's OpenAPI document. One dependency, httpx.

pip install clockster

Requires Python 3.10 or newer.

Quickstart

One token authenticates one company. Create it under Settings → API in the web application.

import os

from clockster import Clockster

clockster = Clockster(token=os.environ["CLOCKSTER_TOKEN"])

me = clockster.me()

locations = clockster.locations.upsert({"items": [{"external_id": "HQ", "title": "Head office"}]})

clockster.users.upsert(
    {
        "users": [
            {
                "external_id": "HR-1",
                "first_name": "Aisulu",
                "role": "employee",
                "location_id": locations["data"][0]["id"],
            }
        ]
    }
)

timesheets = clockster.timesheets.list(date_from="2026-08-01", date_to="2026-08-31")

A method answers the parsed body, so rows are response["data"]. Nothing is validated on the way in: the answer is the JSON as it arrived, and a field we add tomorrow reaches your code today.

Refusals

A refusal is raised, never returned.

from clockster import ClocksterError, RateLimitError, ValidationError

try:
    clockster.users.upsert({"users": [{"first_name": "Aisulu"}]})
except ValidationError as error:
    print(error.code, error.errors)  # validation_failed {'users.0.role': [...]}
except RateLimitError as error:
    print(error.retry_after)  # seconds, from Retry-After
except ClocksterError as error:
    print(error.code, error.request_id)

code is what to branch on; message is for a log; quote request_id when asking us about a call. AuthenticationError, ForbiddenError, NotFoundError, ConflictError, ValidationError, RateLimitError and ServerError all descend from ClocksterError, so catching that one catches everything.

What is available

Group Operations
me() —
users list get upsert dismiss
locations, departments, positions, user_filters list get upsert delete
schedules create get delete
attendance list record
timesheets list
tasks list get upsert
documents list get upsert delete
files upload
payroll.payslips list
user_requests list get
webhooks list get create update delete rotate_secret
webhooks.deliveries list get redeliver
webhooks.events list

Paging

Listings are cursor-paged. paginate walks the pages and yields the rows:

from clockster import paginate

for user in paginate(clockster.users.list, per_page=100):
    print(user["external_id"] or user["id"])

Filters go where you would put them anyway; the cursor is the helper's business:

for mark in paginate(clockster.attendance.list, date_from="2026-08-01", date_to="2026-08-31"):
    print(mark["id"])

A refused page raises where it was refused — a half-read listing is not a result. A cursor is bound to the filters it was issued under; change them and start again.

Listings answer oldest first, so a first call on a long-lived company lands years back. Ask with updated_since when you want recent activity rather than all of it.

Relations

A related object is absent unless include names it, and its type says so: location on an employee, user on a mark.

users = clockster.users.list(include=["location", "department"])

print(users["data"][0]["location"]["title"])

Every list parameter takes a list and travels comma-separated: include, ids, locations and the rest.

An absent key is not the same as a null one. null means we know the value is empty; absent means you did not ask.

Types

The shapes are TypedDicts, so a type checker sees the fields of a row while your code keeps plain dictionaries:

from clockster.models import UsersListRow

user: UsersListRow
for user in paginate(clockster.users.list):
    print(user["first_name"])

Async

AsyncClockster mirrors the whole surface.

from clockster import AsyncClockster, paginate_async

async with AsyncClockster(token=os.environ["CLOCKSTER_TOKEN"]) as clockster:
    timesheets = await clockster.timesheets.list(date_from="2026-08-01", date_to="2026-08-31")

    async for user in paginate_async(clockster.users.list, per_page=100):
        print(user["id"])

Webhooks

verify_webhook takes the body as received and answers the event, so the only path to the event runs through the check.

from clockster import WebhookVerificationError, verify_webhook


@app.post("/clockster")
async def receive(request: Request) -> Response:
    try:
        event = verify_webhook(
            body=await request.body(),
            signature=request.headers.get("X-Clockster-Signature"),
            timestamp=request.headers.get("X-Clockster-Timestamp"),
            secret=os.environ["CLOCKSTER_WEBHOOK_SECRET"],
        )
    except WebhookVerificationError:
        return Response(status_code=400)

    queue.put(event)

    return Response(status_code=202)
  • Pass the raw bytes. Re-serialising a parsed object does not reproduce what was signed.
  • Answer 2xx quickly and do the work afterwards; a timeout is retried.
  • Deduplicate on id. The same event may arrive twice.

Deliveries older than five minutes are refused as replays; tolerance_seconds changes that.

Versioning

Semver, independent of the API version. This package targets Company API v3; a new API version is a major release here, not a second package.

Development

src/clockster/_generated is produced from openapi/company-v3.json and committed, so an API change appears in review as the lines of the client it moves.

make spec        # refresh the specification from the deployed API
make generate    # regenerate the client from it
make check       # ruff, mypy and the tests

CI checks that the committed client is what the committed specification produces, and that every operation is reachable on it. Drift against the deployed API is checked nightly.

Licence

MIT. See LICENSE.

Release files for clockster 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for clockster 0.1.0
File Size Uploaded
clockster-0.1.0.tar.gz 104.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for clockster 0.1.0
File Interpreter ABI Platform
clockster-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 151.9 kB

Release files / clockster-0.1.0.tar.gz

Download URL clockster-0.1.0.tar.gz
Size 104.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5903821ac20fd3d3c6523521816ed6a2017826ceb7eaff697c19d1c68138c742
BLAKE2b-256 checksum
How to use checksums
026cff970003b2462c552a370602547e4240737f2ebc826e4a5c14161fee4f9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.

Transparency log

Release files / clockster-0.1.0-py3-none-any.whl

Download URL clockster-0.1.0-py3-none-any.whl
Size 47.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d9bdc785036a5f39b90d1d53fa23f491fd329757e40c7c2799c30de81c145518
BLAKE2b-256 checksum
How to use checksums
940035099b701f5aeecf50d30542e8d80e80beabc91cb42aa56a7d79d174a2d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page