Alle onderwerpen

API

Met de API koppel je een ander systeem aan je organisatie, zoals een supportdesk, een CRM of je eigen software. Dat systeem kan bijna alles wat je in het dashboard doet: toestellen en nummers inrichten, belgroepen en workflows beheren, gesprekken, opnames en voicemail ophalen, en het adresboek bijhouden.

Koppelen

  1. Ga naar Instellingen en dan API.
  2. Geef de sleutel een naam, zoals de naam van het systeem, en kies per onderdeel wat hij mag: niets, lezen, of lezen en schrijven, net als bij een rol. Je kunt alleen geven wat je zelf mag.
  3. Kopieer de sleutel en plak hem in het andere systeem. Je ziet hem maar één keer: kwijt is een nieuwe maken.

Wat een sleutel doet, staat in Activiteit onder zijn naam. Trek je hem in, dan werkt hij vanaf de volgende aanroep niet meer. Een sleutel kan nooit eigenaar zijn: de organisatie verwijderen, iemand eigenaar maken of een eigenaar wijzigen of verwijderen kan alleen in het dashboard.

De API

Alle aanroepen gaan naar https://api.talkip.nl/v1, met de sleutel als Bearer-token in de header Authorization. De sleutel hoort bij één organisatie, dus er staat geen organisatie in de paden. Wat je meestuurt en terugkrijgt is JSON, behalve audio en de pdf van een factuur. Tijden zijn ISO 8601 in UTC, bedragen in eurocent.

Alles hieronder staat ook in een OpenAPI-document, voor Swagger, Postman of om een client mee te maken: talkip-api.json downloaden. Het wordt uit de API zelf gemaakt, dus het loopt nooit achter. In de API-referentie bekijk je het hier, en probeer je aanroepen uit met je eigen sleutel.

curl https://api.talkip.nl/v1/me \
  -H "Authorization: Bearer tkt_..."
Sleutel
Begint met tkt_ en is 44 tekens lang. Bewaar hem zoals je een wachtwoord bewaart.
Limiet
600 aanroepen per minuut per sleutel. Voor wat geld of AI-credits kost of mail verstuurt, zoals nummers kopen, uitnodigen, transcripties en media maken of uploaden en AI-agents aanmaken of wijzigen, geldt daarnaast elk een limiet van 100 per uur.
Fouten
Een foutcode met een JSON-body, zoals { "error": "forbidden", "message": "API_KEY_PERMISSION_ERROR" }. Klopt de body, een parameter of de query niet, dan is error validation en staat in issues wat er mis is.
400
De body of de parameters kloppen niet.
401
Geen, een onbekende of een ingetrokken sleutel.
403
Niet toegestaan. API_KEY_PERMISSION_ERROR: de sleutel mist de toegang, of wie hem maakte heeft die niet meer. API_KEY_CREATOR_GONE_ERROR: wie de sleutel maakte, is geen lid meer van de organisatie. PLAN_FEATURE_UNAVAILABLE_ERROR: het abonnement heeft het niet, of heeft geen API meer. TENANT_INACTIVE_ERROR: de organisatie is opgeschort.
404
Bestaat niet, of is niet van deze organisatie.
409
Kan nu niet, bijvoorbeeld een toestelnummer dat al bestaat of te weinig AI-credits.
429
Te veel aanroepen. Wacht het aantal seconden uit Retry-After (ook in retryAfterSeconds) en probeer het dan opnieuw.

Toegang

Een sleutel heeft per onderdeel van het dashboard geen toegang, lezen, of lezen en schrijven, net als een rol. Elke aanroep vraagt lezen of schrijven op zijn onderdeel, zoals Belgroepen voor /ring-groups; dat staat hieronder bij elk deel. Mag wie de sleutel maakte iets niet meer, dan de sleutel ook niet. Zonder toegang kan een sleutel alleen GET /me, het verbruik, de AI-credits, de limieten en de opname-instellingen lezen.

Wat er in gesprekken is gezegd, zoals opnames, transcripties, samenvattingen en AI-gesprekken, vraagt lezen op Gespreksopnames. Zonder dat staan die velden in de gesprekshistorie op null.

