Ga naar inhoud
Denkchat
Developer Guides

API Integratie

De Denkchat API stelt je in staat om chatbots programmatisch aan te sturen, gesprekken te beheren en data op te halen.

Base URL

https://denkchat.nl/api

Authenticatie

Dashboard API-endpoints vereisen een Bearer token (Supabase access token) in de header:

Authorization: Bearer YOUR_ACCESS_TOKEN

De embed chat API (/api/embed/chat) vereist geen authenticatie — deze is publiek toegankelijk voor widget-integraties.

Chat API

Bericht versturen

Stuur berichten naar een agent en ontvang een streaming text response.

curl -X POST https://denkchat.nl/api/embed/chat \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "JOUW_AGENT_ID",
    "messages": [
      { "role": "user", "content": "Wat zijn jullie openingstijden?" }
    ],
    "sessionId": "optioneel-session-id",
    "visitorEmail": "optioneel@email.nl"
  }'

Request body:

VeldTypeBeschrijvingVerplicht
agentIdstringJe agent IDJa
messagesarrayArray van { role, content } objectenJa
sessionIdstringBestaand sessie-ID om gesprek voort te zettenNee
visitorEmailstringE-mailadres van de bezoekerNee

Response:

De response is een plain text stream. De volledige tekst van het antwoord wordt chunk-voor-chunk gestreamd:

Onze openingstijden zijn maandag t/m vrijdag van 9:00 tot 17:00.

Response headers:

HeaderBeschrijving
X-Session-IdHet sessie-ID (nieuw aangemaakt of bestaand)

JavaScript voorbeeld

const response = await fetch('https://denkchat.nl/api/embed/chat', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    agentId: 'JOUW_AGENT_ID',
    messages: [
      { role: 'user', content: 'Hoe kan ik een bestelling retourneren?' }
    ],
  }),
});

// Sessie-ID ophalen voor vervolgberichten
const sessionId = response.headers.get('X-Session-Id');

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(decoder.decode(value, { stream: true }));
}

Python voorbeeld

import requests

response = requests.post(
    'https://denkchat.nl/api/embed/chat',
    json={
        'agentId': 'JOUW_AGENT_ID',
        'messages': [
            {'role': 'user', 'content': 'Wat kosten jullie producten?'}
        ],
    },
    stream=True,
)

session_id = response.headers.get('X-Session-Id')

for chunk in response.iter_content(decode_unicode=True):
    if chunk:
        print(chunk, end='')

Gesprek samenvatting

Genereer een AI-samenvatting van een chatsessie.

curl "https://denkchat.nl/api/chat/summary?sessionId=SESSION_ID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
  "summary": "De bezoeker vroeg naar openingstijden en retourbeleid. De agent heeft beide vragen correct beantwoord. Sentiment: positief."
}

Agent configuratie ophalen

curl "https://denkchat.nl/api/embed/config?agentId=JOUW_AGENT_ID"

Response:

{
  "name": "Klantenservice Bot",
  "welcomeMessage": "Hoi! Hoe kan ik je helpen?",
  "primaryColor": "#E54D2E",
  "position": "bottom-right"
}

Kennisbank API

Externe systemen (zoals de WordPress plugin) beheren kennisbank-content via /api/embed/knowledge. Deze endpoints vereisen een API-key (dk_live_...) als Bearer token — zie Authenticatie.

Kennisbank items synchroniseren

Stuur pagina's of documenten naar de kennisbank van een agent. Items worden geüpsert op basis van hun bron-URL (url) en daarna verwerkt: chunken, samenvatten, embedden.

curl -X POST https://denkchat.nl/api/embed/knowledge \
  -H "Authorization: Bearer dk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "title": "Over ons",
        "content": "Wij zijn een familiebedrijf sinds 1998...",
        "url": "https://voorbeeld.nl/over-ons",
        "type": "page"
      }
    ]
  }'

Request body:

VeldTypeBeschrijvingVerplicht
itemsarrayArray van items (max. 50 per request)Ja
titlestringTitel van het itemJa
contentstringPlatte tekst (HTML wordt niet gestript)Ja
urlstringBron-URL; dit is de sleutel waarop geüpsert wordtJa
typestringVrij label, belandt in metadata.wp_typeJa

Ongewijzigde items worden overgeslagen

