Device API

The Device API is the API expected by the clock (the screen) in the course of its normal operation.

This documentation is useful for developers who are:

  • creating their own clocks, making use of the existing poem.town back-end; or,
  • replacing poem.town with their own, compatible back-end.

If, instead, you want to post notes to an existing clock, please contact us to discuss the Web API.

Usage#

Endpoints

The root for all API endpoints is https://poem.town/api/v1/clock.

Poem/1 clocks allow for changing the server URL via the Wi-Fi configuration interface. This will change the server URL but not the path. For example, changing the server URL to example.org will change the endpoint root to “https://example.org/api/v1/clock`.

Authorization

All API require an HTTP header with a valid API key of the form:

Authorization: Bearer poem.dummyKey

Request and response format

All requests are made using HTTP POST with a JSON body. Responses are JSON.

Datetimes always use ISO8601 without milliseconds and with an explicit Z, e.g. 2025-01-03T16:49:10Z.

/status#

Use /status as an end-to-end test when a device is booting, before fetching a poem. Note: this method must be called at least once before the user visits the personalization website. (If it is not called then there is a risk that the screen ID will not be recognised.)

Example

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"screenId": "80AB412341234"}' \
https://poem.town/api/v1/clock/status

Request

The request body is an object with screenId.

{
  "screenId": "80AB412341234"
}

Response

The request object is returned with a success property, and information about this device.

{
  "success": true  // boolean,
  "device": {
    screenId: "80AB412341234", // string
    lastSeen: "2025-01-03T16:49:10Z", // string, ISO date
    seen: 2, // number
    createdAt: "2025-01-03T12:00:00Z", // string, ISO date
    isClaimed: false // boolean
  }
}

/compose#

Use /compose every minute to compose a new poem.

Examples

Use time24 to compose a poem for a specific time:

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"time24": "12:34"}' \
https://poem.town/api/v1/clock/compose

Alternatively use geolocate to pass in the time in UTC, and allow the server to auto-detect the device’s local time:

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"geolocate": "2024-08-20T19:51:00Z"}' \
https://poem.town/api/v1/clock/compose

Additionally pass in screenId to allow the server to load personalization settings such as preferred font:

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"screenId": "80AB412341234", "geolocate": "2024-08-20T19:51:00Z"}' \
https://poem.town/api/v1/clock/compose

Request

The request body must include EITHER time24 or geolocate, but not both. The screenId is optional.

{
  "screenId": "80AB412341234", // string, optional
  "time24": "12:34", // string, either time24 or geolocate
  "geolocate": "2024-09-01T12:34:00Z" // string, either time24 or geolocate
}

Response

The response object includes the composed poem and a number of display hints.

The device may decide how to handle a note. For example, a Poem/1 device will display a note on its screen until it is 30 minutes old, and then remove it — even if the note is unseen. The latest note is included in the response object (seen or not) for up to 24 hours.

If the screensaver property is present and is true then a Poem/1 device will display a blank screen (unless the user interacts with the device).

{
  "poemId": "123456", // string
  "time24": "12:34", // string
  "poem": "The poem text / Two lines with a slash", // string
  "note": {
    // optional
    "noteId": "123456", // string
    "body": "The note text", // string
    "posted": "2024-09-01T12:34:00Z", // string, ISO date
    "seen": false // boolean
  },
  "preferredFont": "INTER", // "INTER" | "PLAYFAIR", optional
  "screensaver": true, // boolean, should default to false
  "debug": {
    // optional, should be ignored by the device
    // ...
  }
}

/notes/{noteId}/seen#

When the user interacts with the device to mark a note as seen, use this endpoint to update the note’s status.

Example

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"screenId": "80AB412341234"}' \
https://poem.town/api/v1/clock/notes/30/seen

Request

The note ID is part of the URL. (Retain it from the /compose response.)

The request body is an object with screenId.

{
  "screenId": "80AB412341234"
}

Response

A 404 error is returned if screenId is not known.

The response object will indicate success whether or not the note ID is known, so long as it was valid.

{
  "success": true // boolean
}

/likes/{poemId}/mark#

When the user interacts with the device to like a poem, use this endpoint to record it.

Example

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"screenId": "80AB412341234"}' \
https://poem.town/api/v1/clock/likes/832253/mark

Request

The poem ID is part of the URL. (Retain it from the /compose response.)

The request body is an object with screenId.

The screenId must be claimed.

{
  "screenId": "80AB412341234"
}

Response

The response will indicate success if the screenId is known, valid, and claimed, and the request was well formed.

A 404 will be returned if the poemId in the URL is not known.

{
  "success": true // boolean
}

/likes/{poemId}/unmark#

When the user interacts with the device to remove their like from a poem, use this endpoint to record the action.

The request and response are identical to the /likes/\{poemId}/mark endpoint.

Example

curl \
-H "Authorization: Bearer poem.dummyKey" \
--json '{"screenId": "80AB412341234"}' \
https://poem.town/api/v1/clock/likes/832253/unmark

Request

See /likes/\{poemId}/mark.

Response

See /likes/\{poemId}/mark.