From a160552ac9502a30c0f9345b83e0ff93add9cfc0 Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 2 Oct 2026 01:09:11 +0000 Subject: [PATCH] docs(api): document request bodies, required params and status codes in REST reference Git-Session-Id: 9fac --- src/api/rest.rst | 161 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 13 deletions(-) diff --git a/src/api/rest.rst b/src/api/rest.rst index 5693938..e594f2d 100644 --- a/src/api/rest.rst +++ b/src/api/rest.rst @@ -34,7 +34,26 @@ REST Reference -------------- .. note:: - This reference is highly incomplete. For an interactive view of the API, try out the API playground running on your local server at: http://localhost:5600/api/ + This reference covers the endpoints watchers and clients use most. For an interactive view of the API, try out the API playground running on your local server at: http://localhost:5600/api/ + +All endpoints live under ``/api/0/``. Request and response bodies are JSON unless noted. +Timestamps must be RFC 3339 with a timezone (``2026-10-01T10:00:00Z``). +Durations are in seconds. + +.. note:: + There are two server implementations: ``aw-server-rust`` (the default) and ``aw-server`` (Python). + They agree on the happy path but differ on error handling. Differences are called out below. + Do not rely on error response bodies: aw-server-rust returns an HTML page for 400/422 errors, + and some invalid inputs cause a 500 on the Python server. + +Server info +~~~~~~~~~~~ + +.. code-block:: shell + + GET /api/0/info + +Returns ``{"hostname": ..., "version": ..., "testing": ..., "device_id": ...}``. Buckets API ~~~~~~~~~~~ @@ -45,12 +64,12 @@ Buckets are data containers used to group data together which shares some metada Get Bucket Metadata ^^^^^^^^^^^^^^^^^^^ -Will return 404 if bucket does not exist - .. code-block:: shell GET /api/0/buckets/ +Status codes: ``200``, ``404`` if the bucket does not exist. + List ^^^^ @@ -58,36 +77,90 @@ List GET /api/0/buckets/ +Returns an object mapping bucket id to bucket metadata. + Create ^^^^^^ -Will return 304 if bucket already exists - .. code-block:: shell POST /api/0/buckets/ +Body (all three fields are required): + +.. code-block:: json + + {"client": "aw-watcher-example", "type": "app.example", "hostname": "my-host"} + +Status codes: ``200`` created, ``304`` if the bucket already exists (the existing bucket is left unchanged), +``400`` for malformed JSON, ``422`` for missing fields (aw-server-rust; the Python server returns ``500``). + +Delete +^^^^^^ + +.. code-block:: shell + + DELETE /api/0/buckets/?force=1 + +Deletes the bucket **and all its events**. The ``force=1`` parameter is required. +Status codes: ``200``, ``404`` if the bucket does not exist. Events API ~~~~~~~~~~ -The most common API used by ActivityWatch clients is the API providing read and append `Events <../buckets-and-events>` to buckets. -Buckets are data containers used to group data together which shares some metadata (such as client type, hostname or location). +The events API provides read and append access to `Events <../buckets-and-events>` in a bucket. Get events ^^^^^^^^^^ .. code-block:: shell - GET /api/0/buckets//events + GET /api/0/buckets//events?start=&end=&limit= -Create event -^^^^^^^^^^^^ +All parameters are optional. Events are returned newest first, as a list of +``{"id": 1, "timestamp": "...", "duration": 10.0, "data": {...}}``. +A negative ``limit`` means no limit. + +Status codes: ``200``, ``400`` if ``start``/``end`` cannot be parsed, ``404`` if the bucket does not exist. + +Create events +^^^^^^^^^^^^^ .. code-block:: shell POST /api/0/buckets//events +Body: a JSON **list** of events, each with ``timestamp``, ``duration`` and ``data`` (an object): + +.. code-block:: json + + [{"timestamp": "2026-10-01T10:00:00Z", "duration": 10, "data": {"app": "firefox"}}] + +Always send a list, even for a single event. aw-server-rust rejects a bare object with ``422``, +while the Python server accepts it, so a client tested only against the Python server can break on the default one. + +Status codes: ``200``, ``404`` if the bucket does not exist, ``422`` for an invalid body (aw-server-rust). + +Count events +^^^^^^^^^^^^ + +.. code-block:: shell + + GET /api/0/buckets//events/count?start=&end= + +Returns the number of events as a bare JSON number. + +Get / delete a single event +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + GET /api/0/buckets//events/ + DELETE /api/0/buckets//events/ + +``GET`` returns ``404`` for an unknown id on the Python server but ``500`` on aw-server-rust. +``DELETE`` returns ``200`` even if no event with that id exists. + Heartbeat API ~~~~~~~~~~~~~ @@ -95,8 +168,70 @@ The `heartbeat ` API is one of the most useful endpoints for writing .. code-block:: shell - POST /api/0/buckets//heartbeat + POST /api/0/buckets//heartbeat?pulsetime= + +The ``pulsetime`` query parameter is **required** and must be a number: it is the maximum gap, in seconds, +between two heartbeats with identical ``data`` for them to be merged into one event. +Requests without it are rejected (``400`` on the Python server, an HTML ``422`` on aw-server-rust). + +Body: a single event object (not a list), with ``timestamp``, ``duration`` (usually ``0``) and ``data``: + +.. code-block:: json + + {"timestamp": "2026-10-01T11:00:05Z", "duration": 0, "data": {"app": "firefox"}} + +Returns the resulting (possibly merged) event. Status codes: ``200``, ``404`` if the bucket does not exist, +``400``/``422`` for an invalid body or ``pulsetime``. Query API -~~~~~~~~~~~~~ -`Writing Queries <./../examples/querying-data.html>`_ +~~~~~~~~~ + +See `Writing Queries <./../examples/querying-data.html>`_ for the query language. + +.. code-block:: shell + + POST /api/0/query/ + +.. code-block:: json + + { + "timeperiods": ["2026-10-01T00:00:00Z/2026-10-02T00:00:00Z"], + "query": ["events = query_bucket(\"my-bucket\");", "RETURN = events;"] + } + +``timeperiods`` is a list of ``start/end`` RFC 3339 intervals and ``query`` is a list of statements +(a single string is rejected). The response is a list with one result per time period. + +Status codes: ``200``, ``422`` for a malformed request body (aw-server-rust), ``400`` for a query that fails to parse (Python server). +aw-server-rust reports query errors (syntax errors, undefined variables, unknown buckets) as ``500`` with a JSON ``message``. + +Export and import +~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + GET /api/0/buckets//export + GET /api/0/export + POST /api/0/import + +Per-bucket export returns ``{"buckets": {: {..., "events": [...]}}}``, or ``404`` for an unknown bucket. +``/api/0/import`` takes that same format (JSON body, or a multipart file upload as the web UI does) +and returns ``400`` for malformed input. +Importing into a bucket that already exists is not consistent between servers: aw-server-rust (master) merges +the events, while the Python server fails with ``500``. + +Settings API +~~~~~~~~~~~~ + +Key-value storage for client settings (used by the web UI). + +.. code-block:: shell + + GET /api/0/settings + GET /api/0/settings/ + POST /api/0/settings/ + DELETE /api/0/settings/ + +``GET`` of an unset key returns ``null``. ``POST`` takes any JSON value as the body and returns ``201`` on aw-server-rust +(``200`` on the Python server), and ``400`` for invalid JSON. +``DELETE`` exists only on aw-server-rust; on the Python server it returns ``405`` and a falsy ``POST`` value deletes the key instead.