Docs1.0
Developers / Docs

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.

Keep it secret.Keys are shown once and belong only on your server. For browsers, mint a widget token instead.

Don’t send a store in your requests; the key already says which one. Requests that try are rejected with 400.

Sign in to create a key →

Environment variable
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).
POST /v1/conversations
curl -X POST https://hawkshift.com/api/futurehawk/v1/conversations \
  -H "Authorization: Bearer $HAWKSHIFT_KEY"
Response · 201
{
  "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.
POST /v1/conversations/{id}/stream
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.
Tip.The field is text (also mirrored as reply), not answer.
Stream · example
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.
Node · handling actions
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).
Expiry.On 401 from a widget token, mint a fresh one from your server and retry. Revoking the source API key invalidates outstanding tokens.
POST /v1/widget-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"}'
Response · 201
{
  "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.

CORS.Public conversation routes answer CORS for widget tokens so the browser can read errors (including 401 and 429). Permanent API keys are for servers — not for browsers.
Dashboard
# Theme Studio → Installation
https://shop.example.com
https://www.shop.example.com
http://localhost:3000

Token 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.

Server only.Your API key stays in this endpoint. The browser only ever sees the short-lived token.
Node · token endpoint
// 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.
Events.The container fires 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.
HTML · any website
<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 body
{
  "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 / day
stream30 / min · 800 / day
widget-tokens60 / min · 2000 / day
task60 / min · 2000 / day
task-stream30 / min · 1000 / day
task-kick20 / min · 500 / day
On 429
# 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.

Promise.Clients that ignore unknown action types and unknown event fields stay compatible.
Base URL
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 minutes
WooCommerceAvailable October 16
MagentoAvailable October 16
WixAvailable October 16
SquarespaceAvailable October 16
Any storefrontConcierge API + widget

AI 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.
Agent endpoint (MCP · REST)
# 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.
Catalogue grounding
# Product claims Concierge asserts
# are checked against your catalogue.
# Framing without product facts is allowed;
# invented SKUs are not.
Last updated October 2026 · Concierge API 1.0Questions? Contact us or read the developer overview.