ہم کیسے مدد کر سکتے ہیں؟

مختصراً بتائیں کہ معاملہ کیا ہے—ہم آپ کو ای میل کے ذریعے جواب دیں گے۔

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
ابتدائی صفحے پر جائیں

Point de terminaison des données clients : commandes, livraison et factures

Référence technique des données clients : requête signée de reactive.chat vers votre boutique, schéma de réponse, limites, motifs d’échec, points de terminaison complets en PHP et Node et import via l’API.

Avec les données clients, l’assistant IA répond à des questions comme « Où est mon colis ? » ou « Ma facture est-elle payée ? », uniquement pour les visiteurs confirmés et au sujet de leurs propres commandes. Cette page est la référence technique pour la personne qui développe le point de terminaison. L’affichage des données par l’assistant et l’autorisation des champs dans le compte sont décrits dans Données clients dans le chat.

Disponible avec les forfaits payants (y compris pendant l’essai).

Prérequis

  1. Vérification d’identité avec exp. Le visiteur doit être connecté avec un userHash valide et exp (Identifier les visiteurs). Sans exp, il est considéré comme confirmé mais sans preuve récente ; aucune donnée n’est alors récupérée.
  2. Réglage du compte sous Projet → Données clients : choisir le mode, saisir le point de terminaison, autoriser les champs, définir la mention pour les visiteurs non connectés.

Modes :

La requête

reactive.chat appelle votre point de terminaison avec POST :

POST /rc-kundendaten HTTP/1.1
Host: shop.your-company.com
Content-Type: application/json
Accept: application/json
User-Agent: reactive.chat-kundendaten/1
X-RC-Zeit: 1792503600
X-RC-Signatur: 5d41402abc4b2a76b9719d911017c592...

{"user_id":"4711","anliegen":"lieferung","referenz":"2026-0815","sprache":"en","nonce":"9f86d081884c7d659a2feaa0c55ad015"}

En-têtes :

Corps :

Votre point de terminaison doit :

  1. vérifier la signature sur le corps brut (en temps constant, par ex. hash_equals), pas sur un JSON réencodé ;
  2. rejeter les requêtes dont X-RC-Zeit diffère de votre horloge de plus de 300 secondes ;
  3. n’accepter chaque nonce qu’une fois (recommandé) ;
  4. renvoyer uniquement les données du user_id fourni ;
  5. être accessible via https sur le port 443 à une adresse publique, sans redirection ni nom d’utilisateur/mot de passe dans l’adresse ;
  6. répondre entièrement en 3 secondes (établissement de la connexion en 2 secondes maximum).

La réponse

Exactement HTTP 200 avec un objet JSON. Sans résultat, renvoyez {"bestellungen":[]}, également avec 200.

{
  "bestellungen": [
    {
      "nummer": "2026-0815",
      "datum": "2026-09-28",
      "status": "shipped",
      "summe": "49.90",
      "waehrung": "EUR",
      "positionen": [ { "name": "Balance bike blue", "menge": 1 } ],
      "versand": { "dienst": "DHL", "sendungsnummer": "00340434161234567890", "status": "out for delivery" },
      "rechnung": { "nummer": "R-2026-1201", "status": "paid", "faellig_am": "2026-10-12" }
    }
  ]
}

Champs par commande :

Limites : au maximum 10 commandes, 20 articles par commande, textes de 200 caractères maximum, réponse entière de 16 384 octets maximum. Les champs inconnus et ceux non autorisés dans votre compte sont écartés sans erreur.

Jamais repris, même si vous les envoyez : rue et autres lignes d’adresse, noms, e-mail, téléphone, IBAN/BIC/compte et données de carte, date de naissance, mots de passe/jetons/clés, numéros fiscaux et d’identité. Mieux vaut ne pas les envoyer du tout.

Traitement de la réponse : elle sert uniquement à cette réponse de l’assistant et n’est stockée ni dans la conversation ni dans la base de connaissances ; le journal n’enregistre que le nombre et la durée. Si votre point de terminaison ne répond pas à temps ou renvoie une erreur, l’assistant répond comme si aucune donnée n’était disponible.

Point de terminaison de référence en PHP

<?php
declare(strict_types=1);

$GEHEIMNIS = (string) getenv('RC_KD_GEHEIMNIS');   // rckd_... from the account

