Ga naar inhoud
Tesoro CRM

API & externe koppelingen

De Tesoro Open API stelt u in staat om externe systemen, websites en applicaties te koppelen aan uw Tesoro CRM-omgeving. Via de API kunt u contacten, notities, bestanden en referentiewaarden beheren vanuit uw eigen software. De API is gebouwd met FastAPI (Python) en volgt RESTful-principes.


De Open API biedt de volgende mogelijkheden:

FunctionaliteitBeschrijving
ContactbeheerContacten aanmaken, opvragen, bijwerken en verwijderen.
NotitiebeheerNotities koppelen aan contacten, vastpinnen en doorzoeken.
BestandsuploadBestanden uploaden naar CRM-resources (woningen, contacten, etc.).
ReferentiewaardenEnum-waarden ophalen voor contactvelden, landen, talen en woningtypes.
Audit loggingAutomatische logging van alle API-verzoeken voor beveiliging en foutopsporing.

Elke externe koppeling vereist een API-client. Bij het aanmaken worden de volgende gegevens vastgelegd:

EigenschapBeschrijving
Client IDUniek identificatienummer van 32 tekens (letters, cijfers, underscore en koppelteken).
Client SecretGeheim wachtwoord, versleuteld opgeslagen via AES-encryptie en gehasht met Blake2b.
NaamHerkenbare naam voor de koppeling (bijv. “Website contactformulier”).
PermissiesWelke acties de client mag uitvoeren (zie onderstaande tabel).
Rate limitsMaximaal aantal verzoeken per minuut, uur en dag.
IP-whitelistOptionele lijst van toegestane IP-adressen.
StatusStatus van de client: active, suspended of revoked.
Laatste gebruikTijdstempel van het laatste API-verzoek (automatisch bijgewerkt).
  1. Ga naar Instellingen > API & Koppelingen in uw Tesoro CRM-omgeving.

  2. Klik op Nieuwe API-client aanmaken.

  3. Vul een herkenbare naam in voor de koppeling (bijv. “Website formulier” of “Externe makelaarskoppeling”).

  4. Selecteer de benodigde permissies voor deze client.

  5. Configureer optioneel de rate limits en IP-whitelist.

  6. Klik op Opslaan. Uw Client ID en Client Secret worden getoond.

  7. Kopieer het Client Secret direct en bewaar het op een veilige locatie.


Elke API-client kan worden voorzien van een of meerdere permissies. Permissies bepalen welke endpoints toegankelijk zijn.

PermissieBeschrijvingVereist voor endpoints
contacts:readContacten opvragen en doorzoeken.GET /contacts, GET /contacts/{id}
contacts:writeContacten aanmaken, bijwerken en verwijderen.POST /contacts, PUT /contacts/{id}, DELETE /contacts/{id}
notes:readNotities opvragen bij contacten.GET /notes, GET /notes/{id}
notes:writeNotities aanmaken, bijwerken, verwijderen en vastpinnen.POST /notes, PUT /notes/{id}, DELETE /notes/{id}, POST /notes/{id}/pin

Alle API-verzoeken (behalve het bestandsupload-endpoint) worden geauthenticeerd via een CLIENT-ID-header.

  1. Voeg de header CLIENT-ID toe aan elk verzoek met daarin uw Client ID (32 tekens).

  2. De API valideert uw client, controleert of de client actief is en haalt de bijbehorende permissies op.

  3. Bij succesvolle authenticatie worden de permissies, rate limits en IP-whitelist van uw client toegepast.

  4. De last_used_at-tijdstempel van de client wordt automatisch bijgewerkt.

Terminal window
curl -X GET "https://api.tesoro.example.com/api/v1/contacts" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__" \
-H "Content-Type: application/json"

Alle API-endpoints retourneren een gestandaardiseerd JSON-formaat.