Een item wordt overgeslagen als de aangeleverde tekst identiek is aan wat er al staat én de bestaande rij gezond is (status ready met chunks). Dat scheelt bij elke sync het opnieuw chunken, samenvatten en embedden van content die niet veranderd is — de duurste stap van dit endpoint. Een overgeslagen item krijgt wél zijn metadata ververst.

Wil je bewust opnieuw laten verwerken — bijvoorbeeld nadat de chunking of de samenvattingen zijn gewijzigd — gebruik dan ?force=true:

curl -X POST "https://denkchat.nl/api/embed/knowledge?force=true" \
  -H "Authorization: Bearer dk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{ "items": [ ... ] }'

Response:

{
  "success": true,
  "synced": 3,
  "skipped": 1,
  "errors": 1,
  "skipped_unchanged": 1,
  "results": [
    { "url": "https://voorbeeld.nl/over-ons", "status": "ready", "knowledgeId": "..." },
    { "url": "https://voorbeeld.nl/contact", "status": "ready", "knowledgeId": "...", "unchanged": true },
    { "url": "https://voorbeeld.nl/kapot", "status": "error" }
  ],
  "remaining": { "currentMb": 2.4, "limitMb": 20 }
}
VeldBeschrijving
syncedItems die geslaagd zijn — nieuw, bijgewerkt, of ongewijzigd
skippedAlleen de mislukte items (zelfde getal als errors, zie de opmerking hieronder)
errorsAlleen de mislukte items
skipped_unchangedItems die ongewijzigd waren en dus niet opnieuw verwerkt zijn
resultsPer item de bron-URL en de status: ready of error. Bij een ongewijzigd item staat er ook unchanged: true bij
remainingOpslaggebruik van de kennisbank na deze request

skipped en errors dragen op dit moment hetzelfde getal. skipped bestond al vóór de "ongewijzigde items overslaan"-optimalisatie hierboven en betekende altijd "mislukte items" — bestaande integraties (zoals de WordPress-plugin) tonen bij skipped > 0 een storage-limit-waarschuwing. Om die niet te breken telt skipped nog steeds alleen fouten; de nieuwe informatie over ongewijzigde items vind je in skipped_unchanged en aan results[].unchanged.

Bij het overschrijden van de opslaglimiet van je plan geeft dit endpoint 402 met error: "plan_limit_reached" en wordt er niets verwerkt.

Kennisbank items verwijderen

Verwijder eerder gesyncte items op basis van hun bron-URL. Bijbehorende chunks en embeddings worden automatisch mee verwijderd.

Alleen items die via deze API (of de WordPress plugin) zijn gesynct kunnen verwijderd worden — kennisbank-content die in het dashboard is toegevoegd blijft buiten bereik van de API-key. Dit endpoint is gelimiteerd tot 30 requests per minuut per agent.

curl -X DELETE https://denkchat.nl/api/embed/knowledge \
  -H "Authorization: Bearer dk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://voorbeeld.nl/over-ons",
      "https://voorbeeld.nl/contact"
    ]
  }'

Request body:

VeldTypeBeschrijvingVerplicht
urlsarrayBron-URL's van de te verwijderen items (1 t/m 100)Ja

Response:

{
  "success": true,
  "deleted": 1,
  "notFound": ["https://voorbeeld.nl/contact"]
}
VeldBeschrijving
deletedAantal daadwerkelijk verwijderde items
notFoundURL's die niet als API-gesynct item in de kennisbank van deze agent gevonden zijn

Product Sync API

Externe systemen kunnen productcatalogusgegevens in agenten synchroniseren via /api/embed/products. Deze endpoints vereisen een API-sleutel (dk_live_...) als Bearer token — zie Authenticatie. API-toegang hoort bij het Standard-plan en hoger.

Deze data vormt de grondslag voor productkaarten en eigenschappenfiltering in de chatwidget.

Draait de winkel op WooCommerce? Gebruik dan de WooCommerce-koppeling in plaats van zelf te pushen: die leest de catalogus uit de publieke Store API, houdt hem automatisch bij en heeft geen API-sleutel nodig. Dit endpoint blijft bestaan voor eigen webshops en andere systemen.

Producten synchroniseren

Synchroniseer of update producten in de productcatalogus van een agent. Producten worden geüpsert op basis van (agent_id, external_id) en hun beschrijvingen worden automatisch ingebed voor eigenschap-gebaseerd filteren.

