Authenticatie

Alle API requests (behalve /login) vereisen een site header plus één van deze twee vormen van authenticatie:

MethodeHeaderBedoeld voorGeldigheid
JWT tokenAuthorization: Bearer <token>Gebruikers en de frontend (inloggen met e-mail en wachtwoord)1 uur
API keyX-API-Key: <key>Systeemkoppelingen (webshop, ERP, scripts)Tot de key wordt uitgeschakeld of verwijderd

Voor koppelingen met andere systemen is een API key de aanbevolen keuze: er hoeft niet elk uur opnieuw ingelogd te worden, er is geen MFA-stap, en de rechten zijn per key te beperken.

Als beide headers worden meegestuurd, wordt alleen de Authorization header gebruikt.

Login

Verkrijg een JWT token door in te loggen met e-mail en wachtwoord.

POST /login

Request

{
  "email": "user@example.com",
  "password": "your-password"
}

Response 200 OK

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "userId": "1",
  "expiresIn": 3600,
  "admin": false,
  "site": "SITE01",
  "name": "Jan Janssen",
  "email": "user@example.com",
  "client": null,
  "fulfillment": false
}
VeldTypeBeschrijving
tokenstringJWT token, geldig voor 1 uur
userIdstringGebruikers-ID
expiresInnumberGeldigheid in seconden (3600 = 1 uur)
adminbooleanOf de gebruiker een admin is
sitestringSite ID
namestringVolledige naam van de gebruiker
emailstringE-mailadres
clientstring|nullClient ID (alleen bij fulfillment)
fulfillmentbooleanOf de site een fulfillment site is

Response 401 Unauthorized

{
  "message": "User/password not correct"
}

MFA

Als MFA voor de site aan staat (setting mfa_mode: optional of required), geeft POST /login nog geen token maar een tijdelijk mfaToken (5 minuten geldig):

{
  "mfaRequired": true,
  "mfaToken": "eyJhbGciOiJIUzI1NiIs..."
}

Wissel dat in voor een JWT token met de code uit de authenticator-app:

POST /login/verify-mfa
{
  "mfaToken": "eyJhbGciOiJIUzI1NiIs...",
  "code": "123456"
}

De response is dan gelijk aan die van een gewone login. Krijg je mfaSetupRequired: true terug, dan moet de gebruiker MFA eerst instellen via de frontend.

In de authenticator-app staat het account als NextWMS met het e-mailadres van de gebruiker. Op de testomgeving heet het NextWMS dev, zodat een account op beide omgevingen niet als twee gelijke regels in de app staat. Dat geldt voor MFA die vanaf 15 oktober 2026 is ingesteld; een eerder ingestelde koppeling houdt de oude naam tot MFA opnieuw wordt ingesteld.

MFA opnieuw instellen

Een gebruiker met MFA kan het zelf opnieuw instellen in het profiel, bijvoorbeeld voor een nieuwe telefoon. Dat gaat in twee stappen, met een volledige login (Authorization: Bearer <token>):

POST /mfa/renew
{ "code": "123456" }

code is de huidige code uit de authenticator-app, of een backupcode. De response bevat een nieuwe QR-code (qrCode), het geheim om handmatig in te voeren (secret) en een renewToken, tien minuten geldig. De huidige koppeling blijft werken tot stap 2.

POST /mfa/renew/confirm
{ "renewToken": "eyJhbGciOiJIUzI1NiIs...", "code": "654321" }

code komt uit de nieuwe koppeling. Daarna werkt alleen de nieuwe koppeling, en de response bevat acht nieuwe backupcodes (backupCodes); de oude vervallen.

Een foute code of een verlopen renewToken geeft 400, niet 401: de gebruiker blijft ingelogd en kan het opnieuw proberen.

  • Telefoon kwijt, wel backupcodes: log in met een backupcode in plaats van de code uit de app, en stel MFA daarna opnieuw in met een volgende backupcode. Elke backupcode werkt één keer.
  • Telefoon kwijt en geen backupcodes: een beheerder met het recht op gebruikers zet MFA terug in het gebruikersscherm; bij de volgende login stelt de gebruiker MFA opnieuw in.

Token verificatie

Controleer of een bestaand token nog geldig is.

GET /verifytoken

Headers

Authorization: Bearer <token>

Response 200 OK

{
  "message": "Token is valid"
}

Response 401 Unauthorized

{
  "message": "Authorization token not valid"
}

Gebruik van het token

Voeg bij elke API request de volgende headers toe:

Authorization: Bearer <token>
site: <site-id>

Let op

Het token verloopt na 1 uur. Na verlopen moet opnieuw ingelogd worden via POST /login.

API keys

Een API key is een vaste sleutel voor één site, met per onderdeel ingestelde rechten. Hij verloopt niet.

Key aanmaken

API keys worden beheerd door een ingelogde gebruiker (JWT), via het API keys-scherm in de frontend of via de API. Een API key kan zelf geen keys aanmaken, wijzigen of opvragen.

POST /api-keys
Authorization: Bearer <token>
site: <site-id>
{
  "name": "Webshop koppeling",
  "permissions": [
    { "resource": "orders", "method": "GET" },
    { "resource": "orders", "method": "POST" },
    { "resource": "skus", "method": "GET" }
  ]
}

Optioneel: client_id (om de key aan een fulfillment-client te koppelen) en enabled (standaard true).

Een key met client_id werkt namens die opdrachtgever: een order via POST /orders en een preadvies via POST /preadvices krijgen altijd die opdrachtgever, GET /inventory/available toont alleen diens artikelen, en de endpoints onder /orders en /preadvices tonen en wijzigen alleen diens orders en preadviezen (een order of preadvies van een andere opdrachtgever geeft 404). Wie met zo'n key een andere opdrachtgever meestuurt, krijgt 403. Andere endpoints filteren nog niet op de opdrachtgever.

