Hannah API: developer sandbox
Hannah is a governed agent, not a chat box. Every call runs five layers server side: authority and consent, memory, tools, the channel, and the lifecycle clocks. You send a buyer message, you get back what Hannah did and why. A sandbox key points at a fictional dealership, so you can build all day without touching a real customer.
1. Get a key
Keys are issued by Quantum, one per integration. A sandbox key starts with qk_test_ and a live key starts with qk_live_. The key is shown once. Send it as a bearer token on every call.
Authorization: Bearer qk_test_...
2. Check the wire
curl https://automotivesalesintelligence.com/api/public/hannah/health \
-H "Authorization: Bearer qk_test_..."
-> { "ok": true, "environment": "sandbox", "allowedChannels": ["web_chat","sms","email"] }3. Find something to talk to
The sandbox has a fixed cast of buyers. Ask for them instead of hard coding ids.
curl https://automotivesalesintelligence.com/api/public/hannah/sandbox \
-H "Authorization: Bearer qk_test_..."
-> { "ok": true, "opportunities": [ { "opportunityId": "...", "buyer": "Marcus Ellery", "vehicle": "2024 Chevrolet Silverado 1500", "stage": "new_lead" } ] }4. Send a buyer message
curl -X POST https://automotivesalesintelligence.com/api/public/hannah/turn \
-H "Authorization: Bearer qk_test_..." \
-H "Content-Type: application/json" \
-d '{
"opportunityId": "<from step 3>",
"channel": "web_chat",
"text": "Is the blue one still available?"
}'
-> 200
{
"ok": true,
"environment": "sandbox",
"conversationId": "uuid",
"status": "sent | held_for_approval | denied | escalated",
"reply": "...",
"reason": "why Hannah did that",
"policyEffect": "allow | deny | require_approval",
"confidence": 0.82,
"correlationId": "uuid"
}Keep the conversationId and send it back on the next message so the thread stays together. A denied or held answer is a normal, expected outcome, not an error: read reason and show it to your operator.
5. Push events instead of asking
If your system already owns the inbox, push what happened and let Hannah react.
POST https://automotivesalesintelligence.com/api/public/hannah/events
{ "type": "buyer.message", "opportunityId": "uuid", "channel": "sms", "text": "..." }
{ "type": "lead.created", "opportunityId": "uuid", "payload": { } }6. Receive what Hannah does
Give Quantum an HTTPS endpoint and every finished turn is posted to it, signed so you can prove it came from us. Verify before you trust the body.
Headers
x-quantum-event: turn.completed | turn.escalated
x-quantum-signature: hex HMAC-SHA256 of the raw body, using your signing secret
Node
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
Answer 200 within 10 seconds. Retries are automatic and duplicates are possible,
so treat the correlationId as the idempotency key.Rules of the road
- Sandbox keys can only see the sandbox dealership. Ids from anywhere else return 404.
- No message from the sandbox ever reaches a phone or an inbox. Delivery is simulated and logged.
- Every key has a daily call cap. Over it, you get 429 with the count.
- 401 means the key is missing or unknown, 403 means revoked, expired or a channel you are not allowed on.
- The sandbox can be reset at any time, so do not store its ids permanently.
Machine readable spec: https://automotivesalesintelligence.com/api/public/hannah/openapi
