# Google Calendar API gebruiken voor afsprakenbeheer [[TOC]] ## Waarom de Google Calendar API? De Google Calendar API geeft je programmatische toegang tot Google Agenda: je kunt afspraken aanmaken, lezen, bijwerken en verwijderen vanuit je eigen applicatie. Dit is handig voor: - CRM-systemen die automatisch agenda-items aanmaken bij een verkoop - Booking-applicaties die beschikbaarheid controleren en afspraken vastleggen - Geautomatiseerde herinneringen of terugkerende planning - Rapporten over vergadertijd en agenda-gebruik :::info title="Gratis tot een quotum" De Google Calendar API is gratis tot een ruim quotum (zie de FAQ onderaan voor de actuele cijfers). Google heeft aangekondigd dat verbruik boven de limieten later in 2026 kosten kan gaan opleveren via je Google Cloud-factuur. Controleer de actuele limieten en eventuele tarieven altijd in de Google Cloud Console. ::: ## Stap 1: API inschakelen en authenticatie opzetten :::howto title="API activeren in de Cloud Console" 1. Ga naar `console.cloud.google.com`. 2. Maak een nieuw project aan of selecteer een bestaand project. 3. Ga naar **API's en services > Bibliotheek** en zoek naar **Google Calendar API**. 4. Klik op **Inschakelen**. 5. Ga naar **Inloggegevens** en maak de juiste credentials aan: een **OAuth 2.0 Client-ID** voor applicaties die namens een gebruiker werken, of een **Serviceaccount** voor server-to-server authenticatie zonder gebruikersinteractie. ::: ### OAuth 2.0 of serviceaccount? Onderstaande tabel helpt je kiezen tussen de twee authenticatiemethodes. | Situatie | Kies dit | | --- | --- | | Je voert acties uit namens een specifieke gebruiker | OAuth 2.0 | | De gebruiker moet zelf toestemming geven | OAuth 2.0 | | Je benadert agenda's van verschillende externe gebruikers | OAuth 2.0 | | Je draait een server-side proces zonder gebruikersinteractie | Serviceaccount | | Je beheert agenda's binnen je eigen Workspace-domein | Serviceaccount met domeinbrede delegatie | | Je bouwt een achtergrondproces dat automatisch agenda's beheert | Serviceaccount | ## Stap 2: Authenticatie implementeren (Python) Onderstaand voorbeeld gebruikt de officiele Google-clientbibliotheken (`google-auth-oauthlib` en `google-api-python-client`). Het slaat het token lokaal op zodat de gebruiker niet bij elke run opnieuw hoeft in te loggen. ```python from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build import os SCOPES = ['https://www.googleapis.com/auth/calendar'] def get_calendar_service(): creds = None if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES ) creds = flow.run_local_server(port=0) with open('token.json', 'w') as token: token.write(creds.to_json()) return build('calendar', 'v3', credentials=creds) ``` :::warn title="Houd je credentials uit je repository" Zet `credentials.json` en `token.json` nooit in versiebeheer. Voeg ze toe aan je `.gitignore` en bewaar geheimen in productie in een secrets manager. Een gelekte refresh token geeft directe toegang tot de agenda. ::: ## Stap 3: Afspraken aanmaken ```python def create_event(service, calendar_id, titel, start_dt, end_dt, deelnemers=None): event = { 'summary': titel, 'start': { 'dateTime': start_dt.isoformat(), 'timeZone': 'Europe/Amsterdam', }, 'end': { 'dateTime': end_dt.isoformat(), 'timeZone': 'Europe/Amsterdam', }, } if deelnemers: event['attendees'] = [{'email': email} for email in deelnemers] result = service.events().insert( calendarId=calendar_id, body=event, sendUpdates='all' ).execute() return result.get('htmlLink') ``` Met `sendUpdates='all'` krijgen alle deelnemers automatisch een uitnodiging. Gebruik `'none'` als je geen mails wilt versturen, bijvoorbeeld bij een bulk-import. ## Stap 4: Afspraken ophalen ```python from datetime import datetime, timezone def get_upcoming_events(service, calendar_id, max_results=10): now = datetime.now(timezone.utc).isoformat() events_result = service.events().list( calendarId=calendar_id, timeMin=now, maxResults=max_results, singleEvents=True, orderBy='startTime' ).execute() return events_result.get('items', []) ``` Zet `singleEvents=True` zodat terugkerende afspraken worden uitgesplitst naar losse instanties. Alleen dan werkt `orderBy='startTime'` correct. ## Beschikbaarheid controleren met FreeBusy De FreeBusy-query is ideaal om beschikbaarheid te controleren voordat je een afspraak plant. Je krijgt per agenda de bezette tijdsblokken terug, zonder de details van de afspraken zelf. ```python def check_availability(service, email_addresses, start_dt, end_dt): body = { 'timeMin': start_dt.isoformat(), 'timeMax': end_dt.isoformat(), 'timeZone': 'Europe/Amsterdam', 'items': [{'id': email} for email in email_addresses] } result = service.freebusy().query(body=body).execute() return result.get('calendars', {}) ``` :::tip title="Voorkom dubbele boekingen" Roep FreeBusy aan vlak voordat je een afspraak vastlegt en controleer de teruggegeven `busy`-blokken. Combineer dit met een korte lock of database-controle in je eigen app, zodat twee gelijktijdige boekingen niet allebei in hetzelfde gat vallen. ::: ## Webhooks voor real-time updates In plaats van periodiek de API te pollen, kun je een notificatiekanaal instellen dat je applicatie een POST-verzoek stuurt zodra er iets in de agenda wijzigt. ```python def setup_calendar_watch(service, calendar_id, webhook_url): channel = { 'id': 'mijn-unieke-channel-id', 'type': 'web_hook', 'address': webhook_url, } result = service.events().watch( calendarId=calendar_id, body=channel ).execute() return result ``` Het kanaal verloopt na verloop van tijd (de vervaldatum staat in het antwoord). Plan een proces dat het kanaal op tijd vernieuwt en de oude weer afsluit met `service.channels().stop()`. Je `webhook_url` moet publiek bereikbaar zijn via HTTPS met een geldig certificaat. :::faq ### Hoe lang zijn OAuth-tokens geldig? Access tokens zijn standaard 1 uur geldig. Refresh tokens blijven in productie geldig totdat ze worden ingetrokken, maar vervallen automatisch na zes maanden zonder gebruik. Let op: zolang je OAuth-toestemmingsscherm op de status `Testing` staat met gebruikerstype `Extern`, vervalt de refresh token al na 7 dagen. Zet de publicatiestatus op `In productie` om dat te voorkomen. ### Kan ik de API gebruiken voor agenda's van andere gebruikers in mijn organisatie? Met een serviceaccount en domeinbrede delegatie kun je namens alle gebruikers in je Workspace-domein acties uitvoeren. Dit moet een beheerder eerst goedkeuren in de Admin-console. ### Is er een limiet aan het aantal API-aanroepen? Ja. De Calendar API kent een drempel van ongeveer 1.000.000 verzoeken per dag per project en 600 verzoeken per minuut per gebruiker. Projecten die op of na 1 mei 2026 zijn aangemaakt vallen onder een herziene quotumstructuur, dus controleer de actuele cijfers altijd in de Cloud Console. ### Kan ik terugkerende evenementen aanmaken? Ja, gebruik het veld `recurrence` in de event-body met RRULE-syntax. Bijvoorbeeld `RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR` voor een wekelijkse afspraak op maandag, woensdag en vrijdag. ### Hoe verwijder ik een afspraak via de API? Gebruik `service.events().delete(calendarId=calendar_id, eventId=event_id).execute()`. Verwijderen is permanent. Wil je een afspraak alleen annuleren zonder hem te verwijderen, zet dan het veld `status` op `cancelled`. ### Waarom krijg ik foutmelding 403 "usage limits exceeded"? Je raakt dan een snelheidslimiet, meestal de limiet per gebruiker per minuut. Bouw exponentiele back-off met retries in en spreid bulk-bewerkingen over de tijd. Per gebruiker een eigen quota-identifier meesturen helpt om verzoeken eerlijk te verdelen. :::