Als reseller

Een reseller kan met zijn eigen sleutel, die met tk_ begint, de API van elke organisatie gebruiken die hij beheert. Zet dan in de header TalkIP-Tenant-Id het id van de organisatie. Zo'n sleutel mag alles hierboven, ook als het abonnement van de organisatie geen API heeft. Wat je zo doet, staat in de activiteit van de organisatie onder je naam.

curl https://api.talkip.nl/v1/calls/live \
  -H "Authorization: Bearer tk_..." \
  -H "TalkIP-Tenant-Id: 01a1..."

Zonder geldige header krijg je een 400 met TENANT_REQUIRED_ERROR. Een organisatie die niet van jou is of die je hebt beëindigd, geeft een 404.

De sleutel

GET /me

Bij welke organisatie de sleutel hoort en wat hij mag. Handig om een geplakte sleutel te controleren.

{
  "tenant": {
    "id": "01a1...",
    "name": "Bakkerij Jansen",
    "slug": "bakkerij-jansen",
    "sipDomain": "bakkerij-jansen.<sip-domein>",
    "plan": "pro",
    "seats": 3,
    "features": { "transcription": true, "aiAgents": true, "api": true, ... }
  },
  "apiKey": {
    "id": "01a1...",
    "name": "Loxxa",
    "prefix": "tkt_dryEJS",
    "access": { "devices": "write", "live-calls": "write", "call-history": "read" }
  }
}

Leden

Lezen vraagt Leden lezen, de rest Leden schrijven. Rollen maken en wijzigen kan alleen een eigenaar, in het dashboard.

GET /members
Leden en openstaande uitnodigingen, met owner en hun role.
GET /roles
De rollen, met wat elk per onderdeel mag en hoeveel leden hem hebben.
POST /members
Nodigt iemand uit met email en eventueel een roleId. De mail komt namens de organisatie.
POST /members/:memberId/resend
Verstuurt een uitnodiging opnieuw.
PUT /members/:memberId/role
Geeft een lid een rol met roleId, of null voor geen. Niet bij een eigenaar en niet bij wie de sleutel maakte.
DELETE /members/:memberId
Verwijdert een lid of trekt een uitnodiging in, geen eigenaar.

Toestellen, toestelnummers en nummers

Toestellen, agents en toestelnummers vallen onder Toestellen, nummers en aanvragen onder Nummers: lezen om te bekijken, schrijven voor de rest. De limieten lezen mag elke sleutel.

GET /devices
Alle toestellen.
POST /devices
Maakt een toestel met name, userId (of null voor een toestel van niemand) en callerId: een nummer van de organisatie of een dat TalkIP heeft goedgekeurd, anders 409. Geeft de SIP-gegevens terug, met het wachtwoord, dat alleen nu te zien is.
PATCH /devices/:deviceId
Wijzigt naam, eigenaar, nummerweergave of aan/uit.
POST /devices/:deviceId/password
Een nieuw SIP-wachtwoord. Het oude werkt meteen niet meer.
POST /devices/:deviceId/join-code
Een koppelcode voor de app.
DELETE /devices/:deviceId
Verwijdert een toestel.
GET /extensions
Alle toestelnummers met hun bestemming.
POST /extensions
Maakt een toestelnummer met extension en destination.
PUT /extensions/:extensionId/destination
Waar het toestelnummer heen gaat.
DELETE /extensions/:extensionId
Verwijdert een toestelnummer.
GET /numbers
De nummers van de organisatie met hun bestemming.
GET /numbers/available
Nummers die je kunt kopen. Nummers schrijven.
POST /numbers
Koopt een nummer. Niet bij een organisatie die een reseller beheert.
PUT /numbers/:numberId/destination
Waar het nummer heen gaat.
PUT /numbers/:numberId/caller-rules
De bellerregels van het nummer, als callerRules: hoogstens 20, op volgorde, elk met name, match en destination. De regels staan ook in GET /numbers.
DELETE /numbers/:numberId
Geeft een nummer op.
GET /number-requests
Aanvragen voor nummers die niet op voorraad zijn.
POST /number-requests
Vraagt nummers aan.
DELETE /number-requests/:requestId
Trekt een aanvraag in.
GET /limits
De limieten voor belminuten en het verbruik nu.
PUT /limits
Zet de limieten per gesprek, dag en maand. Instellingen schrijven.

Een destination is een object met type en het id dat erbij hoort, zoals { "type": "ringGroup", "ringGroupId": "01a1..." }. De types zijn user, device, ringGroup, ivr, workflow, voicemail, businessHours, aiAgent, queue, conferenceRoom en directory. Een aankondiging is { "type": "announcement", "mediaId": "01a1..." }: het fragment speelt één keer en dan wordt opgehangen. Een nummer buiten TalkIP is { "type": "externalNumber", "number": "06 1234 5678" }, getypt zoals je het kiest en bewaard als E.164. Een nummer buiten de belbestemmingen geeft 400 met EXTERNAL_NUMBER_NOT_ALLOWED_ERROR, een nummer van de organisatie zelf EXTERNAL_NUMBER_IS_OWN_ERROR.

PUT /numbers/01a1.../caller-rules
{
  "callerRules": [
    { "name": "Anoniem", "match": { "type": "anonymous" }, "destination": null },
    {
      "name": "Amsterdam",
      "match": { "type": "numbers", "numbers": ["020*", "0612345678"] },
      "destination": { "type": "queue", "queueId": "01a1..." }
    }
  ]
}

Een regel geldt voor anonymous, bellers zonder nummer, of voor numbers: hoogstens 500, met een * aan het eind voor alles wat zo begint. De eerste regel die past telt. destination null weigert het gesprek.

Routering

Elk deel heeft zijn eigen onderdeel, zoals Belgroepen of Media: bekijken vraagt lezen, maken, wijzigen en verwijderen schrijven. De bodies zijn dezelfde als die het dashboard stuurt, met dezelfde limieten van het abonnement.

GET, POST /ring-groups
Belgroepen.
PUT, DELETE /ring-groups/:ringGroupId
Een belgroep wijzigen of verwijderen. strategy is simultaneous, sequential, roundRobin, longestIdle of random, en met skipBusy gaan leden die al in gesprek zijn niet over.
GET, POST /queues
Wachtrijen, met hun leden en wie er is aangemeld. Maken vraagt Pro of Business.
PUT, DELETE /queues/:queueId
Een wachtrij wijzigen of verwijderen. Wie lid blijft, blijft aangemeld.
GET /queues/:queueId/statistics
Hoe de wachtrij liep, per dag en per collega, met wachttijden en serviceLevel van 0 tot 1. Met from en to als YYYY-MM-DD kies je de dagen, standaard de laatste zeven, hooguit 366.
GET, POST /conference-rooms
Vergaderlijnen. Maken vraagt Pro of Business.
PUT, DELETE /conference-rooms/:conferenceRoomId
Een vergaderlijn wijzigen of verwijderen.
GET, POST /directories
Telefoonboeken.
PUT, DELETE /directories/:directoryId
Een telefoonboek wijzigen of verwijderen.
GET, POST /ivrs
Keuzemenu's.
PUT, DELETE /ivrs/:ivrId
Een keuzemenu wijzigen of verwijderen.
GET, POST /business-hours
Openingstijden.
PUT, DELETE /business-hours/:businessHoursId
Openingstijden wijzigen of verwijderen.
GET, POST /call-actions
Gespreksacties, ook parkeren met de actie park.
PUT, DELETE /call-actions/:callActionId
Een gespreksactie wijzigen of verwijderen.
GET, POST /ai-agents
AI-agents.
PUT, DELETE /ai-agents/:aiAgentId
Een AI-agent wijzigen of verwijderen. Wordt hij net al gewijzigd, dan krijg je 409 met AI_AGENT_BUSY_ERROR: probeer het over een minuut opnieuw.
GET, POST /workflows
Workflows. Maken vraagt de module Workflows.
GET, PUT, DELETE /workflows/:workflowId
Eén workflow, met de hele tekening. Opslaan kan AI-credits kosten voor nieuwe vragen.
GET /workflows/:workflowId/executions
Hoe de workflow is gelopen.
GET /workflows/:workflowId/executions/:executionId
Eén keer, stap voor stap. Wat de beller zei en intoetste alleen met Gespreksopnames lezen.
GET /media
Fragmenten.
POST /media
Uploadt een fragment als multipart, met name en file. Gebruikt de organisatie al twee keer de opslag van haar abonnement, dan krijg je 409 met STORAGE_FULL_ERROR.
GET /media/:mediaId/audio
Het fragment als WAV.
DELETE /media/:mediaId
Verwijdert een fragment dat nergens meer wordt gebruikt.
GET /media/generation/options
Stemmen en soorten om met AI te maken. Media schrijven.
POST /media/generation
Maakt een fragment met AI, voor AI-credits.

