Quickstart
This is the 5-minute path to a working chat widget. If any step takes longer than expected, that’s a docs bug — please open an issue.
What you’ll have at the end
A working chat widget on a real page, talking to a real agent of yours, streaming tokens from Gemini.
-
Mint an API key (≈30 s)
In the dashboard sidebar, go to Build → API keys and click New key. When selecting permissions, enable at minimum:
- Create or edit agents (
agents:write) — needed to create the agent in step 2. - Mint widget sessions (
widget:mint) — needed to mint a widget session in step 3.
Copy the key immediately — it’s shown once. Format:
ck_live_<prefix8>_<secret32>.In your terminal, export it so the next steps can use it:
Terminal window export CORTEX_API_KEY="ck_live_..." - Create or edit agents (
-
Create an agent (≈60 s)
Server-side call (curl or your backend). All fields below are required —
additionalProperties: falseis enforced, so misspellings are rejected.Terminal window curl -sS https://api.cortexlayer.dev/v1/agents \-H "Authorization: Bearer $CORTEX_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "Support bot","systemPrompt": "You are a friendly support agent for ACME Inc.","modelPolicy": {"provider": "gemini","model": "gemini-2.5-flash"},"budget": {"maxCostUsd": 0.05,"maxSteps": 8,"wallClockMs": 30000},"tools": [],"allowedDomains": [],"allowedOrigins": ["https://your-site.com"]}'The response is the created agent. Save its
id(a UUID — that’s youragentIdfor the next step). -
Mint a widget session (≈45 s)
This is the only call that needs your API key. Run it on your backend (so the key never reaches the browser) and inject the returned token into the page.
Terminal window curl -sS https://api.cortexlayer.dev/v1/widget/session \-H "Authorization: Bearer $CORTEX_API_KEY" \-H "Origin: https://your-site.com" \-H "Content-Type: application/json" \-d '{ "agentId": "<your-agent-uuid>" }'Returns
{ "sessionToken": "cs_…", "expiresAt": "...", "messageCap": 50 }. The token is valid for 15 minutes and 50 messages — refresh it on page load. For long-lived pages, refresh in-place viahandle.setSessionToken(newToken)(see Widget reference) so the active conversation isn’t lost when the token rolls over.Important: The
Originheader must be the actual browser origin (the value the browser sends). If omitted or mismatched againstallowedOrigins, the API returns403 origin_not_allowed.app/api/cortex/session/route.ts import { createCortexClient } from '@cortex/sdk';import { createMintRouteHandler } from '@cortex/sdk/next';const client = createCortexClient({baseUrl: 'https://api.cortexlayer.dev',auth: { apiKey: process.env.CORTEX_API_KEY! },});export const POST = createMintRouteHandler({client,agentId: '<your-agent-uuid>',});The browser POSTs to
/api/cortex/session; the handler forwards your realOriginheader to Cortex.The key is forwarding the browser’s
Originheader verbatim to the Cortex API. If you strip it or replace it with your server’s hostname, the allowlist check fails with403 origin_not_allowed.// Node.js + Express exampleapp.post('/api/cortex/session', async (req, res) => {const origin = req.headers.origin; // Read from inbound requestif (!origin) {return res.status(400).json({ error: 'Origin header required' });}const response = await fetch('https://api.cortexlayer.dev/v1/widget/session', {method: 'POST',headers: {'Authorization': `Bearer ${process.env.CORTEX_API_KEY}`,'Origin': origin, // Forward the browser's origin'Content-Type': 'application/json',},body: JSON.stringify({agentId: '<your-agent-uuid>',}),});if (!response.ok) {const error = await response.json();return res.status(response.status).json(error);}const { sessionToken, expiresAt, messageCap } = await response.json();res.json({ sessionToken, expiresAt, messageCap });});The pattern is the same for Python (Flask/FastAPI), Go, Ruby, etc.: read
Originfrom the inbound request headers, forward it on the upstream call toPOST /v1/widget/session, and proxy the response back to your client. -
Drop the script tag (≈30 s)
Inject the token into your page (server-rendered or fetched on load) and paste this:
<script src="https://cdn.cortexlayer.dev/widget.v1.js" integrity="sha384-ldmdUZIvmluHqHci9bid79TfpkEZHPf9ge/I1tXZsz7V9FlWQ8G37ULLBvIjLZLi" crossorigin="anonymous" data-cortex-widget data-api-base="https://api.cortexlayer.dev" data-agent-id="00000000-0000-0000-0000-000000000000" data-session-token="cs_REPLACE_ME" ></script>The
integrityhash above is generated at docs build time from the live widget bundle. If the hash changes, copy the new one — the browser will refuse to execute a bundle whose hash doesn’t match. -
Verify (≈60 s)
Open the page. The launcher button should appear in the bottom-right corner. Click it, type “hello”, hit send. You should see streamed deltas within a second.
If nothing appears, check the browser console:
Refused to load … integrity mismatch— the SRI hash in your snippet doesn’t match the bundle. Rebuild and copy the latest hash from this page.session token rejected— the page’s origin isn’t in the agent’sallowedOrigins. Update the agent.plan_limit_exceeded(429) — you’re past your free-plan budget. CheckGET /v1/usagefor current consumption.
What’s next
- The Widget reference lists every
data-*attribute (theming, position, greeting overrides). - The API reference documents the agent/session endpoints.
- The SDK reference covers the
@cortex/sdknpm package — useful if your UI is custom and the floating widget isn’t the right fit.