REST API v1
Integreer het Korporaal Media Platform in uw eigen applicatie. Toegang tot tickets, bestellingen, hosting, domeinen en meer.
Base URL: https://korporaal.media/api/v1
Aan de slag
Token aanvragen
Login via /auth/token (wachtwoord) of /auth/sso-token (Authentik SSO).
Token meesturen
Voeg het token toe als Authorization: Bearer <token> header bij elke request.
API aanroepen
Alle responses zijn in JSON. Prijzen zijn altijd in centen (integers).
curl -X POST https://korporaal.media/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"email": "uw@email.nl",
"password": "uw_wachtwoord",
"device_name": "Mijn App"
}'
{
"token": "1|abc123def456...",
"user": {
"id": 1,
"name": "Jan Jansen",
"email": "jan@bedrijf.nl",
"role": "customer",
"customer_id": 5
}
}
Endpoints
Alle endpoints starten met /api/v1. Endpoints met een slotje vereisen authenticatie.
Authenticatie
POST
/auth/login
Inloggen (e-mail + wachtwoord)
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| string | verplicht | E-mailadres | |
| password | string | verplicht | Wachtwoord |
| device_name | string | verplicht | Naam van het apparaat (bijv. "iPhone", "Mijn App") |
Response
{ "token": "1|abc...", "user": { "id", "name", "email", "role", "customer_id" } }
POST
/auth/token
Token aanmaken (alias voor /auth/login)
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| string | verplicht | E-mailadres | |
| password | string | verplicht | Wachtwoord |
| device_name | string | verplicht | Naam van het apparaat |
Response
{ "token": "1|abc...", "user": { "id", "name", "email", "role", "customer_id" } }
POST
/auth/sso-token
Token aanmaken via Authentik SSO (OIDC code exchange)
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| code | string | verplicht | OIDC authorization code van Authentik |
| redirect_uri | string | verplicht | Redirect URI die bij de authorization request is gebruikt |
| device_name | string | verplicht | Naam van het apparaat (bijv. "iPhone 15") |
| code_verifier | string | optioneel | PKCE code verifier (aanbevolen voor mobiele apps) |
Response
{ "token": "1|abc...", "user": { "id", "name", "email", "role", "customer_id" }, "is_new_user": false, "needs_customer_profile": false }
GET
/auth/sso-config
OIDC configuratie ophalen voor SSO login flow
Response
{ "authorization_endpoint", "token_endpoint", "userinfo_endpoint", "client_id", "scopes" }
GET
/auth/user
Huidige gebruiker ophalen
Response
{ "id", "name", "email", "role", "customer_id", "customer": { "id", "name" } }
POST
/auth/logout
Token verwijderen (uitloggen)
Response
{ "message": "Token verwijderd." }
Profiel & klantgegevens
GET
/profile
Profiel met klantgegevens ophalen
Response
{ "data": { "id", "name", "email", "role", "customer": { "id", "name", "email", "phone", "address", "kvk_number", "vat_number" } } }
GET
/profile/hosting-packages
Hosting pakketten van de klant
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| per_page | integer | optioneel | Resultaten per pagina (standaard 15) |
Response
{ "data": [{ "id", "domain", "status", "product", "amount", "next_due_date", "auto_renew" }] }
GET
/profile/domains
Domeinen van de klant
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| per_page | integer | optioneel | Resultaten per pagina (standaard 15) |
Response
{ "data": [{ "id", "domain", "tld", "status", "expires_at", "days_until_expiry", "auto_renew" }] }
GET
/profile/orders
Bestellingen van de klant
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| per_page | integer | optioneel | Resultaten per pagina (standaard 15) |
Response
{ "data": [{ "id", "order_number", "status", "total", "items", "paid_at" }] }
GET
/profile/invoices
Facturen ophalen via Moneybird
Response
{ "data": [{ "id", "invoice_number", "date", "total", "status", "pdf_url" }] }
Integraties & service tokens
Wat is een service token?
Een service token is een Sanctum personal access token dat hoort bij een applicatie (geen mens). Externe systemen zoals KM Desk gebruiken zo'n token om, namens bekende eindgebruikers, tickets aan te maken in het Korporaal Media platform, zonder dat die eindgebruikers handmatig hoeven in te loggen.
Tokens hebben abilities (scopes). Een KM Desk token heeft bijvoorbeeld
tickets:create-on-behalf
, daarmee mag het ticket-endpoint aangeroepen worden, maar bijvoorbeeld geen orders
aanmaken of klanten verwijderen.
Tokens worden via een artisan command op de server aangemaakt en moeten direct na aanmaak bewaard worden, ze zijn daarna niet meer op te vragen. Wel kunnen ze worden ingetrokken.
KM Desk integratie, stap voor stap
-
Token aanvragen. Vraag de beheerder om een token via:
Bewaar de output (formaatphp artisan api:issue-token --name="KM Desk"1|abc...) alsKM_PLATFORM_TOKENin de KM Desk config. -
Ticket aanmaken namens een gebruiker. Roep
POST /api/v1/tickets/on-behalfaan met het emailadres van de KM Desk gebruiker. Het platform zoekt die op in zijn eigen userlijst (matching op email). -
Foutafhandeling. Krijgt KM Desk een
404 user_not_found? Dan bestaat de gebruiker niet in het portaal (of heeft hij geen email). Toon dan in KM Desk de melding: "Vraag de hoofdgebruiker van uw organisatie om dit ticket aan te maken." Eindgebruikers zonder email kunnen geen tickets aanmaken, die loopt via hun primaire contactpersoon. -
Status terug naar KM Desk. Registreer een webhook (via
POST /api/v1/webhooks) voor de eventsticket.replied,ticket.status_changed,ticket.resolvedenticket.closed. KM Desk kan dan in real-time tonen wat de status van het ticket is.
Voorbeeld request
curl -X POST https://korporaal.media/api/v1/tickets/on-behalf \
-H "Authorization: Bearer $KM_PLATFORM_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"subject": "Printer doet het niet",
"description": "De HP LaserJet op de eerste verdieping start niet meer op.",
"priority": "high",
"user_email": "jan@bedrijf.nl",
"user_name": "Jan Jansen",
"external_reference": "kmdesk-ticket-4821"
}'
Voorbeeld response (201)
{
"data": {
"id": 1234,
"subject": "Printer doet het niet",
"status": "open",
"status_label": "Open",
"priority": "high",
"priority_label": "Hoog",
"source": "kmdesk",
"customer": { "id": 17, "name": "Bedrijf B.V." },
"assignee": { "id": 1, "name": "Sanne Jansen" },
"created_at": "2026-04-08T14:23:11+02:00"
}
}
Foutscenario: gebruiker onbekend
HTTP/1.1 404 Not Found
{
"message": "Gebruiker niet bekend in het Korporaal Media portaal. Vraag de hoofdgebruiker van uw organisatie om dit ticket aan te maken.",
"code": "user_not_found"
}
POST
/tickets/on-behalf
Ticket aanmaken namens een KM Platform gebruiker (service token vereist)
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| subject | string | verplicht | Onderwerp (max 255 tekens) |
| description | string | verplicht | Beschrijving (max 10.000 tekens) |
| user_email | string | verplicht | Email van de eindgebruiker, moet bestaan in KM Platform |
| user_name | string | optioneel | Weergavenaam (voor audit/notifications) |
| priority | string | optioneel | low, normal (standaard), high of urgent |
| category_id | integer | optioneel | Ticket categorie ID |
| source | string | optioneel | Bron tag (standaard: kmdesk) |
| external_reference | string | optioneel | Eigen referentie van het externe systeem (audit only) |
Response
{ "data": { "id", "subject", "status", "priority", "source", "customer", "assignee", "created_at" } }
Tickets
GET
/tickets
Tickets ophalen
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| status | string | optioneel | Filter op status (open, pending, closed, etc.) |
| open | boolean | optioneel | Alleen openstaande tickets tonen |
| per_page | integer | optioneel | Resultaten per pagina (standaard 15) |
Response
{ "data": [{ "id", "subject", "status", "priority", "category", "replies_count", "created_at" }] }
GET
/tickets/{id}
Ticket details met reacties
Response
{ "id", "subject", "description", "status", "priority", "replies": [{ "id", "message", "is_from_customer", "sender_name", "attachments" }] }
POST
/tickets
Nieuw ticket aanmaken
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| subject | string | verplicht | Onderwerp (max 255 tekens) |
| description | string | verplicht | Beschrijving (max 10.000 tekens) |
| priority | string | optioneel | low, normal (standaard), high of urgent |
| category_id | integer | optioneel | Categorie ID |
Response
Ticket object (zie GET /tickets/{id})
POST
/tickets/{id}/replies
Reactie op ticket plaatsen
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| message | string | verplicht | Bericht (max 10.000 tekens) |
Response
{ "id", "message", "is_from_customer", "sender_name", "attachments", "created_at" }
Notificaties
GET
/notifications
Alle notificaties (gepagineerd)
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| per_page | integer | optioneel | Resultaten per pagina (standaard 20) |
Response
{ "data": [{ "id", "type", "title", "body", "read_at", "created_at" }], "meta": { "unread_count" } }
GET
/notifications/unread
Alleen ongelezen notificaties
Response
Zelfde als GET /notifications
POST
/notifications/{id}/read
Notificatie als gelezen markeren
Response
{ "message": "Gelezen." }
POST
/notifications/read-all
Alle notificaties als gelezen markeren
Response
{ "message": "Alle notificaties gelezen." }
Winkelwagen
GET
/cart
Winkelwagen ophalen
Response
{ "data": { "items": [{ "id", "type", "name", "price", "quantity", "total" }], "subtotal", "tax", "total", "item_count" } }
POST
/cart/items
Item toevoegen
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| type | string | verplicht | hosting, domain, product of print |
| product_id | integer | verplicht | Product ID |
| name | string | verplicht | Productnaam |
| price | integer | verplicht | Prijs in centen |
| quantity | integer | optioneel | Aantal (standaard 1, max 100) |
| options | object | optioneel | Extra opties (bijv. billing cycle, domein) |
Response
{ "message": "Item toegevoegd.", "cart_item_id": "...", "cart": { ... } }
PUT
/cart/items/{id}
Aantal wijzigen
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| quantity | integer | verplicht | Nieuw aantal (0 = verwijderen, max 100) |
Response
{ "message": "Winkelwagen bijgewerkt.", "cart": { ... } }
DELETE
/cart/items/{id}
Item verwijderen
Response
{ "message": "Item verwijderd.", "cart": { ... } }
DELETE
/cart
Winkelwagen legen
Response
{ "message": "Winkelwagen geleegd.", "cart": { ... } }
Bestellingen
GET
/orders
Bestellingen ophalen
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| per_page | integer | optioneel | Resultaten per pagina (standaard 15) |
Response
{ "data": [{ "id", "order_number", "status", "total", "items", "paid_at", "created_at" }] }
GET
/orders/{id}
Bestelling details
Response
{ "data": { "id", "order_number", "status", "payment_status", "subtotal", "tax_amount", "total", "items": [{ "name", "type", "quantity", "price", "total" }] } }
Producten
Deze endpoints zijn openbaar en vereisen geen authenticatie.
GET
/hosting-products
Hosting pakketten catalogus
Response
{ "data": [{ "id", "name", "slug", "price_monthly", "price_yearly", "disk_space_gb", "features", "is_featured" }] }
GET
/hosting-products/{id}
Hosting pakket details
Response
{ "data": { "id", "name", "slug", "description", "price_monthly", "price_yearly", "disk_space_gb", "bandwidth_gb", "max_domains", "features" } }
Domeinen
Dit endpoint is openbaar en vereist geen authenticatie.
POST
/domains/check
Domein beschikbaarheid controleren
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| domain | string | verplicht | Domeinnaam zonder extensie (2-63 tekens) |
| tlds | array | optioneel | Extensies om te controleren (standaard: nl, com, eu, be, de, net) |
Response
{ "data": [{ "domain": "voorbeeld.nl", "tld": "nl", "available": true, "price": 995 }] }
Push notificaties (apparaten)
POST
/devices
Apparaat registreren voor push notificaties
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| player_id | string | verplicht | OneSignal player/subscription ID |
| platform | string | verplicht | ios, android of web |
| device_model | string | optioneel | Apparaat model (bijv. "iPhone 15") |
Response
{ "message": "Apparaat geregistreerd.", "user_id": 1, "external_id": "1" }
Webhooks
Beschikbare events
order.created Bestelling aangemaaktorder.paid Bestelling betaaldorder.completed Bestelling afgerondorder.cancelled Bestelling geannuleerdhosting.provisioned Hosting actiefhosting.suspended Hosting opgeschortdomain.registered Domein geregistreerdticket.created Ticket aangemaaktticket.replied Reactie op ticketticket.status_changed Status gewijzigdticket.resolved Ticket opgelostticket.closed Ticket geslotenPayload-formaat
Elke webhook is een POST naar de geregistreerde URL met JSON body en de headers
X-Webhook-Event en
X-Webhook-Signature
(HMAC-SHA256 van de body met het webhook-secret).
{
"event": "ticket.replied",
"timestamp": "2026-04-08T14:23:11+02:00",
"data": {
"ticket": {
"id": 1234,
"subject": "Printer doet het niet",
"status": "in_progress",
"priority": "high",
"source": "kmdesk",
"requester_email": "jan@bedrijf.nl",
"requester_name": "Jan Jansen",
"customer_id": 17,
"customer_name": "Bedrijf B.V.",
"assignee_name": "Sanne Jansen",
"url": "https://korporaal.media/admin/tickets/1234"
},
"reply": {
"id": 9876,
"message": "Ik heb het ticket opgepakt en ga ermee aan de slag.",
"is_from_customer": false,
"is_internal": false,
"sender_name": "Sanne Jansen",
"created_at": "2026-04-08T14:23:11+02:00"
}
}
}
Signature verifiëren
Bereken aan de ontvangerskant hash_hmac('sha256', $rawBody, $webhookSecret)
en vergelijk met de header X-Webhook-Signature. Verwerp het verzoek bij
mismatch. Failed deliveries worden tot 10 keer geprobeerd, daarna wordt de webhook
automatisch gedeactiveerd.
GET
/webhooks
Webhooks ophalen
Response
{ "data": [{ "id", "url", "events", "is_active", "last_triggered_at", "failure_count" }], "available_events": [...] }
POST
/webhooks
Webhook aanmaken
Parameters
| Naam | Type | Vereist | Beschrijving |
|---|---|---|---|
| url | string | verplicht | URL om events naartoe te sturen (HTTPS aanbevolen) |
| events | array | verplicht | Lijst van events (zie hierboven) |
Response
{ "message": "Webhook aangemaakt.", "data": { "id", "url", "events", "secret" } }
DELETE
/webhooks/{id}
Webhook verwijderen
Response
{ "message": "Webhook verwijderd." }
HTTP statuscodes
Belangrijke informatie
Prijzen in centen
Alle bedragen worden geretourneerd als integers in centen. Deel door 100 voor euros. Voorbeeld: 1995 = €19,95.
Paginering
Gepagineerde responses bevatten meta en links objecten met paginatie-informatie.
Multi-tenancy
Klanten zien alleen hun eigen data. Tickets, bestellingen, domeinen en hosting worden automatisch gefilterd op basis van uw account.
Admin endpoints
Endpoints onder /admin vereisen een account met role: admin. Niet-admins ontvangen een 403.
Machine-leesbare docs
Een automatisch gegenereerd overzicht van alle endpoints is beschikbaar op GET /api.
Rate limiting
De API is gelimiteerd tot 60 requests per minuut per token. Bij overschrijding ontvangt u een 429 status.
Hulp nodig bij de integratie?
Neem contact op voor ondersteuning bij het koppelen van uw applicatie aan onze API.