Gesprekken

GET /calls/live
Wie er nu belt. Live gesprekken lezen.
GET /calls
De gesprekshistorie, met dezelfde filters als het dashboard. Gesprekshistorie lezen; opname, transcriptie en AI-gesprekken alleen met Gespreksopnames lezen.
GET /calls/:callRecordId/flow
Waar het gesprek heen ging: openingstijden, keuzemenu, wie er overging en wie opnam, de workflows onderweg. Gesprekshistorie lezen.
GET /calls/:callRecordId/ai-conversations
Wat een AI-agent in het gesprek heeft genoteerd.
GET, POST, DELETE /calls/:callRecordId/transcript
De transcriptie lezen, laten maken (voor AI-credits) of verwijderen.
GET, POST, DELETE /calls/:callRecordId/summary
De samenvatting lezen, laten maken (voor AI-credits) of verwijderen.
GET /recordings
Opnames.
GET /recordings/:recordingId/audio
Een opname als stereo-WAV: de beller links, de ander rechts.
DELETE /recordings/:recordingId
Verwijdert een opname.
GET /recording-settings
Of gesprekken standaard worden opgenomen, getranscribeerd en samengevat.
PUT /recording-settings
Zet die standaard. Instellingen schrijven.
GET /voicemail-boxes
Voicemailboxen.
POST, PUT, DELETE /voicemail-boxes[/:boxId]
Een voicemailbox maken, wijzigen of verwijderen.
GET /voicemail/messages
Voicemailberichten.
GET /voicemail/messages/:messageId/audio
Een bericht als WAV.
PUT /voicemail/messages/:messageId/read
Markeert een bericht als gelezen.
DELETE /voicemail/messages/:messageId
Verwijdert een bericht.

Adresboek

Lezen vraagt Contacten lezen, maken, wijzigen en verwijderen Contacten schrijven.

GET /contacts
Het gedeelde adresboek op naam, als items met nextCursor: geef die als cursor mee voor de volgende pagina, tot hij null is. Met search zoek je op naam, bedrijf of nummer, en limit is 100 per pagina, hooguit 500.
GET /contacts/:contactId
Eén contact.
POST /contacts
Maakt een contact met name, company, number en email.
PUT /contacts/:contactId
Wijzigt een contact.
DELETE /contacts/:contactId
Verwijdert een contact.

Bellen vanuit een ander systeem

Zo neemt een supportdesk, zoals Loxxa, de telefonie over: zijn medewerkers bellen en worden gebeld in zijn eigen scherm, via TalkIP.

  1. Maak een sleutel die Toestellen, Live gesprekken en API & webhooks mag lezen en schrijven, en plak hem in het andere systeem. Dat meldt met POST /webhooks zelf een webhook aan.
  2. Het systeem maakt voor elke medewerker een agent met POST /agents, met zijn eigen id in externalId. Een agent is een toestel zonder TalkIP-account en neemt een gebruiker in, net als een lid.
  3. Zet de agents in een belgroep en stuur een nummer naar die belgroep, of geef ze een toestelnummer. Inkomende gesprekken komen dan binnen in de softphone van het andere systeem, en call.started vertelt wie er belt.
  4. In de browser van de medewerker bel je met de softphone-SDK @talkip/softphone. De server van het andere systeem vraagt daarvoor een token met POST /agents/:agentId/softphone, met de origin van de pagina, en geeft het aan de browser.
import { Softphone } from '@talkip/softphone';

