Handleiding voor ontwikkelaars

API voor bezoekersidentificatie

Identificeer ingelogde gebruikers via code, zodat ze nooit de vraag om hun e-mailadres zien en hun gesprekken automatisch aan een contact worden gekoppeld.

Wanneer gebruik je dit

Heeft je website ingelogde gebruikers (SaaS-apps, dashboards, ledenportalen), dan weet je al wie ze zijn. Gebruik het commando identify om hun e-mailadres aan Sonny door te geven, zodat ze het niet opnieuw hoeven in te vullen.

  • Sla de vraag om een e-mailadres helemaal over voor ingelogde gebruikers
  • Koppel chatgesprekken automatisch aan hun contact
  • Zie de naam en het e-mailadres van de bezoeker meteen in je inbox
  • Laat de geschiedenis doorlopen in andere browsers en op andere apparaten met een geverifieerde identiteit

Doorlopen op elk apparaat

Geverifieerde bezoekersidentiteit

Basisidentificatie via e-mail is handig, maar de browser kan elk willekeurig e-mailadres opgeven. Een geverifieerde identiteit voegt een kortlevende JWT toe die je server ondertekent. Sonny kan het contact van de klant dan veilig als eigenaar van de chatgeschiedenis op je website gebruiken, zodat dezelfde gesprekken in een andere browser of op een ander apparaat verschijnen.

Uit

De standaard. Er verandert niets voor bestaande embeds of bezoekers; de geschiedenis blijft gekoppeld aan de bezoekers-ID van de browser.

Optionele verificatie (aanbevolen)

Geldige JWT's krijgen geschiedenis op alle apparaten. Bezoekers zonder JWT houden de bestaande anonieme ervaring of identificatie via e-mail.

Bewijs vereisen om te identificeren

Anoniem chatten werkt nog steeds, maar voor identify en aanroepen met eigen kenmerken is een geldige ondertekende JWT vereist.

De verificatiemodus maakt verplichte velden vooraf niet optioneel. Bekijk hoe elke modus aan een verplicht e-mailadres voldoet onder verplichte gegevens vooraf.

1. Genereer een ondertekeningsgeheim

Open Kanalen → je kanaal → Livechat, zoek Veilige bezoekersidentiteit, kies een modus en genereer een geheim. De platte tekst wordt één keer getoond. Bewaar het in het geheimenbeheer van je backend als SONNY_IDENTITY_SECRET. Zet het ondertekeningsgeheim nooit in browsercode, een embedcode, een openbare omgevingsvariabele of je broncoderepository.

2. Maak een kortlevende JWT op je backend

Onderteken met HS256. Sonny vereist user_id, email, iat en exp. De user_id moet een vaste ID uit je eigen database zijn, geen e-mailadres. Tokens zijn maximaal 24 uur geldig; 15 minuten is een goede standaard. Klokken mogen tot 60 seconden van elkaar afwijken.

Je kunt ook een door de server ondertekend traits-object meesturen voor betrouwbare context voor support, zoals merchantName, subdomain, plan, platform en role. Traitwaarden moeten strings, eindige getallen, booleans of null zijn. Sonny bewaart ze bij de geverifieerde contactidentiteit van de website. Kenmerken die de browser aanlevert, blijven ongeverifieerd en worden nooit omgezet naar deze ondertekende traits.

Node.js
import { SignJWT } from 'jose';

export async function createSonnyIdentityToken(user) {
  const secret = new TextEncoder().encode(process.env.SONNY_IDENTITY_SECRET);

  return new SignJWT({
    user_id: String(user.id),
    email: user.email,
    traits: {
      merchantName: user.merchant.name,
      subdomain: user.merchant.subdomain,
      plan: user.merchant.plan,
      platform: user.merchant.platform,
      role: user.role
    }
  })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('15m')
    .sign(secret);
}
Ruby
require 'jwt'

def sonny_identity_token(user)
  now = Time.now.to_i
  payload = {
    user_id: user.id.to_s,
    email: user.email,
    traits: {
      merchantName: user.merchant.name,
      subdomain: user.merchant.subdomain,
      plan: user.merchant.plan,
      platform: user.merchant.platform,
      role: user.role
    },
    iat: now,
    exp: now + 15 * 60
  }

  JWT.encode(payload, ENV.fetch('SONNY_IDENTITY_SECRET'), 'HS256')
end
Python
import os
from datetime import datetime, timedelta, timezone
import jwt

def sonny_identity_token(user):
    now = datetime.now(timezone.utc)
    return jwt.encode({
        "user_id": str(user.id),
        "email": user.email,
        "traits": {
            "merchantName": user.merchant.name,
            "subdomain": user.merchant.subdomain,
            "plan": user.merchant.plan,
            "platform": user.merchant.platform,
            "role": user.role,
        },
        "iat": now,
        "exp": now + timedelta(minutes=15),
    }, os.environ["SONNY_IDENTITY_SECRET"], algorithm="HS256")
PHP
use Firebase\JWT\JWT;

function sonnyIdentityToken($user): string {
    $now = time();
    return JWT::encode([
        'user_id' => (string) $user->id,
        'email' => $user->email,
        'traits' => [
            'merchantName' => $user->merchant->name,
            'subdomain' => $user->merchant->subdomain,
            'plan' => $user->merchant->plan,
            'platform' => $user->merchant->platform,
            'role' => $user->role,
        ],
        'iat' => $now,
        'exp' => $now + (15 * 60),
    ], $_ENV['SONNY_IDENTITY_SECRET'], 'HS256');
}

3. Geef alleen de JWT door aan de widget

Lever de JWT aan via een endpoint dat beschermd is door de normale sessie van je applicatie. Roep identify aan vóór of na init. De widget houdt de JWT alleen in het geheugen: hij wordt nooit opgeslagen in localStorage, cookies of een URL.

JavaScript
// Fetch a short-lived JWT from your authenticated backend.
// Your signing secret never reaches this code.
const { userJwt } = await fetch('/api/sonny-identity').then((res) => res.json());

sonny('identify', { userJwt });
sonny('init', { siteId: 'YOUR_SITE_ID' });

// Sonny asks for a fresh token after expiry or an emergency key change.
window.addEventListener('sonny:identity-required', async () => {
  const { userJwt } = await fetch('/api/sonny-identity').then((res) => res.json());
  sonny('identify', { userJwt });
});

Veilig vernieuwen, uitloggen en roteren

  • Vernieuwen: vernieuw de JWT voordat hij verloopt—na ongeveer 10 minuten bij een token van 15 minuten—en roep daarna sonny('identify', { userJwt }) aan. Luister ook naar sonny:identity-required als terugvaloptie bij verlopen tokens of een gewijzigde ondertekeningssleutel.
  • Uitloggen: roep sonny('reset') aan. Dit gooit de JWT uit het geheugen weg, wist de widgetsessie van de browser en start een nieuwe anonieme bezoeker.
  • Van account wisselen: roep sonny('reset') aan voor gebruiker A voordat je de JWT van gebruiker B ophaalt en sonny('identify', { userJwt }) aanroept. Neem het token van de ene gebruiker nooit mee naar een andere ingelogde sessie.
  • Regelmatige rotatie: Sonny accepteert het vorige geheim nog 24 uur, zodat je tijd hebt om elke backendinstantie bij te werken. Een tweede regelmatige rotatie is geblokkeerd totdat die overlap voorbij is.
  • Vermoedelijk gelekt geheim: kies Direct vervangen. Beide oude ondertekeningssleutels authenticeren meteen geen nieuwe requests meer; verbonden widgets vragen de hostpagina om een nieuwe JWT.
  • Verificatie uitschakelen: Sonny gooit het huidige en vorige ondertekeningsgeheim weg en verbreekt de verbinding met geverifieerde widgets. Genereer een nieuw geheim voordat je verificatie weer inschakelt.

Identiteitsconflicten worden niet automatisch samengevoegd

Verwijzen een vaste gebruikers-ID en een e-mailadres naar verschillende Sonny-contacten, dan geeft de verificatie een conflict terug in plaats van klantgegevens ongemerkt samen te voegen. Corrigeer het token of voeg de contacten samen in Sonny en probeer het daarna opnieuw.

Een chat die alleen gekoppeld is via een eerder, niet-ondertekend e-mailadres, geldt niet automatisch als geverifieerde geschiedenis. Zo kan een e-mailadres uit de browser nooit de gesprekken van een andere klant ontgrendelen.

Inloggen op het helpcentrum

Koppel je bestaande klantlogin aan helppagina's op ons domein of op je eigen domein. Gebruik hetzelfde ondertekeningsgeheim van de website en dezelfde kortlevende JWT als de widget. Basisidentificatie via e-mail en inloggen als Sonny-medewerker geven geen toegang als geverifieerde lezer.

  1. Rond hierboven de instelling van geverifieerde bezoekersidentiteit af voor dit kanaal. Schakel Optionele verificatie of Bewijs vereisen om te identificeren in onder Kanalen → je kanaal → Livechat.
  2. Bouw in je app een geauthenticeerd endpoint dat { "userJwt": "SIGNED_TOKEN" } teruggeeft. Maak het token op je server aan op basis van de ingelogde klant en betrouwbare traits; accepteer nooit een gevraagd abonnement of gevraagde rol uit de browser.
  3. Kies in Kanalen → je kanaal → Helpcentrum → Toegang tot helpcentrum voor Geverifieerde klanten en eventueel een Klantdoelgroep. Vul de inlogpagina van je app in als Inlog-URL voor klanten en kies Toegang opslaan.
  4. Voer nadat de klant is ingelogd de uitwisseling hieronder uit en vervang YOUR_SLUG door het Adres van je helpcentrum. De inlog-URL alleen is niet genoeg: je app moet deze uitwisseling afronden.
JavaScript
// Run after your application authenticates the customer.
// This endpoint must use the server's session and trusted customer traits.
const response = await fetch('/api/sonny-identity');
if (!response.ok) throw new Error('Unable to sign in to the help center');
const { userJwt } = await response.json();
const signIn = new URL('https://www.usesonny.com/help/YOUR_SLUG/auth');
signIn.searchParams.set('token', userJwt);
signIn.searchParams.set('return', '/help/YOUR_SLUG');
window.location.assign(signIn);

Stel bij een eigen domein signIn in op https://help.example.com/auth en keer terug naar / of /articles/getting-started. Terugkeerpaden op ons domein beginnen met /help/YOUR_SLUG. Terugkeerbestemmingen moeten op dezelfde host blijven.

De uitwisseling zet een beveiligde, HTTP-only cookie en stuurt door om het token uit de URL te halen. De lezerssessie verloopt samen met de JWT, na maximaal 24 uur. Gebruik kortlevende tokens en log de uitwisselings-URL niet. De JWT hoort alleen in deze ene inloguitwisseling, niet in gedeelde artikellinks.

Inloggen en toegang testen

  1. Ga uitgelogd naar een privé-helpcentrum. Volg de inlogknop, log in op je app en controleer of je terugkomt in het helpcentrum op hetzelfde domein, van ons of je eigen.
  2. Controleer één toegestaan en één geweigerd artikel via bladeren, zoeken en een directe URL. Een klant buiten de doelgroep van het helpcentrum ziet een melding over toegang; een geweigerd artikel geeft niet gevonden terug.
  3. Gebruik Uitloggen in het helpcentrum en controleer of privé-inhoud verdwijnt. Herhaal dit met een klant met andere traits.

Vernieuwen en uitloggen

De widget stuurt zijn huidige JWT automatisch mee. Vernieuw hem als Sonny erom vraagt, en roep sonny('reset') aan als je klant uitlogt. De widgetidentiteit en de helpcentrumcookie staan los van elkaar: de widget resetten logt niet uit bij een helpcentrumsessie op ons domein.

Ga om uit te loggen bij pagina's op ons domein naar /help/YOUR_SLUG/auth/logout; gebruik op je eigen domein /auth/logout. Neem die actie op in de uitlogflow van je app als je beide sessies wilt beëindigen. Ongeldige of verlopen inloggegevens krijgen bezoekerstoegang. Met identiteitsverificatie uit krijgt elke lezer bezoekerstoegang.

Veranderen de traits van een klant, maak dan een nieuwe JWT aan en identificeer opnieuw in de widget; herhaal de inloguitwisseling voor pagina's op ons domein. Bestaande lezerscookies houden de vorige ondertekende traits tot ze verlopen. Wijzigingen in doelgroepregels gelden vanaf het volgende request.

Doelgroepen aanmaken, toegang bekijken en beperkingen oplossen

Identificatie via e-mail is geen authenticatie

Het e-mailadres dat de browser aanlevert, geeft je support meer context, maar authenticeert de bezoeker niet. Een bezoeker kan op zijn eigen pagina JavaScript bekijken en uitvoeren, dus e-mailadres, naam en eigen kenmerken ontgrendelen nooit de Sonny-geschiedenis van een andere klant. Een geverifieerde identiteit vereist de door de server ondertekende JWT die hierboven is beschreven. Regel autorisatie voor acties in je eigen product binnen je ingelogde applicatie.

Als bezoekersverificatie is ingeschakeld, betekent een Geverifieerd-badge in de inbox dat het gesprek is gekoppeld met een door de server ondertekende JWT. Een Niet geverifieerd-badge betekent dat geen door de server ondertekende identiteit het gesprek heeft geauthenticeerd. Een getoonde naam of e-mailadres is door de bezoeker aangeleverde context voor support, geen bewijs van identiteit.

Codevoorbeelden

De eenvoudigste aanroep — geef alleen het e-mailadres van de gebruiker mee:

JavaScript
// Identify a logged-in user
sonny('identify', {
  email: 'jane@example.com'
});

Geef ook de naam van de gebruiker mee, zodat medewerkers die in de inbox zien:

JavaScript
// Identify with full name
sonny('identify', {
  email: 'jane@example.com',
  name: 'Jane Smith'
});

Voeg bij het identificeren nuttige context voor support toe, werk die later bij, of volg een waarde die verandert terwijl de pagina open is:

JavaScript
// Identify with support context
sonny('identify', {
  email: 'jane@example.com',
  name: 'Jane Smith',
  attributes: {
    plan: 'starter',
    seats: 5,
    trial: true
  }
});

// Update only the values that changed
sonny('setAttributes', {
  plan: 'growth',
  seats: 8,
  trial: null // Clears this property
});

// Keep a changing value in sync (checks every 10 seconds)
sonny('watchAttributes', () => ({
  monthly_usage: window.currentUsage
}), { interval: 10000 });

Volledig voorbeeld met de asynchrone code. Let op: identify kan vóór init worden aangeroepen — de identiteit komt in de wachtrij en wordt verzonden zodra de widget verbinding maakt:

HTML
<!-- Sonny widget snippet -->
<script>
  (function(w,d,s,o,f,js,fjs){
    w['Sonny']=o;w[o]=w[o]||function(){
    (w[o].q=w[o].q||[]).push(arguments)};
    js=d.createElement(s);fjs=d.getElementsByTagName(s)[0];
    js.id=o;js.src=f;js.async=1;fjs.parentNode.insertBefore(js,fjs);
  })(window,document,'script','sonny','https://www.usesonny.com/widget.js');

  // Identify before init — identity is queued and sent on connect
  sonny('identify', {
    email: 'jane@example.com',
    name: 'Jane Smith'
  });

  sonny('init', { siteId: 'YOUR_SITE_ID' });
</script>

Roep reset aan als de gebruiker uitlogt, om de identiteit te wissen en een nieuwe sessie te starten:

JavaScript
// Reset on logout — clears identity and starts a fresh session
sonny('reset');

Hoe het werkt

  1. 01

    De widget laadt en maakt verbinding

    De widget maakt verbinding met Sonny en stuurt bij het verbinden een eventueel opgeslagen identiteit mee.

  2. 02

    De identiteit gaat naar de server

    Sonny zoekt in je werkruimte naar een contact met dat e-mailadres en maakt er een aan als het nog niet bestaat.

  3. 03

    Gesprekken worden gekoppeld

    Niet-gekoppelde gesprekken in de bezoekerssessie van de huidige browser worden aan het geïdentificeerde contact gekoppeld. Identificatie voegt geen geschiedenis van verschillende browsers of apparaten samen.

  4. 04

    De e-mailvraag wordt overgeslagen

    Omdat de bezoeker al geïdentificeerd is, verschijnt de e-mailvraag in de widget niet — geen onderbreking voor de gebruiker.

Regels voor eigen kenmerken

  • Stuur maximaal 50 kenmerken per aanroep.
  • Een waarde kan een string, getal, boolean of null zijn. Strings zijn maximaal 1000 tekens lang. Geef null of een lege string mee om een opgeslagen waarde te wissen.
  • Sleutels moeten met een letter beginnen, mogen alleen letters, cijfers en underscores bevatten en zijn maximaal 64 tekens lang.
  • Deze sleutels zijn gereserveerd en worden genegeerd: email, name, id, phone, createdAt, updatedAt.

API-referentie

sonny('identify', { email, name?, attributes? })
Identificeert de huidige bezoeker. Stelt het e-mailadres en een optionele naam in, slaat de e-mailvraag over en stuurt de identiteit naar de server. Kan vóór of na init worden aangeroepen.
  • emailstringE-mailadres van de bezoeker
  • namestring?Weergavenaam van de bezoeker
  • attributesobject?Eigen kenmerken om aan het contact te koppelen (zie de installatiehandleiding van de widget voor de regels voor sleutels en waarden)
sonny('identify', { userJwt, name?, attributes? })
Identificeert de huidige ingelogde klant veilig aan de hand van een JWT die je server heeft gemaakt. Het token blijft in het geheugen en wordt alleen verzonden in geauthenticeerde requests of socketpayloads.
  • userJwtstringEen verse HS256-JWT, gemaakt door je geauthenticeerde backend
  • namestring?Weergavenaam van de bezoeker
  • attributesobject?Eigen kenmerken om aan het geverifieerde contact te koppelen
sonny('setAttributes', { ... })
Werkt de eigen kenmerken van de geïdentificeerde bezoeker bij. Alleen gewijzigde waarden worden verzonden. Is de bezoeker nog niet geïdentificeerd, dan wachten de updates en worden ze verzonden nadat identify is uitgevoerd.
  • attributesobjectSleutel-waardeparen om in te stellen. Geef null als waarde mee om een kenmerk te wissen.
sonny('watchAttributes', getter, { interval? })
Roept je getterfunctie op een timer aan en synchroniseert gewijzigde kenmerken automatisch. Handig als waarden zoals abonnement of gebruik veranderen terwijl de pagina open is.
  • getterfunctionEen functie die het huidige object met kenmerken teruggeeft
  • intervalnumber?Hoe vaak er gecontroleerd wordt, in milliseconden. Standaard 10000, minimaal 2000.
sonny('reset')
Wist de widget-ID, het e-mailadres, de naam en de lokale gespreksgeschiedenis van de huidige browser en start daarna een nieuwe bezoekerssessie. Het contact en zijn opgeslagen eigenschappen in Sonny worden niet verwijderd. Gebruik dit bij uitloggen.

Hulp nodig?

Bekijk de installatiehandleiding van de widget of neem contact op met ons team.

Gerelateerde handleidingen