This guide assumes your server is installed at example.com, although you can
change this address to match your actual installed location.
This address should be available to any devices that will be communicating with it. For example, if you wish to scrobble using 4G, the external API should be publicly accessible.
The internal API should ALWAYS remain hidden behind a firewall, as it allows direct manipulation of the database without authentication.
You may want to keep track of individual devices which submit data to the API. To submit any data to the API, you will need at least one device, which will have been set up after you start the server for the first time. If you wish to add more, go to the "devices" table within the database, and add a new device there. Your device ID must be a randomly generated UUID, and you should keep your API key secure.
For future reference in this document, <API-KEY> refers to an API key
generated for a device in this database.
Unfortunately, due to connecting to various services, several of these endpoints
are not consistent with the others (eg. sending apiKey as a body parameter, or
in the URL, or as an HTTP header). While I have also tried to make the response
payload consistent across all the endpoints, some are still different, so if you
choose to connect to these endpoints manually, please check that you are sending
the correct authorisation parameters and checking for the correct responses.
The main scrobbling endpoint matches the official ListenBrainz one - you should
only need to change the endpoint from https://api.listenbrainz.org to
https://example.com/api/listenbrainz
Authorization:token <API-KEY>(eg.token e2cbe426-d193-...)Content-Type:application/json
listen_type: "single", "import", or "playing_now".
if you send "playing_now", it will set the currently played track on the website, but will not save the scrobble to the database. This usually happens at the start of the song, and a "single" payload will be sent near the end.payload, an array of objects, containing the following properties:listened_at: unix timestamp in secondstrack_metadata, an object containing the following properties:artist_nametrack_namerelease_nameadditional_info, an optional object containing the following properties:date: The date this song/album was released, in ISO8601 formattags: An array of strings, containing the music genres of the tracktracknumber: An integerduration_ms: An integer, the length of the song in milliseconds
Typically, more information about this track may be included by scrobblers, but the information provided above is all Everything uses to store scrobbles.
{
"listen_type": "single",
"payload": [
{
"listened_at": 1717347046,
"track_metadata": {
"artist_name": "TomboFry",
"release_name": "Floating Amongst the Stars",
"track_name": "Taken For a Ride",
"additional_info": {
"date": "2024-04-26",
"tags": ["Progressive Rock", "Indie Rock"],
"tracknumber": 2,
"duration_ms": 451736
}
}
}
]
}200, successful response:
{
"status": "ok"
}500, failure:
{
"status": "error",
"code": 500,
"error": "Information about the error"
}No headers required, no payload required.
200, valid token
{
"code": 200,
"message": "Token valid.",
"valid": true,
"user": "A description about this device"
}200, invalid token
{
"code": 200,
"message": "Token invalid.",
"valid": false
}You can set up automation services - such as IFTTT or Zapier - to POST to this endpoint when periodically checking your Liked Videos playlist on YouTube. Alternatively, you can also set up an iOS Shortcut to POST to this endpoint when receiving YouTube URLs from the Share sheet for manual submissions.
Content-Type:application/json
url: The YouTube URL, can be in the formatyoutube.com/watch?v=...oryoutu.be/...title: Optional, to override the real title of the videocreated_at: Optional, to override the liked date, in ISO8601 formatapiKey: Value of<API-KEY>
{
"url": "https://www.youtube.com/watch?v=4Q0p2WnVvMU",
"title": "Floating Amongst The Stars (Official Lyric Video)",
"created_at": "2024-01-01T09:00:00.000Z",
"apiKey": "0ccdd0ad-dd26-...",
}200, successful:
{
"status": "ok"
}400, failure:
{
"status": "Information about the error"
}You can set up automation services - such as IFTTT or Zapier - to POST to this endpoint when periodically checking other services, such as Pocket. Alternatively, you can also set up an iOS Shortcut to POST to this endpoint when receiving URLs from the Share sheet for manual submissions.
Content-Type:application/json
apiKey: Value of<API-KEY>url: The page URL being bookmarkedtitle: The title of the pagecreated_at: Optional, set a custom date, in ISO8601 date/time format
{
"url": "https://floof.fm/",
"title": "moonfloof",
"apiKey": "a732cb0b-c24f-...",
"created_at": "2024-01-01T09:45:00.000Z"
}200, successful:
{
"status": "ok"
}400, failure:
{
"status": "Information about the error."
}Authorization:<API-KEY>(do not include "Bearer" or "token")Content-Type:application/json
battery_level: A number between 0.0 and 1.0 (eg.0.56is 56%)battery_state: One of:true,false, or a free-form string containing the state (eg. "charging", "unplugged", etc)
{
"battery_level": 0.56,
"battery_state": "charging"
}200, successful:
{
"status": "ok"
}400, failure:
{
"status": "err",
"message": "Information about the error"
}An endpoint which follows the Overland API specification, which can be used with the Overland app for Android or iOS to log your location.
You can set the app up by changing the Server URL in the Settings tab as
follows: https://example.com/api/device/overland?apiKey=<API-KEY>
Make sure you put your API key in the URL query, but otherwise the payload and response information can be found in the link above.
NOTE: All endpoints in this category require the following headers, and return the same responses:
Authorization:<API-KEY>(do not include "Bearer" or "token")Content-Type:application/json
200, successful:
{
"status": "ok"
}400, failure:
{
"status": "Information about the error."
}💡 If you're tracking steps with Apple Health, you could set up an automation using Shortcuts to fetch the number of steps taken today, and POST it to this endpoint at 23:59 every day.
created_at: the date you're logging steps for, inYYYY-MM-DDformat. You can provide a full ISO8601 date but it will be truncated to the whole day in the database, so you only need to log this once per day. If not provided, the API will default to the current date.steps: number of steps taken on this day
{
"created_at": "2024-01-01",
"steps": 3056
}💡 You could set up an iOS Shortcut to log your weight to both Apple Health and POST to this endpoint at the same time.
created_at: the date you're logging weight for, inYYYY-MM-DDformat. You can provide a full ISO8601 date but it will be truncated to the whole day in the database, so you only need to log this once per day. If not provided, the API will default to the current date.weight_kgs: weight in kilograms, as a number (technically there's nothing stopping you from logging pounds, stone, or some other unit).
{
"created_at": "2024-01-01",
"weight_kgs": 70.0
}created_at: full date/time in ISO8601 format. If not provided, the API will default to the current date/time.name: what you're currently eating/drinkingtype: used to categorise food types. You may wish to track takeouts, caffeinated drinks, and normal meals separately from one another. Some examples include: "food", "drink", "soft drink", "coffee", "tea", "takeout", "snack", etc. If not provided, the API will default to "food".
{
"created_at": "2024-01-01T09:00:00.000Z",
"name": "Chicken and mushroom curry",
"type": "takeout"
}💡 You could set up an iOS Shortcut to display a list of categories, then POST to this endpoint to start/end a session.
created_at: date/time, in ISO8601ended_at: date/time, in ISO8601category: what you're time tracking
You do not have to provide created_at or ended_at - if you send a payload
without dates, it will start timetracking at the current date/time. If you send
another payload afterwards, the previous session will end and a new one will
begin at the current date/time. You can send created_at without ended_at if
you wish to start a timetracking session with a custom date/time.
Also, if you send the category as "stop" while a session is currently running,
it will end the session.
Start a sleep session (which will end an existing session, if it is running):
{
"category": "sleep"
}Start a cooking/eating session, which will start the session at the specifed time, and end the previous session at that time as well.
{
"category": "cooking / eating",
"created_at": "2024-01-01T09:00:00.000Z"
}💡 You could set up an iOS Shortcut to fetch all heart rate records for the previous day once per day and send them to this endpoint.
history- either an array or a string (explained below)format- (optional) eitherjsonorcsv
If you provide history as an array, each element must be in the following
format:
rate- a number, as beats per minutecreated_at- date/time, as an ISO8601 or as a unix timestamp in seconds or milliseconds
If you provide history as a string, you MUST provide format. If the chosen
format is JSON, it must be a stringified version of the syntax above, where the
value is an array of objects. If the chosen format is CSV, the first column must
be the heart rate, and the second column is the timestamp.
In this example, three heart rate samples were provided, using each of the different date/time formats.
{
"history": [
{
"rate": 70,
"created_at": "2026-01-01T09:30:00.000Z"
},
{
"rate": 72,
"created_at": 1767259830
},
{
"rate": 74,
"created_at": 1767259900000
},
]
}{
"history": "[{\"rate\":70,\"created_at\":\"2026-01-01T09:30:00.000Z\"}]",
"format": "json"
}In this example, the same three heart rate samples were provided, using unix timestamps as seconds
{
"history": "70,1767259800\n72,1767259830\n74,1767259900",
"format": "csv"
}To keep track of your income/outgoings, you'll need to set up a webhook using
your Monzo account, and point it to the
following address: https://example.com/api/purchases?apiKey=<API-KEY>.
Alternatively, if you don't have a Monzo account, you can still post to this endpoint using the following payload.
Content-Type:application/json
account_id: string, which MUST match theEVERYTHING_MONZO_ACCOUNT_IDvalue provided in.env, otherwise an error will be thrownamount: number, an outgoing payment is negative, and 100 times the amount of the transaction (eg. 5.49 is-549). Income is positive (eg. 15.32 is1532)currency: The 3-letter code of the currency used by the transaction (eg. £ isGBP, and $ could beUSD,AUD,NZD, etc.)created: the date/time of the transaction in ISO8601 format.category: arbitrary value used to categorise the transaction.description: arbitrary value - will only be used if merchant name is not providedmerchant: an object containing the following properties:name: The name of the store/website/service the transaction was made with.
{
"account_id": "acc_df50c4ee-1333-...",
"amount": -500,
"currency": "GBP",
"created": "2024-01-01T09:00:00.000Z",
"category": "groceries",
"merchant": {
"name": "Tesco"
}
}200, successful:
{
"status": "ok"
}400, failure:
{
"status": "Information about the error."
}You can log check-ins via Swarm, however there's a little bit of setup required,
which you can follow via the instructions in .env.template. Once that's done,
you can use the follow endpoints:
Visit this URL in your browser - you'll be redirected to login via Swarm.
Be sure to add apiKey to your query, using an API key from your devices, as
mentioned at the top of the file. This will be used to authenticate the request.
checkin: string, a stringified JSON object containing all the check-in details, which includesid,createdAt,user,venue, etc. For more details, see the check-in details endpoint docs. Do keep in mind that this data does not include photos, coins, or stickers, amongst some other important details.
{
"checkin": "{\"id\":\"12345678\",\"createdAt\":1728327484,\"shout\":\"This is my check-in!\"}"
}