# Google People API gebruiken voor contactbeheer [[TOC]] ## Wat is de Google People API? De Google People API geeft programmatische toegang tot contacten in Google Contacts. Je kunt contacten lezen, aanmaken, bijwerken en verwijderen. De API vervangt de oudere Google Contacts API v3 (de `m8/feeds`-scope) en biedt modernere endpoints met betere ondersteuning voor zakelijke contacten. Veelvoorkomende toepassingen: - CRM-synchronisatie waarbij klantdata automatisch naar Google Contacts wordt gestuurd. - Contactimport vanuit een legacy-systeem. - Automatisch bijhouden van contactinformatie op basis van e-mailinteracties. - Organisatiecontacten beschikbaar maken voor medewerkers. :::info title="Twee soorten contacten" In Google Workspace bestaan twee typen contacten: **persoonlijke contacten** (eigendom van de gebruiker) en **directory-contacten** (beheerd door de organisatie via de Admin Console). De People API geeft toegang tot persoonlijke contacten. Directory-contacten lees je via de Admin SDK of via de scope `directory.readonly`. ::: ## API inschakelen :::howto title="People API activeren in Google Cloud" 1. Ga naar [console.cloud.google.com](https://console.cloud.google.com). 2. Selecteer een bestaand project of maak een nieuw project aan. 3. Open **API's en services > Bibliotheek**. 4. Zoek op **People API** en klik op **Inschakelen**. 5. Maak OAuth 2.0-credentials aan via **Credentials > Create Credentials** en stel het OAuth-toestemmingsscherm in. ::: ## Scopes kiezen De People API vereist specifieke OAuth-scopes afhankelijk van de operaties. Vraag altijd de minimaal benodigde scope aan, dus geen schrijftoegang als alleen lezen voldoende is. | Scope | Toegang | |---|---| | `https://www.googleapis.com/auth/contacts.readonly` | Persoonlijke contacten alleen lezen | | `https://www.googleapis.com/auth/contacts` | Persoonlijke contacten lezen en schrijven | | `https://www.googleapis.com/auth/contacts.other.readonly` | Overige contacten (automatisch verzameld) lezen | | `https://www.googleapis.com/auth/directory.readonly` | Organisatie-directory lezen | Alle schrijfacties (`createContact`, `updateContact`, `deleteContact`, `updateContactPhoto`) vereisen de volledige `contacts`-scope. ## Contacten ophalen Gebruik `people.connections.list` met een `personFields`-masker om te bepalen welke velden je terugkrijgt. Paginering verloopt via `nextPageToken`. ```python from google.oauth2.credentials import Credentials from googleapiclient.discovery import build def get_contacts(credentials, page_size=100): service = build('people', 'v1', credentials=credentials) results = service.people().connections().list( resourceName='people/me', pageSize=page_size, personFields='names,emailAddresses,phoneNumbers,organizations' ).execute() connections = results.get('connections', []) contacts = [] for person in connections: contact = {} names = person.get('names', []) if names: contact['name'] = names[0].get('displayName', '') emails = person.get('emailAddresses', []) if emails: contact['email'] = emails[0].get('value', '') phones = person.get('phoneNumbers', []) if phones: contact['phone'] = phones[0].get('value', '') contacts.append(contact) return contacts ``` :::tip title="Vergeet paginering niet" `connections.list` geeft standaard maximaal 100 resultaten per pagina (maximaal 1000). Bij grotere adresboeken moet je doorbladeren met de `nextPageToken` uit de respons, anders mis je contacten. ::: ## Een contact aanmaken ```python def create_contact(service, naam, email, telefoon=None, bedrijf=None): delen = naam.split() contact_body = { 'names': [{ 'givenName': delen[0], 'familyName': ' '.join(delen[1:]) }], 'emailAddresses': [{'value': email, 'type': 'work'}], } if telefoon: contact_body['phoneNumbers'] = [{'value': telefoon, 'type': 'work'}] if bedrijf: contact_body['organizations'] = [{'name': bedrijf, 'type': 'work'}] result = service.people().createContact(body=contact_body).execute() return result.get('resourceName') ``` ## Contacten bijwerken Bij een update moet je de actuele `etag` van het contact meesturen. Haal daarom eerst het contact op, neem de etag over en gebruik `updatePersonFields` om aan te geven welke velden je wijzigt. ```python def update_contact(service, resource_name, update_fields): person = service.people().get( resourceName=resource_name, personFields='names,emailAddresses,phoneNumbers' ).execute() update_fields['etag'] = person.get('etag') velden = [k for k in update_fields if k != 'etag'] result = service.people().updateContact( resourceName=resource_name, updatePersonFields=','.join(velden), body=update_fields ).execute() return result ``` :::warn title="etag is verplicht bij updates" De `etag` voorkomt dat je per ongeluk wijzigingen overschrijft die intussen door iemand anders zijn gemaakt. Klopt de etag niet meer met de serverversie, dan krijg je een `400`-fout met reden `failedPrecondition`. Haal in dat geval het contact opnieuw op en probeer het opnieuw met de verse etag. ::: ## Contactgroepen beheren Contactgroepen (labels) helpen je contacten te categoriseren: ```python def create_contact_group(service, naam): body = {'contactGroup': {'name': naam}} result = service.contactGroups().create(body=body).execute() return result.get('resourceName') def add_to_group(service, group_resource_name, contact_resource_names): body = {'resourceNamesToAdd': contact_resource_names} service.contactGroups().members().modify( resourceName=group_resource_name, body=body ).execute() ``` ## Synchroniseren met een CRM Voor een betrouwbare sync vergelijk je contacten op een stabiele sleutel (zoals e-mailadres of een eigen ID) en houd je per kant bij wat het laatst is gewijzigd. :::tip title="Praktische sync-aanpak" Gebruik **incrementele synchronisatie**: bewaar het `syncToken` uit een eerdere `connections.list`-aanroep en geef dat mee bij de volgende aanroep. Je krijgt dan alleen de gewijzigde en verwijderde contacten terug, in plaats van het hele adresboek. Combineer dit met het `metadata.deleted`-veld om verwijderingen aan jouw kant door te voeren. ::: :::faq ### Kan ik directory-contacten (organisatiecontacten) bewerken via de People API? Nee. Directory-contacten worden beheerd via de Admin Console en zijn via de People API alleen-lezen. Voor het beheren van organisatiecontacten gebruik je de Admin SDK Directory API. ### Hoe synchroniseer ik een CRM met Google Contacts? Gebruik bij voorkeur incrementele synchronisatie met een `syncToken`, zodat je alleen wijzigingen ophaalt. Vergelijk contacten op e-mailadres of een eigen unieke ID en werk wijzigingen bidirectioneel bij. Voor verwijderingen let je op het `metadata.deleted`-veld. ### Hoeveel contacten kan ik via de API aanmaken? De People API kent quota per minuut en per dag. Voor grote imports verdeel je het werk in batches en bouw je een korte wachttijd of exponentiële backoff in zodat je niet tegen een `429`-fout aanloopt. De actuele limieten staan in de Cloud Console onder Quota. ### Kan ik foto's van contacten via de API beheren? Ja. Met `people.updateContactPhoto` stel je een profielfoto in. De foto lever je aan als base64-gecodeerde string en moet in JPEG- of PNG-formaat zijn. ### Hoe verwijder ik een contact? Roep `service.people().deleteContact(resourceName=resource_name).execute()` aan. Verwijderde contacten belanden in de prullenbak van Google Contacts en zijn daar 30 dagen herstelbaar, daarna worden ze definitief verwijderd. ### Waarom krijg ik een 400-fout bij het bijwerken? Meestal ontbreekt de juiste `etag` of het `updatePersonFields`-masker. Stuur altijd de actuele etag mee en geef expliciet op welke velden je wijzigt. Wijzig je groepslidmaatschappen, dan moet je ook de bestaande memberships meesturen. :::