Documentatie

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.

1Maak een sleutel

In Curbo: Beheer → API → Nieuwe sleutel. Kies alleen de rechten die je nodig hebt.

2Doe een verzoek

Stuur de sleutel mee als Authorization: Bearer. Basisadres: https://curbo.nl/api/v1

3Blijf bij

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.

RechtWatPakket
organisatie:lezenNaam, teams en vestigingen.Gratis
medewerkers:lezenNaam, e-mail, functie, team en vestiging. Nooit BSN, IBAN of salaris.Gratis
rooster:lezenDiensten met tijden, functie en wie hem draait.Gratis
uren:lezenGewerkte uren (ingediend en geaccordeerd).Gratis
verlof:lezenGoedgekeurd verlof. Ziekte en de reden van afwezigheid niet.Gratis
medewerkers:schrijvenMedewerkers aanmaken en hun basisgegevens wijzigen.Curbo Koppel
rooster:schrijvenDiensten 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."
  }
}
400Het verzoek klopt niet (een parameter ontbreekt of is ongeldig).
401Geen of een ongeldige, ingetrokken of verlopen sleutel.
402Hoort bij Curbo Koppel, of de organisatie staat op pauze.
403De sleutel mist het recht voor dit endpoint.
404Bestaat niet (of niet in jullie organisatie).
409Bestaat al (bijvoorbeeld een medewerker met dit e-mailadres).
422Een veld is ongeldig; het bericht zegt welk.
429Te 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

VeldTypeUitleg
actiefbooleanAlleen in dienst (true) of ook uit dienst (false). Standaard true.
limietintegerAantal per pagina, 1 tot 200 (standaard 100).
nastringDe 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

VeldTypeUitleg
voornaam *stringVoornaam.
achternaam *stringAchternaam.
email *stringWerkmail; uniek binnen de organisatie.
functiestringFunctie.
team_iduuidTeam.
vestiging_iduuidVestiging.
in_dienst_sindsdateDatum 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

VeldTypeUitleg
voornaamstringVoornaam.
achternaamstringAchternaam.
functiestringFunctie.
team_iduuidTeam (leeg = geen team).
vestiging_iduuidVestiging (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

VeldTypeUitleg
van *dateEerste dag (JJJJ-MM-DD).
tot *dateLaatste dag; hooguit 93 dagen na van.
medewerker_iduuidAlleen van deze medewerker.
limietintegerAantal per pagina, 1 tot 200 (standaard 100).
nastringDe 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

VeldTypeUitleg
datum *dateDatum.
begin *timeBegintijd (UU:MM).
einde *timeEindtijd (UU:MM).
pauze_minutenintegerPauze in minuten (standaard 0).
functiestringFunctie op de dienst.
medewerker_iduuidWie hem draait.
team_iduuidTeam.
vestiging_iduuidVestiging.
publicerenbooleanMeteen 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

VeldTypeUitleg
datumdateDatum.
begintimeBegintijd.
eindetimeEindtijd.
pauze_minutenintegerPauze.
functiestringFunctie.
medewerker_iduuidWie hem draait (null = open dienst).
publicerenbooleanZichtbaar 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

VeldTypeUitleg
van *dateEerste dag (JJJJ-MM-DD).
tot *dateLaatste dag; hooguit 93 dagen na van.
medewerker_iduuidAlleen van deze medewerker.
limietintegerAantal per pagina, 1 tot 200 (standaard 100).
nastringDe 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

VeldTypeUitleg
van *dateEerste dag (JJJJ-MM-DD).
tot *dateLaatste dag; hooguit 93 dagen na van.
limietintegerAantal per pagina, 1 tot 200 (standaard 100).
nastringDe 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.aangemaaktEr is een medewerker aangemaakt (in het portaal of via de API).
medewerker.gewijzigdBasisgegevens van een medewerker zijn gewijzigd via de API.
dienst.aangemaaktEr is een dienst aangemaakt via de API.
dienst.gewijzigdEen dienst is gewijzigd via de API.
dienst.geschraptEen dienst is geschrapt via de API.
verlof.goedgekeurdEen verlofaanvraag is goedgekeurd.
verlof.afgewezenEen 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.

1.0.0 · 2026-11-12
  • Eerste versie: organisatie, medewerkers, diensten, uren en verlof lezen.
  • Met Curbo Koppel: medewerkers en diensten schrijven, en webhooks.