Status-webhook
De fotobox meldt zijn status regelmatig aan een adres dat de beheerder invult. Elke melding is een JSON met dezelfde waarden die het portaal voor beheer op afstand voor deze fotobox toont. Wat de ontvanger ermee doet, bepaalt hij zelf.
Dit wordt ingeschakeld in het beheergedeelte "Licht en accessoires" > "Status-webhook". Beheer op afstand is hiervoor niet nodig: de webhook werkt ook op een fotobox zonder portaal.
Waarvoor het handig is#
- Op de eigen website tonen of de fotobox op dit moment in gebruik is en hoeveel foto's er al zijn gemaakt.
- Een eigen overzicht van meerdere fotoboxen bijhouden, in een bestaand systeem.
- Een melding krijgen wanneer het papier opraakt, de camera-accu zwakker wordt of een fotobox niet meer meldt - via domotica of een chat.
- Tellers bijhouden, bijvoorbeeld voor de facturatie aan de klant.
Status-webhook of triggers?#
Beide melden naar buiten, maar verschillend:
| Status-webhook | Triggers voor externe programma's | |
|---|---|---|
| Wanneer | met een vast interval, standaard elke 30 seconden | op het moment dat een stap plaatsvindt |
| Wat | de volledige status van de fotobox | een enkele gebeurtenis met enkele waarden |
| Waarheen | een adres op internet of in het netwerk | een adres of een programma op de fotobox |
| Typisch | weergave, bewaking, statistiek | licht, stopcontacten, scripts tijdens de sessie |
Beide kunnen tegelijk worden gebruikt. De triggers worden beschreven in het hoofdstuk Triggers voor externe programma's.
Instellen#
- Een ontvanger klaarzetten: een adres dat een POST-verzoek met JSON aanneemt en antwoordt met een status van 200 tot en met 299. De voorbeelden verderop volstaan daarvoor.
- In het gedeelte "Status-webhook" het adres invullen en opslaan. Daarbij ontstaat de sleutel voor de handtekening.
- De sleutel met "Kopiëren" overnemen en bij de ontvanger invullen.
- Op "Testmelding versturen" drukken. Daaronder verschijnen het antwoord van de ontvanger en de verstuurde inhoud.
- "Status-webhook gebruiken" inschakelen. De eerste melding gaat direct weg, daarna met het ingestelde interval.
Wat er binnenkomt#
Elke melding is een POST-verzoek met deze headers:
| Header | Inhoud |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | RAWCaptureBooth-Statuswebhook/<versie> |
X-RAWCaptureBooth-Timestamp | Tijdstip van de melding in seconden sinds 1970 (Unix-tijd) |
X-RAWCaptureBooth-Signature | sha256= gevolgd door de handtekening, zie verderop |
De inhoud ziet er zo uit (ingekort tot één printer en één buzzer):
{
"schema_version": 1,
"sent_at": "2026-10-03T21:14:05+02:00",
"report_interval_seconds": 30,
"computer_name": "FOTOBOX-01",
"rawcapturebooth_version": "3.28.0",
"rawcapturebooth_latest_version": "3.28.0",
"cockpit_version": null,
"cockpit_latest_version": null,
"uptime": "5:12:03",
"network_status": "WLAN (Feestzaal)",
"connectivity_mode": "online",
"email_enabled": true,
"print_enabled": true,
"cloud_enabled": false,
"event_name": "Bruiloft Jansen",
"sessions_total": 1843,
"sessions_since_start": 112,
"session_limit": 0,
"total_print_jobs": 2210,
"print_jobs_since_start": 131,
"print_limit": 300,
"ai_portraits_total": 0,
"ai_portraits_since_start": 0,
"ai_portrait_limit": 0,
"ai_portrait_warn_threshold": 0,
"last_session_at": "2026-10-03T19:13:40Z",
"last_capture_at": "2026-10-03T19:13:40Z",
"error_count": 0,
"last_error": null,
"last_error_at": null,
"cpu_used_percent": 23.5,
"memory_used_percent": 61.2,
"disk_free_gb": 182.4,
"disk_total_gb": 476.3,
"outbox_pending": 0,
"outbox_email_pending": 0,
"outbox_cloud_pending": 0,
"camera_battery_percent": null,
"camera_power_source": "ac",
"printers": [
{
"role": "print",
"mode": "single",
"name": "DP-DS620",
"available": true,
"state": "ready",
"queue_length": 0,
"issues": [],
"media_remaining": 268,
"media_capacity": 400,
"total_prints": 15320
}
],
"buzzers": [
{
"name": "Buzzer 1",
"connection": "connected",
"battery_level": 3,
"millivolt": 4010,
"seconds_since_press": 25
}
]
}
"Testmelding versturen" toont de echte inhoud van de eigen fotobox onder "Verstuurde inhoud".
De velden#
Een veld zonder waarde is null. In latere versies kunnen nieuwe velden bijkomen; een ontvanger slaat over wat hij niet kent. schema_version stijgt alleen als de betekenis van een veld verandert of een veld vervalt.
| Veld | Inhoud |
|---|---|
schema_version | Opbouw van de melding, momenteel 1 |
sent_at | Verzendtijdstip in de lokale tijd van de fotobox, met tijdzone |
report_interval_seconds | Meldinterval in seconden |
computer_name | Computernaam van de fotobox - de herkenning als meerdere fotoboxen aan dezelfde ontvanger melden |
rawcapturebooth_version | Geïnstalleerde versie |
rawcapturebooth_latest_version | Nieuwste gepubliceerde versie, leeg zolang de fotobox die niet kon ophalen |
cockpit_version, cockpit_latest_version | Hetzelfde voor RAWCaptureBooth Cockpit, leeg zonder Cockpit |
uptime | Looptijd sinds de start van het programma, bijvoorbeeld 5:12:03 of 1 day, 2:03:04 |
network_status | Werkelijke netwerksituatie: LAN, WLAN (netwerknaam), Online of Offline |
connectivity_mode | Ingestelde bedrijfsmodus: online of offline |
email_enabled, print_enabled, cloud_enabled | Of e-mail, afdrukken en cloud-upload zijn ingeschakeld |
event_name | Naam van het actieve event |
sessions_total, sessions_since_start | Sessies in totaal en sinds de start van het programma |
session_limit | Maximum aantal sessies, 0 betekent geen limiet |
total_print_jobs, print_jobs_since_start, print_limit | Hetzelfde voor afdrukopdrachten |
ai_portraits_total, ai_portraits_since_start, ai_portrait_limit | Hetzelfde voor AI-portretten |
ai_portrait_warn_threshold | Vanaf dit aantal AI-portretten waarschuwt de fotobox, 0 betekent uit |
last_session_at, last_capture_at | Tijdstip van de laatste sessie en de laatste opname, meestal in UTC (eindigt op Z) |
error_count | Fouten sinds de start van het programma |
last_error, last_error_at | De laatste fout als tekst, met tijdstip |
cpu_used_percent | Processorbelasting sinds de vorige melding, leeg in de eerste melding na de start |
memory_used_percent | Gebruikt werkgeheugen |
disk_free_gb, disk_total_gb | Vrije en totale ruimte van het station met de opnamen |
outbox_pending | Wachtende e-mails en uploads, bijvoorbeeld zonder netwerk |
outbox_email_pending, outbox_cloud_pending | Daarvan e-mails en cloud-uploads |
camera_battery_percent | Camera-accu in procent, leeg op netstroom of als de camera hem niet meldt |
camera_power_source | battery, ac (netadapter) of leeg |
printers | Eén item per printer, zie hieronder |
buzzers | Eén item per draadloze buzzer, zie hieronder |
Een item in printers:
| Veld | Inhoud |
|---|---|
role | print (fotoprinter) of strip (fotostripprinter) |
mode | single (één printer) of pool (printerpool, dan ook strategy) |
name | Naam van de printer in Windows |
available | Of de printer gereed is |
state | Status, bijvoorbeeld ready, printing, paused, error, offline of unknown |
queue_length | Opdrachten in de wachtrij |
issues | Lijst van gemelde problemen, leeg als er geen zijn |
media_remaining, media_capacity | Resterend materiaal en capaciteit in vellen, leeg als de printer ze niet meldt |
total_prints | Afdrukken over de hele levensduur, alleen bij DNP-printers |
Een item in buzzers:
| Veld | Inhoud |
|---|---|
name | Naam van de draadloze buzzer |
connection | connected, sleeping, disconnected, never (nooit verbonden) of unavailable (Bluetooth niet beschikbaar) |
battery_level | Batterij in drie niveaus: 3 vol, 2 half, 1 zwak, 0 onbekend |
millivolt | Batterijspanning in millivolt |
seconds_since_press | Seconden sinds de laatste druk, leeg als er nog niet is gedrukt |
De handtekening controleren#
Elke melding is ondertekend met de sleutel uit het beheergedeelte. De ontvanger berekent de handtekening zelf en neemt de melding alleen aan als beide overeenkomen:
- De inhoud zoals hij binnenkomt als bytes lezen - niet eerst als JSON inlezen en weer uitschrijven.
- Het tijdstip uit
X-RAWCaptureBooth-Timestamp, een punt en de inhoud aan elkaar plakken. - Daarover HMAC-SHA256 met de sleutel berekenen, als hex-tekenreeks, en
sha256=ervoor zetten. - Vergelijken met
X-RAWCaptureBooth-Signature, in constante tijd. - Meldingen weigeren waarvan het tijdstip meer dan vijf minuten van de eigen klok afwijkt. Zo kan een onderschepte melding later niet opnieuw worden ingespeeld.
"Opnieuw genereren" in het beheergedeelte vervangt de sleutel. Tot hij bij de ontvanger is ingevuld, weigert die elke melding.
Voorbeeld: weergave op de eigen website#
Een website kan een melding niet zelf aannemen - daarvoor is een klein script op de server nodig. Dit PHP-script controleert de handtekening en slaat alleen de waarden die openbaar mogen zijn op in een bestand fotobox-status.json:
<?php
// fotobox-webhook.php - als adres invullen in het beheergedeelte
$secret = 'HIER-DE-SLEUTEL-INVULLEN';
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_RAWCAPTUREBOOTH_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_RAWCAPTUREBOOTH_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (!hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$status = json_decode($body, true);
if (!is_array($status)) {
http_response_code(400);
exit;
}
// Alleen doorgeven wat op de website thuishoort
$public = [
'event_name' => $status['event_name'] ?? null,
'sessions_since_start' => $status['sessions_since_start'] ?? 0,
'report_interval_seconds' => $status['report_interval_seconds'] ?? 30,
'received_at' => time(),
];
file_put_contents(__DIR__ . '/fotobox-status.json', json_encode($public), LOCK_EX);
http_response_code(204);
De website leest het bestand en beslist zelf of de fotobox bereikbaar is:
<p id="fotobox">Fotobox: wordt geladen …</p>
<script>
fetch('/fotobox-status.json', { cache: 'no-store' })
.then((response) => response.json())
.then((status) => {
const age = Date.now() / 1000 - status.received_at;
const online = age <= 2 * status.report_interval_seconds;
document.getElementById('fotobox').textContent = online
? 'Fotobox in gebruik, ' + status.sessions_since_start + ' sessies sinds de start'
: 'Fotobox momenteel niet bereikbaar';
});
</script>
Voorbeeld: ontvanger in Node.js#
Zonder extra pakketten, met de ingebouwde module http:
const http = require('http');
const crypto = require('crypto');
const SECRET = 'HIER-DE-SLEUTEL-INVULLEN';
http.createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const body = Buffer.concat(chunks);
const timestamp = req.headers['x-rawcapturebooth-timestamp'] || '';
const signature = req.headers['x-rawcapturebooth-signature'] || '';
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET)
.update(timestamp + '.').update(body).digest('hex');
const valid = signature.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
if (!valid) {
res.writeHead(401).end();
return;
}
const status = JSON.parse(body.toString('utf8'));
console.log(status.computer_name, status.event_name, status.sessions_total);
res.writeHead(204).end();
});
}).listen(8080);
Herkennen dat een fotobox niet meer meldt#
Een fotobox kan niet zelf "offline" melden - zonder verbinding komt ook geen melding aan. De ontvanger onthoudt daarom wanneer de laatste melding binnenkwam. Blijft die langer dan twee meldintervallen uit (report_interval_seconds), dan is de fotobox niet bereikbaar. Twee intervallen in plaats van één vangen een enkele vertraagde melding op.
Problemen oplossen#
- "Testmelding versturen" geeft HTTP 401 of 403: De ontvanger weigert de handtekening. Klopt de sleutel? Wordt de ruwe inhoud gecontroleerd (zie hierboven)? Loopt de klok van de server goed?
- HTTP 404: Het adres klopt niet - pad en bestandsnaam controleren.
- "Doorverwijzing naar …": Het adres verwijst door, vaak van
http://naarhttps://of naar een adres metwww. De fotobox volgt geen doorverwijzingen; het doeladres uit de melding direct invullen. - "Geen antwoord binnen 15 seconden": De ontvanger is niet bereikbaar of antwoordt te traag. Hij moet de melding aannemen en direct antwoorden, in plaats van haar eerst te verwerken.
- Meldingen komen minder vaak dan ingesteld: Na een mislukte poging wacht de fotobox langer tot de volgende poging - eerst 15 seconden, dan telkens twee keer zo lang, hooguit een kwartier. Bij het eerste succes geldt weer het ingestelde interval. Hoeveel pogingen op rij zijn mislukt, staat in het gedeelte onder "Test en status".