Response 201 Created

{
  "id": 7,
  "api_key": "nk_live_3f9a1c2b...",
  "key_prefix": "nk_live_3f9a1c2b",
  "name": "Webshop koppeling",
  "message": "Bewaar deze API key veilig. Na het sluiten van dit scherm is de key niet meer op te vragen."
}

Let op

De volledige key (api_key) wordt alleen in deze response getoond. Er wordt alleen een hash opgeslagen; kwijt is kwijt, maak dan een nieuwe key aan.

Key gebruiken

X-API-Key: nk_live_3f9a1c2b...
site: <site-id>
curl https://api.nextwms.net/orders \
  -H "X-API-Key: nk_live_3f9a1c2b..." \
  -H "site: SITE01"

Een API key is geen gebruiker. Wat via een key wordt aangemaakt of geboekt, heeft daarom geen gebruiker: created_by bij orders en preadviezen en user_name bij voorraadmutaties zijn leeg.

Rechten

Elke request wordt gecontroleerd op onderdeel + HTTP-methode. Zonder bijbehorend recht volgt 403. De beschikbare onderdelen en methodes staan in GET /api-keys/resources:

Onderdeel (resource)EndpointsMethodes
skus/skus, /skugroups, /sync/productsGET, PUT, POST, DELETE
locations/locations, /putaway-algorithms, /allocation-algorithms, /pickmethodsGET, POST, PUT, DELETE
preadvices/preadvicesGET, POST, PUT, DELETE
orders/ordersGET, POST, PUT, DELETE
inventory/inventoryGET, POST
receipt/receiptPOST
waves/waves, /wave-definitionsGET, POST, DELETE
tasks/tasks, /shipdockGET, POST
customers/customers, /clientsGET, POST, PUT, DELETE
carriers/carriersGET, POST, PUT, DELETE
suppliers/suppliersGET, POST, PUT, DELETE
shipping/shippingGET, POST
webhooks/webhooksGET, POST, PUT, DELETE
labels/labelsGET, POST, PUT, DELETE
dashboard/dashboard, /settings, /logsGET

Endpoints die niet in deze tabel staan (zoals /api-keys zelf) zijn niet bereikbaar met een API key.

Rechten van een bestaande key wijzigen: PUT /api-keys/:id/permissions met { "permissions": [...] } (vervangt de volledige lijst). Een key uitschakelen: PUT /api-keys/:id met "enabled": false. Verwijderen: DELETE /api-keys/:id.

Foutmeldingen

StatusMessageOorzaak
401Invalid API keyKey onbekend voor deze site, of uitgeschakeld
401No Authorization token or API keyGeen Authorization en geen X-API-Key header
403API key does not have POST permission on 'orders'Recht ontbreekt voor dit onderdeel/deze methode
403API key access is not available for this endpointEndpoint is niet beschikbaar voor API keys
403API keys cannot manage API keysKey probeert /api-keys te gebruiken

Rechten van gebruikers

Een ingelogde gebruiker (JWT) heeft de menurechten van zijn gebruikersgroep. De frontend toont daarmee alleen de schermen waar de gebruiker bij mag; de API controleert dezelfde rechten per endpoint. API keys vallen hier buiten: die hebben hun eigen rechten, zie hierboven.

Instelling rights_enforcement

De controle staat per site aan of uit, met een rij in settings:

WaardeGedrag
offGeen controle. Dit geldt ook als de instelling ontbreekt.
logNiets wordt geweigerd. Wat geweigerd zou zijn, komt in het log (GET /logs) als regel die begint met Rechten:.
enforceEen request zonder het juiste recht krijgt 403. De weigering komt ook in het log.
INSERT INTO settings (site_id, setting, value) VALUES ('<site-id>', 'rights_enforcement', 'log');

Een onbekende waarde werkt als off en geeft een waarschuwing in de serverlog. Een wijziging van de instelling of van iemands rechten werkt binnen 30 seconden door.

Aanzetten bij een bestaande site: begin met log, laat de gebruikers een aantal dagen normaal werken en bekijk de regels Rechten: in het log. Elke regel is een actie die bij enforce geweigerd wordt: de gebruiker mist een recht, of de regel voor die route klopt niet. Zet de instelling pas op enforce als er geen onverwachte regels meer bijkomen.

Wat wordt gecontroleerd

  • Alle schrijvende endpoints (POST, PUT, DELETE) vragen het recht van het scherm waar de actie bij hoort. Wordt een endpoint door meerdere schermen gebruikt, dan volstaat één van die rechten.
  • Gevoelige leesendpoints: gebruikers (/mfa/users), gebruikersgroepen en rechten (/user-groups), API keys, webhooks en logs.
  • Overige leesendpoints staan open voor elke ingelogde gebruiker. Stamgegevens zoals SKU's en locaties worden door vrijwel elk scherm gelezen.
  • Eigen account: wachtwoord wijzigen, MFA instellen en labels afdrukken mag elke ingelogde gebruiker.
  • POST /wrapper: alleen de acties task/picktask, task/shipClaimset en wave/reset, elk met het recht van het bijbehorende scherm. Elke andere actie wordt geweigerd.

Response 403 Forbidden

{
  "message": "Onvoldoende rechten voor deze actie"
}

De site header is verplicht bij elke request. Dit identificeert de warehouse site waarvoor de data wordt opgevraagd. De waarde kan een site_id of een client_id zijn.

Als de site header ontbreekt of ongeldig is, wordt een 403-fout geretourneerd:

{
  "message": "Missing header site"
}
{
  "message": "Invalid site"
}