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.

/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:10.374Z", // string, ISO date
    seen: 2, // number
    createdAt: "2025-01-03T12:00:00.000Z", // 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.

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