# Google Calendar API gebruiken in Python [[TOC]] Planning is een dankbaar terrein voor automatisering. Met de Calendar API in Python maak je afspraken aan vanuit je eigen systemen, controleer je beschikbaarheid, stuur je uitnodigingen en synchroniseer je agenda's met externe bronnen. Of je nu een boekingssysteem bouwt of resources reserveert, deze API regelt het. In dit artikel bouw je de kernfuncties stap voor stap op: een afspraak aanmaken, beschikbaarheid opvragen, een boekingsflow ontwerpen en efficient synchroniseren. ## Verbinding maken Je begint met een geauthenticeerde service-client. Voor server-naar-server-scenario's gebruik je doorgaans een serviceaccount met domeinbrede delegatie; voor een gebruikersgerichte app een OAuth-flow met het scope `https://www.googleapis.com/auth/calendar`. ```python from googleapiclient.discovery import build service = build("calendar", "v3", credentials=credentials) ``` ## Een afspraak aanmaken Een event heeft minimaal een begin- en eindtijd nodig. Geef tijdzones expliciet mee om verwarring te voorkomen. ```python event = { "summary": "Kennismakingsgesprek", "start": {"dateTime": "2026-06-10T10:00:00", "timeZone": "Europe/Amsterdam"}, "end": {"dateTime": "2026-06-10T10:30:00", "timeZone": "Europe/Amsterdam"}, "attendees": [{"email": "klant@voorbeeld.nl"}], } service.events().insert( calendarId="primary", body=event, sendUpdates="all" ).execute() ``` :::tip title="Stuur de uitnodiging echt mee" Zet `sendUpdates` op `"all"` zodat genodigden automatisch een uitnodiging per e-mail krijgen. Vergeet je dit, dan staat de afspraak wel in de agenda maar weet niemand ervan. Voor stille wijzigingen gebruik je `"none"`. ::: ## Beschikbaarheid opvragen Voordat je inplant, wil je weten of iemand vrij is. De `freebusy().query()`-aanroep geeft per agenda de bezette blokken terug. ```python body = { "timeMin": "2026-06-10T08:00:00Z", "timeMax": "2026-06-10T18:00:00Z", "items": [{"id": "collega@jouwdomein.nl"}], } resultaat = service.freebusy().query(body=body).execute() bezet = resultaat["calendars"]["collega@jouwdomein.nl"]["busy"] ``` :::info title="Freebusy respecteert privacy" Freebusy toont alleen of een tijdslot bezet is, niet de details van de afspraken. Dat is precies de bedoeling: je respecteert de privacy van de agenda terwijl je toch slim kunt plannen. ::: ## Een boekingsflow opbouwen Een typisch boekingssysteem combineert beschikbaarheid checken en inplannen. De flow ziet er meestal zo uit: 1. De klant kiest een gewenste datum. 2. Je vraagt `freebusy().query()` op voor de betrokken agenda's. 3. Je toont alleen de vrije tijdsloten. 4. De klant kiest een slot. 5. Je maakt het event aan met `events().insert()` en stuurt uitnodigingen. 6. Bij annulering verwijder je het event met `events().delete()`. :::tip title="Voorkom dubbele boekingen" Tussen het tonen van een vrij slot en het bevestigen kan een ander iemand hetzelfde tijdstip kiezen. Vraag de beschikbaarheid daarom nog één keer op vlak voordat je `insert()` aanroept, of gebruik een korte reservering in je eigen database. ::: ## Efficient synchroniseren Wil je een agenda gespiegeld houden in je eigen systeem? Haal niet steeds alles op, maar gebruik incrementele synchronisatie met een `syncToken`. :::howto title="Zo synchroniseer je incrementeel" 1. Doe een eerste volledige `events().list()` en blader desnoods door alle pagina's heen. 2. Bewaar de `nextSyncToken` uit het laatste antwoord (die staat alleen op de laatste pagina). 3. Bij de volgende sync geef je die `syncToken` mee aan `events().list()`. 4. Je krijgt nu alleen de gewijzigde en verwijderde events terug. 5. Bewaar de nieuwe `nextSyncToken` voor de volgende ronde. ::: :::warn title="Vang een verlopen syncToken op" Een `syncToken` kan verlopen, bijvoorbeeld na lange inactiviteit. De API geeft dan een 410-fout (GONE). Vang die op, wis je lokale opslag en doe een volledige hersynchronisatie zonder token, anders loopt je gespiegelde agenda uit de pas. ::: ## Veelgestelde vragen :::faq ### Hoe maak ik een terugkerende afspraak? Voeg een `recurrence`-veld toe met een RRULE, bijvoorbeeld `["RRULE:FREQ=WEEKLY;COUNT=10"]` voor tien wekelijkse herhalingen. Het veld is een lijst, zodat je meerdere regels kunt combineren. ### Kan ik een Google Meet-link toevoegen? Ja. Zet `conferenceData` in de body met een uniek `createRequest`, en geef `conferenceDataVersion=1` mee aan `insert()`. De API genereert dan automatisch een Meet-link. ### Welke calendarId gebruik ik? Gebruik `primary` voor de hoofdagenda van de gebruiker, of het e-mailadres van een specifieke agenda waartoe je toegang hebt. Een gedeelde of resource-agenda heeft een eigen lange id die je via `calendarList().list()` opvraagt. ### Hoe vermijd ik dubbele afspraken bij herhaalde runs? Geef een eigen `id` mee of gebruik het `iCalUID`-veld om idempotent te werken, zodat een tweede insert dezelfde afspraak niet dupliceert. Bij een botsing krijg je dan een 409-fout die je kunt negeren. ### Waarom krijg ik een 403 of 401? Een 401 wijst meestal op een verlopen of ontbrekend token; ververs je credentials. Een 403 betekent vaak dat het juiste scope ontbreekt of dat het serviceaccount geen toegang heeft tot de agenda. Deel de agenda expliciet met het serviceaccount of stel domeinbrede delegatie correct in. ### Hoe ga ik om met rate limits? De API hanteert quota per project en per gebruiker. Vang een 403 of 429 met `userRateLimitExceeded` op en wacht met exponentiële back-off voordat je het opnieuw probeert. ::: Met de Calendar API in Python automatiseer je planning betrouwbaar, van losse afspraken tot een volledig boekingssysteem.