Developers

Automation API

Drive check-in, check-out and emergencies from anywhere — and react to bathroom events in real time. Built for n8n, Home Assistant, sensors and plain HTTP.

Overview

The Automation API is the inbound counterpart to Thronfrei's outbound Smart Home webhooks.

Thronfrei sends events when a bathroom becomes occupied or free, or when someone raises an emergency (see Outbound webhooks). The Automation API lets external systems act back on Thronfrei: check a family member in or out, raise emergencies, or read the current status.

Everything is JSON over HTTPS. If you use n8n, the dedicated community node wraps all of this for you.

Base URL

All endpoints live under /v1:

https://automation.thronfrei.de/v1

Requests and responses are JSON. Send content-type: application/json on requests with a body.

Authentication

Every request except /ping needs a family-scoped API key. Create one in the Thronfrei app under More → Smart Home. Keys start with tfa_ and are shown only once.

Authorization: Bearer tfa_xxxxxxxxxxxxxxxx

As a fallback for clients that cannot set Authorization, the header X-Api-Key: tfa_... is also accepted. The key alone determines the family — you never pass a family ID.

Acting user

Writes happen in the name of a family member. Choose who with the optional userId field; if omitted, the key's configured default user is used. The chosen user must be an active member of the key's family.

{ "userId": "66f8...a12" }

Errors

Failed requests return a consistent shape with the matching HTTP status (400, 401, 403, 404, 409, 500):

{
  "ok": false,
  "error": "bathroom_occupied",
  "message": "Bad oben ist besetzt."
}

error is a stable machine-readable reason code; message is a human-friendly explanation.

Endpoints

GET /v1/status

All bathrooms of the family with occupancy and active emergencies. Accepts an optional userId to flag the caller's own rooms.

{
  "ok": true,
  "action": "status",
  "familyId": "66f8...f01",
  "bathrooms": [
    {
      "id": "bad_oben",
      "name": "Bad oben",
      "floor": "OG",
      "status": "occupied",
      "occupiedByName": "Max",
      "hasPeeEmergency": false,
      "hasToiletPaperEmergency": false,
      "occupiedSince": "2026-07-22T18:20:00.000Z"
    }
  ]
}
GET /v1/bathrooms

A compact bathroom list — ideal to populate a dropdown.

{
  "ok": true,
  "familyId": "66f8...f01",
  "bathrooms": [
    { "id": "bad_oben", "name": "Bad oben", "floor": "OG", "status": "free" }
  ]
}
POST /v1/bathrooms/{bathroomId}/check-in

Marks the bathroom occupied by the acting user and opens a session.

FieldTypeNotes
userIdstringoptionalActing member; defaults to the key's default user.
# request
curl -X POST https://automation.thronfrei.de/v1/bathrooms/bad_oben/check-in \
  -H "Authorization: Bearer tfa_..." \
  -H "content-type: application/json" \
  -d '{"userId":"66f8...a12"}'

# 200
{ "ok": true, "action": "check_in", "bathroomId": "bad_oben", "message": "Bad oben ist jetzt für Max reserviert." }

409 if the bathroom is occupied or the user is already checked in elsewhere.

POST /v1/bathrooms/{bathroomId}/check-out

Ends the acting user's active session and frees the bathroom. Any matching pee emergency is resolved automatically.

FieldTypeNotes
userIdstringoptionalActing member; defaults to the key's default user.

{bathroomId} is validated against the user's active session. 409 if the user is not checked in, or is in another bathroom.

POST /v1/emergencies/pee

Raises a pee emergency for the acting user.

FieldTypeNotes
userIdstringoptionalActing member.
bathroomIdstringoptionalTarget bathroom.
urgencyLevelintegeroptional1–3, default 2.
messagestringoptionalMax 240 chars.
{ "ok": true, "action": "pee_emergency", "bathroomId": null, "message": "Pipi-Notruf gesendet." }

409 if the requester already has an active emergency.

POST /v1/emergencies/toilet-paper

Raises a toilet-paper emergency. The acting user must currently occupy the target bathroom.

FieldTypeNotes
userIdstringoptionalActing member.
bathroomIdstringoptionalDefaults to the user's active session.

403 if the user does not occupy the bathroom · 409 if the bathroom is free or the emergency is already active.

Outbound webhooks

Configure targets in the app under More → Smart Home. Thronfrei POSTs a compact JSON payload to each enabled target when a matching event occurs. No internal IDs, tokens or secrets are ever sent.

{
  "app": "Thronfrei",
  "event": "pipi_notruf",
  "title": "Pipi-Notruf",
  "message": "Max wartet auf Bad oben.",
  "bathroom": "Bad oben",
  "person": "Max",
  "occurredAt": "2026-07-22T18:20:00.000Z"
}

Event names

bad_besetzt

A bathroom became occupied.

bad_frei

A bathroom became free.

klopapier_notruf

Toilet-paper emergency raised.

klopapier_erledigt

Toilet-paper emergency resolved.

pipi_notruf

Pee emergency raised.

pipi_gesehen

Pee emergency acknowledged.

pipi_erledigt

Pee emergency resolved.

pipi_abgebrochen

Pee emergency cancelled.

Targets support GET/POST/PUT/PATCH and WebSocket (ws:// local, wss:// remote), a payload template with {{placeholders}}, and plain HTTP for private LAN devices (e.g. a Shelly plug).

Signature verification

If a target has a secret, Thronfrei signs the exact request body and sends it as an HMAC-SHA256 header. Verify it to be sure a request really came from Thronfrei:

x-thronfrei-signature: sha256=<hex>
x-thronfrei-event: pipi_notruf
// Node.js
const expected = 'sha256=' +
  crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));

Sign over the raw request body bytes, not a re-serialized object.

n8n node

The community package n8n-nodes-thronfrei ships two nodes:

Thronfrei Trigger

A webhook receiver. Copy its Production URL into a Smart Home target, pick your events, and optionally verify the HMAC signature.

Thronfrei

Actions for check-in, check-out, status and emergencies. The bathroom dropdown is filled live from your family.

Install via Settings → Community Nodes and search for n8n-nodes-thronfrei. Add a Thronfrei API credential with your base URL and tfa_ key.

Source code, issues and releases: github.com/pandee-de/n8n-nodes-thronfrei.

OpenAPI spec

The full API is described as an OpenAPI 3.1 document. Import it into Postman, Insomnia, or n8n's HTTP Request node, or generate a client:

Download openapi.yaml