Skip to Content
APIAPI integratie

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
ParameterVerplichtBeschrijving
client_idJaClient ID van je OAuth-app (UUID).
redirect_uriJaMoet exact overeenkomen met een geregistreerde redirect URI.
response_typeJaAltijd code.
code_challengeJaBase64url-gecodeerde SHA-256 hash van je code_verifier.
code_challenge_methodJaAltijd S256.
scopeJaSpatiegescheiden lijst met gevraagde scopes.
stateAanbevolenWillekeurige 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_authorizations aangemaakt dat de app koppelt aan de gekozen organisatie.
  • Wordt de gebruiker teruggestuurd naar redirect_uri met ?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_id en client_secret naar het token endpoint.
  • Routix valideert het geheim door SHA-256 hashes te vergelijken.
  • Er wordt een JWT opgebouwd met organization_id, allowed_scopes en allowed_branch_ids van 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

AspectAuthorization Code + PKCEClient credentials
GebruikersinteractieJa, consent screenNee
Token endpoint/auth/v1/oauth/token/functions/v1/oauth-token
OrganisatiebindingGekozen door gebruiker bij consentUit app-registratie
Refresh tokensJa, roterendNee, vraag een nieuwe token aan
Use caseGebruikersgerichte apps, marketplaceBackend sync, BI, automation

Security best practices

PraktijkWaarom
Gebruik altijd PKCE met S256Verplicht voor Authorization Code flow. Plain challenges worden niet ondersteund.
Bewaar secrets veiligDe client secret wordt maar een keer getoond. Gebruik een secrets manager en zet hem nooit in source code.
Valideer de state parameterBeschermt tegen CSRF tijdens de redirect flow.
Vraag minimale scopes aanVraag alleen de rechten die je applicatie echt nodig heeft.
Roteer secrets regelmatigBeperk risico door secrets periodiek te vervangen.
Handel token expiry goed afTokens verlopen na 1 uur. Refresh of vraag een nieuwe token aan.
Zet secrets nooit in frontendcodeClient credentials mag alleen vanaf een backendserver worden gebruikt.

Architectuur

Het integratiesysteem bestaat uit drie lagen:

LaagBeschrijving
OAuth serverAuthenticeert externe apps en geeft JWT-tokens uit met organisatie-, scope- en branch-claims.
API proxyVersiebeheerend REST endpoint dat tokens valideert, scopes afdwingt, branches oplost en gefilterde data retourneert.
App managementDashboard 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 fields

Belangrijke concepten

Scopes

Elke API-actie wordt beschermd door een scope met dit patroon:

routix:<resource>:<action>
ScopeBeschrijving
routix:accounts:readLees klanten, leveranciers en vervoerders.
routix:accounts:writeMaak accounts aan en werk ze bij.
routix:orders:readLees orders.
routix:orders:writeMaak orders aan en werk ze bij.
routix:vehicles:readLees voertuigen.
routix:vehicles:writeMaak voertuigen aan en werk ze bij.
routix:staff:readLees medewerkers.
routix:equipment:readLees equipment.
routix:planning:readLees planning- en routedata.
routix:invoices:readLees facturen.
routix:invoices:writeMaak 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

VersieGedrag
v1Stabiele, onveranderlijke veldset die veilig is voor productie-integraties.
v2Uitbreiding 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
Last updated on