Reference
Security model
A widget’s site key is public, and Origin or User-Agent headers can be forged outside a browser. AskMerra therefore layers controls so that abuse is expensive, detectable and financially bounded.
1. Domain lock and per-shop CORS
Requests whose Origin (or Referer) is not one of the shop’s allowed domains are rejected with 403 origin_not_allowed. Because the site key travels in the query string, CORS is evaluated per shop even for preflight requests: a page on another domain does not get an Access-Control-Allow-Origin header and the browser blocks the call before it is sent.
2. Browser screening
Requests from command-line tools and HTTP libraries (curl, python, axios, Postman…), with missing user agents, or with fetch metadata a browser would never send (Sec-Fetch-Mode other than cors) get 403 client_not_allowed. Headless browsers and missing fetch metadata add risk but are not blocked on their own. This filter is spoofable by design. It removes low-effort abuse cheaply.
3. Proof-of-work sessions
Chat endpoints require a signed session token (HMAC-SHA256) bound to the shop, the visitor id and the page’s site, valid for 30 minutes. A token from one site or visitor cannot be replayed for another (401 session_mismatch). Obtaining one requires solving a single-use proof-of-work challenge: around 131,000 hash attempts by default, a fraction of a second for a real visitor, a real cost for a bot opening thousands of sessions. In protection mode the difficulty rises 16×.
4. Rate limits
| Limit | Default | Keyed by |
|---|---|---|
| Messages per visitor | 20 / minute | shop + visitor id |
| Messages per IP | 60 / minute | hash of the IP address |
| Messages per shop | 600 / minute | shop |
| New conversations per visitor | 30 / day | shop + visitor id |
| New conversations per IP | 60 / day | shop + IP hash (rotating visitor ids does not help) |
| Widget sessions per IP | 60 / hour | IP hash |
| Challenges per IP | 60 / minute | IP hash |
5. Spend circuit breakers and protection mode
These bound the money anyone can burn, however well they imitate a browser:
| Breaker | Default | Effect |
|---|---|---|
| Shop AI cost per hour | $5 | Protection mode for 60 minutes |
| Shop AI cost per day | $25 | Protection mode until midnight UTC |
| New conversations per shop per hour | 500 | Protection mode |
| Platform AI cost per hour | global | All shops protected, our on-call team alerted |
In protection mode the AI model is never called. Greetings, FAQ, precomputed and cached answers keep working; other questions get a localized “we’re very busy” reply with the contact form (unavailable: busy), and proof-of-work gets harder. The owner receives one alert email per window and can resume the assistant from the dashboard.
6. Included usage and spending caps
When the plan’s included usage is used up (with pay-as-you-go off or no prepaid credits left) or the shop’s monthly spending cap is reached, AI answers stop regardless of everything above.
AI safety
- Catalog and knowledge content is fenced as data in the prompt; instructions inside product descriptions are ignored.
- Tools are read-only: the model can search and read, never write.
- Product ids in the model’s output are validated against the products it received; prices and stock always come from the database.
Platform security
- Dashboard sessions: httpOnly,
SameSite=Lax,__Host-prefixed cookies over HTTPS; double-submit CSRF tokens plus Origin checks. - Passwords hashed with argon2id; login brute-force limits per IP and per account.
- Secret API keys stored as SHA-256 hashes with constant-time comparison; shown once.
- Tenant isolation enforced on every query and verified by an automated test that calls every route across tenants.
- No raw IP addresses stored; country from CDN headers only.
Stricter setups