REST API
REST API
PrivateLAN biedt een JSON REST API voor het programmatisch beheren van apparaten, VLAN's en apparaatgroepen, zodat u provisioning kunt integreren in uw eigen tooling in plaats van voor elke wijziging de webinterface te gebruiken.
De API draait op dezelfde hostnaam als uw PrivateLAN-appliance, onder /api/v1/, bijvoorbeeld https://app.privatelan.nl/api/v1/device.
Uw appliance host ook een live, doorbladerbare referentie en een machineleesbare specificatie — handig om precies te zien welke endpoints uw geïnstalleerde versie heeft, of om te importeren in een tool zoals Postman of Insomnia:
https://<uw-hostnaam>/api/docs— doorbladerbare referentiepaginahttps://<uw-hostnaam>/api/openapi.json— OpenAPI 3.1-specificatie
Beide zijn publiek (geen API-key nodig) — net als deze geschreven documentatie beschrijven ze alleen de vorm van de API, geen accountgegevens, en dit is dezelfde conventie die grote API's (Stripe, GitHub, ...) hanteren voor hun eigen spec-pagina's.
Authenticatie
De API is beveiligd met een API-key, die u aanmaakt vanaf de Gebruikers-pagina op dezelfde manier als een gewoon gebruikersaccount — kies alleen "API key (bot)" als type in plaats van "Human". Een API-key is een beperkte gebruiker: er worden rollen en een licentieplek aan toegewezen zoals bij een menselijke gebruiker, en elke actie die de key uitvoert wordt weggeschreven naar het audit log.
Bij het aanmaken van een API-key wordt de volledige key precies één keer getoond. Hij kan daarna niet meer worden opgevraagd — bewaar hem veilig. Bent u de key kwijt, genereer dan een nieuwe vanaf de bewerkpagina van de gebruiker ("Rotate API key"); dit maakt de oude key onmiddellijk ongeldig.
Stuur de key als bearer-token mee met elk verzoek:
Authorization: Bearer plk_5f3a1c9e7b2d4f18_9a7c...Een API-key die tien keer achter elkaar niet correct authenticeert vanaf hetzelfde IP-adres binnen vijf minuten, wordt tijdelijk geblokkeerd — precies zoals bij een menselijke login. Wacht enkele minuten en probeer het opnieuw.
Beperken vanaf welk IP-adres een key gebruikt mag worden
Optioneel kan een API-key worden beperkt tot één of meer bron-IP-adressen of subnetten (CIDR-notatie), in te stellen op de bewerkpagina van de gebruiker. Verzoeken vanaf een ander adres worden geweigerd alsof de key ongeldig is. Laat dit veld leeg om de key vanaf elk adres te laten werken.
Formaat van verzoeken en antwoorden
Alle verzoeken en antwoorden gebruiken JSON. POST- en PUT-verzoeken moeten een JSON-body meesturen met Content-Type: application/json.
Een geslaagd antwoord heeft altijd deze vorm:
{
"success": true,
"data": { ... }
}Een foutmelding heeft altijd deze vorm:
{
"success": false,
"error": {
"code": 3000,
"slug": "DEVICE_NOT_FOUND",
"message": "Device does not exist."
}
}De numerieke code is voor elke endpoint hetzelfde, zodat uw integratie elke foutmelding maar één keer hoeft af te handelen, ongeacht waar deze optreedt.
Veilig opnieuw proberen (Idempotency-Key)
Stuur een Idempotency-Key-header mee (een willekeurige unieke string die u zelf genereert, bijvoorbeeld een UUID) op een POST-verzoek om het veilig opnieuw te kunnen proberen na een netwerkfout of timeout, zonder het risico dat hetzelfde twee keer gebeurt:
POST /api/v1/device
Content-Type: application/json
Idempotency-Key: 8f14e45f-ceea-467e-9d1a-1f3e5c9b2a11
{ "device_hostname": "printer-floor2", ... }- Opnieuw proberen met dezelfde key en dezelfde request-body geeft precies hetzelfde antwoord terug als het oorspronkelijke verzoek — het apparaat wordt niet twee keer aangemaakt, er wordt geen dubbele taak in de wachtrij gezet.
- Opnieuw proberen met dezelfde key maar een andere body wordt geweigerd met foutcode
4006(IDEMPOTENCY_KEY_MISMATCH) — hergebruik een key alleen voor het herhalen van exact hetzelfde verzoek. - Geen key meesturen werkt precies zoals voorheen — er verandert niets voor integraties die dit niet gebruiken.
- Een key wordt 24 uur onthouden na het oorspronkelijke verzoek.
Verzoeklimieten (rate limits)
Elke API-key mag een beperkt aantal verzoeken per minuut doen. Dat beschermt de appliance en de switches erachter tegen een op hol geslagen integratie; het staat los van de blokkade die al geldt voor mislukte aanmeldpogingen.
Er zijn twee budgetten, en die worden apart geteld:
| Budget | Standaard | Geldt voor |
|---|---|---|
| Algemeen | 100 verzoeken per minuut | Alle API-endpoints. |
| Switch-belastend | 10 verzoeken per minuut | Apparaatacties, switchacties, live apparaatstatus, live switchstatus, activeren van een servicepoort, uitgeven of intrekken van een certificaat, en het starten van een systeemupdate. |
Een switch-belastend verzoek telt mee voor beide budgetten, omdat elk zo'n verzoek een SSH-sessie naar een switch opent of een taak inplant die dat doet. Een switch heeft maar een handvol terminalverbindingen, en daarom is dat budget veel kleiner. Verzoeken die alleen al verzamelde gegevens teruglezen — een lijst apparaten opvragen, het statusoverzicht van meerdere apparaten tegelijk, de interfacelijst van een switch — tellen alleen mee voor het algemene budget.
Beide limieten zijn door een beheerder in te stellen onder Systeem → Beveiliging, en elk van beide kan op 0 worden gezet om hem uit te schakelen.
Elk antwoord laat zien hoe u ervoor staat:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 93
X-RateLimit-Bucket: default
X-RateLimit-Reset: 60X-RateLimit-Bucket geeft aan welk budget is aangesproken — default, of heavy bij een switch-belastend verzoek. Bij zo'n verzoek beschrijven de headers het kleinste budget, want dat raakt als eerste op.
Boven een limiet komen levert een 429 op met foutcode 5003 en een Retry-After-header:
HTTP/1.1 429 Too Many Requests
Retry-After: 6
{
"success": false,
"error": {
"code": 5003,
"slug": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded for this API key. See the Retry-After header.",
"retry_after": 6,
"bucket": "heavy"
}
}Wacht het aantal seconden uit Retry-After af en probeer het opnieuw. Het budget loopt continu weer vol in plaats van op een vast moment te resetten, dus een client die zijn verzoeken gelijkmatig verdeelt loopt nooit tegen de limiet aan: 100 per minuut is ook ongeveer 1,7 per seconde aanhoudend, met ruimte om na een rustige periode in één keer tot 100 verzoeken te doen.
Foutcodes
| Code | Slug | Betekenis |
|---|---|---|
| 1000 | INVALID_API_KEY | De API-key ontbreekt, is onjuist opgemaakt, of komt niet overeen met een bekende key. |
| 1001 | API_KEY_DISABLED | De key bestaat maar is uitgeschakeld. |
| 1002 | API_KEY_NOT_YET_VALID | De key heeft een "geldig vanaf"-datum in de toekomst. |
| 1003 | API_KEY_EXPIRED | De key is verlopen. |
| 1004 | TOO_MANY_ATTEMPTS | Te veel mislukte authenticatiepogingen vanaf dit adres. Probeer het later opnieuw. |
| 1100 | FORBIDDEN | De key heeft niet de rol die nodig is voor deze actie. |
| 2000 | VALIDATION_ERROR | Eén of meer velden zijn niet geldig — zie het fields-object in het antwoord voor details. |
| 2001 | INVALID_JSON_BODY | De request-body ontbreekt of is geen geldige JSON. |
| 2002 | METHOD_NOT_ALLOWED | Deze HTTP-methode wordt niet ondersteund op deze endpoint. |
| 2004 | INVALID_LIMIT | De query-parameter limit moet een getal tussen 1 en 500 zijn. |
| 2005 | INVALID_CURSOR | De query-parameter cursor is ongeldig of wijst niet meer naar een bestaand item. |
| 3000 | DEVICE_NOT_FOUND | Het opgevraagde apparaat bestaat niet. |
| 3001 | VLAN_NOT_FOUND | Het opgevraagde VLAN bestaat niet. |
| 3002 | DEVICE_GROUP_NOT_FOUND | De opgevraagde apparaatgroep bestaat niet. |
| 3003 | SWITCH_NOT_FOUND | De opgevraagde switch bestaat niet. |
| 3004 | SWITCH_GROUP_NOT_FOUND | De opgevraagde switchgroep bestaat niet. |
| 3005 | VLAN_DEVICE_GROUP_NOT_FOUND | De opgevraagde VLAN/apparaatgroep-koppeling bestaat niet. |
| 3006 | VLAN_SWITCH_GROUP_NOT_FOUND | De opgevraagde VLAN/switchgroep-koppeling bestaat niet. |
| 3007 | INTERFACE_NOT_AVAILABLE | De interface bestaat niet, is al toegewezen, of is geen apparaatpoort. |
| 3008 | JOB_NOT_FOUND | De opgevraagde taak bestaat niet. |
| 3009 | CERTIFICATE_NOT_FOUND | Dit certificaatbestand bestaat niet — mogelijk is het nog niet gegenereerd. |
| 3010 | WEBHOOK_NOT_FOUND | Het opgevraagde webhook-endpoint bestaat niet. |
| 3011 | WEBHOOK_CONDITION_NOT_FOUND | De opgevraagde webhookvoorwaarde bestaat niet. |
| 3012 | SERVICE_PORT_NOT_FOUND | De interface bestaat niet, of is niet gemarkeerd als servicepoort. |
| 3013 | SBOM_NOT_FOUND | Er is op deze appliance nog geen SBOM gegenereerd. |
| 4000 | DEVICE_LOCKED | Het apparaat is vergrendeld en kan niet worden gewijzigd, verwijderd of bediend. |
| 4001 | LINK_IN_USE | Deze VLAN/apparaatgroep-koppeling wordt nog gebruikt door één of meer apparaten. |
| 4002 | MISSING_IP | Wordt niet meer teruggegeven. Voor het uitgeven van een certificaat was eerst een IP-adres nodig; dat is niet langer zo. De code blijft vermeld zodat een client die erop test niet stukloopt. |
| 4003 | JOB_ALREADY_STARTED | De taak is al gestart en kan niet meer worden geannuleerd. |
| 4004 | JOB_NOT_FINISHED | Alleen een afgeronde taak (geslaagd, mislukt of geannuleerd) kan opnieuw worden geprobeerd. |
| 4005 | UNKNOWN_ACTION | Deze actie wordt niet ondersteund voor deze resource. |
| 4006 | IDEMPOTENCY_KEY_MISMATCH | Deze Idempotency-Key is al gebruikt met een andere request-body. |
| 4007 | UPDATE_ALREADY_RUNNING | Er loopt al een systeemupdate. |
| 4008 | SERVICE_PORT_CONFIG_EMPTY | Er is geen servicepoortconfiguratie ingesteld, dus de poort kan niet geprogrammeerd worden. |
| 4009 | DEVICE_IS_VIRTUAL | Een virtueel apparaat heeft geen eigen poorten; wijs interfaces toe aan het apparaat waarop het draait. |
| 4010 | DEVICE_HAS_CHILDREN | Op dit apparaat draaien nog virtuele apparaten; verwijder of verplaats die voordat u het verwijdert. |
| 4011 | POE_CLASS_INSUFFICIENT | De interface kan de PoE-klasse die de apparaatgroep vereist niet leveren. |
| 4012 | SBOM_GENERATION_RUNNING | Er staat al een SBOM-generatie in de wachtrij of deze loopt nog. Wacht tot die klaar is. |
| 5000 | INTERNAL_ERROR | Er is iets misgegaan bij het verwerken van het verzoek. |
| 5001 | LICENSE_LIMIT_REACHED | Het aanmaken van dit object zou uw licentielimiet overschrijden. |
| 5002 | UPDATE_CHECK_FAILED | Kan niet controleren op beschikbare updates (bijvoorbeeld geen verbinding met de updateserver). |
| 5003 | RATE_LIMIT_EXCEEDED | Deze API-key heeft zijn verzoeklimiet overschreden. Wacht het aantal seconden uit de Retry-After-header af en probeer opnieuw. |
Endpoints
Elke resource ondersteunt dezelfde zes acties:
| Methode | Pad | Actie |
|---|---|---|
| GET | /api/v1/{resource} | Alles opvragen |
| GET | /api/v1/{resource}/{id} | Eén item opvragen |
| POST | /api/v1/{resource} | Aanmaken |
| PUT | /api/v1/{resource}/{id} | Volledig vervangen (weggelaten velden worden teruggezet naar hun standaardwaarde) |
| PATCH | /api/v1/{resource}/{id} | Gedeeltelijk bijwerken (weggelaten velden blijven ongewijzigd) |
| DELETE | /api/v1/{resource}/{id} | Verwijderen |
Beschikbare resources: device, vlan, device-group, switch, switch-group, vlan-device-group, vlan-switch-group.
Gedeeltelijk bijwerken met PATCH
PUT vervangt het hele record — elk veld dat u niet meestuurt wordt teruggezet naar zijn standaardwaarde, precies alsof u het in de webinterface had leeggemaakt. PATCH wijzigt alleen het veld (of de velden) dat u daadwerkelijk meestuurt; al het andere blijft precies zoals het was:
PATCH /api/v1/device/42
Content-Type: application/json
{ "device_description": "Verplaatst naar 3e verdieping" }Alleen device_description wijzigt — de hostnaam, het IP-adres, het MAC-adres, het beveiligingstype en al het andere van apparaat 42 blijven ongewijzigd. Gebruik PATCH als u maar één of twee velden wilt wijzigen; gebruik PUT als u een record volledig wilt vervangen.
Door lange lijsten bladeren
Standaard geeft GET /api/v1/{resource} alle items in één antwoord terug, precies zoals voorheen — er verandert niets voor bestaande integraties. Om in plaats daarvan door de resultaten te bladeren, voegt u ?limit= toe:
GET /api/v1/device?limit=50{
"success": true,
"data": [ ... tot 50 apparaten ... ],
"meta": { "next_cursor": "NDI=", "limit": 50 }
}Als next_cursor niet null is, zijn er meer resultaten — vraag de volgende pagina op met:
GET /api/v1/device?limit=50&cursor=NDI=limit moet tussen 1 en 500 liggen. Behandel next_cursor als een ondoorzichtig token — gebruik altijd exact de teruggegeven waarde, probeer hem niet zelf samen te stellen of te decoderen.
Apparaten (devices)
GET /api/v1/device/42{
"success": true,
"data": {
"device_id": 42,
"device_hostname": "printer-floor2",
"device_ip": "10.20.0.55",
"device_mac": ["aabbccddeeff"],
"device_security": "MAC",
"device_dg": 3
}
}POST /api/v1/device
Content-Type: application/json
{
"device_hostname": "printer-floor2",
"device_ip": "10.20.0.55",
"device_mac": ["aa:bb:cc:dd:ee:ff"],
"device_description": "Printer 2e verdieping",
"device_security": "MAC",
"device_dg": 3
}device_mac is altijd een array van strings, ook bij één enkel adres — zo blijft het formaat consistent, ongeacht of een apparaat één of meerdere MAC-adressen heeft (zie hieronder). Elk item wordt op dezelfde manier genormaliseerd als in de webinterface: scheidingstekens (:/-/.) en hoofdletters worden automatisch verwijderd/omgezet, dus "aa:bb:cc:dd:ee:ff" en "aabbccddeeff" zijn gelijkwaardig. Laat het veld weg, of stuur een lege array, voor een apparaat zonder MAC-adres.
device_dg is het ID van de combinatie apparaatgroep + VLAN waartoe het apparaat behoort (zichtbaar op de pagina Apparaatbeheer). Zie Apparaatbeheer voor de betekenis van elk veld en welke beveiligingstypen een gebruikersnaam/wachtwoord vereisen.
device_username en device_password zijn verplicht wanneer device_security PEAP is (willekeurige gebruikersnaam/wachtwoord, 4–100 tekens) of MAB (beide moeten gelijk zijn aan het MAC-adres van het apparaat — PrivateLAN normaliseert hoofdletters/scheidingstekens voor u). Laat beide weg bij Unsecure, MAC en EAP-TLS.
{
"device_hostname": "telefoon-verd2",
"device_ip": "10.20.0.60",
"device_security": "PEAP",
"device_username": "telefoon-verd2",
"device_password": "een-sterk-wachtwoord",
"device_dg": 3
}device_connection (wired of wireless, standaard wired) geeft aan hoe het apparaat het netwerk bereikt. Een draadloos apparaat hangt aan een accesspoint en heeft geen switchpoort, dus poortkoppeling, poortconfiguratie, de poortacties en de rapporten per interface zijn er niet op van toepassing — maar het authenticeert nog steeds, wordt nog steeds op bereikbaarheid gecontroleerd en kan nog steeds een certificaat krijgen.
device_ip_mode (static of dynamic, standaard static) geeft aan waar het adres vandaan komt. Bij static is device_ip verplicht en stuurt u het zelf mee. Bij dynamic wordt het adres achterhaald uit de DHCP snooping-tabel van de switches: device_ip mag dan niet worden meegestuurd — een verzoek met allebei wordt geweigerd in plaats van dat er stilzwijgend één van vervalt — en twee alleen-lezen velden melden het resultaat: device_ip_source (manual of dhcp-snooping) en device_ip_seen (wanneer het voor het laatst is bevestigd). Zet u een bestaand apparaat om naar dynamic, dan wordt het adres gewist totdat er een is waargenomen.
device_kind (hardware of virtual, standaard hardware) geeft aan of het apparaat eigen switchpoorten heeft of op een ander geregistreerd apparaat draait — bijvoorbeeld een virtuele machine op een hypervisor. Een virtueel apparaat noemt dat apparaat in device_parent (een geheel getal; null voor een hardware-apparaat, en er een meesturen voor een hardware-apparaat wordt geweigerd) en gebruikt diens poorten: de status- en actie-endpoints hieronder antwoorden met de interfaces van de parent, en POST /api/v1/device-interface weigert het met foutcode 4009 (DEVICE_IS_VIRTUAL). De parent moet een bekabeld hardware-apparaat zijn zonder eigen parent, en mag niet vergrendeld zijn; staat de apparaatgroep van de parent in de poortmodus access (zie Apparaatgroepen), dan moet het virtuele apparaat in het VLAN van de parent zitten. Elk apparaat heeft daarnaast twee alleen-lezen velden, parent_hostname en child_count. Het verwijderen van een apparaat waarop nog virtuele apparaten draaien geeft 4010 (DEVICE_HAS_CHILDREN). Zie Apparaatbeheer voor hoe een gedeelde poort wordt geprogrammeerd.
Een PUT vervangt alle velden, dus stuur device_connection, device_ip_mode en device_kind mee bij een volledige update, anders vallen ze terug op hun standaardwaarde; een PATCH laat velden die u niet noemt ongemoeid.
device_is_camera (boolean, standaard false) markeert het apparaat voor de optionele functie Camera live-view. Het instellen van de eigen ONVIF-verbindingsgegevens van de camera is een aparte stap die na het aanmaken van het apparaat vanuit de webinterface gebeurt — dat maakt geen deel uit van deze API.
device_mac accepteert meerdere MAC-adressen — voeg gewoon meer items toe aan de array. Dit wordt meestal gebruikt bij beveiligingstype MAC (sticky), waarbij elk van de opgegeven adressen op de poort wordt geaccepteerd.
{
"device_hostname": "voip-telefoon-12",
"device_mac": ["aabbccddee01", "aabbccddee02"],
"device_security": "MAC",
"device_dg": 3
}Switches
POST /api/v1/switch
Content-Type: application/json
{
"switch_hostname": "sw-verd2-01",
"switch_group": 1,
"switch_location": "Gebouw A",
"switch_rack": "Rack 4",
"switch_type": "Cisco-IOS",
"switch_ip": "10.10.0.11",
"switch_username": "svc-privatelan",
"switch_port": 22,
"switch_auth_mode": "password",
"switch_password": "...",
"switch_enable": "..."
}switch_port is de TCP-poort waarop PrivateLAN de SSH-sessie naar de switch opent. Het veld is optioneel — laat u het weg of stuurt u een lege waarde, dan wordt de standaardpoort 22 gebruikt. Vul het alleen in wanneer de switch beheer-SSH ergens anders aanbiedt; een waarde buiten 1–65535 wordt geweigerd met een 422.
switch_type moet één van Cisco-IOS, ArubaOS, ArubaOS-CX zijn. switch_password, switch_enable, switch_ssh_key en switch_ssh_key_passphrase zijn write-only — ze worden nooit teruggegeven door GET, en bij PUT blijft een weggelaten of lege waarde de huidig opgeslagen inloggegevens ongewijzigd (stuur alleen een nieuwe waarde mee als u die wilt roteren).
Authenticatie met SSH-sleutel
switch_auth_mode bepaalt hoe PrivateLAN op de switch inlogt: password (de standaard) of key. Stuur voor een SSH-sleutel de private key mee samen met de modus:
PUT /api/v1/switch/12
Content-Type: application/json
{
"switch_hostname": "sw-verd2-01",
"switch_group": 1,
"switch_type": "Cisco-IOS",
"switch_ip": "10.10.0.11",
"switch_username": "svc-privatelan",
"switch_auth_mode": "key",
"switch_ssh_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEA...\n-----END OPENSSH PRIVATE KEY-----",
"switch_ssh_key_passphrase": ""
}Zowel PEM- als OpenSSH-sleutelformaten worden geaccepteerd (RSA, ECDSA en Ed25519). De sleutel wordt versleuteld opgeslagen en wordt nooit meer teruggegeven. Een sleutel die niet gelezen kan worden — ook wanneer de switch_ssh_key_passphrase niet klopt — wordt geweigerd met een 422.
switch_ssh_key_passphrase hoort bij de sleutel waarmee die wordt meegestuurd: de passphrase wordt alleen gelezen wanneer switch_ssh_key in hetzelfde verzoek zit, dus stuur ze samen of geen van beide. switch_auth_mode op key zetten zonder dat er ooit een sleutel is opgeslagen, wordt geweigerd met een 422.
Het antwoord bevat switch_ssh_pubkey, de publieke helft die uit de verstuurde sleutel is afgeleid. Dat is de waarde die u op de switch zelf installeert — hij is read-only en wordt ook op de pagina van de switch in de webinterface getoond.
DELETE /api/v1/switch/{id} accepteert een optionele ?switch_action= query-parameter voordat de eigen gegevens van de switch worden verwijderd:
| Waarde | Effect |
|---|---|
lock_devices | Reset eerst alleen de poorten die momenteel aan apparaten zijn toegewezen naar hun standaardstatus. |
lock_all | Reset eerst elke poort op de switch (inclusief uplinks) naar de standaardstatus. |
reset | Voer eerst een fabrieksreset uit op de switch zelf. |
| (weggelaten) | Geen actie vooraf — verwijder alleen de gegevens van de switch uit PrivateLAN. |
Switchgroepen
POST /api/v1/switch-group
Content-Type: application/json
{
"sg_name": "verd2-switches",
"sg_description": "Toegangsswitches 2e verdieping"
}VLAN/apparaatgroep-koppelingen
Koppelt een VLAN aan een apparaatgroep — het ID van de resulterende koppeling is wat het device_dg-veld van een apparaat (zie Apparaten hierboven) daadwerkelijk aanduidt. Een apparaatgroep kan aan meerdere VLAN's gekoppeld worden, en andersom.
POST /api/v1/vlan-device-group
Content-Type: application/json
{
"vlan_id": 20,
"dg_id": 3
}DELETE /api/v1/vlan-device-group/{id} wordt geweigerd met foutcode 4001 (LINK_IN_USE) zolang een apparaat deze koppeling nog als device_dg gebruikt — wijs die apparaten eerst opnieuw toe of verwijder ze.
VLAN/switchgroep-koppelingen
Koppelt een VLAN aan een switchgroep, zodat deze op elke switch in die groep wordt geprogrammeerd.
POST /api/v1/vlan-switch-group
Content-Type: application/json
{
"vlan_id": 20,
"sg_id": 1
}Het verwijderen van een koppeling herprogrammeert de betreffende switches niet automatisch — start de VLAN-programmering vanaf de VLAN-pagina als u de wijziging direct wilt doorvoeren.
Een switchinterface aan een apparaat toewijzen
Geen CRUD-resource — één endpoint regelt alle acties, omdat het om twee ID's gaat (apparaat en interface) in plaats van één.
Om een interface_id te vinden voor een bekende poort op een bekende switch (bijvoorbeeld om GigabitEthernet1/0/5 toe te wijzen op een switch waarvan u al de switch_id heeft — zie Switches), vraagt u alle interfaces van die switch op:
GET /api/v1/device-interface?switch_id=3{
"success": true,
"data": [
{
"interface_id": 87,
"name": "GigabitEthernet1/0/5",
"non_device_port": false,
"trunk": false,
"sfp": false,
"service": false,
"assigned_device_id": null,
"free": true
}
]
}free is alleen true wanneer de interface momenteel niet is toegewezen (assigned_device_id is null) en geen niet-apparaat-, trunk- of uplink-poort is. Alleen vrije interfaces kunnen worden toegewezen.
Zodra u een interface_id heeft, vraagt u in plaats daarvan de interfaces op die momenteel aan een specifiek apparaat zijn toegewezen:
GET /api/v1/device-interface?device_id=12{
"success": true,
"data": [
{
"switch_interface_id": 87,
"switch_interface_name": "GigabitEthernet1/0/12",
"switch_hostname": "sw-verd2-01",
"sg_name": "verd2-switches",
"switch_interface_patchpoint_value": "Patchpaneel 3 - poort 12"
}
]
}POST /api/v1/device-interface
Content-Type: application/json
{ "device_id": 12, "interface_id": 87 }Alleen een momenteel niet-toegewezen apparaatpoort (geen netwerk/uplink-poort) kan worden toegewezen. Voeg optioneel "patchpoint" toe aan hetzelfde verzoek om het in één keer in te stellen (zie hieronder); mislukt dat onderdeel, dan slaagt de toewijzing zelf nog steeds — probeer het patchpunt dan apart opnieuw met PUT.
DELETE /api/v1/device-interface
Content-Type: application/json
{ "device_id": 12, "interface_id": 87 }Beide acties hierboven worden geweigerd met foutcode 4000 (DEVICE_LOCKED) zolang het apparaat vergrendeld is, en met 4009 (DEVICE_IS_VIRTUAL) voor een virtueel apparaat, dat geen eigen poorten heeft — wijs de poort toe aan het apparaat waarop het draait. De interfaces van een virtueel apparaat opvragen (?device_id=) geeft die van zijn parent terug.
Toewijzen wordt daarnaast geweigerd met 4011 (POE_CLASS_INSUFFICIENT) wanneer de interface de PoE-klasse die de apparaatgroep vereist (dg_poe_class) niet kan leveren. Elk item van GET /api/v1/device-interface?switch_id= bevat poe_max_class: de hoogste PoE-klasse die de poort via zijn [P0]–[P8]-label aangeeft, zodat u vooraf een geschikte poort kunt kiezen. -1 betekent dat de poort helemaal geen PoE aangeeft, en dat is ook wat een poort zonder label betekent.
DELETE zet normaal ook de standaard poortconfiguratie op de vrijgemaakte poort. Het antwoordveld default_skipped meldt het enige geval waarin dat niet gebeurt: een poort met het eigen LAN-adres van de appliance houdt de configuratie die hij heeft, omdat het resetten ervan de appliance van zijn eigen netwerk zou afsnijden. Bij elke andere ontkoppeling is het veld false.
Patchpunt
Een vrije-tekstnotitie over waar de kabel van een toegewezen interface fysiek eindigt (bijvoorbeeld een patchpaneel en poortnummer). Blijft bij de interface staan, ook als deze later wordt losgekoppeld en met een ander apparaat wordt verbonden.
PUT /api/v1/device-interface
Content-Type: application/json
{ "device_id": 12, "interface_id": 87, "patchpoint": "Patchpaneel 3 - poort 12" }De interface moet op dit moment aan het opgegeven apparaat zijn toegewezen — een patchpunt instellen op een interface die bij een ander apparaat hoort (of bij geen enkel apparaat) geeft foutcode 3007 (INTERFACE_NOT_AVAILABLE). Stuur een lege string om het te wissen. Max 100 tekens; alleen letters, cijfers, streepjes, punten, enkele/dubbele aanhalingstekens en spaties.
Een apparaatcertificaat uitgeven en intrekken
Voor apparaten met EAP-TLS. Geen CRUD-resource — beide acties zetten alleen het werk in de wachtrij en antwoorden direct (202 Accepted) met een job_id (zie Taken hieronder); controleer device_cert_generated via GET /api/v1/device/{id}, of volg de taak, om te zien wanneer het klaar is.
POST /api/v1/device-certificate
Content-Type: application/json
{ "device_id": 12 }{
"success": true,
"data": { "queued": true, "device_id": 12, "job_id": "b3f2c1a0-...", "status": "queued" }
}DELETE /api/v1/device-certificate
Content-Type: application/json
{ "device_id": 12 }Voor het uitgeven is geen IP-adres meer nodig. Is er geen — bijvoorbeeld bij een apparaat dat zijn adres via DHCP krijgt — dan wordt het certificaat op de hostnaam van het apparaat uitgegeven in plaats van op het adres. Dat bepaalt sowieso of de authenticatie slaagt, dus aan de werking van het certificaat verandert niets.
Certificaten downloaden
Zodra een apparaatcertificaat is gegenereerd, kunt u het rechtstreeks downloaden met uw API-key — geen browsersessie nodig:
GET /api/v1/device/{id}/certificate/download?format=pemformat is één van pem, crt, pfx, pfx-legacy, p12, csr, key. Geeft 3009 (CERTIFICATE_NOT_FOUND) terug als het certificaat nog niet (in dat formaat) is gegenereerd.
Het CA-certificaat (nodig om supplicants PrivateLAN's RADIUS-server te laten vertrouwen) is op dezelfde manier beschikbaar, zonder apparaat-ID:
GET /api/v1/ca-certificate/download?format=pemformat is pem of der.
VLAN's
POST /api/v1/vlan
Content-Type: application/json
{
"vlan_id": 20,
"vlan_name": "guests",
"vlan_ip": "10.20.0.0",
"vlan_subnet": "255.255.255.0",
"vlan_gateway": "10.20.0.1"
}Zie VLAN's voor routeringsgerelateerde velden.
Apparaatgroepen
POST /api/v1/device-group
Content-Type: application/json
{
"dg_name": "printers",
"dg_description": "Netwerkprinters",
"dg_port_mode": "access",
"dg_poe_class": -1,
"dg_deploy_config": "...",
"dg_unsecure_config": "...",
"dg_secure_config_mac": "...",
"dg_secure_config_mab": "...",
"dg_secure_config_peap": "...",
"dg_secure_config_eap_tls": "..."
}Elk configuratieveld moet de markeringen [Cisco-IOS], [ArubaOS] en [ArubaOS-CX] op eigen regels bevatten, precies zoals de webinterface dat vereist — zie Apparaatbeheer.
dg_port_mode (access of trunk, standaard access) geeft aan wat voor poort de sjablonen van de groep opleveren. In de modus access moet een virtueel apparaat in het VLAN zitten van het apparaat waarop het draait; in de modus trunk mag het in een ander VLAN zitten en geeft de plaatshouder #vlan-list# ze allemaal weer. Een groep terugzetten naar access wordt geweigerd zolang een virtueel apparaat achter een van haar apparaten in een ander VLAN zit.
dg_poe_class (-1 tot en met 8, standaard -1) is de IEEE PoE-klasse die de apparaten van de groep nodig hebben; -1 betekent dat de groep geen PoE-eis stelt. Een interface kan alleen aan een apparaat in deze groep worden toegewezen wanneer de klasse die hij via zijn [P0]–[P8]-label aangeeft minstens zo hoog is; een zwakkere poort wordt geweigerd met 4011 (POE_CLASS_INSUFFICIENT). De klasse verhogen wordt geweigerd zolang een apparaat in de groep al op een poort zit die dat niet kan leveren. De waarde configureert niets op een switch: de PoE-configuratie die een poort krijgt komt nog steeds uit de configuratiesjablonen van de groep, waar een expliciete power inline never leidend blijft.
Operationele acties, status & taken
Naast het beheren van configuratie kan de API ook live acties op apparaten en switches uitvoeren, status opvragen en achtergrondtaken volgen. Deze endpoints vereisen hetzelfde soort rol die een API-key ook voor andere acties nodig heeft — wijs deze toe op de Gebruikers-pagina zoals elke andere rol.
Apparaatacties
POST /api/v1/device/{id}/actions/{action}
Content-Type: application/json
{ "params": { "interface": "GigabitEthernet1/0/12" } }action is één van:
| Actie | Effect |
|---|---|
restart-interface | De poort(en) waarop dit apparaat is aangesloten bouncen. |
enable-interface | De poort(en) inschakelen. |
disable-interface | De poort(en) uitschakelen. |
reauthenticate | Het apparaat forceren opnieuw te authenticeren (802.1x/MAB). |
check-authentication | De huidige authenticatiestatus opvragen. |
ping | Controleren of het apparaat op een ping antwoordt. |
params.interface is optioneel — laat dit weg om de actie op elke interface toe te passen die momenteel aan het apparaat is toegewezen. Dit is een live actie: er wordt een sessie naar de switch(es) geopend en het resultaat wordt direct teruggegeven (niet als taak in de wachtrij gezet).
restart-interface, enable-interface, disable-interface en reauthenticate wijzigen de toestand van een live switchpoort en worden daarom geweigerd met foutcode 4000 (DEVICE_LOCKED) zolang het apparaat vergrendeld is. ping en check-authentication lezen alleen en blijven beschikbaar — zie "Vergrendelde apparaten".
disable-interface, restart-interface en reauthenticate leggen de poort alle drie plat — bij een restart en een reauthenticate slechts kort, maar de sessie naar de switch loopt over diezelfde poort, dus de tweede helft komt nooit aan als de appliance erachter zit. Op de poort met het eigen LAN-adres van de appliance worden deze drie daarom helemaal niet naar de switch gestuurd: die interface komt terug in results met "success": false en een detail met de reden, terwijl elke andere interface in dezelfde aanroep gewoon wordt uitgevoerd. Zonder deze bescherming zou het uitschakelen van de eigen poort de appliance afsnijden van zijn eigen netwerk én van de switch die nodig is om de poort weer aan te zetten — een seriële console of een tweede machine op die switch is dan de enige uitweg. De poort wordt herkend aan het LAN-adres dat is ingesteld onder System > Networking; het WAN-adres telt niet mee.
ping is de enige actie die niet over interfaces gaat en gebruikt daarom params.from in plaats van params.interface:
POST /api/v1/device/{id}/actions/ping
Content-Type: application/json
{ "params": { "from": "appliance" } }params.from | Betekenis |
|---|---|
appliance (standaard) | Pingen vanaf de appliance zelf. Geeft antwoord op de vraag of de appliance het apparaat überhaupt kan bereiken, en geeft de gemiddelde reistijd terug in avg_ms. |
switch | Pingen vanaf de switch waarop het apparaat is aangesloten. Geeft antwoord op de vraag of het apparaat binnen zijn eigen VLAN reageert — precies wat u wilt weten als de appliance niet in dat VLAN zit. Geeft één resultaat per switch terug. |
Pingen vanaf een switch opent een sessie naar die switch en is daarmee trager dan pingen vanaf de appliance; de switch-login moet werken.
Apparaatstatus (live)
GET /api/v1/device/{id}/statusGeeft de huidige linkstatus, authenticatiestatus, PoE-status en ontdekte buur van het apparaat terug, live opgevraagd bij de switch waarop het is aangesloten.
Switchacties
POST /api/v1/switch/{id}/actions/{action}action is één van reload, factory-reset, clear-counters (allemaal live, direct) of sync (zet een directe verversing van de gecachede status van deze switch in de wachtrij — zie hieronder — in plaats van te wachten op de volgende automatische verversing; geeft een job_id terug).
Switchstatus & interfaces
GET /api/v1/switch/{id}/statusLive overzicht van de switch zelf (uptime, stackleden, enz.).
GET /api/v1/switch/{id}/interfacesElke interface op de switch, inclusief welk apparaat (indien aanwezig) aan elke poort is toegewezen, het patchpunt en de laatst bekende status. device_id en device_hostname noemen het apparaat dat de poort bezit; devices somt elk apparaat op de poort op — eerst de eigenaar, daarna de virtuele apparaten die erop draaien — elk met device_id, device_hostname en kind.
Servicepoorten
Servicepoorten geven tijdens onderhoud tijdelijk toegang tot het netwerk. Een poort wordt een servicepoort door de interface in de webinterface te voorzien van het label [SERVICE] — dat label is de enige manier waarop er een ontstaat, dus er is hier geen endpoint om er een aan te maken of te verwijderen.
GET /api/v1/service-port
GET /api/v1/service-port?switch_id=3Alle servicepoorten met hun huidige sessiestatus:
{
"success": true,
"data": [
{
"interface_id": 87,
"interface_name": "GigabitEthernet1/0/7",
"switch_id": 3,
"switch_hostname": "CISCO-SW1",
"switch_group": "Default",
"link_status": "connected",
"active": true,
"vlan_id": 1030,
"expires_at": "2026-08-30 15:30:41",
"activated_at": "2026-08-30 11:30:41",
"activated_by": 4,
"config": null
}
]
}config is null wanneer de poort de algemene configuratie gebruikt; er staat alleen een template in wanneer die ene poort een eigen configuratie heeft gekregen.
Een sessie openen — de poort wordt in het gekozen VLAN geprogrammeerd en gaat vanzelf dicht zodra de sessie verloopt:
POST /api/v1/service-port/87/actions/activate
{ "params": { "vlan_id": 1030, "duration_hours": 4 } }duration_hours moet 4, 8, 12 of 24 zijn, en het VLAN moet beschikbaar zijn op de switch waar de poort bij hoort — beide worden gecontroleerd, zodat via de API geen langere sessie of een VLAN geopend kan worden dat de webinterface zou weigeren.
Eerder afsluiten:
POST /api/v1/service-port/87/actions/disableBeide acties keren terug zodra de sessie is vastgelegd; de switch wordt op de achtergrond geconfigureerd. Een geslaagd antwoord betekent dus "de sessie staat open" (of is gesloten), niet "de switch is klaar" — lees de poort terug met GET /api/v1/service-port/87 voor het resultaat.
De configuratie die bij activatie wordt toegepast:
GET /api/v1/service-port-config
PUT /api/v1/service-port-config
{ "config": "[Cisco-IOS]\nconfigure terminal\n..." }Deze geldt voor alle servicepoorten en moet een [Cisco-IOS]-, [ArubaOS]- en [ArubaOS-CX]-sectie bevatten, elk op een eigen regel. Gebruik #interface# en #vlan-id# op de plek van de poortnaam en het gekozen VLAN. Een losse poort kan een eigen template krijgen:
PUT /api/v1/service-port/87
{ "config": "[Cisco-IOS]\n..." }Stuur { "config": null } om die poort weer op de algemene configuratie te zetten.
Status van meerdere apparaten tegelijk
GET /api/v1/devices/status?device_ids=12,13,14of, voor een hele apparaatgroep:
GET /api/v1/devices/status?device_group_id=3In tegenstelling tot de status-endpoint voor één apparaat hierboven, wordt dit gelezen uit een periodiek ververste cache (ongeveer elke 5 minuten) in plaats van per apparaat een live sessie te openen — hierdoor is het praktisch mogelijk om honderden apparaten in één verzoek te controleren. Het antwoord bevat een cached_as_of-tijdstempel zodat u weet hoe actueel de gegevens zijn.
Taken
Acties die niet direct klaar zijn (certificaat genereren/intrekken hierboven, een switch sync) geven een job_id terug. Gebruik deze om de voortgang te volgen:
GET /api/v1/jobs/{id}{
"success": true,
"data": {
"job_id": "b3f2c1a0-...",
"status": "succeeded",
"created_at": "2026-08-22T10:00:00Z",
"finished_at": "2026-08-22T10:00:04Z",
"result": { ... },
"error": null
}
}status is één van queued, running, succeeded, failed, cancelled.
POST /api/v1/jobs/{id}/cancelWerkt alleen zolang de taak nog queued is — een taak die al gestart is kan niet meer worden onderbroken (foutcode 4003, JOB_ALREADY_STARTED).
POST /api/v1/jobs/{id}/retryZet een nieuwe taak in de wachtrij die een afgeronde taak herhaalt — werkt alleen op een taak die succeeded, failed of cancelled is (anders foutcode 4004, JOB_NOT_FINISHED). Geeft een nieuwe job_id terug; de oorspronkelijke taak blijft ongewijzigd staan.
Systeemupdates
Controleer op en start PrivateLAN-systeemupdates zonder de webinterface te gebruiken — handig om een update automatisch te starten direct na een configuratiewijziging.
GET /api/v1/system-update{
"success": true,
"data": {
"current_version": "26.8.5",
"update_available": true,
"latest_available_version": "26.9.0",
"update_running": false,
"reboot_pending": false,
"firmware_update_pending": false,
"automatic_updates_enabled": true
}
}POST /api/v1/system-updateStart een update naar de laatst beschikbare versie en geeft direct 202 terug — dit wacht niet tot de update klaar is en er is geen taak om te volgen. De update draait op de achtergrond en duurt meestal enkele minuten; vraag GET /api/v1/system-update opnieuw op om te zien wanneer current_version/update_running aangeven dat het klaar is. Bent u al op de laatste versie, dan antwoordt dit met {"already_up_to_date": true} in plaats van iets te starten. Geeft foutcode 4007 (UPDATE_ALREADY_RUNNING) terug als er al een update loopt.
SBOM
Genereer en download de Software Bill of Materials (SBOM) van de appliance — de lijst van alle geïnstalleerde softwarecomponenten in CycloneDX JSON-formaat. Handig om een kwetsbaarhedenscanner te voeden of voor uw eigen CRA- of NIS2-documentatie, zonder in te loggen op de webinterface. De API-key heeft de rol system-sbom nodig ("Can view SBOM").
GET /api/v1/system-sbom{
"success": true,
"data": {
"generation_running": false,
"sbom": {
"bom_ref": "PrivateLAN 26.9.4",
"release": "26.9.4",
"operating_system": "Ubuntu 26.04",
"spec_version": "1.6",
"generated_at": "2026-09-14T10:12:31+02:00",
"component_count": 951,
"size_bytes": 528099,
"sha256": "8960b6c2def76f38e05a9f1a782c72ffe728c5576224420f303bac53d977b8be"
}
}
}sbom is null zolang er nog geen SBOM is gegenereerd. release is null als de appliance op het moment van genereren haar eigen versie niet kon bepalen.
POST /api/v1/system-sbomZet een nieuwe SBOM-generatie in de wachtrij en geeft direct 202 met een job_id terug. Het genereren duurt enkele minuten. Vraag GET /api/v1/system-sbom opnieuw op tot generation_running false is en generated_at later ligt dan uw verzoek — dat is het betrouwbare signaal dat het klaar is. Geeft foutcode 4012 (SBOM_GENERATION_RUNNING) terug als er al een generatie in de wachtrij staat of loopt.
GET /api/v1/system-sbom/downloadDownloadt de huidige SBOM als JSON-bestand. De responsheader X-Checksum-SHA256 bevat de SHA-256 van het bestand, dezelfde waarde als sbom.sha256 hierboven. Geeft 3013 (SBOM_NOT_FOUND) terug als er geen SBOM is en 4012 zolang een generatie nog loopt, zodat u nooit per ongeluk de vorige SBOM ontvangt.
curl -s -X POST -H "Authorization: Bearer $KEY" https://privatelan.example/api/v1/system-sbom
curl -s -H "Authorization: Bearer $KEY" https://privatelan.example/api/v1/system-sbom
curl -s -H "Authorization: Bearer $KEY" -o sbom.json https://privatelan.example/api/v1/system-sbom/downloadWebhooks
Waar de rest van deze API bestaat uit vragen die u aan PrivateLAN stelt, is een webhook PrivateLAN die u vertelt dat er iets gebeurd is — een switch die offline gaat, een apparaat dat niet door 802.1x komt, een servicepoort die geopend wordt. U registreert een URL, vinkt de gebeurtenissen aan waar u iets mee wilt, en PrivateLAN roept die URL aan zodra er een optreedt.
Een webhookdoel hoeft niet uw eigen server te zijn. De methode, de authenticatie en de body zijn allemaal instelbaar, zodat hetzelfde mechanisme rechtstreeks een relaismodule of een ander apparaat kan aanroepen — daarom kan bijvoorbeeld een deurrelais geschakeld worden door een mislukte authenticatie, zonder iets ertussen.
Webhooks beheert u onder Logging > Webhooks in de webinterface, of via onderstaande endpoints. Beide vereisen het recht "Can manage webhooks"; u ziet altijd alleen uw eigen webhooks, tenzij u beheerder bent.
GET /api/v1/webhook
POST /api/v1/webhook
GET /api/v1/webhook/{id}
PATCH /api/v1/webhook/{id}
DELETE /api/v1/webhook/{id}
GET /api/v1/webhook/{id}/deliveriesWebhooks opvragen, aanmaken, lezen, gedeeltelijk bijwerken en verwijderen, en het afleverlog van één webhook lezen. Bij het verwijderen van een webhook verdwijnen ook zijn voorwaarden en zijn afleverlog.
{
"url": "https://example.com/hooks/privatelan",
"events": ["switch.offline", "device.authentication.failed"],
"condition_logic": "AND",
"conditions": [
{ "field": "switch_hostname", "operator": "contains", "value": "core" }
]
}Bij het aanmaken van een webhook krijgt u eenmalig een ondertekeningsgeheim (whsec_…), alleen in het antwoord op het aanmaken. Het wordt nooit opnieuw getoond — bewaar het meteen.
Voorwaarden
Een webhook zonder voorwaarden ontvangt elke gebeurtenis waarop hij geabonneerd is. Voorwaarden beperken dat: elke voorwaarde noemt een veld uit de payload, een operator (eq, neq, contains, gt, lt, in) en een waarde, en condition_logic bepaalt of ze allemaal moeten kloppen (AND) of één ervan (OR).
Doordat veldnamen gedeeld worden tussen verwante gebeurtenissen — elke gebeurtenis over een switchpoort noemt die switch_hostname, beide authenticatiegebeurtenissen dragen dezelfde velden — dekt één voorwaarde meestal een hele groep gebeurtenissen in plaats van slechts één.
Gebeurtenissen
| Gebeurtenis | Treedt op wanneer |
|---|---|
device.created | Er een apparaat wordt toegevoegd |
device.updated | De instellingen van een apparaat wijzigen. Alleen een echte wijziging telt; een ongewijzigd formulier opnieuw opslaan doet niets |
device.deleted | Een apparaat wordt verwijderd |
device.authentication.succeeded | Een apparaat zich met succes op het netwerk authenticeert |
device.authentication.failed | Een authenticatiepoging wordt geweigerd |
device.online | Een apparaat weer antwoordt na onbereikbaar te zijn geweest |
device.offline | Een apparaat niet meer antwoordt |
device.ip_changed | Een apparaat dat zijn adres via DHCP krijgt, op een ander adres wordt aangetroffen |
device.ip_conflict | Een gevonden adres al bij een ander geregistreerd apparaat hoort. Het adres wordt gemeld, nooit overgenomen |
device.insecure_port_open | De SSL-controle op een apparaat een poort open vindt die dicht hoort te zijn (standaard poort 80) |
device.ssl_problem | De SSL-controle de beveiligde poort van een apparaat dicht vindt, zonder versleuteling, of met het verkeerde certificaat (standaard poort 443) |
device.ssl_recovered | Een apparaat met een probleem uit de SSL-controle er geen meer heeft |
switch.online | Een switch weer antwoordt na onbereikbaar te zijn geweest |
switch.offline | Een switch niet meer antwoordt |
service.port.opened | Een onderhoudssessie op een servicepoort wordt gestart |
service.port.closed | Een onderhoudssessie eindigt — handmatig, doordat de tijd verstrijkt, of doordat de poort niet langer als servicepoort is gemarkeerd |
inspection.unexpected_port_usage | Een verbonden poort waaraan geen apparaat is toegewezen |
inspection.unexpected_port_usage.resolved | Die poort verkeert niet langer in die toestand |
inspection.disconnected_port | Een als uplink, SFP of niet-apparaatpoort gemarkeerde poort is niet verbonden |
inspection.disconnected_port.resolved | Die poort verkeert niet langer in die toestand |
certificate.issued | Er een apparaatcertificaat is aangemaakt |
certificate.revoked | Een apparaatcertificaat is ingetrokken |
certificate.expiring | Een certificaat zijn vervaldatum nadert |
auditlog.critical | Er een kritieke regel in het auditlog wordt geschreven |
system.reboot_required | Het apparaat een herstart nodig heeft om updates af te ronden |
system.firmware_update_available | Er firmware-updates klaarstaan |
system.update_available | Er een nieuwe PrivateLAN-versie beschikbaar is |
system.reboot_required.resolved | De herstart heeft plaatsgevonden |
system.firmware_update_available.resolved | De firmware-updates zijn geïnstalleerd |
system.update_available.resolved | De nieuwe versie is geïnstalleerd |
honeypot.triggered | Een apparaat verbinding maakt met een lokpoort die het apparaat zelf niet gebruikt |
Een paar gebeurtenissen staan in de webinterface met de vermelding dat ze nog niet beschikbaar zijn; die kunt u via de API wel selecteren, maar ze leveren pas iets af in een latere release.
Hoe vaak een gebeurtenis optreedt
Gebeurtenissen die iets beschrijven wat een beheerder gedaan heeft — een apparaat toegevoegd, een onderhoudssessie gestart — treden één keer per handeling op. Gebeurtenissen die een toestand beschrijven treden op bij de verandering, niet doorlopend: een switch die al een week onbereikbaar is stuurt één switch.offline, niet één per controle, en stuurt switch.online zodra hij terug is.
De bereikbaarheid van apparaten volgt dezelfde regel als die van switches. Houd er daarbij rekening mee wat dat betekent voor apparatuur die niet altijd aan staat: een werkplek die 's avonds wordt uitgezet stuurt elke dag een offline in de avond en een online in de ochtend. Wilt u dat niet, filter dan op een veld uit de payload, of abonneer alleen de ontvanger die het wél moet horen.
Eén onbeantwoorde ping geldt niet als storing. Een switch of apparaat dat bereikbaar was, wordt een tweede keer gepingd voordat het als offline wordt gemeld. Eén verloren pakket levert dus geen offline op met vijf minuten later een online.
device.ip_conflict wordt per apparaat één keer verstuurd wanneer het conflict voor het eerst wordt gevonden, en niet opnieuw bij elke switch-poll zolang het duurt. Zodra het apparaat zonder conflict wordt gezien, wordt het vergeten; een conflict dat later terugkomt wordt dus opnieuw gemeld.
De twee inspectiegebeurtenissen beschrijven een bevinding, geen moment. Het apparaat controleert beide doorlopend en meldt een poort één keer wanneer die begint te voldoen en nog één keer wanneer dat niet meer zo is — de .resolved-helft. Een poort die nog niemand heeft opgelost meldt zichzelf dus niet telkens opnieuw, en elke melding die u ontvangt wordt uiteindelijk ook weer afgesloten. opened_at in het resolved-bericht geeft aan wanneer de bevinding voor het eerst optrad. Het gaat om dezelfde bevindingen die de pagina Inspection toont, en er geldt een maximum aan het aantal meldingen per controle, zodat één grote gebeurtenis — een switch die herstart, een uplink die uitvalt — wordt samengevat in plaats van poort voor poort verstuurd.
Bij authenticatie merkt u dat het meest. Een apparaat authenticeert zichzelf veel vaker opnieuw dan iemand daarover bericht wil krijgen, dus er wordt alleen iets verstuurd als het resultaat van een apparaat verandert — de eerste weigering na een reeks geslaagde pogingen, of de eerste geslaagde poging na een reeks weigeringen. Een apparaat dat blijft falen herhaalt de melding dus niet elke paar seconden, en daarbovenop geldt een minimale tussentijd per apparaat, zodat ook een apparaat dat heen en weer springt tussen beide uw ontvanger niet kan overspoelen.
certificate.expiring werkt in stappen: bij 30, 14, 7 en 1 dag resterend stuurt een certificaat telkens één bericht, nooit meer. Die stappen zijn instelbaar.
Pogingen die een switch zelf weigert zonder ze ooit aan PrivateLAN voor te leggen — een poort die om een andere reden dicht staat, een losgetrokken kabel — zijn geen authenticatiegebeurtenissen en leveren hier niets op.
honeypot.triggered wordt beperkt per bronadres en poort: herhaalde pogingen vanaf hetzelfde apparaat binnen een kort tijdvenster leveren één melding op, niet één per poging.
De drie gebeurtenissen van de SSL-controle komen uit de controle die het apparaat elke vijf minuten uitvoert (Inspection > SSL) en beschrijven ook een bevinding. device.insecure_port_open en device.ssl_problem worden één keer per poort verstuurd wanneer die een probleem wordt, en pas opnieuw wanneer het een ander probleem wordt — bijvoorbeeld van een verlopen certificaat naar een certificaat voor een andere naam. device.ssl_recovered wordt één keer per apparaat verstuurd zodra het geen problemen meer heeft. De payload noemt het apparaat, de port, de status, een lijst korte problems-codes en hetzelfde message dat de pagina Inspection toont; bij device.ssl_problem ook de TLS-versie en het certificaat dat het apparaat aanbood. Een gedempt apparaat verstuurt geen van deze gebeurtenissen, en de eerste controle nadat de functie is ingeschakeld legt alleen vast wat ze aantreft, zodat bestaande problemen wel op de pagina staan maar niet als een golf meldingen binnenkomen.
Voor de inspectiegebeurtenissen en de gebeurtenissen van de SSL-controle is de optie Inspection in uw licentie nodig.
Payloads en aflevering
Standaard is de body JSON:
{
"event": "service.port.closed",
"timestamp": 1756900000,
"data": {
"interface_id": 412,
"interface_name": "GigabitEthernet1/0/24",
"switch_id": 7,
"switch_hostname": "sw-core-01",
"switch_group": "Head office",
"vlan_id": 30,
"expires_at": "2026-09-03 18:00:00",
"reason": "expired",
"occurred_at": "2026-09-03T14:02:11+02:00"
}
}Elke aanroep bevat een X-PrivateLAN-Signature-header, een HMAC-SHA256 over de body en het tijdstempel, plus het X-PrivateLAN-Timestamp waarmee die berekend is. Controleer die voordat u iets met een aflevering doet. U kunt de body ook volledig vervangen door uw eigen sjabloon als de ontvanger een specifiek formaat verwacht.
Payloads bevatten nooit inloggegevens. Het authenticatiewachtwoord van een apparaat, switchwachtwoorden, private sleutels van certificaten en het wachtwoord dat bij een geweigerde inlogpoging wordt vastgelegd blijven er bewust uit — device.updated noemt om dezelfde reden wel welke velden gewijzigd zijn, maar niet hun waarden. Het afleverlog bewaart elke payload gedurende de ingestelde bewaartermijn, en iedereen die webhooks mag beheren kan dat log lezen.
Een mislukte aflevering wordt met oplopende tussenpozen tot acht keer opnieuw geprobeerd; daarna wordt hij als onbestelbaar gemarkeerd en krijgt de webhook de status "falend". Antwoord snel met 2xx en doe het echte werk daarna: een ontvanger die traag antwoordt geldt als mislukking. Door die herhalingen moet een ontvanger ertegen kunnen dat dezelfde gebeurtenis twee keer binnenkomt.
Afleverlog
GET /api/v1/webhook/{id}/deliveries{
"success": true,
"data": [
{
"id": 918,
"event": "device.authentication.failed",
"attempt": 1,
"status": "delivered",
"last_http_status": 200,
"last_error": null,
"next_retry_at": null,
"created_at": "2026-09-03 14:02:12"
}
]
}status is pending, delivered, failed (wacht op een nieuwe poging) of dead_letter (geen pogingen meer over). Regels verdwijnen zodra ze de ingestelde bewaartermijn passeren.
Validatiefouten
Een 422-antwoord met foutcode 2000 bevat een fields-object dat elk ongeldig veld koppelt aan een leesbare reden:
{
"success": false,
"error": {
"code": 2000,
"slug": "VALIDATION_ERROR",
"message": "One or more fields failed validation.",
"fields": {
"device_hostname": "Hostname: This hostname already exists.",
"device_ip": "IP: This IP is not part of the correct subnet."
}
}
}Een apparaat verwijderen
Het verwijderen van een vergrendeld apparaat geeft foutcode 4000 (DEVICE_LOCKED) terug. Ontgrendel het eerst vanaf de pagina Apparaatbeheer.
Vergrendelde apparaten
Een apparaat kan vanaf de pagina Apparaatbeheer worden vergrendeld om het te bevriezen. Zolang het vergrendeld is, weigert de API elk verzoek dat het apparaat of zijn poorten zou wijzigen met foutcode 4000 (DEVICE_LOCKED) en HTTP-status 409:
| Verzoek | Geweigerd bij vergrendeling |
|---|---|
PUT / PATCH /api/v1/device/{id} | Ja |
DELETE /api/v1/device/{id} | Ja |
POST /api/v1/device-interface en DELETE /api/v1/device-interface | Ja |
POST /api/v1/device-certificate (uitgeven en intrekken) | Ja |
POST /api/v1/device/{id}/actions/{restart-interface,enable-interface,disable-interface,reauthenticate} | Ja |
POST /api/v1/device/{id}/actions/{ping,check-authentication} | Nee — alleen lezen |
GET-verzoeken | Nee — alleen lezen |
Een vergrendeld apparaat uitlezen, evenals de status en de authenticatiestatus ervan, blijft gewoon werken, zodat het nog steeds gediagnosticeerd kan worden. Ontgrendel het vanaf de pagina Apparaatbeheer om wijzigingen te kunnen doorvoeren.
Er zijn drie soorten vergrendeling. Ze verschillen alleen in wie de vergrendeling weer mag opheffen — de API weigert voor alle drie dezelfde verzoeken:
| Vergrendeling | Op te heffen door |
|---|---|
| Basic lock | Elke gebruiker die kan inloggen |
| Admin lock | Administrators en het PrivateLAN Support Team |
| Support lock | Uitsluitend het PrivateLAN Support Team |
Een support lock is bedoeld voor een apparaat waar PrivateLAN-support aan werkt; een beheerder van uw eigen installatie kan die niet opheffen. U krijgt alleen de soorten aangeboden die u zelf ook weer ongedaan kunt maken.