curl -X POST https://denkchat.nl/api/embed/products \
  -H "Authorization: Bearer dk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {
        "external_id": "123",
        "name": "SPF 50 Zonnecrème",
        "sku": "ZC-SPF50-200",
        "price": 24.99,
        "regular_price": 29.99,
        "on_sale": true,
        "in_stock": true,
        "product_url": "https://voorbeeld.nl/products/spf50-crème",
        "image_url": "https://voorbeeld.nl/images/spf50.jpg",
        "add_to_cart_url": "https://voorbeeld.nl/products/spf50-crème?add-to-cart=123",
        "brand": "Zonneexperts",
        "categories": ["Zonnecrèmes", "Face"],
        "attributes": ["SPF 50", "Waterproof", "Gevoelige huid"],
        "attributes_source": {
          "SPF 50": "shop",
          "Waterproof": "shop",
          "Gevoelige huid": "llm"
        },
        "description": "Zeer effectieve dagcreme met SPF 50+ UV-filter..."
      }
    ]
  }'

Request body:

VeldTypeBeschrijvingVerplicht
productsarrayArray van product-objecten (max. 500)Ja
external_idstringUnieke product-ID uit je winkelssysteemJa
namestringProductnaamJa
skustringArtikelnummer uit je winkelsysteemNee
pricenumberHuidige verkoopprijsJa
price_frombooleanIs price een vanaf-prijs? Zet dit op true bij een product met meerdere uitvoeringen, waarvan je de laagste prijs meestuurt — de chatbot toont dan "vanaf €24,99" in plaats van dat bedrag als dé prijs (standaard false)Nee
regular_pricenumberNormale prijs (voor aanbiedingen)Nee
on_salebooleanGeldt er een aanbieding?Nee
in_stockbooleanIs het product beschikbaar?Nee
product_urlstringLink naar productdetailpaginaJa
image_urlstringURL van productafbeeldingNee
add_to_cart_urlstringLink om product direct in winkelwagen te doenNee
brandstringMerknaamNee
categoriesarrayProductcategorieën (string array)Nee
attributesarrayProducteigenschappen/tags (string array)Nee
attributes_sourceobjectVoor elke attribuut: "shop" of "llm" (bron-markering)Nee
descriptionstringProductbeschrijving (embedded voor filtering)Nee

Vul description zo volledig mogelijk: de chatbot gebruikt deze tekst om zijn advies te onderbouwen (wat het product doet, voor wie het bedoeld is, ingrediënten). Zonder beschrijving kan hij alleen op naam, prijs en attributes adviseren. De eerste 700 tekens worden meegegeven aan het model; de beschrijving zelf verschijnt niet op de productkaart in de widget.

Response:

{
  "success": true,
  "synced": 1
}
VeldBeschrijving
successOf het synchronisatieproces succesvol was
syncedAantal daadwerkelijk gesyncte of bijgewerkte producten

Productlimiet per plan

Het aantal producten per agent is begrensd door je plan:

PlanMax. producten
Free0
Hobby500
Standard2.000
Pro10.000
Enterpriseonbeperkt

Alleen nieuwe external_id's tellen mee: een request dat uitsluitend bestaande producten bijwerkt (een prijs- of voorraadwijziging) gaat altijd door, ook als je al op je limiet zit. Zou het request de limiet overschrijden, dan wordt er niets geschreven en volgt een 402:

{
  "error": "plan_limit_reached",
  "current": 500,
  "max": 500
}

Producten verwijderen

Verwijder eerder gesyncte producten op basis van hun externe IDs.

curl -X DELETE https://denkchat.nl/api/embed/products \
  -H "Authorization: Bearer dk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "external_ids": ["123", "456"]
  }'

Request body:

VeldTypeBeschrijvingVerplicht
external_idsarrayExterne product-IDs om te verwijderen (1 t/m 500)Ja

Response:

{
  "success": true,
  "deleted": 2,
  "notFound": []
}
VeldBeschrijving
deletedAantal daadwerkelijk verwijderde producten
notFoundExterne IDs die niet in deze agent gevonden zijn

Rate limits

PlanBerichten/dag
Free50
Hobby500
Standard4.000
Pro15.000
Enterprise100.000

Bij overschrijding ontvang je een 429 Too Many Requests response.

On this page