{
"result": true,
"message": "Contact has been created successfully",
"data": {
"_id": "507f1f77bcf86cd799439011",
"first_name": "Jan",
"last_name": "De Vries",
"email": "jan@voorbeeld.nl",
"status": "new",
"type": "lead",
"company_id": "507f1f77bcf86cd799439000",
"created_at": 1709395200,
"updated_at": 1709395200
}
}
{
"result": true,
"message": "Contact has been fetched correctly",
"data": {
"models": [
{
"_id": "507f1f77bcf86cd799439011",
"first_name": "Jan",
"last_name": "De Vries",
"email": "jan@voorbeeld.nl"
}
],
"pagination": {
"page": 1,
"pageCount": 5,
"pageSize": 20,
"totalCount": 94
}
}
}
{
"result": false,
"message": "Validation failed",
"error_code": "VALIDATION_ERROR",
"status_code": 400,
"data": null,
"errors": [
{
"code": "INVALID_FORMAT",
"field": "email",
"details": "Invalid email format"
}
]
}

MethodeEndpointBeschrijvingPermissie
POST/api/v1/contactsNieuw contact aanmaken.contacts:write
GET/api/v1/contactsContacten opvragen met paginering en filters.contacts:read
GET/api/v1/contacts/{id}Een specifiek contact opvragen op basis van ID.contacts:read
PUT/api/v1/contacts/{id}Contact bijwerken.contacts:write
DELETE/api/v1/contacts/{id}Contact verwijderen (soft delete).contacts:write
ParameterTypeStandaardBeschrijving
pageinteger1Paginanummer (minimaal 1).
limitinteger20Aantal resultaten per pagina (1-100).
searchstring-Zoektekst (doorzoekt naam, e-mail, etc.).
statusstring-Filtert op contactstatus (bijv. new, active).
typestring-Filtert op contacttype (bijv. lead, client).
rolestring-Filtert op rol.
lead_sourcestring-Filtert op leadbron.
lead_stagestring-Filtert op leadfase.

Bij het aanmaken van een contact (POST) zijn de volgende velden beschikbaar:

VeldTypeVerplichtBeschrijving
first_namestringJaVoornaam van het contact.
last_namestringJaAchternaam van het contact.
emailstringJaE-mailadres (wordt gevalideerd).
phonestringNeeTelefoonnummer met landcode (bijv. +31612345678).
salutationstringNeeAanhef (enum-waarde).
languagestringNeeTaalcode (standaard en).
statusstringNeeStatus (standaard new).
rolestringNeeRol van het contact (enum-waarde).
typestringNeeType contact (standaard lead).
additional_informationstringNeeAanvullende informatie.
addressobjectNeeAdresgegevens (street, city, zip_code, country, etc.).
property_addressobjectNeeAdres van het vastgoedobject.
leadobjectNeeLeadgegevens (status, source, stage, source_mls).
property_detailsobjectNeeVastgoeddetails (type, locatie, slaapkamers, prijs, etc.).
timingobjectNeeTiming (looking_to, timeline_max).
way_of_sellingstringNeeVerkoopwijze (enum-waarde).
commisionfloatNeeCommissiepercentage (0-100).

Bij het bijwerken (PUT) zijn alle velden optioneel.

MethodeEndpointBeschrijvingPermissie
POST/api/v1/notesNotitie aanmaken bij een contact.notes:write
GET/api/v1/notesNotities opvragen voor een contact (met paginering, zoeken, sortering en filter op vastgepinde notities).notes:read
GET/api/v1/notes/{id}Een specifieke notitie opvragen.notes:read
PUT/api/v1/notes/{id}Notitie bijwerken.notes:write
DELETE/api/v1/notes/{id}Notitie verwijderen.notes:write
POST/api/v1/notes/{id}/pinVastpinstatus van een notitie wisselen.notes:write
ParameterTypeStandaardBeschrijving
resource_namestringcontactType resource (momenteel alleen contact ondersteund).
resource_idstringverplichtID van de resource (bijv. contact-ID).
pageinteger1Paginanummer.
limitinteger20Resultaten per pagina (1-100).
searchstring-Zoektekst.
pinned_onlybooleanfalseAlleen vastgepinde notities tonen.
sortstring-created_atSortering: -created_at (nieuwste eerst) of created_at (oudste eerst).
VeldTypeVerplichtBeschrijving
titlestringJaTitel van de notitie.
contentstringJaInhoud van de notitie.
pinnedbooleanNeeVastpinstatus (standaard false).
resource_namestringJa (bij aanmaken)Type resource: contact.
resource_idstringJa (bij aanmaken)ID van de gekoppelde resource.
MethodeEndpointBeschrijvingPermissie
GET/api/v1/enum/contactContactspecifieke enum-waarden ophalen (status, rol, type, leadbron, aanhef, etc.).contacts:read
GET/api/v1/enum/sharedGedeelde enum-waarden ophalen (landen, talen).contacts:read
GET/api/v1/enum/propertyVastgoed enum-waarden ophalen (woningtypes).contacts:read
MethodeEndpointBeschrijvingAuthenticatie
POST/api/v1/files/uploadBestand uploaden naar een resource (woning, contact, etc.).Bearer-token
ParameterTypeVerplichtBeschrijving
filebestandJaHet te uploaden bestand (multipart form-data).
resource_namestringJaType resource (bijv. property, contact).
resource_idstringNeeID van de gekoppelde resource.
file_titlestringNeeTitel voor het bestand.
sortstringNeeSorteervolgorde.
MethodeEndpointBeschrijvingAuthenticatie
GET/healthStatuscontrole van de API. Retourneert de servicenaam en versie.Geen

Terminal window
curl -X POST "https://api.tesoro.example.com/api/v1/contacts" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jan",
"last_name": "De Vries",
"email": "jan@voorbeeld.nl",
"phone": "+31612345678",
"language": "nl",
"status": "new",
"type": "lead",
"address": {
"street": "Keizersgracht 123",
"city": "Amsterdam",
"zip_code": "1015 AA",
"country": "NL"
},
"lead": {
"source": "website",
"stage": "new"
},
"property_details": {
"type": ["apartment"],
"number_of_bedrooms": 3,
"price_min": 250000,
"price_max": 500000
}
}'
Terminal window
# Alle leads ophalen, pagina 1, 10 resultaten per pagina
curl -X GET "https://api.tesoro.example.com/api/v1/contacts?type=lead&page=1&limit=10" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__"
# Zoeken op naam of e-mailadres
curl -X GET "https://api.tesoro.example.com/api/v1/contacts?search=jan&status=new" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__"
Terminal window
curl -X POST "https://api.tesoro.example.com/api/v1/notes" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__" \
-H "Content-Type: application/json" \
-d '{
"title": "Bezichtiging gepland",
"content": "Bezichtiging gepland op 15 maart 2026 om 14:00 voor appartement aan de Herengracht.",
"pinned": true,
"resource_name": "contact",
"resource_id": "507f1f77bcf86cd799439011"
}'
Terminal window
# Contactspecifieke enum-waarden (status, rol, type, leadbron, etc.)
curl -X GET "https://api.tesoro.example.com/api/v1/enum/contact" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__"
# Gedeelde waarden (landen, talen)
curl -X GET "https://api.tesoro.example.com/api/v1/enum/shared" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__"
# Vastgoed enum-waarden (woningtypes)
curl -X GET "https://api.tesoro.example.com/api/v1/enum/property" \
-H "CLIENT-ID: uw_32_karakter_client_id_hier__"
Terminal window
curl -X POST "https://api.tesoro.example.com/api/v1/files/upload" \
-H "Authorization: Bearer uw_bearer_token_hier" \
-F "file=@/pad/naar/document.pdf" \
-F "resource_name=property" \
-F "resource_id=507f1f77bcf86cd799439022" \
-F "file_title=Plattegrond begane grond"

Elke API-client heeft configureerbare rate limits. De standaardwaarden zijn:

LimietStandaardwaardeRedis-sleutel
Per minuut100 verzoekenrate_limit:{client_id}:minute:{timestamp}
Per uur1.000 verzoekenrate_limit:{client_id}:hour:{timestamp}
Per dag10.000 verzoekenrate_limit:{client_id}:day:{timestamp}

Bij overschrijding van een limiet ontvangt u een HTTP 429 Too Many Requests-fout:

{
"detail": "Minute rate limit exceeded. Limit: 100 requests"
}

Optioneel kunt u een lijst van toegestane IP-adressen instellen per API-client. Wanneer er IP-adressen zijn geconfigureerd, worden verzoeken vanaf niet-whitelisted adressen geweigerd met een HTTP 403 Forbidden-fout.

De API ondersteunt de volgende IP-headers voor correcte identificatie achter een load balancer of proxy:

HeaderBeschrijving
X-Forwarded-ForStandaard proxy-header (eerste IP-adres wordt gebruikt).
X-Real-IPAlternatieve proxy-header.
Directe verbindingFallback naar het IP-adres van de directe verbinding.

