Athena — europeLogin/api.md

API Reference — Europe Login

Base URL: http://localhost:8091 (local) / https://api.europe-login.glorylabs.nl (prod — legacy domain; 2026-05-19 decision is to migrate europeLogin under mahmoudholding. GHCR migration PR in flight: #76. Final product domain still to be chosen.)

Interactive docs: GET /swagger-ui.html

All error responses follow RFC 7807 shape:

{ "status": 400, "message": "...", "timestamp": "...", "details": null }

Authentication

POST /api/auth/login

Authenticate a company representative.

Request

{
  "kvkNumber": "12345678",
  "email": "bestuurder@company.nl",
  "password": "Secr3t!",
  "requiredAssuranceLevel": "BASIS"
}

Response 200

{
  "accessToken": "<JWT>",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "sessionToken": "<UUID>",
  "kvkNumber": "12345678",
  "companyName": "Acme BV",
  "assuranceLevel": "BASIS",
  "representativeEmail": "bestuurder@company.nl",
  "representativeName": "Jan de Vries",
  "representativeRole": "BESTUURDER"
}

Errors

  • 400 — invalid KvK format
  • 401 — wrong credentials
  • 404 — KvK not registered

POST /api/auth/register

Register a company with its first BESTUURDER representative.

Request

{
  "kvkNumber": "12345678",
  "companyName": "Acme BV",
  "legalForm": "BV",
  "registeredAddress": "Hoofdstraat 1, Amsterdam",
  "representativeFirstName": "Jan",
  "representativeLastNamePrefix": "de",
  "representativeLastName": "Vries",
  "representativeEmail": "jan@acme.nl",
  "representativePhone": "0612345678",
  "password": "Secr3t!"
}

Response 201 — empty body


POST /api/auth/logout

Revoke the current session. Public endpoint (no JWT required).

Headers

X-Session-Token: <UUID from login>

Response 204 — empty body


Companies

GET /api/companies/{kvkNumber}

Get company info. Requires JWT.

Response 200

{
  "kvkNumber": "12345678",
  "companyName": "Acme BV",
  "assuranceLevel": "BASIS",
  "active": true,
  "kvkVerified": true,
  "createdAt": "2024-01-01T10:00:00Z"
}

GET /api/companies/validate-kvk/{kvkNumber}

Validate a KvK number format and check KvK registry. Public endpoint.

Response 200

{ "kvkNumber": "12345678", "valid": true }

Onboarding

All /api/onboarding/** endpoints are public. The sessionId acts as a bearer secret.

POST /api/onboarding

Initiate onboarding session.

Request

{ "kvkNumber": "87654321" }

Response 201

{
  "sessionId": "<UUID>",
  "kvkNumber": "87654321",
  "companyName": "New Company BV",
  "currentStep": "BANK_CONNECT",
  "status": "KVK_VERIFIED"
}

Errors

  • 400 — invalid KvK format, company already registered, or active session in progress

GET /api/onboarding/{sessionId}

Get session state (for polling).

Response 200OnboardingSessionDto with all session fields


POST /api/onboarding/{sessionId}/psd2/initiate

Start PSD2 bank authentication.

Request

{
  "institutionId": "ING_INGBNL2A",
  "redirectUri": "http://localhost:4301/onboarding/psd2-callback"
}

Response 200

{
  "redirectUrl": "https://bankaccountdata.gocardless.com/...",
  "requisitionId": "<UUID>"
}

POST /api/onboarding/{sessionId}/psd2/complete

Complete PSD2 after bank redirect.

Request

{ "ref": "<ref from bank callback>" }

Response 200 — updated OnboardingSessionDto


POST /api/onboarding/{sessionId}/representative

Add representative identity (BSN is encrypted before storage).

Request

{
  "firstName": "Jan",
  "lastNamePrefix": "de",
  "lastName": "Vries",
  "email": "jan@company.nl",
  "phone": "0612345678",
  "bsn": "123456782",
  "role": "BESTUURDER"
}

Response 200 — updated OnboardingSessionDto


POST /api/onboarding/{sessionId}/complete

Finalise onboarding — creates Company + AuthorizedRepresentative records.

Request

{ "password": "Secr3t!" }

Response 200 — final OnboardingSessionDto with status: "COMPLETED"


GET /api/onboarding/institutions?country=NL

List available banks for PSD2 (cached 1 hour).

Response 200

[
  { "id": "ING_INGBNL2A", "name": "ING", "bic": "INGBNL2A", "logoUrl": "..." },
  ...
]

Audit Trail

All audit endpoints require JWT + BESTUURDER role.

GET /api/audit/company/{kvkNumber}

Get paginated audit trail for a company.

Query params: page (default 0), size (default 50, max 200)

Response 200

{
  "content": [
    {
      "id": "...",
      "eventType": "LOGIN_SUCCESS",
      "actorEmail": "jan@company.nl",
      "actorKvkNumber": "12345678",
      "actorRole": "BESTUURDER",
      "result": "SUCCESS",
      "assuranceLevelUsed": "BASIS",
      "timestamp": "2024-01-01T10:00:00Z"
    }
  ],
  "totalElements": 42,
  "totalPages": 1
}

GET /api/audit/verify

Verify hash chain integrity.

Response 200

{
  "intact": true,
  "eventsChecked": 142,
  "brokenAtId": null
}

Errors

| HTTP | When | |------|------| | 400 | Validation failure, bad KvK format, duplicate company, onboarding flow error | | 401 | Missing or invalid JWT, wrong credentials | | 403 | Authenticated but insufficient role (AccessDeniedException) | | 404 | Company not found | | 409 | Duplicate company registration | | 500 | Unhandled server error | | 502 | GoCardless/PSD2 connectivity error |

Reacties

Nog geen reacties