Curbo API
Koppel je eigen systemen aan Curbo: haal medewerkers, roosters, uren en verlof op voor je loonpakket, kassa of Power BI, en laat je eigen systemen diensten en medewerkers bijwerken. Eén REST-API met JSON, een sleutel per systeem en webhooks voor wat er verandert.
In Curbo: Beheer → API → Nieuwe sleutel. Kies alleen de rechten die je nodig hebt.
Stuur de sleutel mee als Authorization: Bearer. Basisadres: https://curbo.nl/api/v1
Met Curbo Koppel meldt een webhook het meteen als er iets verandert.
curl https://curbo.nl/api/v1/organisatie \
-H "Authorization: Bearer curbo_live_..."Sleutels en rechten
Een sleutel hoort bij één organisatie en ziet alleen haar gegevens. Je ziet hem één keer bij het aanmaken; Curbo bewaart alleen een hash. Trek een sleutel die uitlekt meteen in. Lezen is gratis; schrijven hoort bij de add-on Curbo Koppel. BSN, IBAN, salaris en gezondheidsgegevens gaan nooit via de API.
| Recht | Wat | Pakket |
|---|---|---|
| organisatie:lezen | Naam, teams en vestigingen. | Gratis |
| medewerkers:lezen | Naam, e-mail, functie, team en vestiging. Nooit BSN, IBAN of salaris. | Gratis |
| rooster:lezen | Diensten met tijden, functie en wie hem draait. | Gratis |
| uren:lezen | Gewerkte uren (ingediend en geaccordeerd). | Gratis |
| verlof:lezen | Goedgekeurd verlof. Ziekte en de reden van afwezigheid niet. | Gratis |
| medewerkers:schrijven | Medewerkers aanmaken en hun basisgegevens wijzigen. | Curbo Koppel |
| rooster:schrijven | Diensten aanmaken, wijzigen en schrappen. | Curbo Koppel |
Fouten en limieten
Hooguit 120 verzoeken per minuut per sleutel; daarboven krijg je 429 met een Retry-After-kop. Een fout heeft altijd dezelfde vorm:
{
"fout": {
"code": "geen_recht",
"bericht": "Deze sleutel mist het recht rooster:schrijven."
}
}| 400 | Het verzoek klopt niet (een parameter ontbreekt of is ongeldig). |
| 401 | Geen of een ongeldige, ingetrokken of verlopen sleutel. |
| 402 | Hoort bij Curbo Koppel, of de organisatie staat op pauze. |
| 403 | De sleutel mist het recht voor dit endpoint. |
| 404 | Bestaat niet (of niet in jullie organisatie). |
| 409 | Bestaat al (bijvoorbeeld een medewerker met dit e-mailadres). |
| 422 | Een veld is ongeldig; het bericht zegt welk. |
| 429 | Te veel verzoeken; wacht een minuut. |
Pagina's
Lijsten geven { data, volgende } terug. Is volgende niet null, vraag dan de volgende pagina op met ?na=die waarde. Met limiet kies je 1 tot 200 per pagina.
Probeer het
Een echt verzoek met je eigen sleutel. Let op: schrijven wijzigt echte gegevens.
Organisatie
GET/api/v1/organisatie
De organisatie van deze sleutel, met teams en vestigingen.
Recht: organisatie:lezen · gratis
curl -X GET "https://curbo.nl/api/v1/organisatie" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"id": "0d9c8b7a-0000-4000-8000-000000000000",
"naam": "Bakkerij De Vier Seizoenen",
"teams": [
{
"id": "a1b2c3d4-0000-4000-8000-000000000001",
"naam": "Bakkerij"
}
],
"vestigingen": [
{
"id": "a1b2c3d4-0000-4000-8000-000000000002",
"naam": "Centrum"
}
]
}Medewerkers
GET/api/v1/medewerkers
Alle medewerkers, op achternaam. Zonder BSN, IBAN, salaris of gezondheidsgegevens.
Recht: medewerkers:lezen · gratis
| Veld | Type | Uitleg |
|---|---|---|
| actief | boolean | Alleen in dienst (true) of ook uit dienst (false). Standaard true. |
| limiet | integer | Aantal per pagina, 1 tot 200 (standaard 100). |
| na | string | De waarde van `volgende` uit het vorige antwoord, voor de volgende pagina. |
curl -X GET "https://curbo.nl/api/v1/medewerkers" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"data": [
{
"id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"voornaam": "Sanne",
"achternaam": "de Boer",
"email": "[email protected]",
"functie": "Bakker",
"team": {
"id": "a1b2c3d4-0000-4000-8000-000000000001",
"naam": "Bakkerij"
},
"vestiging": {
"id": "a1b2c3d4-0000-4000-8000-000000000002",
"naam": "Centrum"
},
"in_dienst_sinds": "2024-03-01",
"actief": true
}
],
"volgende": null
}Eén medewerker
GET/api/v1/medewerkers/{id}
Een medewerker op id.
Recht: medewerkers:lezen · gratis
curl -X GET "https://curbo.nl/api/v1/medewerkers/7c0f6d3e-1b2a-4c5d-9e8f-001122334455" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"voornaam": "Sanne",
"achternaam": "de Boer",
"email": "[email protected]",
"functie": "Bakker",
"team": {
"id": "a1b2c3d4-0000-4000-8000-000000000001",
"naam": "Bakkerij"
},
"vestiging": {
"id": "a1b2c3d4-0000-4000-8000-000000000002",
"naam": "Centrum"
},
"in_dienst_sinds": "2024-03-01",
"actief": true
}Medewerker aanmaken
POST/api/v1/medewerkers
Maakt een medewerker aan zonder inlogaccount. Uitnodigen doe je in het portaal. Curbo Koppel.
Recht: medewerkers:schrijven · Curbo Koppel
| Veld | Type | Uitleg |
|---|---|---|
| voornaam * | string | Voornaam. |
| achternaam * | string | Achternaam. |
| email * | string | Werkmail; uniek binnen de organisatie. |
| functie | string | Functie. |
| team_id | uuid | Team. |
| vestiging_id | uuid | Vestiging. |
| in_dienst_sinds | date | Datum in dienst. |
curl -X POST "https://curbo.nl/api/v1/medewerkers" \
-H "Authorization: Bearer $CURBO_SLEUTEL" \
-H "Content-Type: application/json" \
-d '{"voornaam":"Sanne","achternaam":"de Boer","email":"[email protected]"}'Antwoord
{
"id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"voornaam": "Sanne",
"achternaam": "de Boer",
"email": "[email protected]",
"functie": "Bakker",
"team": {
"id": "a1b2c3d4-0000-4000-8000-000000000001",
"naam": "Bakkerij"
},
"vestiging": {
"id": "a1b2c3d4-0000-4000-8000-000000000002",
"naam": "Centrum"
},
"in_dienst_sinds": "2024-03-01",
"actief": true
}Medewerker wijzigen
PATCH/api/v1/medewerkers/{id}
Wijzigt alleen de velden die je meestuurt. Curbo Koppel.
Recht: medewerkers:schrijven · Curbo Koppel
| Veld | Type | Uitleg |
|---|---|---|
| voornaam | string | Voornaam. |
| achternaam | string | Achternaam. |
| functie | string | Functie. |
| team_id | uuid | Team (leeg = geen team). |
| vestiging_id | uuid | Vestiging (leeg = geen vestiging). |
curl -X PATCH "https://curbo.nl/api/v1/medewerkers/7c0f6d3e-1b2a-4c5d-9e8f-001122334455" \
-H "Authorization: Bearer $CURBO_SLEUTEL" \
-H "Content-Type: application/json" \
-d '{"voornaam":"Sanne","achternaam":"de Boer","functie":"Bakker","team_id":"7c0f6d3e-1b2a-4c5d-9e8f-001122334455"}'Antwoord
{
"id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"voornaam": "Sanne",
"achternaam": "de Boer",
"email": "[email protected]",
"functie": "Bakker",
"team": {
"id": "a1b2c3d4-0000-4000-8000-000000000001",
"naam": "Bakkerij"
},
"vestiging": {
"id": "a1b2c3d4-0000-4000-8000-000000000002",
"naam": "Centrum"
},
"in_dienst_sinds": "2024-03-01",
"actief": true
}Diensten
GET/api/v1/diensten
Diensten in een periode, ook open diensten (medewerker_id is dan null). Geschrapte diensten niet.
Recht: rooster:lezen · gratis
| Veld | Type | Uitleg |
|---|---|---|
| van * | date | Eerste dag (JJJJ-MM-DD). |
| tot * | date | Laatste dag; hooguit 93 dagen na van. |
| medewerker_id | uuid | Alleen van deze medewerker. |
| limiet | integer | Aantal per pagina, 1 tot 200 (standaard 100). |
| na | string | De waarde van `volgende` uit het vorige antwoord, voor de volgende pagina. |
curl -X GET "https://curbo.nl/api/v1/diensten?van=2026-11-16&tot=2026-11-22" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"data": [
{
"id": "5e6f7a8b-0000-4000-8000-000000000003",
"datum": "2026-11-16",
"begin": "06:00",
"einde": "14:00",
"pauze_minuten": 30,
"functie": "Bakker",
"medewerker_id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"team_id": "a1b2c3d4-0000-4000-8000-000000000001",
"vestiging_id": "a1b2c3d4-0000-4000-8000-000000000002",
"gepubliceerd": true
}
],
"volgende": null
}Dienst aanmaken
POST/api/v1/diensten
Plant een dienst. Zonder medewerker_id wordt het een open dienst. Curbo Koppel.
Recht: rooster:schrijven · Curbo Koppel
| Veld | Type | Uitleg |
|---|---|---|
| datum * | date | Datum. |
| begin * | time | Begintijd (UU:MM). |
| einde * | time | Eindtijd (UU:MM). |
| pauze_minuten | integer | Pauze in minuten (standaard 0). |
| functie | string | Functie op de dienst. |
| medewerker_id | uuid | Wie hem draait. |
| team_id | uuid | Team. |
| vestiging_id | uuid | Vestiging. |
| publiceren | boolean | Meteen zichtbaar voor de medewerker (standaard false). |
curl -X POST "https://curbo.nl/api/v1/diensten" \
-H "Authorization: Bearer $CURBO_SLEUTEL" \
-H "Content-Type: application/json" \
-d '{"datum":"2026-11-16","begin":"06:00","einde":"14:00"}'Antwoord
{
"id": "5e6f7a8b-0000-4000-8000-000000000003",
"datum": "2026-11-16",
"begin": "06:00",
"einde": "14:00",
"pauze_minuten": 30,
"functie": "Bakker",
"medewerker_id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"team_id": "a1b2c3d4-0000-4000-8000-000000000001",
"vestiging_id": "a1b2c3d4-0000-4000-8000-000000000002",
"gepubliceerd": true
}Dienst wijzigen
PATCH/api/v1/diensten/{id}
Wijzigt alleen de velden die je meestuurt. Curbo Koppel.
Recht: rooster:schrijven · Curbo Koppel
| Veld | Type | Uitleg |
|---|---|---|
| datum | date | Datum. |
| begin | time | Begintijd. |
| einde | time | Eindtijd. |
| pauze_minuten | integer | Pauze. |
| functie | string | Functie. |
| medewerker_id | uuid | Wie hem draait (null = open dienst). |
| publiceren | boolean | Zichtbaar maken. |
curl -X PATCH "https://curbo.nl/api/v1/diensten/7c0f6d3e-1b2a-4c5d-9e8f-001122334455" \
-H "Authorization: Bearer $CURBO_SLEUTEL" \
-H "Content-Type: application/json" \
-d '{"datum":"2026-11-16","begin":"06:00","einde":"14:00","pauze_minuten":30}'Antwoord
{
"id": "5e6f7a8b-0000-4000-8000-000000000003",
"datum": "2026-11-16",
"begin": "06:00",
"einde": "14:00",
"pauze_minuten": 30,
"functie": "Bakker",
"medewerker_id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"team_id": "a1b2c3d4-0000-4000-8000-000000000001",
"vestiging_id": "a1b2c3d4-0000-4000-8000-000000000002",
"gepubliceerd": true
}Dienst schrappen
DELETE/api/v1/diensten/{id}
Schrapt de dienst; de medewerker ziet hem niet meer. Curbo Koppel.
Recht: rooster:schrijven · Curbo Koppel
curl -X DELETE "https://curbo.nl/api/v1/diensten/7c0f6d3e-1b2a-4c5d-9e8f-001122334455" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"id": "5e6f7a8b-0000-4000-8000-000000000003",
"geschrapt": true
}Uren
GET/api/v1/uren
Gewerkte uren in een periode, met status ingediend of akkoord.
Recht: uren:lezen · gratis
| Veld | Type | Uitleg |
|---|---|---|
| van * | date | Eerste dag (JJJJ-MM-DD). |
| tot * | date | Laatste dag; hooguit 93 dagen na van. |
| medewerker_id | uuid | Alleen van deze medewerker. |
| limiet | integer | Aantal per pagina, 1 tot 200 (standaard 100). |
| na | string | De waarde van `volgende` uit het vorige antwoord, voor de volgende pagina. |
curl -X GET "https://curbo.nl/api/v1/uren?van=2026-11-16&tot=2026-11-22" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"data": [
{
"id": "9a8b7c6d-0000-4000-8000-000000000004",
"medewerker_id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"datum": "2026-11-16",
"begin": "06:02",
"einde": "14:05",
"pauze_minuten": 30,
"status": "akkoord",
"dienst_id": "5e6f7a8b-0000-4000-8000-000000000003"
}
],
"volgende": null
}Verlof
GET/api/v1/verlof
Goedgekeurd verlof dat in de periode valt. Ziekte en de reden van afwezigheid gaan niet via de API.
Recht: verlof:lezen · gratis
| Veld | Type | Uitleg |
|---|---|---|
| van * | date | Eerste dag (JJJJ-MM-DD). |
| tot * | date | Laatste dag; hooguit 93 dagen na van. |
| limiet | integer | Aantal per pagina, 1 tot 200 (standaard 100). |
| na | string | De waarde van `volgende` uit het vorige antwoord, voor de volgende pagina. |
curl -X GET "https://curbo.nl/api/v1/verlof?van=2026-11-16&tot=2026-11-22" \
-H "Authorization: Bearer $CURBO_SLEUTEL"Antwoord
{
"data": [
{
"id": "1f2e3d4c-0000-4000-8000-000000000005",
"medewerker_id": "7c0f6d3e-1b2a-4c5d-9e8f-001122334455",
"soort": "wettelijk",
"van": "2026-12-24",
"tot": "2026-12-31",
"dagen": 5
}
],
"volgende": null
}Webhooks
Met Curbo Koppel stuurt Curbo een POST met JSON naar je https-adres zodra er iets gebeurt. Antwoord binnen 10 seconden met een 2xx-status; anders proberen we het opnieuw na 1, 5, 30, 120 en 720 minuten. Elk bericht is ondertekend in de kop Curbo-Handtekening(HMAC-SHA256 over tijd.lichaam met het geheim dat je bij het aanmaken kreeg). Controleer die altijd.
{
"id": "3f9a1c0e8b7d6e5f4a3b2c1d",
"gebeurtenis": "verlof.goedgekeurd",
"op": "2026-11-12T09:30:00.000Z",
"data": {
"id": "1f2e3d4c-…",
"medewerker_id": "7c0f6d3e-…",
"van": "2026-12-24",
"tot": "2026-12-31"
}
}import crypto from "node:crypto";
// kop = de waarde van de header "Curbo-Handtekening": "t=1731400000,v1=ab12…"
function klopt(kop, ruwLichaam, geheim) {
const delen = Object.fromEntries(kop.split(",").map((d) => d.split("=")));
const verwacht = crypto.createHmac("sha256", geheim).update(`${delen.t}.${ruwLichaam}`).digest("hex");
const vers = Math.abs(Date.now() / 1000 - Number(delen.t)) < 300; // hooguit 5 minuten oud
return vers && crypto.timingSafeEqual(Buffer.from(verwacht), Buffer.from(delen.v1));
}import hmac, hashlib, time
def klopt(kop: str, ruw_lichaam: bytes, geheim: str) -> bool:
delen = dict(d.split("=", 1) for d in kop.split(","))
verwacht = hmac.new(geheim.encode(), f"{delen['t']}.".encode() + ruw_lichaam, hashlib.sha256).hexdigest()
vers = abs(time.time() - int(delen["t"])) < 300
return vers and hmac.compare_digest(verwacht, delen["v1"])| medewerker.aangemaakt | Er is een medewerker aangemaakt (in het portaal of via de API). |
| medewerker.gewijzigd | Basisgegevens van een medewerker zijn gewijzigd via de API. |
| dienst.aangemaakt | Er is een dienst aangemaakt via de API. |
| dienst.gewijzigd | Een dienst is gewijzigd via de API. |
| dienst.geschrapt | Een dienst is geschrapt via de API. |
| verlof.goedgekeurd | Een verlofaanvraag is goedgekeurd. |
| verlof.afgewezen | Een verlofaanvraag is afgewezen. |
Wijzigingen
Versie 1 blijft werken: nieuwe velden en endpoints komen erbij, maar bestaande veranderen niet. Wat niet anders kan, komt in een nieuwe versie (/api/v2) en wordt minstens zes maanden vooraf aangekondigd.
- Eerste versie: organisatie, medewerkers, diensten, uren en verlof lezen.
- Met Curbo Koppel: medewerkers en diensten schrijven, en webhooks.

