Müşteri verileri uç noktası: siparişler, kargo ve faturalar
Müşteri verileri bağlantısının teknik referansı: reactive.chat tarafından mağazanıza gönderilen imzalı istek, yanıt şeması, sınırlar, hata nedenleri, eksiksiz PHP ve Node örnek uç noktaları ve API ile içe aktarma.
Müşteri verileri sayesinde yapay zekâ asistanı, “Kargom nerede?” veya “Faturam ödendi mi?” gibi soruları yanıtlar; bunu yalnızca doğrulanmış ziyaretçiler için ve yalnızca kendi siparişleri hakkında yapar. Bu sayfa, uç noktayı geliştiren kişi için teknik referanstır. Asistanın neleri gösterdiği ve hesabınızda hangi alanları etkinleştirebileceğiniz Sohbette müşteri verileri sayfasında açıklanır.
Ücretli planlarda kullanılabilir (deneme süresi dâhil).
Gereksinimler
- exp ile kimlik doğrulama. Ziyaretçinin geçerli bir
userHashveexpile oturum açmış olması gerekir (Ziyaretçileri tanımlama).expolmadan doğrulanmış sayılır, ancak kimliği güncel sayılmaz; bu durumda veri alınmaz. - Hesabınızdaki ayar, Proje → Müşteri verileri altında: modu seçin, uç noktayı girin, alanları etkinleştirin ve oturum açmamış ziyaretçilere gösterilecek bildirimi belirleyin.
Modlar:
- Veri alma – reactive.chat, ilgili her soru için uç noktanızı sorgular. Yanıt saklanmaz. Önerilen seçenektir.
- İçe aktarma – mağazanız bir müşterinin siparişlerini API üzerinden bize gönderir; bunlar bizde şifreli olarak en fazla 90 gün saklanır.
- İkisi de – önce içe aktarılan veriler kullanılır; orada bir şey bulunamazsa uç noktadan veri alınır.
- Kapalı.
İstek
reactive.chat uç noktanızı POST ile çağırır:
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"}
Üstbilgiler:
- X-RC-Zeit – isteğin gönderildiği andaki Unix zamanı, saniye cinsinden.
- X-RC-Signatur –
hex(HMAC_SHA256(endpoint_secret, X-RC-Zeit + "." + raw_body)), 64 küçük harfli karakter, ön ek olmadan. Anahtar, hesabınızdaki uç nokta gizli anahtarının dize hâlidir (rckd_ile başlar).
Gövde:
- user_id (dize) –
identifyile gelen doğrulanmış kimlik. Asla sohbetten alınan bir değer kullanılmaz. - anliegen (dize) –
bestellung(sipariş),lieferung(teslimat),rechnung(fatura),retoure(iade); test düğmesi içintest. - referenz (dize veya
null) – müşterinin sohbette belirttiği bir numara. Yalnızca buuser_idkimliğine ait siparişler içinde bir filtredir; başka birinin numarası hiçbir sonuç döndürmemelidir. - sprache (dize) – iki harf, örneğin
de. - nonce (dize) – her istekte yenilenen 32 onaltılık karakter.
Uç noktanızın yapması gerekenler:
- imzayı yeniden kodlanmış JSON üzerinden değil, ham gövde üzerinden doğrulamak (sabit zamanlı karşılaştırma, örneğin
hash_equals); X-RC-Zeitdeğeri kendi saatinizden 300 saniyeden fazla farklı olan istekleri reddetmek;- her
noncedeğerini yalnızca bir kez kabul etmek (önerilir); - yalnızca verilen
user_idkimliğine ait verileri döndürmek; - herkese açık bir adreste, 443 numaralı bağlantı noktasında
httpsüzerinden erişilebilir olmak; yönlendirme ve adreste kullanıcı adı/şifre bulunmamalıdır; - 3 saniye içinde eksiksiz yanıt vermek (bağlantı kurulması en fazla 2 saniye).
Yanıt
Tam olarak HTTP 200 ve bir JSON nesnesi. Eşleşme yoksa yine 200 ile {"bestellungen":[]} döndürülür.
{
"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" }
}
]
}
Sipariş başına alanlar:
- nummer (dize, zorunlu) – numarası olmayan siparişler atılır.
- datum (dize,
YYYY-MM-DD). - status (dize) – düz metin olarak sipariş durumu.
- summe (dize veya sayı), waehrung (ISO 4217, örneğin
EUR). - positionen (liste, en fazla 20) – her öğe
namevemengeiçerir. - versand (nesne) –
dienst,sendungsnummer,status, isteğe bağlı olarakortveplz(yalnızca hesabınızda açıkça etkinleştirilmişse). - rechnung (nesne) –
nummer,status,faellig_am.
Sınırlar: en fazla 10 sipariş, sipariş başına 20 kalem, metinler en fazla 200 karakter, yanıtın tamamı en fazla 16.384 bayt. Bilinmeyen ve hesabınızda etkinleştirilmemiş alanlar hata verilmeden atılır.
Gönderseniz bile asla alınmayan veriler: sokak ve diğer adres satırları, adlar, e-posta, telefon, IBAN/BIC/hesap ve kart bilgileri, doğum tarihi, şifreler/tokenlar/anahtarlar, vergi ve kimlik numaraları. En iyisi bunları hiç göndermemektir.
Yanıtın kullanımı: yalnızca asistanın o tek yanıtında kullanılır ve saklanmaz; ne sohbete ne de bilgi tabanına kaydedilir. Kayıtta yalnızca sayı ve süre tutulur. Uç noktanız zamanında yanıt vermez veya hata döndürürse asistan veri yokmuş gibi yanıtlar.
PHP ile örnek uç nokta
<?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]);
Node.js (Express) ile örnek uç nokta
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) });
});
Bağlantıyı test etme
Hesabınızdaki Bağlantıyı test et düğmesi, uç noktanızı user_id rc-test ve anliegen test ile çağırır. Bunun için boş bir liste veya örnek bir sipariş döndürün. Çağrı başarısız olursa hesabınızda şu nedenlerden biri belirtilir:
- kein_endpunkt, kein_geheimnis – hesabınızda bir eksik var.
- url_ungueltig, nur_https, port_verboten, zugangsdaten_in_url – adrese izin verilmiyor (yalnızca
https, bağlantı noktası 443, adreste erişim bilgisi olmamalı). - host_unaufloesbar, adresse_privat, adresse_gewechselt – ad çözümlenmiyor veya özel bir adrese çözümleniyor.
- tls, verbindung, zeitueberschreitung – sertifika, bağlantı veya 3 saniyelik süre sınırı.
- umleitung – uç noktanız 3xx döndürüyor.
- http_<code> – 200 dışında bir durum (örneğin
http_401: imza kontrolünüz isteği reddediyor). - antwort_zu_gross, antwort_kein_json, antwort_ohne_bestellungen – yanıt şemaya uymuyor.
- tarif – proje ücretli bir planda değil.
API ile içe aktarma
Mağazanız bir uç nokta sunamıyorsa verileri bize gönderirsiniz. Yalnızca müşteri verilerini içe aktarma (kundendaten:schreiben) kapsamına sahip bir API anahtarı ve İçe aktarma ya da İkisi de modu gerekir.
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"}]}'
- PUT /v1/kundendaten/{user_id} – bu müşterinin tüm siparişlerinin yerine geçer (en fazla 50; boş bir liste bunları siler). Yanıt:
{"data":{"stored":1,"dropped":0,"max_orders":50,"expires_in_days":90}}. - DELETE /v1/kundendaten/{user_id} – bunları kaldırır; plan olmasa bile her zaman çalışır. Yanıt:
{"data":{"deleted":1}}. - project_id – çalışma alanınızda birden fazla proje olduğunda zorunludur.
- user_id –
identifyiçinde imzaladığınız kimliğin aynısı; URL kodlamalı, en fazla 200 karakter. Kodlanmış eğik çizgi (%2F) kullanılamaz. GETyoktur.
İçe aktarılan veriler şifreli saklanır (müşteri numarası yalnızca özet olarak) ve son içe aktarmadan 90 gün sonra silinir. Bu nedenle değişiklikleri düzenli gönderin; örneğin her durum değişikliğinde.
Hatalar: 402 plan_required (ücretli plan yok), 409 import_disabled (mod içe aktarmaya izin vermiyor, kd_modus ile), param (user_id, project_id, bestellungen) ile 400 bad_request, 404 (başkasının projesi). Genel hata biçimi Sunucu API’si altında açıklanır.
Oturum açmamış ziyaretçiler
Doğrulanmış kimliği olmayan biri bir sipariş hakkında soru sorarsa asistan veri almaz; bunun yerine hesabınızdaki bildirimi gösterir (dile göre metin, isteğe bağlı oturum açma bağlantısı) veya ekibinize aktarır.
Sonraki: Webhooks · Sunucu API’si
చివరిగా నవీకరించినది: