Webhookit
Webhookit lähettävät jokaisen päättyneen keskustelun palvelimellesi JSON-muodossa AI-yhteenvedon ja vastaajan tietojen kera. Niiden avulla voit päivittää CRM:si, avata tikettejä tai ladata tulokset omaan tietokantaasi viemättä mitään käsin.
Mikä laukeaa ja milloin#
Diaform lähettää yhden tapahtuman, conversation.completed. Se laukeaa, kun AI-haastattelija päättää keskustelun ja yhteenveto on valmis, yleensä hetki viimeisen viestin jälkeen.
- Koko organisaation laajuinen. Jokainen päätepiste saa tapahtumat organisaatiosi kaikista projekteista. Erota projektit toisistaan tietosisällön
agent_id-kentällä. - Myös perutut keskustelut laukaisevat sen. Jos vastaaja pyytää lopettamaan, keskustelu päättyy perutuksi ja saat silti tapahtuman
conversation.completedarvolla"status": "cancelled". Tarkistastatusennen kuin käsittelet vastausta valmiina. - Kesken jätetyt keskustelut eivät laukaise sitä. Jos vastaaja sulkee sivun ilman, että keskustelu päättyy, mitään ei lähetetä.
- Hallintapaneelin esikatselut eivät laukaise sitä. Testaa käymällä keskustelu loppuun projektin oikean linkin kautta.
Paketit ja oikeudet#
Webhookit ovat käytettävissä kaikissa maksullisissa paketeissa, mutta eivät ilmaisen kokeilun aikana. Jokaisella paketilla on päätepisteraja:
| Paketti | Päätepisteet |
|---|---|
| Starter | 3 |
| Pro | 5 |
| Business | 10 |
| Enterprise | 25 |
Vain omistajat ja ylläpitäjät voivat lisätä, keskeyttää tai poistaa päätepisteitä. Katso Jäsenet ja roolit ja Tilauksen hallinta.
Lisää päätepiste#
Avaa webhookit
Siirry sivupalkissa kohtaan Asetukset → Webhookit.
Anna URL-osoite
Klikkaa Lisää päätepiste, liitä URL-osoitteesi Uusi webhook-päätepiste -ikkunaan ja klikkaa Lisää päätepiste. URL-osoitteen on alettava https://.
Tallenna salaisuus
Webhook-salaisuus-ikkuna näyttää allekirjoitussalaisuutesi. Klikkaa Kopioi, tallenna salaisuus palvelimesi ympäristöön ja klikkaa sitten Valmis.
Jokaisella päätepisteellä on oma salaisuutensa, joka on muotoa whsec_ ja sen perässä 43 merkkiä. Voit näyttää tai kopioida sen myöhemmin uudelleen päätepisteen rivin Allekirjoitussalaisuus-kohdasta.
Keskeytä tai poista päätepiste#
- Keskeytä: vaihda päätepisteen rivin kytkin tilasta Aktiivinen tilaan Keskeytetty. Keskeytyksen aikana tapahtuneita tapahtumia ei lähetetä jälkikäteen.
- Poista: klikkaa roskakorikuvaketta ja vahvista valitsemalla Poista päätepiste.
Päätepisteen URL-osoitetta ei voi muokata. Jos haluat siirtyä uuteen URL-osoitteeseen, lisää uusi päätepiste, päivitä palvelimellesi sen salaisuus ja poista sitten vanha.
Toimitus#
| Toiminta | Tiedot |
|---|---|
| Metodi | POST, JSON-runko |
| Jakelu | Lähetetään kaikkiin aktiivisiin päätepisteisiin samanaikaisesti |
| Aikakatkaisu | 5 sekuntia. Vastaa millä tahansa 2xx-tilakoodilla ennen sitä. |
| Uudelleenyritykset | Ei ole. Aikakatkaisun tai muun kuin 2xx-vastauksen jälkeen pyyntöä ei lähetetä uudelleen. |
| Toimitusloki | Ei saatavilla hallintapaneelissa |
| Ajoitus | Jos valmiin keskustelun käsittely epäonnistuu, Diaform yrittää käsittelyä uudelleen 30 minuutin välein, yhteensä enintään 4 kertaa. Webhook voi silloin saapua selvästi keskustelun päättymisen jälkeen. |
Vastaa ensin ja tee hidas työ vasta sen jälkeen, esimerkiksi laittamalla tapahtuma jonoon.
Anna Diaformille lopullinen URL-osoite. Uudelleenohjauksia seurataan, mutta 301 tai 302 muuttaa POST-pyynnön GET-pyynnöksi, ja runko katoaa.
Pyyntö#
POST /webhooks/diaform HTTP/1.1
Content-Type: application/json
X-Webhook-Event: conversation.completed
X-Webhook-Signature: 4fa4d553f8abf7a199e5d51ee2401320af843de438e63a2ed6bc33f4f943d906| Otsake | Arvo |
|---|---|
Content-Type | application/json |
X-Webhook-Event | conversation.completed |
X-Webhook-Signature | Raa'an rungon HMAC-SHA256 heksamuodossa, allekirjoitettu päätepisteen salaisuudella |
Aikaleima- tai toimitus-ID-otsaketta ei ole. Käytä conversation_id-arvoa idempotenssiavaimena: tallenna käsittelemäsi ID:t ja ohita toistot.
Tietosisältö#
{
"conversation_id": "0f8d43a2-6df9-49c8-bf5d-fd2b6ec2d9ee",
"agent_id": "b8acb3ab-1f3d-4a7e-a846-b7f493f86b6d",
"organization_id": "4d6ecdb4-8543-4adf-ae65-1f24106d5474",
"status": "completed",
"respondent": {
"email": "alex@acme.com",
"metadata": {},
"identities": [
{ "type": "email", "value": "alex@acme.com", "source": "owner" },
{ "type": "identifier", "value": "customer-123", "source": "owner" },
{ "type": "name", "value": "Alex Morgan", "source": "ai" }
],
"invite_id": "3a4f49c7-b8f4-4c44-8f74-fd8e4277c3e4"
},
"summary": {
"respondent_email": null,
"respondent_identities": [
{ "type": "email", "value": "alex@acme.com" },
{ "type": "identifier", "value": "customer-123" },
{ "type": "name", "value": "Alex Morgan" }
],
"answers": [
{
"question_id": "V1StGXR8_Z5jdHi6B-myT",
"question_text": "How did your first week with the product go?",
"summary": "Setup was quick, but Alex struggled to invite teammates.",
"sentiment": "mixed",
"confidence": "high",
"quotes": ["I had everything running in ten minutes."]
}
],
"overall_sentiment": "mixed",
"urgent_issues": ["Teammate invites fail for Google Workspace accounts."],
"additional_insights": "Alex would pay more for an API."
},
"completed_at": "2026-05-07T12:15:41.123Z"
}Ylätason kentät#
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
conversation_id | string | Keskustelun ID. Käytä sitä kaksoiskappaleiden poistoon. |
agent_id | string | Sen projektin ID, johon keskustelu kuuluu |
organization_id | string | Organisaatiosi ID |
status | string | completed tai cancelled |
respondent | object | Kuka vastaaja on, katso alla |
summary | object | AI-yhteenveto, katso alla |
completed_at | string | Keskustelun päättymisaika ISO 8601 -muodossa |
respondent#
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
email | string tai null | Vastaajan sähköpostiosoite, jos se on tiedossa |
metadata | object | Tyhjä suorissa linkeissä. Upotetuissa keskusteluissa siinä on upotuksen tietoja, kuten "embed": true ja embed_parent_origin. |
identities | array | Kaikki vastaajasta tiedossa oleva muodossa type, value ja source |
identities[].type | string | Esimerkiksi email, name, identifier, user_id, account_id tai company |
identities[].source | string | owner: sinä annoit sen kutsulinkin tai upotuksen tunnisteen kautta. ai: poimittu vastaajan viesteistä. system: Diaformin lisäämä. |
invite_id | string tai null | Kutsun tunnus, kun keskustelu alkoi kutsulinkistä. Katso Vastaajakutsu-API. |
summary#
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
respondent_email | null | Vanha kenttä, aina null. Lue sähköpostiosoitteet kentästä identities. |
respondent_identities | array | Vastaajan tunnisteet muodossa type ja value, ilman kenttää source |
answers | array | Yksi merkintä kutakin kysymystä kohden |
answers[].question_id | string | Kysymyksen ID projektissasi |
answers[].question_text | string | Kysymyksen teksti |
answers[].summary | string | Lyhyt yhteenveto vastauksesta |
answers[].sentiment | string | positive, negative, neutral tai mixed |
answers[].confidence | string | Kuinka kattavasti kysymykseen vastattiin: high, medium tai low |
answers[].quotes | array tai null | Vastaajan huomionarvoiset lainaukset. null, kun niitä ei ole. |
overall_sentiment | string | positive, negative, neutral tai mixed |
urgent_issues | array, null tai puuttuu | AI:n merkitsemät kriittiset ongelmat |
additional_insights | string, null tai puuttuu | Palaute, joka ei sovi minkään tietyn kysymyksen alle |
Litterointi ja projektin nimi eivät ole mukana. Lue, miten Diaform kerää tunnisteita, kohdasta Vastaajien tunnistaminen.
Tarkista allekirjoitus#
Tarkista jokainen pyyntö ennen kuin luotat siihen. Diaform allekirjoittaa pyynnön rungon täsmälleen sellaisenaan HMAC-SHA256:lla käyttäen avaimena päätepisteen salaisuutta ja lähettää heksamuotoisen tiivisteen otsakkeessa X-Webhook-Signature.
- Lue raaka runko tavuina ennen JSON-jäsennystä.
- Laske näiden tavujen HMAC-SHA256 salaisuudellasi heksamuodossa.
- Hylkää pyyntö, jos otsake puuttuu tai sen pituus on eri.
- Vertaa kahta arvoa vakioaikaisella funktiolla.
Käytä koko salaisuutta whsec_-etuliite mukaan lukien tavallisena UTF-8-merkkijonona. Älä pura sitä base64-koodauksesta.
Node.js (Express)#
const crypto = require("node:crypto");
const express = require("express");
const app = express();
const secret = process.env.DIAFORM_WEBHOOK_SECRET;
function isValidSignature(rawBody, signature) {
if (!Buffer.isBuffer(rawBody) || typeof signature !== "string") {
return false;
}
const expected = Buffer.from(
crypto.createHmac("sha256", secret).update(rawBody).digest("hex")
);
const received = Buffer.from(signature);
return (
received.length === expected.length &&
crypto.timingSafeEqual(received, expected)
);
}
app.post(
"/webhooks/diaform",
express.raw({ type: "application/json" }),
(req, res) => {
if (!isValidSignature(req.body, req.get("X-Webhook-Signature"))) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body.toString("utf8"));
res.sendStatus(200);
// Respond first, then do the slow work.
console.log(event.conversation_id, event.status);
}
);
app.listen(3000);Ota express.raw() käyttöön tällä reitillä. Jos express.json() jäsentää rungon ensin, tavut muuttuvat ja jokainen allekirjoitus epäonnistuu.
Python (Flask)#
import hashlib
import hmac
import json
import os
from flask import Flask, request
app = Flask(__name__)
SECRET = os.environ["DIAFORM_WEBHOOK_SECRET"].encode("utf-8")
def is_valid_signature(raw_body, signature):
if not signature:
return False
expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected.encode("utf-8"), signature.encode("utf-8"))
@app.post("/webhooks/diaform")
def diaform_webhook():
raw_body = request.get_data()
if not is_valid_signature(raw_body, request.headers.get("X-Webhook-Signature")):
return "Invalid signature", 401
event = json.loads(raw_body)
print(event["conversation_id"], event["status"])
return "", 200Jos tarkistus epäonnistuu#
- Allekirjoita raa'at tavut, älä uudelleen sarjallistettua JSON-objektia.
- Käytä sen päätepisteen salaisuutta, joka vastaanotti pyynnön. Jokaisella päätepisteellä on omansa.
- Tarkista, ettei tallentamassasi salaisuudessa ole ylimääräisiä välilyöntejä tai rivinvaihtoja.