function antworte(int $status, array $daten): never {
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store');
    echo json_encode($daten, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') { antworte(405, ['fehler' => 'POST only']); }

$body = (string) file_get_contents('php://input', false, null, 0, 4097);
if (strlen($body) > 4096) { antworte(413, ['fehler' => 'too large']); }

$zeit = (string) ($_SERVER['HTTP_X_RC_ZEIT'] ?? '');
$sig  = strtolower((string) ($_SERVER['HTTP_X_RC_SIGNATUR'] ?? ''));
if (!preg_match('/^\d{9,11}$/', $zeit) || abs(time() - (int) $zeit) > 300) {
    antworte(401, ['fehler' => 'zeit']);
}
if (!hash_equals(hash_hmac('sha256', $zeit . '.' . $body, $GEHEIMNIS), $sig)) {
    antworte(401, ['fehler' => 'signatur']);
}

$j        = json_decode($body, true);
$userId   = is_string($j['user_id'] ?? null) ? $j['user_id'] : '';
$referenz = is_string($j['referenz'] ?? null) ? trim($j['referenz']) : '';
$nonce    = is_string($j['nonce'] ?? null) ? $j['nonce'] : '';
if ($userId === '' || !preg_match('/^[0-9a-f]{32}$/', $nonce)) {
    antworte(400, ['fehler' => 'anfrage']);
}

$pdo = new PDO(getenv('SHOP_DB_DSN'), getenv('SHOP_DB_USER'), getenv('SHOP_DB_PASS'),
               [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

// nonce only once: CREATE TABLE rc_nonce (nonce CHAR(32) PRIMARY KEY, zeit INT NOT NULL);
$pdo->prepare('DELETE FROM rc_nonce WHERE zeit < ?')->execute([time() - 600]);
try {
    $pdo->prepare('INSERT INTO rc_nonce (nonce, zeit) VALUES (?, ?)')->execute([$nonce, time()]);
} catch (PDOException $e) {
    antworte(409, ['fehler' => 'nonce already used']);
}

if ($userId === 'rc-test') { antworte(200, ['bestellungen' => []]); }   // test button

// ONLY this customer; the reference is only a filter
$sql = 'SELECT id, nummer, datum, status, summe, waehrung, versand_dienst, sendungsnummer,
               versand_status, rechnung_nummer, rechnung_status, faellig_am
          FROM bestellungen WHERE kunde_id = :u';
$w = [':u' => $userId];
if ($referenz !== '') {
    $sql .= ' AND (nummer = :r1 OR rechnung_nummer = :r2 OR sendungsnummer = :r3)';
    $w += [':r1' => $referenz, ':r2' => $referenz, ':r3' => $referenz];
}
$st = $pdo->prepare($sql . ' ORDER BY datum DESC LIMIT 10');
$st->execute($w);

$pos = $pdo->prepare('SELECT name, menge FROM bestell_positionen WHERE bestellung_id = ? LIMIT 20');
$aus = [];
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $b) {
    $pos->execute([$b['id']]);
    $aus[] = [
        'nummer'     => (string) $b['nummer'],
        'datum'      => $b['datum'],
        'status'     => $b['status'],
        'summe'      => $b['summe'],
        'waehrung'   => $b['waehrung'],
        'positionen' => $pos->fetchAll(PDO::FETCH_ASSOC),
        'versand'    => ['dienst' => $b['versand_dienst'], 'sendungsnummer' => $b['sendungsnummer'],
                         'status' => $b['versand_status']],
        'rechnung'   => ['nummer' => $b['rechnung_nummer'], 'status' => $b['rechnung_status'],
                         'faellig_am' => $b['faellig_am']],
    ];
}
antworte(200, ['bestellungen' => $aus]);

Point de terminaison de référence en Node.js (Express)

const crypto = require('crypto');
const express = require('express');
const app = express();
const GEHEIM = process.env.RC_KD_GEHEIMNIS;
const gesehen = new Map();   // nonce -> time; a database in production

app.post('/rc-kundendaten', express.raw({ type: 'application/json', limit: '4kb' }), async (req, res) => {
  const body = req.body.toString('utf8');          // RAW body
  const zeit = String(req.get('X-RC-Zeit') || '');
  const sig  = String(req.get('X-RC-Signatur') || '').toLowerCase();
  if (!/^\d{9,11}$/.test(zeit) || Math.abs(Date.now() / 1000 - Number(zeit)) > 300) {
    return res.status(401).json({ fehler: 'zeit' });
  }
  const soll = crypto.createHmac('sha256', GEHEIM).update(zeit + '.' + body).digest('hex');
  if (sig.length !== soll.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(soll))) {
    return res.status(401).json({ fehler: 'signatur' });
  }
  const j = JSON.parse(body);
  if (!/^[0-9a-f]{32}$/.test(j.nonce || '') || gesehen.has(j.nonce)) {
    return res.status(409).json({ fehler: 'nonce' });
  }
  gesehen.set(j.nonce, Date.now());
  if (j.user_id === 'rc-test') { return res.json({ bestellungen: [] }); }

  const bestellungen = await ladeBestellungen(j.user_id, j.referenz);   // ONLY this customer
  res.json({ bestellungen: bestellungen.slice(0, 10) });
});

Tester la connexion

Tester la connexion dans votre compte appelle votre point de terminaison avec le user_id rc-test et anliegen test. Renvoyez une liste vide ou une commande d’exemple pour cet appel. En cas d’échec, votre compte indique une de ces raisons :

Import via l’API

Si votre boutique ne peut pas proposer de point de terminaison, envoyez-nous les données. Il vous faut une clé d’API avec la portée import des données clients uniquement (kundendaten:schreiben) et le mode Import ou Les deux.

curl -X PUT "https://reactive.chat/v1/kundendaten/4711?project_id=123" \
  -H "Authorization: Bearer rc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"bestellungen":[{"nummer":"2026-0815","datum":"2026-09-28","status":"shipped"}]}'

Les données importées sont stockées chiffrées (le numéro client uniquement sous forme de hachage) et supprimées 90 jours après le dernier import. Envoyez donc les modifications en continu, par exemple à chaque changement de statut.

Erreurs : 402 plan_required (aucun forfait payant), 409 import_disabled (le mode n’autorise pas l’import, avec kd_modus), 400 bad_request avec param (user_id, project_id, bestellungen), 404 (projet d’un autre utilisateur). Le format général des erreurs est décrit dans API serveur.

Visiteurs non connectés

Si une personne sans identité confirmée pose une question sur une commande, l’assistant ne récupère rien ; il affiche votre mention du compte (texte par langue, lien de connexion facultatif) ou transfère à votre équipe.

Suite : Webhooks · API serveur

آخری بار تازہ کاری: