Embed and Public Agent API
Mrs. NetShow is an AI agent.
Put a live agent on a website with the two-line Alive Kit embed, allow its site for voice, and use the public agent doors.
Audience: a developer, or an AI agent, who wants a NetShow agent alive on a website it does not own: a customer site, a WordPress or Shopify store, or a page of its own. Scope: the one embed (the Alive Kit script and its <alive-agent> element), the voice door the element uses on your site, the owner's embed page that hands out the snippet and allows your website, the public agent pages and documents, and the older embed doors that still answer for pages pasted before the kit. How this guide was written: from the code on main. The class and method are named under each door, and the element's attributes are the ones public/alive-kit/alive-kit.js reads. The host is shown as https://app.netshow.ai. A door marked off until your administrator turns it on sits behind a switch that ships off; while it is off the door answers 404, or the element stays a captioned look without a voice.
Which door do I need?
| You want to | Use | Who sets it up |
|---|---|---|
| Put a live agent on any web page | The two lines below: alive-kit.js and <alive-agent> |
You paste them |
| Let that agent speak on your site in the NetShow voice | Your website on the agent's allowed list, with voice on for it | The agent's owner, on the embed page |
| Get the exact snippet for one agent | The owner's embed page, GET /dashboard/agents/{agentId}/embed |
The agent's owner |
| Read a public agent's face, name and look as data | GET /alive-kit/v1/agents/{slug} |
Nobody: public agents only |
| Talk to a public agent from your own agent, not a page | The public agent's MCP or A2A door | See the MCP Integration and A2A Protocol guides |
What you can do without a key
The embed needs no key, no token and no account. The element reads public facts only, and its voice is admitted by the website it runs on (the Origin your browser sends), not by a secret in the page.
| Door | What it gives you | Switch |
|---|---|---|
/alive-kit/alive-kit.js |
The kit: one script that defines <alive-agent>. |
Always on (a static file) |
GET /alive-kit/v1/agents/{slug} |
The public agent's document the element reads: name, look, character, greeting. | ai.features.alive_kit_agent |
GET /alive-kit/v1/agents/{slug}/package.alive.json |
The same agent as a downloadable .alive.json package. |
ai.features.alive_kit_agent |
GET /api/widget/voice/mint-url/{slug} |
A one-minute signed address that starts a voice session, for an allowed website only. | ai.features.widget_voice_door |
GET /agents and GET /agent/{slug} |
The public directory and each public agent's own page. | Always on |
POST /api/agent/{slug}/mcp and POST /api/agent/{slug}/a2a |
A public agent's machine doors. | ai.features.agent_ready_sites and ai.features.public_agent_answers |
A door with a switch is off until your administrator turns it on.
Put a live agent on your site: the two lines
<script src="https://app.netshow.ai/alive-kit/alive-kit.js" defer></script>
<alive-agent agent="your-agent-slug" look="auto" mode="free"></alive-agent>
That is the whole embed (the Alive Kit toolbox, docs/alive-kit/TOOLBOX.md section 1, is its owner's manual). Paste the script once, anywhere in the page, and the element where the agent should live. With agent="netshow" you get the house host.
What a visitor sees: the agent is alive as the page loads. It shows its greeting as a caption, blinks and breathes, and morphs with its room: a live ASCII face when it is tiny, the whole character when there is space. Its face is the talk button. Where your site is allowed for voice (next section), it speaks in the NetShow voice at the visitor's first touch of the page; anywhere else it stays a living, captioned look. It never uses a browser voice or a recorded clip, and it always says it is an AI.
The element
These are the attributes public/alive-kit/alive-kit.js reads. Leave out any you do not need.
| Attribute | Values | Default |
|---|---|---|
agent |
netshow (the house host) or a public agent's slug |
netshow |
look |
auto, 1 to 9, or a look name: ascii, sketch, svg, toon, 2d, 3d. Look 9 (a paid live human face) is opt-in only. |
auto |
character |
mrs-netshow, mr-netshow, pip, robo, byte, owl, cat, fox, drake, momo, scout |
pip on your site |
mode |
container (fills its box), free (rides the page, bottom right), stage (owns the screen; Esc or "Bring me back" returns it) |
container |
lang |
a language tag (en, es, ...) or auto for the visitor's browser language |
the page's <html lang> |
greeting |
the caption shown at load; the live voice says its own words | the character's greeting |
name |
the host's name | the character's name |
mint-url |
the agent's voice door, https://app.netshow.ai/api/widget/voice/mint-url/{slug} with the agent's slug |
none: captions only |
voice-src |
a same-origin address that answers {sessionUrl, agentId} (NetShow's own pages) |
none |
Size it with CSS: --alive-agent-size (in container mode, default 320px) and --alive-agent-free-size (in free mode, default 120px). In free and stage mode the agent draws no buttons around itself: hovering it (or tapping it on a phone) shows its one menu.
The agent's public document
Class: AliveKitAgentController (methods show and package). The element fetches this for any slug other than the house host. Public agents only; the document carries public facts only, never the agent's instructions, knowledge, owner or visitors. It answers with Access-Control-Allow-Origin: * so it works from any site, and is cached for 60 seconds. 240 requests a minute.
curl --max-time 30 https://app.netshow.ai/alive-kit/v1/agents/your-agent-slug -H 'Accept: application/json'
A private agent, an unknown slug, or the switch ai.features.alive_kit_agent off: 404. The package.alive.json door answers the same file as a download (Content-Disposition: attachment).
Stores and site builders
| Where | What to do |
|---|---|
| Any HTML page | The two lines above. |
| WordPress | The owner downloads the NetShow Alive plugin for this agent at GET /dashboard/agents/{agentId}/embed/wordpress-plugin.zip (class AgentWordPressPluginController), installs it and ticks "Put the live host on every page". It prints the same two lines. |
| Shopify | The theme section in integrations/shopify/netshow-alive/sections/netshow-alive.liquid, added to the footer group in Customize. Captions and the one menu today. |
| A sandboxed frame you cannot load modules into | See docs/alive-kit/TOOLBOX.md section 1, "A sandboxed frame". |
Give it a voice on your site
The element's voice comes only from the signed mint, and the mint answers only a website the agent's owner has allowed and switched voice on for. Nothing in the page is a secret.
-
The owner allows your website. On the embed page the owner adds the origin (
https://your-site.example):POST /dashboard/agents/{agentId}/embed/originswith the fieldorigin. Class:AgentEmbedOriginController(methodstore). The site starts as pending. Switches:ai.features.embed_selfserveandai.features.embed_origin_selfserve. -
You prove you control the site. Publish the exact token the embed page shows at
https://your-site.example/.well-known/netshow-origin.txt(classEmbedOriginVerification), with no redirect. Whereai.features.embed_origin_verify_metais on, a<meta name="netshow-origin" content="...">tag inside your home page's<head>also counts. -
The owner presses Verify.
POST /dashboard/agents/{agentId}/embed/origins/verifyfetches the proof once and moves the site to active.POST /dashboard/agents/{agentId}/embed/origins/withdrawtakes it off the list again (it is kept as withdrawn, never deleted). -
The owner turns voice on for that site.
POST /dashboard/agents/{agentId}/embed/origins/voice(classAgentEmbedOriginVoiceController). Switches:ai.features.widget_voice_doorandai.features.widget_voice_owner_switch. -
Put
mint-urlon the element. The owner's snippet already carries it.
GET /api/widget/voice/mint-url/{slug}
Class: WidgetVoiceMintUrlController (method show). The element calls it from the visitor's browser at the visitor's first touch; the Origin header is the website asking. 10 requests a minute. Every answer carries Access-Control-Allow-Origin set to that origin and Cache-Control: private, no-store.
curl --max-time 30 https://app.netshow.ai/api/widget/voice/mint-url/your-agent-slug \
-H 'Origin: https://your-site.example' -H 'Accept: application/json'
Response 200 (the address lives 60 seconds):
{"mintUrl": "https://app.netshow.ai/api/realtime/session/public?agent_id=...&widget_voice=embed&widget_origin=https%3A%2F%2Fyour-site.example&expires=...&signature=..."}
Where the agent has a voice ladder, the answer also carries voiceLadder, rung and voicePageUrl, the agent's own voice page.
| Status | Body message |
Why |
|---|---|---|
403 |
Voice is not available on this site right now. You can keep typing. |
The website is not allowed, or voice is not on for it. |
404 |
The agent is not public, the slug is unknown, or ai.features.widget_voice_door is off. |
|
409 |
Captions are the available lane. Keep typing, or open the voice page. |
Captions are the agent's voice today. |
503 |
Live voice is awaiting its session budget. You can keep typing. |
The daily voice ceiling (ai.spend.lanes.realtime_voice_session.daily_ceiling_usd) is not set, or is used up. |
POST /api/realtime/session/public
Class: RealtimeSessionController (method createPublic). The element posts to the signed mintUrl it was handed; the signature, the website and the agent are checked again, and the house daily ceilings apply. 10 requests a minute. The answer starts the session on the NetShow proxy voice (gpt-realtime-2.1-mini by default). You never build this request yourself: changing any query parameter breaks the signature and the door answers 403.
The owner's embed page
Class: AgentEmbedController (method show), at GET /dashboard/agents/{agentId}/embed, signed in, the agent's owner only (anyone else gets 404). Switch: ai.features.embed_selfserve. The page is titled "Put
-
The snippet. While
ai.features.owner_embed_alive_kitis on, it is the two lines above for this agent, built byAliveEmbedKit::kitSnippet:look="auto", themodethat follows the agent's Own the stage setting, and itsmint-url. While it is off, the page shows the older snippet for owners who already pasted it. - Your websites. The allowed list from the section above, with each site's state and its voice switch.
-
Checks.
POST /dashboard/agents/{agentId}/embed/check(classAgentSnippetCheckerController, switchai.features.studio_snippet_checker) checks a pasted snippet;POST /dashboard/agents/{agentId}/embed/live-check(classAgentEmbedLiveCheckController, switchai.features.embed_site_live_check) loads your page once and reports whether the agent is on it. - The WordPress plugin download (above).
Publish the agent
The embed, the public document and the public page work only for a public agent. POST /dashboard/agents/{agentId}/publish (class AgentPublishController), signed in as the owner, with a CSRF token: the field make_public (default true) sets the agent public or private. Making it public also needs confirm_publish=1; without it the agent is not changed and the page asks the owner to confirm first. Another owner's agent answers 404.
Public agent pages
| Door | Class and method | What it is |
|---|---|---|
GET /agents |
AgentProfileController@directory |
The public directory: 24 a page, ?category= and ?q= to filter. |
GET /agent/{slug} |
AgentProfileController@show |
The agent's public page, with its live host. Public or marketplace agents only, else 404. |
GET /agent/{slug}/voice |
AgentVoicePageController@show |
The agent's own voice page (the voicePageUrl the mint hands out). |
POST /agent/{slug}/chat |
AgentProfileController@trialChat |
The typed turn of the agent's own page. |
POST /agent/{slug}/chat is the page's own conversation, not an API for other sites: it is a same-site browser request that needs the page's session and CSRF token. Body message (required, at most 500 characters); 5 requests a minute per visitor; 15 messages a visitor session before the page asks the visitor to sign up. Its answer:
{"reply": "<the agent's answer>", "messagesLeft": 14, "limitReached": false, "tier": "...", "greetTier": "...", "degraded": false}
and, at the cap:
{"reply": null, "limitReached": true, "signupUrl": "/register?agent=your-agent-slug"}
To talk to a public agent from your own software, use its MCP door (POST /api/agent/{slug}/mcp) or A2A door (POST /api/agent/{slug}/a2a): the MCP Integration and A2A Protocol guides show each with a request and a response.
Older embed doors
These still answer for pages that were pasted before the kit. They are not the embed to build on: a new page uses the two lines above.
| Door | Class | What it does now |
|---|---|---|
GET /act/embed/{agentSlug} |
ActEmbedController@show |
An iframe target. While ai.features.act_embed_public is off it sends a public agent's visitor on to the logged-out ACT chat; on, it draws the public agent's chat in the frame. 404 for a private agent either way. |
GET /embed/agents/{agentId}/chat |
a closure in routes/web.php |
An iframe chat widget keyed by the agent's id; 403 for a private agent. |
/js/ns-chat-widget.js with data-api set to the agent's door |
WidgetSnippet |
The script-tag chat widget the deploy page hands out while ai.features.embed_snippet_live_widget is on; it answers only a website on the allowed list. |
How to get a key
The embed needs none. What stands in for a key is the allowed list: the agent's owner adds your website, you publish the proof file, the owner presses Verify and turns voice on. For machine access to an agent (MCP, A2A or the owner's API), see the Authentication and Keys guide.
Was this helpful?
We can turn this into interactive help, search, and guided checklists next.
Previous guide
MCP Integration
Next guide