Deploy Agentic Pages as an External Developer
Use this guide when you are building an agentic page for a handle you manage, a client handle, or an automation that publishes 10x pages.
An Agentic Page deployment is not a separate JavaScript app or AWS deployment. You deploy handle-owned page content, safe widget configuration, and public-agent knowledge into 10x. The 10x page shell injects the platform widget and the anonymous visitor runtime when the handle is eligible.
What you deploy
| Layer | Who owns it | What you configure |
|---|---|---|
| Public page | Your handle | title, description, template, content, teaser, accessMode, and publish state |
| Public-agent KB | Your handle | Public documents tagged with containerTags: ["public-page-agent"] |
| Widget configuration | Your handle or page | Variant, theme tokens, copy, starter chips, safe behavior flags, and authenticated rich slots |
| Visitor runtime | 10x platform | Anonymous agentic-question, agentic-chat, widget asset, generation, retrieval, and lead submission |
The normal deployment boundary is:
external developer publishes page and KB -> 10x shell injects widget -> visitor asks anonymous public routes
Do not ask visitors to provide JWTs or PATs. Tokens are setup credentials only.
Prerequisites
- A 10x handle, for example
acme. - Page publishing access on the handle.
- Public-agent availability enabled for the handle by plan entitlement, environment switch, or operator allowlist.
- A creator/operator JWT for full setup.
- Optional PAT with
pages.writefor page-only automation. - Public knowledge documents that do not contain secrets, private paid content, customer PII, internal runbooks, signed URLs, or unpublished claims.
Endpoint map
Setup with JWT
Use JWT when you need the complete bootstrap, including public-agent KB documents.
| Job | Method and path | Auth | Success |
|---|---|---|---|
| Create page | POST /v2/handles/{handle}/pages | JWT, CREATOR+ | 201 |
| Update page | PUT /v2/handles/{handle}/pages/{pageSlug} | JWT, CREATOR+ | 200 |
| Publish page | POST /v2/handles/{handle}/pages/{pageSlug}/publish | JWT, CREATOR+ | 200 |
| Create KB document | POST /v2/handles/{handle}/knowledge/documents | JWT, OPERATOR+ | 201 |
| Query KB | POST /v2/handles/{handle}/knowledge/query | JWT, handle access | 200 |
Page automation with PAT
Use PAT when an external integration or MCP workflow should manage page content without a browser session.
| Job | Method and path | Required PAT scope | Success |
|---|---|---|---|
| List pages | GET /v2/public/handles/{handle}/pages | pages.read | 200 |
| Create page | POST /v2/public/handles/{handle}/pages | pages.write | 201 |
| Update page | PUT /v2/public/handles/{handle}/pages/{pageSlug} | pages.write | 200 |
| Publish page | POST /v2/public/handles/{handle}/pages/{pageSlug}/publish | pages.write | 200 |
| Preview page content | GET /v2/public/handles/{handle}/pages/{pageSlug}/preview | pages.read | 200 |
| Delete page | DELETE /v2/public/handles/{handle}/pages/{pageSlug} | pages.write | 200 |
PAT page routes do not create public-agent KB documents. For KB seeding, use the JWT knowledge route or an approved MCP/automation flow that has knowledge.write.
Visitor runtime
These routes are anonymous. They are called by the widget or by public validation scripts.
| Job | Method and path | Auth | Success |
|---|---|---|---|
| JSON answer smoke test | POST /v2/public/pages/{handle}/{pageSlug}/agentic-question | None | 200 JSON |
| Streaming widget runtime | POST /v2/public/pages/{handle}/{pageSlug}/agentic-chat | None | 200 text/event-stream |
| Lead submission | POST /v2/public/handles/{handle}/leads | None | 200 or 201 style success payload |
Configure your shell variables
export API_BASE="https://ai.10x.in"
export HANDLE="acme"
export PAGE_SLUG="launch-agent"
export PUBLIC_PAGE_URL="https://${HANDLE}.10x.in/${PAGE_SLUG}"
export JWT_TOKEN="<creator-or-operator-jwt>"
For JWT setup calls:
export AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}"
export PAGES_BASE="${API_BASE}/v2/handles/${HANDLE}/pages"
For PAT page automation:
export PAT_TOKEN="patv1_<tokenId>.<secret>"
export AUTH_HEADER="Authorization: Bearer ${PAT_TOKEN}"
export PAGES_BASE="${API_BASE}/v2/public/handles/${HANDLE}/pages"
Use the JWT AUTH_HEADER for the KB steps unless your integration has a separate approved knowledge-write automation.
1. Create the page content
Use template: "html_render" and send an HTML fragment, not a full document. The 10x shell owns <html>, <head>, <body>, meta tags, default typography, the widget config script, and /assets/public-page-agent.js.
This example uses an inline chat mount. If you omit the mount, the widget falls back to a floating Ask launcher.
curl -sS -X POST "${PAGES_BASE}" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d '{
"pageSlug": "'"${PAGE_SLUG}"'",
"title": "Launch Agent",
"description": "Ask questions about launch support, onboarding, proof, pricing boundaries, and implementation handoff.",
"template": "html_render",
"accessMode": "PUBLIC",
"status": "DRAFT",
"content": "<main class=\"agentic-page\"><section><p>Implementation support</p><h1>Launch Agent</h1><p>Get onboarding checklists, launch templates, implementation support, proof points, and handoff guidance from a public assistant.</p><a href=\"#agent\">Ask the launch guide</a></section><section><h2>What this page can answer</h2><ul><li>What launch support includes.</li><li>What details are useful for follow-up.</li><li>Which claims are public and approved.</li></ul></section><section id=\"agent\"><h2>Ask the launch guide</h2><div id=\"tenx-public-page-agent-inline\" data-tenx-agent-variant=\"sales\" data-tenx-agent-launcher-label=\"Ask launch\" data-tenx-agent-default-open=\"true\"></div></section></main>"
}'
Expected response:
{
"page": {
"handle": "acme",
"pageSlug": "launch-agent",
"title": "Launch Agent",
"template": "html_render",
"accessMode": "PUBLIC",
"status": "DRAFT",
"version": 1
}
}
Common create errors:
| Status | Error | Fix |
|---|---|---|
400 | invalid_payload | Include title and non-empty content. |
403 | insufficient_role | Use a creator/operator JWT or PAT with pages.write; paid pages require owner access. |
403 | feature_locked | Pages require the appropriate plan tier. |
409 | page_exists | Use PUT /pages/{pageSlug} to update instead. |
409 | slug_conflict | Pick a page slug that is not already used by a short link. |
2. Publish the page
curl -sS -X POST "${PAGES_BASE}/${PAGE_SLUG}/publish" \
-H "${AUTH_HEADER}"
Expected response:
{
"ok": true,
"pageSlug": "launch-agent",
"publishedAt": "2026-06-16T04:30:00.000Z"
}
After publish, the visitor URL is:
https://{handle}.10x.in/{pageSlug}
Custom domains use the same path shape:
https://pages.example.com/{pageSlug}
3. Add public-agent knowledge
Agentic Pages retrieve handle KB documents only when they carry the exact public-agent container tag.
["public-page-agent"]
Create small, single-purpose public documents. Use one document for offer facts, one for pricing boundaries, one for support/handoff policy, and one for refusal rules.
curl -sS -X POST "${API_BASE}/v2/handles/${HANDLE}/knowledge/documents" \
-H "Authorization: Bearer ${JWT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"title": "Launch support policy",
"topic": "agentic-pages",
"source": "external-developer-deployment",
"contentType": "text/plain",
"containerTags": ["public-page-agent"],
"content": "Launch support includes onboarding checklists, implementation templates, proof review, and a two-business-day handoff window. Do not quote private pricing. For blocked launches, ask the visitor to submit the generated follow-up form."
}'
Expected response:
{
"documentId": "kdoc_abc123",
"title": "Launch support policy",
"topic": "agentic-pages",
"source": "external-developer-deployment",
"contentType": "text/plain",
"containerTags": ["public-page-agent"],
"status": "INDEXED",
"createdAt": "2026-06-16T04:30:00.000Z",
"updatedAt": "2026-06-16T04:30:00.000Z"
}
Validate retrieval before sending traffic:
curl -sS -X POST "${API_BASE}/v2/handles/${HANDLE}/knowledge/query" \
-H "Authorization: Bearer ${JWT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "What launch support is included?",
"limit": 4,
"containerTags": ["public-page-agent"]
}'
Expected response fields:
{
"query": "What launch support is included?",
"containerTags": ["public-page-agent"],
"count": 1,
"retrievalMode": "vector",
"backend": "aurora_pgvector",
"results": [
{
"title": "Launch support policy",
"content": "Launch support includes onboarding checklists..."
}
]
}
If the query returns zero results, do not proceed to public validation. Fix the tag, content, or indexing state first.
4. Verify the page shell injects the widget
Fetch the public page and check for both the JSON config script and widget asset.
curl -sS "${PUBLIC_PAGE_URL}" | grep -E "tenx-public-page-agent-config|/assets/public-page-agent.js"
Expected markers:
If the markers are missing:
- Confirm the page is
PUBLISHED. - Confirm the handle is public-agent eligible.
- Confirm the public page is rendered through the 10x page shell, not a copied static HTML file.
- Confirm you are testing the handle host or the configured custom domain, not only the API host.
5. Smoke test the JSON answer route
Use agentic-question for simple API validation and non-widget integrations.
curl -sS -X POST "${API_BASE}/v2/public/pages/${HANDLE}/${PAGE_SLUG}/agentic-question" \
-H "Content-Type: application/json" \
-d '{
"question": "What launch support is included?"
}'
Expected response shape:
{
"answerMarkdown": "Launch support includes onboarding checklists, implementation templates, proof review, and a two-business-day handoff window.",
"evidenceCards": [
{
"title": "Launch support policy",
"snippet": "Launch support includes onboarding checklists...",
"sourceType": "kb_doc",
"sourceUrl": null
}
],
"ctaCards": [
{
"label": "Open page",
"actionType": "link",
"href": "https://acme.10x.in/launch-agent"
}
],
"followUps": [
"What is included?",
"How do I get started?",
"What happens next?"
],
"degraded": false,
"retrievalMode": "page+related_pages+vector",
"modelId": "anthropic.claude-haiku-4-5-20251001-v1:0"
}
Request errors:
| Status | Error | Fix |
|---|---|---|
400 | invalid_json | Send valid JSON. |
400 | question_required | Send a non-empty question. |
400 | question_too_long | Keep the latest visitor question at or below 500 characters. |
404 | not_found | Check handle eligibility, page publish state, handle status, and page slug. The response intentionally does not reveal which gate failed. |
6. Smoke test the streaming widget route
Use agentic-chat for the embedded widget and generated UI.
curl -i -N -X POST "${API_BASE}/v2/public/pages/${HANDLE}/${PAGE_SLUG}/agentic-chat" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"parts": [
{ "type": "text", "text": "What support is included, and what should I share for follow-up?" }
]
}
]
}'
Expected headers:
HTTP/2 200
content-type: text/event-stream; charset=utf-8
cache-control: no-store
x-accel-buffering: no
Expected stream content includes text deltas plus a lead tool part:
tool-renderLeadQualificationSection
The generated lead UI has two containment layers:
| Layer | Rendered by | Safety rule |
|---|---|---|
| Native workspace | React widget | Renders dynamicView, chips, evidence, and card UI. |
| Generated form HTML | Sandboxed iframe | Only form HTML; no scripts, external assets, inline styles, images, or iframes. |
The iframe uses:
<iframe sandbox="allow-forms allow-scripts"></iframe>
The parent widget submits generated leads with credentials: "omit" to:
POST /v2/public/handles/{handle}/leads
Streaming failure behavior:
| Status | Body | Meaning |
|---|---|---|
400 | messages_required | Body must include a messages array. |
400 | question_required | The latest user message did not contain text. |
400 | question_too_long | Latest user text is over 500 characters. |
404 | not_found | Handle/page unavailable or not eligible. |
200 SSE | event: error and {"error":"chat_unavailable"} | Model streaming failed after configured fallback attempts. |
7. Configure the widget safely
For normal 10x-rendered pages, the platform injects the widget. You only add an inline mount when you want the chat embedded in the page body.
<div id="tenx-public-page-agent-inline"></div>
Safe public embed overrides can be placed on that mount:
<div
id="tenx-public-page-agent-inline"
data-tenx-agent-variant="course"
data-tenx-agent-accent-color="#0b6b3a"
data-tenx-agent-launcher-label="Ask the guide"
data-tenx-agent-default-open="true"></div>
Supported variants:
minimalcoachsalescoursesupport
Authenticated owner configuration can also define richer copy, starter chips, behavior flags, and rich slots:
headeremptyStateleadIntrosuccess
Rich slot HTML is sanitized and rendered inside the widget Shadow DOM. Rich slot CSS is also sanitized; selectors must start with .tenx-agent-slot, and only safe presentation properties such as color, background-color, border-color, border-radius, font-weight, line-height, margin, padding, and text-align are accepted.
Public embed overrides cannot provide rich HTML, arbitrary CSS, endpoint paths, model settings, sandbox flags, or prompt settings.
8. Optional PAT-only page deployment
Use this when a CI job or external service is responsible only for page content.
export PAT_TOKEN="patv1_<tokenId>.<secret>"
export AUTH_HEADER="Authorization: Bearer ${PAT_TOKEN}"
export PAGES_BASE="${API_BASE}/v2/public/handles/${HANDLE}/pages"
Create or update the page through the same payloads:
curl -sS -X PUT "${PAGES_BASE}/${PAGE_SLUG}" \
-H "${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-d '{
"title": "Launch Agent",
"description": "Updated external deployment page.",
"template": "html_render",
"accessMode": "PUBLIC",
"status": "DRAFT",
"content": "<main><h1>Launch Agent</h1><p>Updated public launch support context.</p><div id=\"tenx-public-page-agent-inline\"></div></main>"
}'
Publish with the PAT:
curl -sS -X POST "${PAGES_BASE}/${PAGE_SLUG}/publish" \
-H "${AUTH_HEADER}"
Then switch back to JWT for public-agent KB creation:
export AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}"
PAT-only deployment is acceptable only when the required public-agent KB already exists or is managed by another approved process.
9. Validate end to end
Before sharing the URL, run every check in this table.
| Check | Command or observation | Expected result |
|---|---|---|
| Page loads | curl -I "${PUBLIC_PAGE_URL}" | 200 or expected CDN success |
| Shell config exists | grep tenx-public-page-agent-config | Config script is present |
| Widget asset exists | grep /assets/public-page-agent.js | Asset script is present |
| KB retrieval works | POST /knowledge/query with containerTags | At least one relevant result |
| JSON answer works | POST /agentic-question | 200, answerMarkdown, evidence |
| Streaming works | POST /agentic-chat | 200 text/event-stream |
| Lead UI streams | Inspect stream/UI | tool-renderLeadQualificationSection appears |
| Lead form is sandboxed | Browser dev tools | Form HTML is inside the sandboxed iframe |
| Secret refusal works | Ask for a private marker | No private marker appears |
| Length cap works | Send 501 chars | 400 question_too_long |
| Disabled handle safety works | Test a disabled fixture if available | Non-leaky 404 |
| Paid-page safety works | Test paid fixture if applicable | Teaser-safe answer only |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
POST /agentic-question returns 404 not_found | Handle is disabled, handle is inactive, page is unpublished, slug is wrong, or plan entitlement is missing. | Check publish state and ask the operator to confirm public-agent eligibility. |
| Page loads but no widget markers appear | Shell did not inject public-agent config. | Confirm the page is rendered by the 10x shell and the handle is eligible. |
| Widget appears but answers ignore KB | Missing or wrong containerTags. | Query /knowledge/query with containerTags: ["public-page-agent"] and fix documents until results appear. |
Streaming route returns SSE chat_unavailable | Primary and fallback models failed or stream validation failed. | Retry later, check public-page-agent model alarms/logs, and use agentic-question as a basic route smoke test. |
| Generated lead form is too generic | KB steering is too broad. | Add a short public-agent KB document describing exactly which fields and disclosure to use. |
| Browser lead submission fails | Origin or page host is not accepted, or the widget was copied outside the 10x shell. | Test from the handle host/custom domain, not file:// or an unrelated domain. |
| PAT call works for pages but KB creation fails | PAT page routes do not create KB documents. | Use a creator/operator JWT or an approved knowledge-write automation for KB seeding. |
Deployment checklist
- Page content is an HTML fragment, not a full document.
- Inline mount is present when the chat should be embedded.
- Public-agent KB documents are public-safe and tagged with
["public-page-agent"]. - Page is published and visible on the handle host or custom domain.
- Anonymous
agentic-questionandagentic-chatroutes pass validation. - Generated lead UI renders through the widget and iframe, not host-page HTML injection.
- Visitor lead disclosure mentions that page, question, answer, evidence titles, and retrieval mode are included with the lead.
- Paid pages use teaser-safe content only.
- JWT/PAT credentials are kept server-side and never exposed to visitors.
Related docs
Updated Jun 19, 2026
