Customer data in the chat (orders, shipping, invoices)
Let the AI assistant answer signed-in customers' questions about their own orders – securely via a signed identity, with precisely defined fields, fetched from your shop or imported.
With customer data, the AI assistant answers questions such as “Where is my parcel?”, “Has my invoice been paid?” or “What was in my last order?” – for signed-in customers and only about their own data. The feature is available on the paid plans.
How the data is protected
- The browser proves nothing. No order or invoice number, no email address and nothing shown on the page or written in the chat grants access. Who may see which data is decided solely by an identity that your server has signed.
- A number is only a filter. If a customer names an order number, it is looked up only among that customer's own orders. Someone else's number returns nothing.
- You decide every field. The assistant receives only the fields you enable. Everything else is discarded on arrival – even if your shop sends it.
- No data store on our side (fetch). With fetching, reactive.chat asks your shop for each question and does not store the answer. With import, the data is stored encrypted on our side and deleted after 90 days at the latest.
- Our own machines only. The data goes only to our own AI servers (or your own AI node), never to a third-party AI service.
Prerequisite: identity verification
The assistant uses customer data only for visitors whose identity your server has confirmed. Set up a secret under Project → Identity verification in your account. It stays on your server and never belongs in the browser or in the snippet.
For every signed-in customer, your server computes a hash with an expiry time (at most 24 hours ahead) and passes it to the widget:
$userId = (string) $customer->id;
$exp = time() + 3600;
$hash = hash_hmac('sha256', $userId . '.' . $exp, getenv('RC_IDENT_SECRET'));
echo "<script>ReactiveChat('identify', { userId: " . json_encode($userId)
. ", userHash: " . json_encode($hash) . ", exp: " . $exp . " });</script>";
const crypto = require('crypto');
const exp = Math.floor(Date.now() / 1000) + 3600;
const hash = crypto.createHmac('sha256', process.env.RC_IDENT_SECRET)
.update(String(user.id) + '.' + exp).digest('hex');
// in the template: ReactiveChat('identify', { userId: '<id>', userHash: '<hash>', exp: <exp> });
A hash without exp still confirms the visitor (for example for the conversation history) but is not sufficient for customer data. When you renew the secret, the old one remains valid for 24 hours.
Signing the email too (for appointment booking and email-based integrations). An email next to the hash only counts as confirmed if it is part of the signature: userHash = HMAC-SHA256(secret, userId + "." + exp + "." + email) – the address exactly as you pass it to identify. Without it the visitor stays signed in, but the assistant will not book an appointment for that address and integrations will not look it up. The existing form userId + "." + exp keeps working unchanged.
Fetch, import or both
Under Project → Customer data you choose where the assistant gets the data from:
- Fetch from your shop – reactive.chat calls your endpoint for each matching question. The data stays with you. Recommended.
- Import via API – your shop sends a customer's orders to reactive.chat. Useful if your shop cannot offer an endpoint.
- Both – imported data first; if nothing is found there, the fetch.
Which data the assistant may receive
You enable each field individually. The defaults cover the usual questions:
bestellung.nummer– order number. Default: always on. Used for: required – no order without a numberbestellung.datum– order date (YYYY-MM-DD). Default: on. Used for: “When did I order?”bestellung.status– order status as text. Default: on. Used for: “Has my order shipped?”bestellung.summe– total amount. Default: on. Used for: “How much did I pay?”bestellung.waehrung– currency (ISO, e.g. EUR). Default: on. Used for: only together with the totalpositionen.name– item name. Default: on. Used for: “What was in the order?”positionen.menge– quantity per item. Default: on. Used for: “How many did I order?”versand.dienst– carrier. Default: on. Used for: “Who is delivering the parcel?”versand.sendungsnummer– tracking number. Default: on. Used for: “Where is my parcel?”versand.status– shipping status as text. Default: on. Used for: “Is it on its way?”versand.ort– city of the delivery address. Default: off. Used for: “Where is my parcel going?”versand.plz– postcode of the delivery address. Default: off. Used for: as aboverechnung.nummer– invoice number. Default: on. Used for: “Which invoice belongs to it?”rechnung.status– payment status as text. Default: on. Used for: “Has my invoice been paid?”rechnung.faellig_am– due date. Default: on. Used for: “When do I have to pay?”
A disabled field never reaches the assistant: when fetching it is discarded, when importing it is not stored at all. City and postcode are deliberately possible only when you enable them explicitly – street and name always stay out.
What is never passed on
These cannot be enabled. If your shop sends them, they are discarded:
- street, house number and further address lines
- name of the recipient or customer
- email address and phone number
- IBAN, BIC, account number and card data
- date of birth
- passwords, tokens and access keys
- tax and ID numbers
Limits
At most 10 orders per response, at most 20 items per order, texts at most 200 characters, the whole response at most 16 kB. Unknown fields are discarded without an error.
The fetch endpoint
reactive.chat calls your endpoint with POST:
POST https://shop.your-domain.com/rc-customer-data
Content-Type: application/json
X-RC-Zeit: 1791196400
X-RC-Signatur: <hex(HMAC_SHA256(endpoint secret, X-RC-Zeit + "." + body))>
{"user_id":"4711","anliegen":"bestellung","referenz":"2026-0815","sprache":"en","nonce":"..."}
user_idis the confirmed customer ID from identity verification – never something taken from the chat.anliegenisbestellung(order),lieferung(delivery),rechnung(invoice),retoure(return) ortestfor the test button.referenzis a number the customer mentioned, or empty. Look it up only among the orders of thisuser_id.
Your endpoint must:
- verify the signature (constant-time comparison) and reject requests whose
X-RC-Zeitdiffers by more than 5 minutes, - return only data of the given
user_id, - be reachable via
httpson port 443 at a public address, without redirects, - respond within 3 seconds.
Response:
{
"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": "00340434...", "status": "out for delivery" },
"rechnung": { "nummer": "R-2026-1201", "status": "paid", "faellig_am": "2026-10-12" }
}
]
}
A complete PHP example is available in the developer documentation (kundendaten-referenz-endpunkt.php).
With Test connection, reactive.chat calls your endpoint with the user_id rc-test and the request type test and shows the result. Return an empty list or a sample order for it.
Import via API
With an API key that has the kundendaten:schreiben permission:
PUT https://reactive.chat/v1/kundendaten/4711?project_id=123
Authorization: Bearer <API key>
Content-Type: application/json
{"bestellungen":[ ... as above ... ]}
project_id is the number of your project; if your workspace has only one project, you can leave it out. A PUT replaces all orders of this customer ID (at most 50). DELETE /v1/kundendaten/4711?project_id=123 removes them. Imported data is stored encrypted on our side and deleted 90 days after the last import – so send changes continuously, for example on every status change.
Visitors who are not signed in
If someone without a confirmed identity asks about an order, the assistant fetches nothing. Instead it shows a notice that you configure under Project → Customer data: a text per language and optionally a sign-in link. Alternatively it hands the question over to your team.
What is stored
- Fetch: your shop's response is used only for the one answer of the assistant and is not stored – neither in the conversation nor in the knowledge base.
- Import: encrypted, at most 90 days, deleted together with the project.
- The assistant's answer appears in the conversation history like any message. Your team sees it in the dashboard.
Troubleshooting
- The assistant asks the customer to sign in although they are signed in: if
expis missing, has expired or the hash does not match, the visitor is not considered confirmed. Check the secret, the orderuserId + "." + expand your server's clock. - The test button reports “address not allowed”: the endpoint must be reachable via
httpsat a public address; internal addresses and other ports are rejected. - Your side reports a signature error: the signed string is
X-RC-Zeit + "." + bodywith the endpoint secret – exactly the body as received, not re-encoded. - A field is missing in the assistant's answer: is it enabled under “Which data the assistant may receive”?
Read more in the documentation
In depth: Customer data endpoint. All chapters are in the documentation.
Последна актуализация: