API-documentatie
De OrangeHub dealer-API levert per dealer een actuele, verrijkte catalogus van Orange Office producten — met dealer-specifieke nettoprijzen.
- Base URL
- https://orangehub.cyboxlabs.nl/api/v1
- Auth
- Bearer token
- Format
- JSON
Authenticatie
Elke request vereist een persoonlijke Sanctum-toegangstoken in de
Authorization-header.
Tokens worden door een OrangeHub-beheerder aangemaakt in het admin-panel onder de dealer
(API-tokens → Genereer token). De plain-text token wordt eenmalig getoond; bij verlies moet er een nieuw token worden gegenereerd.
GET https://orangehub.cyboxlabs.nl/api/v1/products HTTP/1.1
Authorization: Bearer <plain-text-token>
Accept: application/json
| Foutsituatie | Status | Body |
|---|---|---|
| Geen of foutief token | 401 | {"message":"Unauthenticated."} |
| Ingetrokken token | 401 | {"message":"Unauthenticated."} |
| Dealer gedeactiveerd | 401 | {"message":"Dealer is not active."} |
/products
Gepagineerde lijst van actieve producten — inclusief verrijking, afbeeldingen, documenten en dealer-specifieke nettoprijs.
Parameters
| Naam | Type | Default | Toelichting |
|---|---|---|---|
| product_group_id | int | — | Filter op productgroep (lokaal id). |
| per_page | int | 50 | Tussen 1 en 200. |
| page | int | 1 | Standaard Laravel-paginering. |
cURL
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://orangehub.cyboxlabs.nl/api/v1/products?per_page=10"
Voorbeeldrespons
{
"data": [
{
"external_id": "DVD",
"sku": "DVD",
"name": "Kabel doorvoerdop boormaat Ø 60mm",
"kind": "product",
"description": "<p>...</p>",
"manufacturer": "Orange Office",
"currency": "EUR",
"parent_sku": null,
"prices": { "base": 19.0, "override": null, "net": 16.15 },
"dimensions": { "length_mm": 72, "width_mm": 72, "height_mm": 19 },
"weight_grams": 50,
"enriched_content": "<p>...</p>",
"product_group": {
"external_id": "OO-cat-1318",
"name": "Losse componenten",
"parent_id": 1
},
"images": [
{
"url": "https://.../storage/products/12/images/DVD-1.jpg",
"alt_text": null,
"sort_order": 0,
"is_primary": true
}
],
"documents": [
{
"url": "https://.../storage/products/12/documents/handleiding.pdf",
"label": "Handleiding",
"original_filename": "handleiding.pdf",
"sort_order": 0
}
],
"custom_fields": {
"eu_energy_label": { "value": "A++", "label": "EU Energielabel", "type": "text", "unit": null },
"power_draw": { "value": 1500, "label": "Vermogen", "type": "integer", "unit": "W" }
}
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "per_page": 50, "total": 30, "last_page": 1 }
}
/products/{sku}
Eén product opvragen via zijn SKU. Identieke shape als één element uit /products, maar dan onder data.
Parameters
| Naam | Type | Default | Toelichting |
|---|---|---|---|
| sku | string | — | SKU van het product (mag forward slashes bevatten). |
cURL
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://orangehub.cyboxlabs.nl/api/v1/products/DVD"
Voorbeeldrespons
{
"data": {
"external_id": "DVD",
"sku": "DVD",
"name": "Kabel doorvoerdop boormaat Ø 60mm",
"prices": { "base": 19.0, "override": null, "net": 16.15 },
"...": "..."
}
}
Foutresponses
| Foutsituatie | Status | Body |
|---|---|---|
| SKU onbekend | 404 | {"message":"Product not found."} |
| SKU bestaat, maar product staat niet op Actief in dealer-API | 404 | {"message":"Product is not available in the dealer-API."} |
/product-groups
De volledige productgroep-boom — alleen root-groepen op het hoogste niveau, met children recursief.
cURL
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://orangehub.cyboxlabs.nl/api/v1/product-groups"
Voorbeeldrespons
{
"data": [
{
"external_id": "OO-cat-25",
"name": "Werkplekken",
"parent_id": null,
"children": [
{
"external_id": "OO-cat-1318",
"name": "Losse componenten",
"parent_id": 7,
"children": []
}
]
}
]
}
/series
Verkoopseries (configureerbare samenstellingen) zichtbaar voor deze dealer, met optie-assen en actieve waarden. Zonder curatieregels ziet de dealer alle actieve series.
cURL
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://orangehub.cyboxlabs.nl/api/v1/series"
Voorbeeldrespons
{
"data": [
{
"id": 1,
"code": "XF3",
"name": "XF3",
"product_type": "Enkel bureau",
"sku_strategy": "generated",
"commercial_text": null,
"options": [
{
"name": "Afmeting",
"kind": "configuration",
"sku_position": 1,
"values": [ { "label": "160x80", "code": "160080" } ]
},
{
"name": "Bladkleur",
"kind": "configuration",
"sku_position": 4,
"values": [ { "label": "Halifax", "code": "HF" } ]
}
]
}
]
}
/series/{id}/variants
Verkoopbare varianten van een serie (niet gearchiveerd, stuklijst volledig opgelost) met SKU volgens de pCon-grammatica en dealer-nettoprijs.
Parameters
| Naam | Type | Default | Toelichting |
|---|---|---|---|
| per_page | int | 100 | Tussen 1 en 500. |
| page | int | 1 | Standaard Laravel-paginering. |
cURL
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://orangehub.cyboxlabs.nl/api/v1/series/1/variants?per_page=10"
Voorbeeldrespons
{
"data": [
{
"sku": "XF3160080P2ZHF",
"base_code": "XF3160080P2",
"status": "draft",
"configuration": {
"Afmeting": { "label": "160x80", "code": "160080" },
"Display": { "label": "XPREM-2", "code": "P2" },
"Framekleur": { "label": "Zwart", "code": "Z" },
"Bladkleur": { "label": "Halifax", "code": "HF" }
},
"prices": { "base": 500.0, "net": 450.0 }
}
],
"links": { "...": "..." },
"meta": { "...": "..." }
}
Foutresponses
| Foutsituatie | Status | Body |
|---|---|---|
| Serie onbekend of niet zichtbaar voor deze dealer | 404 | {"message":"Series not found."} |
Pricing
Elk product bevat een
prices-object
met de basis-, override- en dealer-specifieke nettoprijs.
| Sleutel | Bron |
|---|---|
| base | base_price uit de feed. |
| override | price_override als een beheerder die handmatig heeft gezet, anders null. |
| net | Effectieve prijs (override of base) minus de dealer-korting die voor het product van toepassing is (productgroep-regel als die bestaat, anders de dealer-brede basis-korting). |
effective = override ?? base
discount = product_group_rule ?? dealer.base_discount_percentage
net = round(effective * (1 - discount / 100), 2)
De toegepaste korting wordt in deze volgorde bepaald: bestaat er voor de productgroep van het product een
DealerDiscount-regel,
dan wint die — ook als hij lager is dan de basis-korting. Anders gebruikt de API de
base_discount_percentage van de dealer (default
0).
Inactieve producten
(is_active = false)
verschijnen nooit in de API-uitvoer.
Custom fields
Naast de vaste velden kan een beheerder per product ad-hoc extra eigenschappen vastleggen. Die komen terug onder
custom_fields
als een object met dynamische sleutels — de sleutels verschillen per product, dus programmeer er defensief op.
Als een product geen extra velden heeft is het object leeg ({}).
| Sleutel per veld | Toelichting |
|---|---|
| value | De typed waarde — een string, integer, decimaal, boolean of null. |
| label | Mens-leesbare naam van het veld, door de beheerder ingegeven. |
| type | Eén van text, long_text, integer, decimal, boolean, select. |
| unit | Optionele eenheid/suffix (bv. "kg", "kWh"), of null. |
De volgorde van keys in custom_fields
reflecteert de volgorde die in het admin-panel is bepaald.