const phone = new Softphone({
  // Elke verbinding een nieuw token, via je eigen server.
  getToken: () => fetch('/talkip/softphone-token', { method: 'POST' }).then((response) => response.json()),
  autoAnswer: true,
});

await phone.connect();
phone.dial('0201234567');

Klik-om-te-bellen, ophangen en doorverbinden

Met POST /calls gaat eerst het toestel van de agent over. Neemt die op, dan belt TalkIP de bestemming, alsof de agent zelf had gekozen: met zijn nummerweergave, de limieten en de opnames van de organisatie. Met autoAnswer neemt de SDK, of een bureautoestel dat het kan, meteen op. Naar 112 bel en verbind je zo nooit door: dat geeft 400. Het alarmnummer belt iemand zelf.

POST /calls
{ "deviceId": "01a1...", "destination": "0612345678", "autoAnswer": true }

202
{ "id": "01a1...", "kind": "originate", "status": "claimed", "error": null, "callRecordId": "01a1...", ... }
status
pending, claimed (de centrale is ermee bezig), done of failed. Klik-om-te-bellen is done zodra de agent opneemt; doorverbinden zodra de bestemming overgaat.
error
Bij failed: waarom. not_registered: de agent is niet online. no_answer, busy, declined, unavailable of cancelled: de agent nam niet op. forbidden: dat nummer mag niet, of er is geen nummerweergave. limit_reached: de belminuten zijn op. not_bridged: doorverbinden kan alleen tijdens een gesprek. not_found, unsupported, congestion, timeout of expired: het lukte niet.
callRecordId
Het gesprek. Ook in de webhooks call.started, call.answered en call.ended.
GET /agents
De agents, als toestellen: online of niet. Met externalId zoek je er één.
POST /agents
Maakt een agent met name, externalId, callerId en eventueel een extension. Kan niet als alle gebruikers in gebruik zijn.
PATCH /agents/:agentId
Wijzigt een agent, of zet hem uit met enabled.
DELETE /agents/:agentId
Verwijdert een agent. Zijn gebruiker komt vrij.
POST /agents/:agentId/softphone
Een token voor de SDK.
POST /calls
Klik-om-te-bellen.
POST /calls/:callRecordId/hangup
Hangt een lopend gesprek op, voor iedereen.
POST /calls/:callRecordId/transfer
Verbindt blind door naar destination. Met deviceId vertrekt die kant, zoals de agent; zonder vertrekt wie er gebeld werd.
GET /call-commands/:commandId
Hoe een opdracht is gegaan.

Alles hier vraagt Live gesprekken schrijven; hoe een opdracht ging lezen vraagt Live gesprekken lezen.

Webhooks

Met een webhook hoort het andere systeem meteen wat er gebeurt, zonder steeds te vragen: een gesprek dat binnenkomt, wordt opgenomen of eindigt, een opname of transcriptie die klaar is, een nieuw voicemailbericht. TalkIP stuurt dan binnen een seconde een POST met JSON naar het adres dat je opgeeft. Je maakt een webhook in het dashboard, onder Instellingen en dan API, of met POST /webhooks, zodat een systeem zich bij het koppelen zelf aanmeldt. Een organisatie heeft er hoogstens 10.

{
  "id": "01a1...",
  "type": "call.started",
  "createdAt": "2026-10-20T09:15:02.000Z",
  "tenantId": "01a1...",
  "data": {
    "call": {
      "id": "01a1...",
      "direction": "inbound",
      "from": { "number": "+31612345678", "name": "Jan Klant (Bakkerij)", "device": null, "deviceId": null },
      "to": { "number": "+31201234567", "name": null, "device": null, "deviceId": null },
      "contact": { "id": "01a1...", "name": "Jan Klant", "company": "Bakkerij", "email": null },
      "startedAt": "2026-10-20T09:15:02.000Z",
      "answeredAt": null,
      "endedAt": null,
      "durationSeconds": null,
      "hangupCause": null
    }
  }
}
call.started
Een gesprek begint. In contact staat het contact met het nummer van de ander, als dat er is.
call.answered
Iemand neemt op. In to.deviceId staat het toestel dat opnam.
call.ended
Het gesprek is voorbij, met de duur en waarom het eindigde.
recording.ready
Een opname is klaar. Haal hem op met GET /recordings/:recordingId/audio.
transcript.ready
Een transcriptie is klaar. Haal hem op met GET /calls/:callRecordId/transcript.
summary.ready
Een samenvatting is klaar.
voicemail.received
Er is een voicemailbericht ingesproken.
ai-conversation.ended
Een AI-agent is klaar met een gesprek. Wat hij noteerde, staat bij GET /calls/:callRecordId/ai-conversations.
webhook.test
Alleen als je om een test vraagt.