Alle API-verzoeken worden automatisch gelogd in de collectie api_audit_logs voor beveiligings- en foutopsporingsdoeleinden. Per verzoek worden de volgende gegevens vastgelegd:

VeldBeschrijving
Client IDDe client die het verzoek heeft uitgevoerd.
BedrijfHet gekoppelde bedrijf.
EndpointHet aangevraagde API-endpoint.
HTTP-methodeGET, POST, PUT of DELETE.
IP-adresHet IP-adres van de aanvrager.
User AgentDe user-agent string van de aanvrager.
VerzoekgegevensGeanonimiseerde versie van de request body (gevoelige velden worden vervangen door [REDACTED]).
ResponsstatusHTTP-statuscode van het antwoord.
VerwerkingstijdDuur van de verwerking in milliseconden.
FoutenEventuele foutmeldingen.
TijdstempelTijdstip van het verzoek.

De API retourneert gestandaardiseerde HTTP-statuscodes en foutberichten:

StatuscodeFoutcodeBeschrijving
400BAD_REQUEST / VALIDATION_ERROROngeldig verzoek of validatiefout.
401UNAUTHORIZEDOntbrekende of ongeldige CLIENT-ID header.
403FORBIDDENOnvoldoende permissies of IP niet gewhitelist.
404NOT_FOUNDResource niet gevonden.
422UNPROCESSABLE_ENTITYOnverwerkbare entiteit (schema-validatiefout).
429-Rate limit overschreden.
500INTERNAL_SERVER_ERROROnverwachte serverfout.
502PROXY_ERRORFout bij communicatie met de interne Tesoro API (alleen bij bestandsupload).


De Open API biedt automatisch gegenereerde, interactieve documentatie via Swagger UI. Deze is beschikbaar op het /docs-endpoint van uw API-omgeving.

Via de Swagger UI kunt u:

  • Alle beschikbare endpoints bekijken met hun parameters en response-schema’s.
  • Uw CLIENT-ID eenmalig invoeren via de Authorize-knop, waarna deze automatisch wordt meegezonden bij alle testverzoeken.
  • Endpoints direct testen vanuit uw browser.
  • Response-voorbeelden en foutmeldingen inzien.

Kan ik meerdere API-clients aanmaken? Ja. U kunt per koppeling een aparte client aanmaken met eigen permissies, rate limits en IP-whitelist. Dit wordt sterk aanbevolen voor het scheiden van verschillende integraties.

Wat gebeurt er als mijn client wordt opgeschort? Een client met de status suspended of revoked kan geen API-verzoeken meer uitvoeren. Alle verzoeken worden geweigerd met een HTTP 403-fout.

Welke ID-formaat wordt gebruikt? De API maakt gebruik van MongoDB ObjectId’s (24-karakter hexadecimale strings). Bij het meegeven van een ongeldig ID-formaat ontvangt u een validatiefout.

Hoe werkt de eigenaar-toewijzing bij nieuwe contacten? Wanneer u een contact aanmaakt via de API, wordt automatisch een eigenaar toegewezen. De API haalt de standaard eigenaar op uit de websiteinstellingen van uw bedrijf. Als er geen standaard eigenaar is geconfigureerd, wordt de eerste gebruiker van het bedrijf toegewezen.

Kan ik notities koppelen aan andere resources dan contacten? Momenteel ondersteunt de API alleen notities voor de resource contact. Ondersteuning voor andere resources (zoals woningen) kan in toekomstige versies worden toegevoegd.

Worden verwijderde contacten definitief verwijderd? Nee. Het DELETE-endpoint voert een soft delete uit. Het contact wordt gemarkeerd als verwijderd maar blijft in de database beschikbaar voor eventueel herstel.

Wat als de telefoonnummervalidatie mislukt? Telefoonnummers moeten het internationale formaat volgen met landcode, beginnend met + (bijv. +31612345678). Nummers zonder landcode worden geweigerd.

Hoe kan ik de geldige waarden voor keuzevelden achterhalen? Gebruik de enum-endpoints (/api/v1/enum/contact, /api/v1/enum/shared, /api/v1/enum/property) om alle geldige waarden en hun labels op te halen. Dit is bijzonder nuttig bij het bouwen van formulieren die contacten aanmaken via de API.