HomeAssistant
Returns a list of bookable resources for Home Assistant.
GET/api/homeassistant/bookables
Each entry contains id and name.
Responses
default
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/bookables \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/bookables', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/bookables"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/bookables', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/bookables"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/bookables")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/bookables"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/bookables'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);Returns a calendar feed (iCal) for a single bookable resource.
GET/api/homeassistant/calendar/{identifier}
Path parameters
identifierrequiredstring |
Responses
default
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/calendar/42 \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/calendar/42', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/calendar/42"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/calendar/42', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/calendar/42"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/calendar/42")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/calendar/42"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/calendar/42'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/booking/42 \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/booking/42', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/booking/42"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/booking/42', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/booking/42"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/booking/42")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/booking/42"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/booking/42'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/webhook \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/webhook"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/webhook', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/webhook"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/webhook")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/webhook"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/webhook'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);Unregister a Home Assistant webhook.
DELETE/api/homeassistant/webhook
Expects JSON body: {"webhook_url": "https://ha-instance/api/webhook/iw_erp_homeassistant"}
Responses
default
curl --request DELETE \
--url https://your-instance.iw-erp.de/api/homeassistant/webhook \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'DELETE', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/webhook"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.delete(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('DELETE', 'https://your-instance.iw-erp.de/api/homeassistant/webhook', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Delete,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/webhook"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/webhook")
.delete(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/webhook"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.delete(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/webhook'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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
excludeHaInstanceIdstring | Home Assistant instance id whose own locks are skipped |
Responses
200Smart locks accessible for the API key's userarray<object>
Show fields (4)
idintegernamestringdescriptionstringtypestring
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/smart_locks \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/smart_locks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/smart_locks"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/smart_locks', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/smart_locks"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/smart_locks")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/smart_locks"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/smart_locks'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);[
{
"id": 42,
"name": "Beispiel",
"description": "Text",
"type": "string"
}
]Current state of an ERP smart lock, mapped to the Home Assistant lock states (locked, unlocked, open, locking, unlocking, opening, jammed, unknown). Asks the lock provider; unlike /api/event/smart_lock/{id}/status it writes no smart lock log entry, because Home Assistant polls it.
GET/api/homeassistant/smart_locks/{identifier}/status
Path parameters
identifierrequiredstring |
Responses
200State of the smart lockobject
Show fields (2)
idintegerstatestring
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/status'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);{
"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
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/lock'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/smart_locks/42/unlock'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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": "
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
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/ha_locks \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/ha_locks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/ha_locks"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/ha_locks', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/ha_locks"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/ha_locks")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/ha_locks"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/ha_locks'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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
curl --request DELETE \
--url https://your-instance.iw-erp.de/api/homeassistant/ha_locks \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'DELETE', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/ha_locks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/ha_locks"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.delete(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('DELETE', 'https://your-instance.iw-erp.de/api/homeassistant/ha_locks', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Delete,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/ha_locks"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/ha_locks")
.delete(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/ha_locks"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.delete(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/ha_locks'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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)
idintegernamestringdevice_idstringtargetstringrefresh_secondsintegerwidthintegerheightinteger
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/displays \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/displays', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/displays"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/displays', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/displays"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/displays")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/displays"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/displays'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);[
{
"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
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/displays/42/frame.png'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);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_mvnumberbattery_voltagenumberrssiintegerfirmwarestringlast_seenstring (date-time)
Responses
default
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"
}
'const options = {
method: 'POST',
headers: {'x-iw-jwt-token': '<TOKEN>', 'content-type': 'application/json'},
body: JSON.stringify({
battery_mv: 1.5,
battery_voltage: 1.5,
rssi: 1,
firmware: 'string',
last_seen: '2026-10-15T09:30:00+02:00'
})
};
fetch('https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry"
payload = {
"battery_mv": 1.5,
"battery_voltage": 1.5,
"rssi": 1,
"firmware": "string",
"last_seen": "2026-10-15T09:30:00+02:00"
}
headers = {
"x-iw-jwt-token": "<TOKEN>",
"content-type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry', [
'body' => '{"battery_mv":1.5,"battery_voltage":1.5,"rssi":1,"firmware":"string","last_seen":"2026-10-15T09:30:00+02:00"}',
'headers' => [
'content-type' => 'application/json',
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
Content = new StringContent("{\"battery_mv\":1.5,\"battery_voltage\":1.5,\"rssi\":1,\"firmware\":\"string\",\"last_seen\":\"2026-10-15T09:30:00+02:00\"}")
{
Headers =
{
ContentType = new MediaTypeHeaderValue("application/json")
}
}
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"battery_mv\":1.5,\"battery_voltage\":1.5,\"rssi\":1,\"firmware\":\"string\",\"last_seen\":\"2026-10-15T09:30:00+02:00\"}");
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry")
.post(body)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.addHeader("content-type", "application/json")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry"
payload := strings.NewReader("{\"battery_mv\":1.5,\"battery_voltage\":1.5,\"rssi\":1,\"firmware\":\"string\",\"last_seen\":\"2026-10-15T09:30:00+02:00\"}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
req.Header.Add("content-type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'dart:convert';
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/displays/42/telemetry'),
headers: {'x-iw-jwt-token': '<TOKEN>', 'content-type': 'application/json'},
body: jsonEncode({
"battery_mv": 1.5,
"battery_voltage": 1.5,
"rssi": 1,
"firmware": "string",
"last_seen": "2026-10-15T09:30:00+02:00"
}),
);
print(response.body);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
bookablestring | Comma separated bookable ids, default all |
Responses
200Occupancy per bookableobject
Show fields (2)
generated_atstring (date-time)bookablesarray<object>Show fields (12)
idintegernamestringlocation_idintegerlocation_namestringoccupiedbooleanpre_start_activebooleanpost_end_activebooleanpre_start_minutesintegerpost_end_minutesintegercurrent_bookingobjectnext_bookingobjectopening_hoursobject
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/occupancy \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/occupancy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/occupancy"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/occupancy', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/occupancy"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/occupancy")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/occupancy"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/occupancy'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);{
"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)
idintegernamestringbookable_idintegerbookable_namestringvaluenumberunitstringuse_real_usage_databooleanupdatedstring (date-time)
curl --request GET \
--url https://your-instance.iw-erp.de/api/homeassistant/usage_counters \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/usage_counters', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/usage_counters"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/homeassistant/usage_counters', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/usage_counters"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/usage_counters")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/usage_counters"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/usage_counters'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);[
{
"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
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}'const options = {
method: 'POST',
headers: {'x-iw-jwt-token': '<TOKEN>', 'content-type': 'application/json'},
body: JSON.stringify({value: 1.5})
};
fetch('https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42"
payload = { "value": 1.5 }
headers = {
"x-iw-jwt-token": "<TOKEN>",
"content-type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42', [
'body' => '{"value":1.5}',
'headers' => [
'content-type' => 'application/json',
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
Content = new StringContent("{\"value\":1.5}")
{
Headers =
{
ContentType = new MediaTypeHeaderValue("application/json")
}
}
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"value\":1.5}");
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42")
.post(body)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.addHeader("content-type", "application/json")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42"
payload := strings.NewReader("{\"value\":1.5}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
req.Header.Add("content-type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'dart:convert';
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/usage_counters/42'),
headers: {'x-iw-jwt-token': '<TOKEN>', 'content-type': 'application/json'},
body: jsonEncode({
"value": 1.5
}),
);
print(response.body);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)
grantedbooleanreasonstringcredential_typestringsmart_lockobjectpersonobjectopenedboolean
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/check_access \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/check_access', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/check_access"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/check_access', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/check_access"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/check_access")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/check_access"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/check_access'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);{
"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)
idintegerstatusstringcreated or already_open
curl --request POST \
--url https://your-instance.iw-erp.de/api/homeassistant/ticket \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'POST', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/homeassistant/ticket', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/homeassistant/ticket"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.post(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://your-instance.iw-erp.de/api/homeassistant/ticket', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/homeassistant/ticket"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/homeassistant/ticket")
.post(null)
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/homeassistant/ticket"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.post(
Uri.parse('https://your-instance.iw-erp.de/api/homeassistant/ticket'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);{
"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
bookablestring | Comma separated bookable ids, default all |
Responses
200Occupancy per bookableobject
Show fields (2)
generated_atstring (date-time)bookablesarray<object>Show fields (12)
idintegernamestringlocation_idintegerlocation_namestringoccupiedbooleanpre_start_activebooleanpost_end_activebooleanpre_start_minutesintegerpost_end_minutesintegercurrent_bookingobjectnext_bookingobjectopening_hoursobject
curl --request GET \
--url https://your-instance.iw-erp.de/api/event/bookable_occupancy \
--header 'x-iw-jwt-token: <TOKEN>'const options = {method: 'GET', headers: {'x-iw-jwt-token': '<TOKEN>'}};
fetch('https://your-instance.iw-erp.de/api/event/bookable_occupancy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://your-instance.iw-erp.de/api/event/bookable_occupancy"
headers = {"x-iw-jwt-token": "<TOKEN>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://your-instance.iw-erp.de/api/event/bookable_occupancy', [
'headers' => [
'x-iw-jwt-token' => '<TOKEN>',
],
]);
echo $response->getBody();using System.Net.Http.Headers;
var client = new HttpClient();
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://your-instance.iw-erp.de/api/event/bookable_occupancy"),
Headers =
{
{ "x-iw-jwt-token", "<TOKEN>" },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://your-instance.iw-erp.de/api/event/bookable_occupancy")
.get()
.addHeader("x-iw-jwt-token", "<TOKEN>")
.build();
Response response = client.newCall(request).execute();package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://your-instance.iw-erp.de/api/event/bookable_occupancy"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-iw-jwt-token", "<TOKEN>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Dart with package:http (no controller in the iw_erp_api package)
import 'package:http/http.dart' as http;
final response = await http.get(
Uri.parse('https://your-instance.iw-erp.de/api/event/bookable_occupancy'),
headers: {'x-iw-jwt-token': '<TOKEN>'},
);
print(response.body);{
"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
}
]
}