Skip to content
Developer

HomeAssistant

Smart home and automation20 EndpointsDataWarehouse / HomeAssistant

Returns a list of bookable resources for Home Assistant.

GET/api/homeassistant/bookables

Each entry contains id and name.

Responses

default

Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/bookables \
  --header 'x-iw-jwt-token: <TOKEN>'

Returns a calendar feed (iCal) for a single bookable resource.

GET/api/homeassistant/calendar/{identifier}

Path parameters

identifierrequiredstring

Responses

default

Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/calendar/42 \
  --header 'x-iw-jwt-token: <TOKEN>'

Returns the iCal for a single booking entry plus its bookable ID.

GET/api/homeassistant/booking/{identifier}

Used by the webhook handler to patch a single event into the calendar without fetching the full calendar feed.

Path parameters

identifierrequiredstring

Responses

default

Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/booking/42 \
  --header 'x-iw-jwt-token: <TOKEN>'

Register a webhook so the ERP notifies Home Assistant when bookings change.

POST/api/homeassistant/webhook

Expects JSON body: {"webhook_url": "https://ha-instance/api/webhook/iw_erp_homeassistant"}

Creates a RegisteredWebhook entry for BaseBooking create/update/delete events.

Optional "events": ["access", "check_in"] - with integration_ha_access_events_enabled the ERP also reports smart lock accesses and check-ins to the same URL (body without the entity, only webhook_data). Every registration states the full list: events left out are removed. The answer then carries "events", the events that are active.

Optional "webhook_token": a secret of 16-190 printable characters, sent back with every webhook of the URL as X-IW-Webhook-Token so Home Assistant can reject forged calls.

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/webhook \
  --header 'x-iw-jwt-token: <TOKEN>'

Unregister a Home Assistant webhook.

DELETE/api/homeassistant/webhook

Expects JSON body: {"webhook_url": "https://ha-instance/api/webhook/iw_erp_homeassistant"}

Responses

default

Request
curl --request DELETE \
  --url https://your-instance.iw-erp.de/api/homeassistant/webhook \
  --header 'x-iw-jwt-token: <TOKEN>'

ERP smart locks the API key's user may use, for the lock entities of the Home Assistant integration ("Import ERP smart locks", opt-in in Home Assistant). Locks that the calling Home Assistant instance offers itself are left out (excludeHaInstanceId).

GET/api/homeassistant/smart_locks

Query parameters

excludeHaInstanceIdstringHome Assistant instance id whose own locks are skipped

Responses

200Smart locks accessible for the API key's userarray<object>

Show fields (4)
  • idinteger
  • namestring
  • descriptionstring
  • typestring
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/smart_locks \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
[
  {
    "id": 42,
    "name": "Beispiel",
    "description": "Text",
    "type": "string"
  }
]
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
{
  "id": 42,
  "state": "string"
}

Locks an ERP smart lock from Home Assistant. Same access rules and smart lock log as /api/event/smart_lock/{id}/lock.

POST/api/homeassistant/smart_locks/{identifier}/lock

Path parameters

identifierrequiredstring

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock \
  --header 'x-iw-jwt-token: <TOKEN>'

Opens an ERP smart lock from Home Assistant. Same access rules and smart lock log as /api/event/smart_lock/{id}/unlock.

POST/api/homeassistant/smart_locks/{identifier}/unlock

Path parameters

identifierrequiredstring

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock \
  --header 'x-iw-jwt-token: <TOKEN>'

Home Assistant offers its locks to the ERP ("Offer Home Assistant locks", opt-in in Home Assistant).

POST/api/homeassistant/ha_locks

Creates or updates a smart lock connection (provider "homeassistant") for the instance. The locks only become ERP smart locks when an administrator syncs the devices of that connection.

Expects JSON body: { "instance_id": "", "name": "Home Assistant", "webhook_url": "https://ha.example.com/api/webhook/iw_erp_homeassistant", "secret": "", "locks": [{"entity_id": "lock.front_door", "name": "Front door", "state": "locked", "supports_open": true}] }

