API integratie
Routix biedt een versiebeheerde REST API waarmee externe applicaties, zoals ERP-systemen, WMS-platformen, BI-tools en AI-agents, veilig toegang krijgen tot je transportmanagementdata.
De API is gebouwd op OAuth 2.1 en gebruikt een proxylayer voor stabiliteit, versiebeheer en fijnmazige toegangscontrole.
Gebruikersniveau: Gevorderd
OAuth flow
Routix gebruikt OAuth 2.1 om externe applicaties te authenticeren. Afhankelijk van het type integratie zijn er twee flows beschikbaar.
Flow 1: Authorization Code + PKCE
Gebruik deze flow wanneer je applicatie namens een Routix-gebruiker moet handelen. De gebruiker geeft expliciet toestemming en kiest de organisatie waarvoor toegang wordt verleend.
Sequence
Externe app Routix Auth Gebruiker
| | |
|-- redirect naar /authorize-> | |
| (client_id, scope, | |
| code_challenge, state) | |
| |-- consent screen -----> |
| | (app naam, scopes, |
| | org selector) |
| | <-- approve + org ----- |
| <-- redirect met ?code= ---- | |
| | |
|-- POST /oauth/token -------> | |
| (code, code_verifier) | |
| <-- { access_token } ------- | |
| | |
|-- GET /api/v1/{branch}/...-> | (API Proxy) |
| <-- { data: [...] } -------- | |Stap 1: Genereer de PKCE challenge
Genereer voor de start van de flow een PKCE code verifier en challenge:
// Generate code_verifier (43-128 characters)
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const codeVerifier = btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
// Generate code_challenge (SHA-256, base64url)
const digest = await crypto.subtle.digest(
'SHA-256',
new TextEncoder().encode(codeVerifier)
);
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');Stap 2: Redirect naar authorize
Redirect de browser van de gebruiker naar:
https://api.routix.com/auth/v1/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&response_type=code
&code_challenge=BASE64URL_SHA256_HASH
&code_challenge_method=S256
&scope=routix:accounts:read routix:orders:read
&state=RANDOM_STATE_VALUE| Parameter | Verplicht | Beschrijving |
|---|---|---|
| client_id | Ja | Client ID van je OAuth-app (UUID). |
| redirect_uri | Ja | Moet exact overeenkomen met een geregistreerde redirect URI. |
| response_type | Ja | Altijd code. |
| code_challenge | Ja | Base64url-gecodeerde SHA-256 hash van je code_verifier. |
| code_challenge_method | Ja | Altijd S256. |
| scope | Ja | Spatiegescheiden lijst met gevraagde scopes. |
| state | Aanbevolen | Willekeurige string ter bescherming tegen CSRF. |
Stap 3: Toestemming van de gebruiker
Routix toont een consent screen waarop de gebruiker:
- De applicatienaam en gevraagde scopes ziet.
- Kiest voor welke organisatie toegang wordt verleend.
- De aanvraag goed- of afkeurt.
Na goedkeuring:
- Wordt een record in
oauth_client_authorizationsaangemaakt dat de app koppelt aan de gekozen organisatie. - Wordt de gebruiker teruggestuurd naar
redirect_urimet?code=xxx&state=xxx.
Stap 4: Wissel de code om voor tokens
curl -X POST https://api.routix.com/auth/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTHORIZATION_CODE",
"redirect_uri": "https://yourapp.com/callback",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "routix_a1b2c3d4...",
"code_verifier": "YOUR_ORIGINAL_CODE_VERIFIER"
}'Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "v1.MjQ0ZWY5..."
}Stap 5: Refresh tokens
Access tokens verlopen na 1 uur. Gebruik de refresh token om een nieuwe op te vragen:
curl -X POST https://api.routix.com/auth/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "v1.MjQ0ZWY5..."
}'Refresh tokens zijn single-use en roteren bij iedere refresh.
Token claims: Authorization Code
De JWT wordt verrijkt via een custom access token hook met:
{
"sub": "user-uuid",
"aud": "authenticated",
"role": "authenticated",
"organization_id": "org-uuid",
"oauth_client_id": "client-uuid",
"oauth_scopes": ["routix:accounts:read", "routix:orders:read"]
}Deze claims worden afgedwongen via Row Level Security (RLS) in de database.
Flow 2: Client credentials
Gebruik deze flow voor server-to-servercommunicatie. Er is geen gebruikersinteractie nodig.
Sequence
Jouw server Routix
| |
|-- POST /oauth-token -------> |
| (client_id, client_secret) |
| <-- { access_token } ------- |
| |
|-- GET /api/v1/{branch}/...-> |
| <-- { data: [...] } -------- |Vraag een token aan
curl -X POST https://api.routix.com/functions/v1/oauth-token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "routix_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
}'Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "routix:accounts:read routix:orders:read",
"organization_id": "org-uuid",
"branch_ids": ["branch-uuid-1", "branch-uuid-2"]
}Hoe dit werkt
- Je server stuurt
client_idenclient_secretnaar het token endpoint. - Routix valideert het geheim door SHA-256 hashes te vergelijken.
- Er wordt een JWT opgebouwd met
organization_id,allowed_scopesenallowed_branch_idsvan de app. - De JWT wordt gesigneerd met HS256 en teruggegeven.
- Daarna gebruik je de token voor de API proxy.
Token claims: Client credentials
{
"iss": "supabase",
"aud": "authenticated",
"role": "authenticated",
"sub": "app-uuid",
"organization_id": "org-uuid",
"oauth_client_id": "client-uuid",
"oauth_scopes": ["routix:accounts:read"],
"oauth_branch_ids": ["branch-uuid-1"],
"oauth_app_name": "My ERP Sync"
}Vergelijking
| Aspect | Authorization Code + PKCE | Client credentials |
|---|---|---|
| Gebruikersinteractie | Ja, consent screen | Nee |
| Token endpoint | /auth/v1/oauth/token | /functions/v1/oauth-token |
| Organisatiebinding | Gekozen door gebruiker bij consent | Uit app-registratie |
| Refresh tokens | Ja, roterend | Nee, vraag een nieuwe token aan |
| Use case | Gebruikersgerichte apps, marketplace | Backend sync, BI, automation |
Security best practices
| Praktijk | Waarom |
|---|---|
| Gebruik altijd PKCE met S256 | Verplicht voor Authorization Code flow. Plain challenges worden niet ondersteund. |
| Bewaar secrets veilig | De client secret wordt maar een keer getoond. Gebruik een secrets manager en zet hem nooit in source code. |
Valideer de state parameter | Beschermt tegen CSRF tijdens de redirect flow. |
| Vraag minimale scopes aan | Vraag alleen de rechten die je applicatie echt nodig heeft. |
| Roteer secrets regelmatig | Beperk risico door secrets periodiek te vervangen. |
| Handel token expiry goed af | Tokens verlopen na 1 uur. Refresh of vraag een nieuwe token aan. |
| Zet secrets nooit in frontendcode | Client credentials mag alleen vanaf een backendserver worden gebruikt. |
Architectuur
Het integratiesysteem bestaat uit drie lagen:
| Laag | Beschrijving |
|---|---|
| OAuth server | Authenticeert externe apps en geeft JWT-tokens uit met organisatie-, scope- en branch-claims. |
| API proxy | Versiebeheerend REST endpoint dat tokens valideert, scopes afdwingt, branches oplost en gefilterde data retourneert. |
| App management | Dashboard binnen Routix om OAuth-apps te registreren, configureren en beheren. |
Hoe het samenwerkt
Externe app
|
|-> POST /functions/v1/oauth-token
| -> JWT met org_id, scopes, branches
|
'--> GET /functions/v1/api/v1/{branch}/accounts
-> Verify JWT -> Check scope -> Resolve branch -> Query DB -> Return filtered fieldsBelangrijke concepten
Scopes
Elke API-actie wordt beschermd door een scope met dit patroon:
routix:<resource>:<action>| Scope | Beschrijving |
|---|---|
| routix:accounts:read | Lees klanten, leveranciers en vervoerders. |
| routix:accounts:write | Maak accounts aan en werk ze bij. |
| routix:orders:read | Lees orders. |
| routix:orders:write | Maak orders aan en werk ze bij. |
| routix:vehicles:read | Lees voertuigen. |
| routix:vehicles:write | Maak voertuigen aan en werk ze bij. |
| routix:staff:read | Lees medewerkers. |
| routix:equipment:read | Lees equipment. |
| routix:planning:read | Lees planning- en routedata. |
| routix:invoices:read | Lees facturen. |
| routix:invoices:write | Maak facturen aan en werk ze bij. |
Branch scoping
De API is per branch afgebakend via een korte publieke ID van 8 tekens, bijvoorbeeld RS2RDH3B. Dat betekent:
- Elke API-call richt zich op exact een branch.
- Apps kunnen bij registratie worden beperkt tot specifieke branches.
- Branch-data blijft volledig gescheiden.
API versioning
| Versie | Gedrag |
|---|---|
| v1 | Stabiele, onveranderlijke veldset die veilig is voor productie-integraties. |
| v2 | Uitbreiding van v1 met extra velden die in de tijd kunnen groeien. |
Beide versies draaien naast elkaar. Gebruik v1 voor stabiele contracten en v2 als je extra data nodig hebt.
Gerelateerde pagina’s
- API calls en voorbeelden
- Setup guide