Een webhook stuurt nooit wat er is gezegd: alleen wat er gebeurde en de id's om de rest op te halen, met een sleutel die Gespreksopnames mag lezen. Kies je geen gebeurtenissen, dan krijg je ze allemaal, ook die er later bij komen.

Controleren dat het van TalkIP komt

Elke webhook heeft een geheim dat begint met whsec_. Je ziet het alleen als hij wordt gemaakt of als je het vernieuwt. Elk bericht heeft de header TalkIP-Webhook-Signature, zoals t=1760951702,v1=5f2b...: v1 is de HMAC-SHA256 met het geheim van t, een punt en de body zoals die binnenkwam, in hex. Klopt hij niet, of is t meer dan vijf minuten oud, gooi het bericht dan weg.

import { createHmac, timingSafeEqual } from 'node:crypto';

const [t, v1] = signature.split(',').map((part) => part.split('=')[1]);
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const valid = timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) && Date.now() / 1000 - Number(t) < 300;

Afleveren en opnieuw proberen

  • Antwoord binnen 10 seconden met een 2xx. Een doorverwijzing wordt niet gevolgd.
  • Lukt het niet, dan proberen we het opnieuw na 10 seconden, 1 minuut, 5 minuten, een half uur, 2, 6, 12 en 24 uur. Daarna geven we het op. In het dashboard of met POST /webhooks/:id/deliveries/:id/retry stuur je een bericht opnieuw.
  • Berichten kunnen in een andere volgorde of twee keer aankomen. De header TalkIP-Webhook-Id is hetzelfde als id in de body. Daarmee herken je een bericht dat je al had.
  • Webhooks gaan alleen naar openbare adressen, en wat er is verstuurd bewaren we 30 dagen.
GET /webhooks
De webhooks, met hoe de laatste aflevering ging. API & webhooks lezen; de rest schrijven.
POST /webhooks
Maakt een webhook met url, description, events en enabled. Het geheim staat alleen in dit antwoord.
PATCH /webhooks/:webhookId
Wijzigt het adres, de gebeurtenissen of zet hem aan of uit.
DELETE /webhooks/:webhookId
Verwijdert een webhook.
POST /webhooks/:webhookId/secret
Een nieuw geheim. Het oude werkt meteen niet meer.
POST /webhooks/:webhookId/test
Stuurt een webhook.test, ook als hij uit staat.
GET /webhooks/:webhookId/deliveries
Wat er is verstuurd, nieuwste eerst.
POST /webhooks/:webhookId/deliveries/:deliveryId/retry
Stuurt een bericht opnieuw.

Verbruik, facturen en activiteit

GET /statistics
De cijfers van het overzicht, voor de hele organisatie. Overzicht lezen.
GET /credits
Het saldo AI-credits.
GET /usage
Het verbruik deze maand, en hoeveel de organisatie heeft van wat het abonnement begrenst.
GET /usage/storage/files
De grootste bestanden. Gespreksopnames lezen.
GET /billing
Het overzicht van Financieel. Financieel lezen.
GET /billing/invoices
Facturen. Financieel lezen.
GET /billing/invoices/:invoiceId
Eén factuur. Financieel lezen.
GET /billing/invoices/:invoiceId/pdf
De factuur als pdf. Financieel lezen.
GET /audits
De activiteit, met het abonnement Business. Instellingen lezen.
  • Betalen, het abonnement, gebruikers en modules wijzigen en AI-credits kopen gaan via het dashboard, niet via de API.
  • Beheert een reseller de organisatie, dan geven de facturen een 403: die staan bij de reseller.