An instance that is already connected must send the secret it registered with. After the connection was removed (DELETE), the instance can register again with a new secret.

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/ha_locks \
  --header 'x-iw-jwt-token: <TOKEN>'

Home Assistant stops offering its locks (opt-in switched off or integration removed).

DELETE/api/homeassistant/ha_locks

Expects JSON body: {"instance_id": "...", "secret": "..."}. Marks the connection as deleted; its smart locks stay but can no longer be used until the instance registers again.

Responses

default

Request
curl --request DELETE \
  --url https://your-instance.iw-erp.de/api/homeassistant/ha_locks \
  --header 'x-iw-jwt-token: <TOKEN>'

Room displays Home Assistant delivers to: the OpenDisplay receivers.

GET/api/homeassistant/displays

OpenDisplay panels are pushed to over Bluetooth by a sender next to them, and Home Assistant with the OpenDisplay integration is exactly that. Home Assistant authenticates with its API token here, so no device secret has to be copied into its configuration.

Responses

200OpenDisplay receiversarray<object>

Show fields (7)
  • idinteger
  • namestring
  • device_idstring
  • targetstring
  • refresh_secondsinteger
  • widthinteger
  • heightinteger
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/displays \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
[
  {
    "id": 42,
    "name": "Beispiel",
    "device_id": "42",
    "target": "string",
    "refresh_seconds": 1,
    "width": 1,
    "height": 1
  }
]

The current frame of one OpenDisplay receiver, for Home Assistant to upload.

GET/api/homeassistant/displays/{identifier}/frame.png

The same response the device path /display/opendisplay/{deviceId} gives - PNG, ETag / If-None-Match, X-Refresh-After - authenticated by the API token instead of the device secret. Fetching is not telemetry: Home Assistant being up says nothing about the panel, so this does not touch lastSeenAt.

Path parameters

identifierrequiredstring

Responses

200Frame as PNG in the panel resolution

304Frame unchanged, do not upload

Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png \
  --header 'x-iw-jwt-token: <TOKEN>'

What Home Assistant knows about the panel: battery, signal, firmware and when it was last heard of.

POST/api/homeassistant/displays/{identifier}/telemetry

last_seen is the panel's own last contact as Home Assistant saw it, not the time of this request - the offline report has to catch a dead panel behind a living Home Assistant. Without it the upload that just worked counts.

Path parameters

identifierrequiredstring

Request body application/json

  • battery_mvnumber
  • battery_voltagenumber
  • rssiinteger
  • firmwarestring
  • last_seenstring (date-time)

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry \
  --header 'content-type: application/json' \
  --header 'x-iw-jwt-token: <TOKEN>' \
  --data '
{
  "battery_mv": 1.5,
  "battery_voltage": 1.5,
  "rssi": 1,
  "firmware": "string",
  "last_seen": "2026-10-15T09:30:00+02:00"
}
'

Occupancy of the bookables for the occupancy sensors (integration_occupancy_api_enabled): booking now, lead time before the next one, lag time after the last one, next booking, opening hours.

GET/api/homeassistant/occupancy

Also served at /api/event/bookable_occupancy for Node-RED and n8n.

Query parameters

bookablestringComma separated bookable ids, default all

Responses

200Occupancy per bookableobject

Show fields (2)
  • generated_atstring (date-time)
  • bookablesarray<object>
    Show fields (12)
    • idinteger
    • namestring
    • location_idinteger
    • location_namestring
    • occupiedboolean
    • pre_start_activeboolean
    • post_end_activeboolean
    • pre_start_minutesinteger
    • post_end_minutesinteger
    • current_bookingobject
    • next_bookingobject
    • opening_hoursobject
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/occupancy \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
{
  "generated_at": "2026-10-15T09:30:00+02:00",
  "bookables": [
    {
      "id": 42,
      "name": "Beispiel",
      "location_name": "Beispiel",
      "location_id": 42,
      "occupied": true,
      "pre_start_active": true,
      "post_end_active": true,
      "pre_start_minutes": 1,
      "post_end_minutes": 1
    }
  ]
}

Usage counters of the bookables, for meters Home Assistant reports (integration_usage_counter_api_enabled).

GET/api/homeassistant/usage_counters

Responses

200Usage countersarray<object>

Show fields (8)
  • idinteger
  • namestring
  • bookable_idinteger
  • bookable_namestring
  • valuenumber
  • unitstring
  • use_real_usage_databoolean
  • updatedstring (date-time)
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/homeassistant/usage_counters \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
[
  {
    "id": 42,
    "name": "Beispiel",
    "bookable_name": "Beispiel",
    "bookable_id": 42,
    "value": 1.5,
    "unit": "string",
    "use_real_usage_data": true,
    "updated": "2026-10-15T09:30:00+02:00"
  }
]

A meter reading from Home Assistant: sets the value of a usage counter. Counters fed by the real usage data of the bookings are refused, Home Assistant would overwrite their sums.

POST/api/homeassistant/usage_counters/{identifier}

Expects JSON body {"value": 1240.2}.

Path parameters

identifierrequiredstring

Request body application/json

  • valuenumber

Responses

default

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42 \
  --header 'content-type: application/json' \
  --header 'x-iw-jwt-token: <TOKEN>' \
  --data '{"value":1.5}'

May a credential a reader at Home Assistant read (RFID card, member card QR, access code of the app) open a lock (integration_ha_access_check_enabled)? Same rules and smart lock log as the access check of Node-RED, with the source "homeassistant".

POST/api/homeassistant/check_access

Expects JSON body: { "credential": "04A1B2C3D4", "credential_type": "auto", // auto, access_code, member_card or card "smart_lock_id": 12, // any ERP smart lock "instance_id": "...", "lock_id": "lock.front_door", // or a lock this Home Assistant offers "open": false // ERP opens a lock of another provider itself }

Responses

200Access decisionobject

Show fields (6)
  • grantedboolean
  • reasonstring
  • credential_typestring
  • smart_lockobject
  • personobject
  • openedboolean
Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/check_access \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
{
  "granted": true,
  "reason": "string",
  "credential_type": "string",
  "opened": true
}

A fault report of Home Assistant as a ticket (integration_ha_ticket_enabled), e.g. a water alarm.

POST/api/homeassistant/ticket

Expects JSON body {"title": "...", "description": "...", "bookable_id": 7, "priority": "low|normal|high|urgent", "dedupe_key": "water_leak_hall_1"}; while a ticket with the dedupe key is open no second one is created.

Responses

200Ticketobject

Show fields (2)
  • idinteger
  • statusstring

    created or already_open

Request
curl --request POST \
  --url https://your-instance.iw-erp.de/api/homeassistant/ticket \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
{
  "id": 42,
  "status": "string"
}

Occupancy of the bookables for the occupancy sensors (integration_occupancy_api_enabled): booking now, lead time before the next one, lag time after the last one, next booking, opening hours.

GET/api/event/bookable_occupancy

Also served at /api/event/bookable_occupancy for Node-RED and n8n.

Query parameters

bookablestringComma separated bookable ids, default all

Responses

200Occupancy per bookableobject

Show fields (2)
  • generated_atstring (date-time)
  • bookablesarray<object>
    Show fields (12)
    • idinteger
    • namestring
    • location_idinteger
    • location_namestring
    • occupiedboolean
    • pre_start_activeboolean
    • post_end_activeboolean
    • pre_start_minutesinteger
    • post_end_minutesinteger
    • current_bookingobject
    • next_bookingobject
    • opening_hoursobject
Request
curl --request GET \
  --url https://your-instance.iw-erp.de/api/event/bookable_occupancy \
  --header 'x-iw-jwt-token: <TOKEN>'
Response 200 application/json
{
  "generated_at": "2026-10-15T09:30:00+02:00",
  "bookables": [
    {
      "id": 42,
      "name": "Beispiel",
      "location_name": "Beispiel",
      "location_id": 42,
      "occupied": true,
      "pre_start_active": true,
      "post_end_active": true,
      "pre_start_minutes": 1,
      "post_end_minutes": 1
    }
  ]
}