Concierge API quickstart
Start a conversation, send a message and stream Concierge’s answer. Two calls. This is Concierge API 1.0 — the stable retailer boundary.
1Get a key
Sign in and create a key in your dashboard (Integrations). Each key belongs to exactly one store, and it decides where your requests go.
Don’t send a store in your requests; the key already says which one. Requests that try are rejected with 400.
export HAWKSHIFT_KEY="fhk_live_…"
2Start a conversation
A conversation holds one shopper’s thread. Create it once and keep its id. The path owns conversation identity on every later turn.
idThe conversation. It goes in the URL of every turn.createdAtWhen it started (ISO-8601).curl -X POST https://hawkshift.com/api/futurehawk/v1/conversations \ -H "Authorization: Bearer $HAWKSHIFT_KEY"
{
"conversation": {
"id": "3f2a…",
"createdAt": "2026-09-23T14:02:11Z"
}
}3Send a message
Post the shopper’s message to the conversation’s stream. You can add what you already know: earlier messages, remembered preferences, the products on screen.
messageRequired. What the shopper said.historyOptional. Earlier turns.memoryOptional. What the shopper allowed Concierge to remember.currentProductsOptional. What they’re looking at.curl -N -X POST \ https://hawkshift.com/api/futurehawk/v1/conversations/$ID/stream \ -H "Authorization: Bearer $HAWKSHIFT_KEY" \ -H "Content-Type: application/json" \ -d '{"message":"Waterproof running shoes, 10 wide"}'
4Read the stream
The answer arrives as server-sent events. Only trust done for decisions. Steps and deltas are for progress and progressive display.
stepProgress while Concierge works. Fields vary by step (for example caText, a line you can show the shopper). Not authoritative.final_deltaIncremental text for live typing, tagged with a composition number. When the number changes, drop the text from the earlier one: that draft was replaced.doneFinal envelope: text, products, actions, meta.errorStream failed. Ends the connection.text (also mirrored as reply), not answer.event: step data: {"caText":"Looking for waterproof running shoes in 10 wide.", "requestId":"…"} event: final_delta data: {"delta":"Three fit. ", "composition":0, "requestId":"…"} event: done data: {"text":"Three fit…", "products":[…], "actions":[…]}
5Run the actions
If Concierge wants to change the cart, save an item, propose a price watch or send the shopper somewhere, it says so in actions (and sometimes navigate_to on the envelope). Nothing happens on your store until your code — or the Shopify storefront bridge — applies it.
Carry out the ones you support, and ignore the rest. New action types can appear in 1.0, so skip anything you don’t recognise.
CART_ADDAdd a product to the shopper cart (client-applied on Shopify).ADD_TO_LISTSave / list an item.PROPOSE_ALERTPropose a price watch — confirm before committing.navigate_toEnvelope field: URL your UI should open.for (const action of done.actions || []) { switch (action.type) { case "CART_ADD": await addToCart(action); break; case "ADD_TO_LIST": await saveItem(action); break; case "PROPOSE_ALERT": await showWatchDraft(action); break; default: // skip unknown } } if (done.navigate_to) router.push(done.navigate_to);
Widget tokens
Permanent fhk_… keys never go in a browser. Your backend calls this endpoint with the API key and receives a short-lived JWT for the widget or your SPA.
originRequired. Must be allowlisted for the store.conversation_idOptional. Bind the token to one conversation.shopperOptional. The signed shopper value from an earlier token, passed back so the shopper keeps their memory. The widget sends it to your token endpoint for you.customerOptional. Your signed-in shopper’s id (letters, numbers, - _ .; no colons).link_browserOptional. true when that customer signed in on this browser, so their anonymous history can join their account.ttl_secondsOptional. 60–900; capped by your dashboard setting (default 300).401 from a widget token, mint a fresh one from your server and retry. Revoking the source API key invalidates outstanding tokens.curl -X POST https://hawkshift.com/api/futurehawk/v1/widget-tokens \ -H "Authorization: Bearer $HAWKSHIFT_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"https://shop.example.com"}'
{
"token": "eyJhbGciOi…",
"tokenType": "Bearer",
"expiresIn": 300,
"expiresAt": "2026-09-23T14:07:11.000Z",
"origin": "https://shop.example.com",
"shopper": "…"
}Allowed origins
Widget tokens are origin-bound. Add each storefront origin in Theme Studio (dashboard). HTTPS required; HTTP is allowed only for localhost. The browser Origin on public conversation routes must match the token.
# Theme Studio → Installation
https://shop.example.com
https://www.shop.example.com
http://localhost:3000Token endpoint
The widget asks an endpoint on your own site for its token. That endpoint calls /v1/widget-tokens with your API key and answers the widget with JSON:
tokenRequired. The widget token.expiresAtRequired. When it expires; the widget asks again 30 seconds before.apiBaseUrlRequired. https://hawkshift.com. Without it the widget shows as unavailable.shopperRecommended. Pass it through, so the shopper keeps their memory across visits.The widget calls it with GET, adding conversation_id and shopper to the query when it has them. Forward both.
// Your server: GET /api/concierge-token (Express shown)
app.get("/api/concierge-token", async (req, res) => {
const r = await fetch("https://hawkshift.com/api/futurehawk/v1/widget-tokens", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HAWKSHIFT_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
origin: "https://shop.example.com",
conversation_id: req.query.conversation_id,
shopper: req.query.shopper,
// customer: req.user?.id, // your signed-in shopper, if any
}),
});
const t = await r.json();
if (!r.ok) return res.status(r.status).json(t);
res.json({
token: t.token,
expiresAt: t.expiresAt,
shopper: t.shopper,
apiBaseUrl: "https://hawkshift.com",
});
});Embed snippet
Add a container and the hosted loader to any page. The loader brings in the widget and its styles from HawkShift and mounts every data-futurehawk-widget element on the page. On Shopify, use the app’s theme block instead: nothing to paste.
data-bootstrap-urlRequired. Your token endpoint, on the same origin as the page.data-titleOptional. The chat’s title.data-welcomeOptional. The first line shoppers see.data-positionOptional. right (default) or left.data-accentOptional. Brand colour, plus data-background, data-text, data-default-mode (light / dark), data-radius and data-logo.futurehawk:product-click (call preventDefault() to route it yourself) and futurehawk:effect-committed with the turn’s actions, so your page can update the cart.<div data-futurehawk-widget data-bootstrap-url="/api/concierge-token" data-title="Shopping assistant" data-position="right" data-accent="#6d4aff" ></div> <script async src="https://hawkshift.com/futurehawk/embed.js"></script>
Errors
Pre-stream failures are JSON with a stable error code and a human message. Mid-stream failures arrive as an error SSE event.
400Invalid input or forbidden identity override.401Missing, wrong, expired or revoked credential.403Wrong store, or origin not allowed.409Setup incomplete or widget disabled.429Rate limited — back off and retry.503Catalogue or signing unavailable.{
"error": "credential_invalid",
"message": "API credential is invalid."
}Rate limits
Public routes are guarded per credential. If you hit the ceiling you’ll see 429. Back off; don’t spin.
conversations60 / min · 2000 / daystream30 / min · 800 / daywidget-tokens60 / min · 2000 / daytask60 / min · 2000 / daytask-stream30 / min · 1000 / daytask-kick20 / min · 500 / day# wait, then retry the same request sleep 2 # do not open parallel streams for the same shopper turn
Concierge API 1.0
1.0 is the stable retailer contract. Additive fields and new action or event types may appear. Breaking changes require a new API generation. The URL path still includes /v1/ — that’s the wire version, not the product name.
https://hawkshift.com/api/futurehawk/v1
Platforms
Concierge connects to the store’s own platform for its catalogue, stock and cart. On Shopify it installs as an app, available now; WooCommerce, Magento, Wix and Squarespace open on October 16. Any other storefront uses this API and the widget.
ShopifyApp · install in minutesWooCommerceAvailable October 16MagentoAvailable October 16WixAvailable October 16SquarespaceAvailable October 16Any storefrontConcierge API + widgetAI agents Live from October 9
Shoppers’ own AI agents reach a store’s Concierge at three levels. Each one answers from the same catalogue, live checks and store knowledge as the widget, and none of them can change a cart or an order on its own.
MCPLevel 1, Agent connector. Paste one URL into ChatGPT or Claude.UCP · RESTLevel 2, Open commerce protocol. Shopping agents find your store the standard way.WebMCPLevel 3, On your storefront. Agents in the browser use Concierge’s tools.# an outside agent asks the store POST /ucp/<store>/ask { "query": "Is the Ridge Runner true to size?" } # Concierge's checked answer, read-only { "answer": { "plain": "Runs half a size narrow…" }, "links": [ … ] }
Also available
Beyond the quickstart path, the same 1.0 boundary includes longer agent tasks, shopper data controls and standing intents. Same auth rules. Same additive contract.
/taskSnapshot of an agent task on the conversation./task-streamLive task progress over SSE./task-kickResume runnable background work./shopper/dataShopper-facing data controls.# Product claims Concierge asserts # are checked against your catalogue. # Framing without product facts is allowed; # invented SKUs are not.











