TellWang
Dashboard

API reference

The TellWang control-plane API manages Woks and resources; each Wok also exposes its own data API (PostgREST over your tables, auth, storage). Everything Wang and the dashboard do is available here, so automation and CI use the exact same surface.

Base URL & versioning

The control-plane API is versioned in the path; breaking changes ship under a new version, never in place.

base
https://api.tellwang.com/v1            # control plane (Woks, resources)
https://<wok-id>.tellwang.com/rest/v1  # a Wok's data API

Authentication

Authenticate with a bearer token: an API key or service-account token for the control plane; the Wok's anon or service-role key for its data API. Every request is authorized server-side against the caller's org/project scope.

curl
curl https://api.tellwang.com/v1/woks \
  -H "Authorization: Bearer <api-key>"

Conventions

Example — provision a Wok

A newly provisioned Wok starts empty, and apps are installed from the Marketplace. Its database includes the GEO content foundation: confirmed-author attribution rules and a content worker. The Wok's GEO content panel and Wang can configure topics, up to five search languages, a writing language, a dedicated English Reddit search, author attribution, owner notifications, and daily, weekly, or monthly cadence after the owner opts in. The private model is the default research planner: it combines a bounded live-homepage snapshot with the owner's topics to plan language-specific keywords, with deterministic topic queries as the fail-safe. Research plans, runs, questions, and labeled sources are visible in the dashboard; existing Woks are not changed.

POST /v1/woks
curl -X POST https://api.tellwang.com/v1/woks \
  -H "Authorization: Bearer <api-key>" \
  -H "Idempotency-Key: 7f3a-..." \
  -d '{ "name": "acme-pos" }'

# → 201 { "id": "wok_abc123", "url": "https://wok_abc123.tellwang.com",
#         "anon_key": "...", "state": "ready" }
✦
Prefer not to manage keys? Tell Wang or use the MCP server — same API underneath, with auth handled for you.

Transfer a complete Wok

POST /v1/orgs/{slug}/woks/{id}/transfer with {"dest_org":"destination-slug","include_linked_preview":true} moves the Wok-owned application, database, Storage, Git, RAG corpus, and portable configuration. For a Published Wok, the dashboard moves Published and its linked Preview in one transaction so the pair cannot split across organizations. The same signed-in human must control both organizations; a source-side approval is not destination consent. Managed RAG and GEO model credentials are replaced with destination-owned keys and the source keys are revoked, so later use cannot spend the source organization's allowance.

The boundary deliberately excludes human and organization authority. Source chat and approval history stays in the source organization; member OAuth tokens are revoked; payment gateways and phone routes are disconnected; pending OAuth consent is cancelled; and a marketplace listing becomes unpublished. App-user OAuth connections remain with the app as customer data. Connected hostnames move with the stable Wok id and stay live. Exact matching TellWang-managed DNS or registration ownership moves too; broader parent zones stay with the source. Active runs or deployments still block the transfer.

Diagnostics

Three layers, from cheapest to most detailed. All return JSON.

The site_capture diagnostic reports the health of site capture, with worker-active and queued jobs listed separately alongside active capacity, so a queued segment is not presented as browser work already in progress.

shopify_post_edit_commerce reports whether commerce verification for Git edits to imported Shopify storefronts is available. While it is unavailable, those edits fail closed.

The semantic distinction: /healthz answers "should the load balancer keep sending us traffic"; /diag answers "what's right and what's broken, with evidence." TellWang's automated health monitoring reads /diag as its primary signal.

Wok lifecycle

Provision returns the canonical row; everything below operates against an existing wok. Bearer-of-owning-org on all of them; cross-org returns 404.

Lollipop public-audit handoff

The public Lollipop audit stores the exact approved keywords, prompts, findings, and evidence before account creation. After sign-in, POST /v1/orgs/{slug}/lollipop/onboarding/claim/preview verifies the two-hour handoff token and shows what will be added. POST /v1/orgs/{slug}/lollipop/onboarding/claim with {"lead_id":"…","lead_token":"…","project_id":"…"} creates or matches a watch-only Site, copies the retained Audit, and creates draft Changes for actionable findings. The claim is idempotent, so a retry returns the same receipt. The public audit receipt is Included · $0.00. “Start watching” creates the Site, then its audit setup saves that Site's own sampling_location and sampling_language. The next step lets the owner choose the audit language and resolves the market label to Google's canonical location, asking the owner to choose when supported places share a name, before it prepares inferred buyer questions. The included first audit starts only after those questions are confirmed. Set up first audit on an unaudited Site opens this same recovery path; Generate buyer questions prepares the missing draft before review. An unaudited watch-only Site also exposes a confirmed Remove Site action. Re-adding that domain later restores its retained identity instead of creating another included-audit allowance. Failed attempts retain their safe error and retry receipt without burning that exemption. A legacy Site without a completed report exposes the same first-audit action once it has a public domain or Published address; otherwise the customer is directed to publish or connect the address first. Pro includes eight repeat Site audits per UTC month; Scale, Scale + HA, and Enterprise include thirty. Failed and unreadable attempts do not consume that monthly allowance. Prepaid funds are used only after it is exhausted.

The Project selector lists every Project the signed-in account can reach. It includes current-account Project records and keeps legacy Projects stored in another authorized workspace visible; selecting one refreshes into its exact authorized scope. The signed-in canonical path is /app/<account>/projects/<project>/…, so switching two Projects in one account changes the address, and refresh, back/forward, bookmarks, and shared links restore the exact Project. Older account-only links remain readable and are replaced with the exact Project path after bootstrap. Platform workspace names remain hidden behind the customer-facing Account → Project → Site model. Re-adding a removed watch-only domain restores the original Site, audit history, and first-audit ledger in the selected Project instead of issuing another included audit. Lollipop opens in Simple mode with Sites, Changes, Email, Backlinks, Domains, and Settings. Email, Backlinks, and Domains are direct destinations; Settings contains Billing and Team. AI answers, business information, sources, and Optimize remain in Pro. Older GEO links carrying a selected Site open that Site's Overview; other GEO, Knowledge, and business-information links return to Sites, while Optimize links return to Changes. A completed managed-Site audit exposes Generate changes; a read-only watched Site instead exposes Generate recommendations. Both start or resume a one-time run using that Site's latest approved audit as its only source and reuse the Site's Simple configuration on later clicks. A watched-Site recommendation cannot be applied to the external website. Its Import site and build it action opens the confirmed whole-site or content-only import choice, then builds into a private Preview while the current live Site remains unchanged. Objective, source, and recurring schedule controls remain in the full Pro Optimize workspace. The wrapper/theme popover contains the Simple/Pro switch, and the per-person choice follows the account; a missing choice always resolves to Simple. Pro restores the complete Project, Knowledge, Analytics, Optimize, Email, Backlinks, Receive payment, Files, domain, billing, member, and Shell surfaces. GET /v1/orgs/{slug}/lollipop/me returns preferences.mode, and PATCH …/lollipop/preferences accepts {"mode":"simple|pro"}. The Pro dashboard rail keeps daily Project tools above a labeled Manage divider and Files, Domains, Billing, and Members below it. Receive payment is a separate Pro Project tool: it shows only that Project's collected money and Stripe readiness, and creates a fresh single-use Stripe setup link for an Owner, Admin, or Billing member. Lollipop subscription charges and usage remain under Billing. Move this site remains available on Overview before, during, and after the first audit. A native destination uses POST /v1/orgs/{slug}/lollipop/sites/{site_id}/move with {"project_id":"…"}; the Site, backlink evidence, outreach drafts, and other Site-bound work cross atomically. A managed Site moving to another authorized workspace uses the existing Site-transfer boundary and carries the same Site-owned backlink records. Both require owner/admin control. Active work blocks a cross-workspace move, while connected hostnames move with the Site and stay live.

A managed Site's Overview also exposes Delete site to Owners, Admins, and Editors. The confirmation requires a successful full PostgreSQL backup download, an explicit acknowledgement, and the exact Wok id. A suspended Wok starts only PostgreSQL for the download, then returns to its suspended state; its Site and other services stay stopped. The confirmation files the existing delete_wok approval request; an Owner or Admin may approve it, while an Editor's request waits for one. Approval tears down the linked Preview before the production Wok, and the deleted Site leaves the Lollipop list only after execution succeeds.

A recommendation or change-generation run that stops remains under Needs attention instead of disappearing from Changes. An exhausted AI allowance shows the safe Upgrade plan and Add funds actions, and Retry generation starts the same Site-bound optimization after funding is available. Lollipop checks funding before it refreshes audit evidence or creates another background run.

Watched-site import starts with an explicit choice and a separate confirmation screen. While the start request is pending, the confirmation stays open and shows Starting import…; a rejected start remains visible with a retry message instead of disappearing. After acceptance, the durable Site banner shows import progress and restores it after navigation or refresh. POST /v1/orgs/{slug}/lollipop/sites/{site_id}/import accepts {mode:"whole_site"|"content_only"}. Whole-site import remains the durable clone, provision, asset-copy, and staged-v1 job. Its styles, images, fonts, and other passive presentation assets are retained with the static Site release, remain available while Preview services sleep, and must all complete before staged v1 can become ready. Extensionless image and stylesheet endpoints must return a supported media type; an HTML fallback stops the import. Scripts and SVG files that are deliberately not copied keep an absolute source URL instead of being misrouted into the imported Site. Shopify and Shopline are never cloned as ordinary full sites: that mode records commerce_required and returns CP_LOLLIPOP_IMPORT_STOREFRONT_REQUIRED. Content-only import may read those public pages. It retains the complete captured page source, provisions a private Preview, copies the source photos into durable static Site storage, and records every page, copied photo path, alt text, and readable content excerpt in the versioned creative brief. The New Site build re-reads every retained page, reuses that exact Preview, and keeps the content and photos while replacing the layout. CSS, scripts, tracking, commerce behavior, and the old visual structure are not reused. The import stops instead of reporting success if discovery was capped, a page was truncated or skipped, or any passive asset copy is incomplete. Neither mode changes the public site before owner review. A platform administrator may restart a stopped watched-Site import or explicitly reimport a ready managed Site through POST /v1/admin/lollipop/orgs/{slug}/sites/{site_id}/import/retry. A capture that failed before banner polling observed it also counts as stopped. Managed reimport additionally requires the existing Published, Preview, and retained-clone bindings, preserving the Site and Change history. The action preserves the selected mode, is audit-recorded, and only reconnects the capture to this same customer-visible workflow; it grants no access to other Site actions. For production acceptance, POST /v1/admin/lollipop/orgs/{slug}/users/{user_id}/operator-sessions creates a separately revocable 30-minute test session bound to an existing member's current role. Its launch credential is delivered in a URL fragment, removed before the first request, and kept only in that browser tab; POST /v1/admin/lollipop/operator-sessions/{session_id}/revoke ends it immediately. Both actions are audit-recorded, and neither adds the operator to the account.

Lollipop's New Site → I already have an estore path consumes the platform contracts directly. Connect commerce starts an idempotent intent:"commerce_only" journey, provisions its empty Preview Wok, and opens only the server-bound Shopify approval URL; it imports and generates no pages and requests no theme scope. Quick clone starts capture_profile:"quick", then polls the retained two-route capture until the homepage and one product-page reference are complete or fail visibly. Retries reuse the same browser-session operation key. Both actions require the person to assert ownership or copying authority, and neither changes the source theme, settings, domain, or shopper traffic.

Lollipop redirects are staged on Preview. POST /v1/orgs/{slug}/lollipop/sites/{site_id}/redirects adds a validated 301 rule and proves that its exact Preview source returns 301 with the expected destination in Location; an ordinary 200 page cannot certify the release. DELETE …/redirects/{redirect_id} removes one after confirmation, and POST …/redirects/verify checks every retained rule against Published without following the redirect. Adding or removing a rule creates a staged release; neither changes Published until the ordinary reviewed publish flow. Existing static Sites with a _redirects file receive the corrected path-routing block during startup reconciliation.

Wang-assisted Email replies use two separate Site-scoped actions. POST /v1/orgs/{slug}/lollipop/sites/{site_id}/email/inbox/{message_id}/draft-reply/estimate with {"project_id":"…","objective":"…"} verifies scope and returns the one-request token estimate without calling a model. The idempotent …/draft-reply action additionally requires "confirmed_model_action":true, makes one metered private→DeepSeek→Kimi completion, and returns an editable draft plus serving-model provenance. Neither route sends email, and only non-draft Project/company knowledge is supplied to the model.

Backlinks is available in both Simple and Pro mode. It combines verified existing links with suggested unlinked mentions, pages accepting relevant community contributions, and editorial opportunities that warrant a direct pitch. The Site and status filters keep those categories distinct. The response also includes the latest Site audit's discovery coverage, check time, bounded search counts, provider attempts, and bounded backlink-index evidence. Lollipop labels incomplete, unavailable, and not-yet-run discovery instead of presenting an empty result as proof that no backlinks exist; a legacy audit marked complete with zero usable results is also treated as degraded, and saved records remain visible with the warning. Search and backlink-index rows are only candidates until the live source page verifies their current state. An index source that could not be confirmed appears separately under Needs verification, with its public metadata and reason; it is excluded from Existing and Suggested counts, filters, drafts, and outreach actions. An editorial contact address is shown only with the public page where it was discovered. Review pitch prepares a durable draft and opens Email → Compose with the Site, recipient, subject, and body filled in; it never sends. Email's existing review step and separate confirmed Send action remain mandatory.

Completed Lollipop audits can be shared as frozen public reports. GET /v1/orgs/{slug}/lollipop/sites/{site_id}/audit-share?project_id={uuid} previews the report and POST to the same path with {"project_id":"uuid"} creates the link; DELETE …/audit-share/{share_id} revokes it. The Project selection binds the snapshot to its latest completed AI-answer run, including the approved prompts, short answer excerpts, each answer's safe citation title, domain, and URL list, separate mention and citation percentages, and unavailable-engine receipts. The in-app preview groups every buyer question in an accordion; expanding one shows its frozen answer excerpts and retained links under Answers and citation sources. The public report renders those retained links below their exact answer; an answer with no returned source says so. Creation and revocation require an owner or admin. Share links open through GET /share/{share_token}, whose server-rendered Open Graph and Twitter metadata includes the exact frozen score, measured check counts, and up to three quick verdicts. Its 1200×630 PNG score card comes from GET /v1/lollipop/reports/{share_token}/card.png, so messaging apps do not need to run JavaScript to build the preview. The report-data response also returns the authoritative share_url; the public report restores that crawler-facing address in the browser and copies it instead of the metadata-free application route. The edge redirects a previously copied /report/{share_token} address to the same versioned share page before a messaging crawler reaches the application shell. Newly returned page and image URLs include a stable preview-version query to bypass older messaging-client caches. Valid metadata and cards permit a five-minute messaging cache while the platform edge still checks the active link on every request. The signed-out report-data route stays no-store. All three public routes are rate-limited, non-indexable, and return the same neutral unavailable response after revocation. The database stores a token hash, not the raw URL token.

Lollipop AI Answers runs from the control plane and is scoped to one Site at a time. The Site selector changes the buyer-question set, sampling history, mention rate, citation rate, excerpts, market, and language together; another Site in the same Project is never used as a fallback. GET /v1/orgs/{slug}/lollipop/mentions/readiness?project_id=…&site_id=… reports that Site's question count, saved market and language, the supported language choices, and whether the server-owned OpenAI web-search, DeepSeek Responses web-search, DataForSEO Google AI Overview, native Naver AI Briefing, and DataForSEO Naver Organic collectors are ready without returning credentials. Each source is identified as an answer or search source. Before buyer questions are loaded or created, GET …/sites/{site_id}/sampling-locations?query=… resolves the owner's city, region, or country without saving state, starting an audit, or charging usage. Exact inputs such as Bern, Switzerland continue with DataForSEO's Swiss city record; same-named places render as keyboard-accessible canonical choices, and the owner can search again if the right location is absent. PUT …/mentions/settings verifies the selected Site and saves the chosen canonical market and language on that Site before sampling. POST …/mentions/queries requires the selected site_id, and idempotent POST …/mentions/sample queues a durable run for only that Site. A missing Site or unmatched market is rejected before queueing or charge. Every source request includes that saved market and language: answer models must resolve ambiguous place names within it and answer in the chosen language, while search requests include the market in the selected-language query. DeepSeek is told to treat that market as authoritative, avoid search-process narration, and return the exact public URLs it cites. Lollipop retains both its structured citation annotations and explicit HTTP(S) links in the returned answer, but does not turn uncited internal search results into citations. Google also receives the matched numeric location code and DataForSEO language field. Native Naver AI Briefing keeps its displayed answer and sources, while Naver Search creates and polls a DataForSEO task and retains only returned organic rows. Naver Search remains visible as SEO evidence but is excluded from AI-answer percentages, check 05, public answer snapshots, and AI share of voice. Every question-and-source check retains a success or classified failure receipt. A mention requires the complete reviewed canonical brand as normalized words; a generic Site name, partial word, or brand copied only from the question does not count. A citation requires a returned URL on the Site's canonical hostname or one of its subdomains; a source title or unrelated URL containing the brand or domain text remains visible evidence but does not raise the Site's citation rate. Each sample also retains every returned citation plus every match against the Project's explicitly tracked competitors. The Site audit report and Project AI Answers show each answer's exact safe citation links and every matching competitor occurrence without relabelling unrelated sources. Each successful question×source check costs $0.01 from the prepaid balance; a provider failure is refunded. OpenAI and DeepSeek output is identified as the corresponding API web-search result rather than claimed to reproduce a person's consumer app session, while Google AI Overview and Naver Search store the exact result types returned by DataForSEO.

Each Site can keep up to twenty active buyer questions. Adding the same question reactivates it without consuming another slot; at the limit, the owner must edit or remove an existing question before adding another.

Verified unlinked brand mentions

Every readable Site audit prepares backlink discovery beside its buyer questions. The review names the canonical brand and business type, lets the owner correct them and the local-business classification, and shows the exact primary queries plus public-only or paid-backup mode before confirmation. A paid-backup review also shows every conditional provider query; a public-only review states that paid discovery is not authorized and shows none. A server token binds the canonical domain, normalized identity, market, language, ordered authorized searches, plan version, and provider mode; editing any of those inputs requires a newly server-stamped plan and a second review. Primary discovery uses TellWang's self-hosted public metasearch. Paid provider discovery is disabled by default. It requires a freshly confirmed paid-backup plan, lollipop-backlink-discovery-provider-enabled set to true, on, yes, enabled, or 1, lollipop-dataforseo-basic-auth, and positive lollipop-backlink-provider-global-daily-batches and lollipop-backlink-provider-org-daily-batches values with the organization limit no higher than the global limit. A credential or later flag change cannot expand an older public-only plan. Under a cluster-wide lease, Lollipop durably reserves the server-owned audit attempt against both UTC-day ceilings before any paid call; that reservation still counts after a process stop or later audit failure. Only one paid request batch runs at a time, and contention or an exhausted ceiling makes coverage partial without calling the provider. Each admitted audit makes one no-retry live backlink-index request for up to twenty direct external source domains. A primary identity/domain, UGC, or editorial lane with no external public-search result may additionally use only its already-disclosed DataForSEO Google Organic query, with no more than three concurrent depth-10 requests and no retry. A confirmed paid plan therefore permits one backlink-index call and up to three conditional Organic calls per audit. The returned provider amount stays private; $0.10 is a post-response circuit tripwire, not a pre-call dollar budget. Provider results are candidates, not findings. Lollipop removes duplicates and the Site's own domain, then safely opens every selected source page. A current anchor to the Site becomes an existing backlink. Visible reviewed-brand or exact canonical-domain text without that anchor may become an unlinked mention; UGC and editorial pages keep their stricter live-page signals. Blocked index sources remain separate Needs-verification evidence. The report includes the page title, public URL, excerpt, query provenance, candidates checked, already-linked exclusions, and pages that could not be verified. Coverage is bounded to up to 20 results per primary query and 45 unique external candidates total, with backlink-index candidates added first; it is not every page on the web. Partial discovery remains visible without changing the audit score or creating another customer answer-check charge. The shared health record is saved immediately when discovery finishes, even if later audit work fails. Scheduled Optimize reuses the plan only while the exact inputs, domain, version, and provider mode still match; older or changed plans require a fresh owner review.

The primary query order is "<reviewed brand>"; a safe quoted title-stripped full name when it remains at least two words; "<reviewed brand>" "<target market>" for a local business; "<reviewed brand>" "<business type>"; "<business type>" ("write for us" OR "contributor guidelines" OR "submit an article"); "<business type>" (magazine OR journal OR news OR editorial); and "<canonical domain>". German audits add für uns schreiben, Gastbeitrag, Autorenrichtlinien, and Artikel einreichen to UGC, plus Blog, Nachrichten, Magazin, Zeitschrift, and Redaktion to editorial discovery. The three possible paid fallbacks are "<canonical domain>" OR "<reviewed brand>" [OR "<safe full name>"], that same localized UGC query, and that same localized editorial query. Lollipop never derives a surname-only identity or runs an undisclosed backup query.

Lollipop unreadable-Site reports

If a public homepage refuses or cannot provide readable HTML, the Site audit completes as 0/100 · Not readable by AI. It stores no invented buyer questions, answer samples, page metrics, or charge. This unreadable result does not consume the included first readable audit.

For a readable Site with completed answer samples, the headline score assigns 60% to the crawl and content result, 20% to the mention rate, and 20% to the citation rate. A numeric section needs 60/100 to show Looks good. If every answer source fails, answer visibility remains unmeasured and does not become an invented zero. Retained reports use their saved crawl result and exact answer counts, so corrected scoring does not require another paid audit.

Lollipop first-site creative brief

A stopped Site audit remains retryable from Overview. The failure appears as an inline notice instead of replacing the entire page, so an earlier report and the Site controls remain usable. Try again resolves the Site's current Project membership before reading answer-source readiness, shows Preparing questions… while it works, and keeps any safe setup error on the same notice. Account switches discard late Project, Site, and Feed responses from the workspace that was just left, and the app never submits readiness or audit writes under a stale Project selection.

A reviewed Change starts with one explicit Apply change action. Because execution changes only Preview, there is no second identically named confirmation. The detail and Change lists immediately show the same durable queued, applying, or verifying progress, continue polling after navigation, and direct the owner to review when Preview is ready. Publishing remains separate.

Publishing an exact Preview normally starts from one click. If the release also contains a function whose check never completed, Lollipop opens a separate confirmation window that names the function and explains the missing evidence. The owner may choose Publish anyway; that explicit signed-in approval is retained through every queued safety check and recorded with the release. A known failed check still blocks publishing and cannot be dismissed as a warning. If a queued Publish stops, Versions shows the safe publish_error and confirms that Published was not changed instead of ending polling silently.

The no-site wizard creates a durable draft with POST /v1/orgs/{slug}/lollipop/site-briefs, autosaves exact revisions with PATCH /site-briefs/{brief_id}, and uses explicit /analyze, /inspiration, and /recommend-style actions for page planning, sanitized palette extraction, and design-language ranking. These authenticated creative actions use the monthly model allowance first, then the prepaid balance. They try the private model first and may fall back to a metered DeepSeek or Kimi route after an explicit provider failure; every stored result names the serving model and whether it was exempt. The pre-account audit and first audit of every Site remain separate $0.00 acquisition paths.

POST /v1/orgs/{slug}/lollipop/sites/{site_id}/audit-questions generates one to six Site-specific buyer questions only when that Site has no saved question set. A buyer question is the first standalone query a buyer would enter into an AI assistant or search engine before knowing the provider, such as Who offers custom floral arrangements for weddings in Toronto? or bold contemporary floral arrangements private event Toronto. Vendor-directed wording such as Do you offer…? and Can you create…? is rejected. The owner reviews the questions before any answer source is sampled. Confirmation persists the reviewed collection on the Site; later manual and scheduled audits reload it instead of regenerating it. The owner can edit, remove, or add questions up to twenty. PUT to the same route saves that collection without starting an audit or charging usage. Prior rows remain historical evidence. The preparation response says whether question_source is generated or saved.

Confirming the reviewed set starts POST …/audits/run and opens a durable six-step checklist for reading the Site, analyzing content, sampling buyer questions, reading cited competitor pages, verifying brand mentions, and saving the report. Refreshing or leaving returns to the saved step. Citation pages are read once without following their links; safe publisher metadata and bounded readable text are retained, while binary bodies are not stored as page text. Competitor candidates remain hidden behind audit_review_status: "pending" until POST …/audit-competitors receives at least one server-issued candidate id. On a completed report, Run another audit is a menu with Rerun full audit, Reselect competitors, and Change buyer questions. A full rerun shows the saved questions and any applicable estimate before confirmation. Competitor reselection updates the latest report without sampling again, while changing buyer questions saves the next audit's set without running one. GEO Optimize consumes saved audit evidence rather than calling answer providers directly.

Model analysis continues against the saved brief while the app polls, so an edge deadline or closed browser cannot erase valid owner input. Style matching persists recommendation_state until the metered result or accessible catalog fallback is ready. GET /style-catalog returns reviewed semantic tokens pinned to an immutable MIT-licensed source commit. POST /site-briefs/{brief_id}/builds freezes the owner-approved revision and starts a live Preview-only build. The exact run records its preparing-Wok, page, function, design-system, interaction-test, and Preview-verification stages through POST /site-briefs/{brief_id}/builds/{build_id}/progress. Sites reloads those stages and pending owner requests across navigation. Completion requires POST /site-briefs/{brief_id}/builds/{build_id}/complete with the exact current Preview receipt and concrete tests. It never publishes; a stopped run retains its evidence for same-brief retry or a new reviewed revision.

The Look & feel stage accepts up to three mixed website and image references in the autosaved brief. Website URLs guide design inspection during the build. Images are decoded, sanitized and reduced to palette and mood notes; raw bytes are never stored. References never authorize copying branding, assets, text or pages. The stage also provides idempotent POST /site-briefs/{brief_id}/palette for explicit private palette derivation from the written brief and up to three preferred colours. It returns the same five semantic roles and serving-model provenance as image analysis; autosave never calls a model. DELETE /site-briefs/{brief_id}/inspiration clears inspiration provenance after the owner decides whether the already-saved derived colours should remain. After an owner selects a verified style, idempotent POST /site-briefs/{brief_id}/refine-style accepts one explicit instruction and stores only allowlisted semantic colour, density, border, heading and motion overrides with parent slug, catalog commit, exact diff, serving model and billing provenance.

Lollipop context now includes exact competitor citation titles from the latest applicable answer sample, associated only when the saved competitor name or domain matches that citation. A Search and AI visibility run must evaluate every approved buyer question against the Site's current relevant pages, its mention and citation result, and those exact titles. Supported gaps become content.update Changes when a suitable page is incomplete or page.create Changes when no suitable page exists; a run that proposes neither records its evidence-based reason. Competitor material is a research lead for topical coverage and answer structure, not a source of copied wording, branding, or claims. When an owner-only fact is missing, the Change stores the question and links each dependent change through needsQuestion, so execution waits for the saved answer instead of inventing it or dropping the opportunity. An approved page.create Change calls POST /v1/orgs/{slug}/lollipop/plans/{plan_id}/runs/{plan_run_id}/article-drafts. The server binds the article to that active execution and Site, requires the exact citation or knowledge titles used, runs the content-quality gate, and places the result in Content for owner review. It never publishes the article or silently writes it into Preview. Every Change opens at a durable direct route, keeps its background attempt and friendly terminal failure across refresh, and can retry a stopped attempt. Changes use action-specific labels derived from their concrete change operations. Applying Changes one after another creates a cumulative Preview: Git source lineage proves which earlier Changes remain included, the Version entry lists the retained set, and publishing the current Preview publishes that set together. A reimport or divergent current deployment offers Reapply change only when its source no longer contains the retained Change; the earlier attempt stays available for audit. A startup failure restores the exact waiting Change instead of leaving a false applied state. A Change or revision checks the organization-wide allowance for the current plan plus prepaid funds before starting; allowance added by an upgrade is available immediately even if the persistent agent key still shows its exhausted prior allocation. A genuinely exhausted run shows a billing recovery box with separate upgrade and prepaid-fund actions, and nested provider details are never shown to the customer. The Agent runs the repository's applicable test, lint, typecheck, and build scripts plus targeted runtime checks before marking Preview ready. Browser checks are optional diagnostics. Third-party scripts remain intact, and browser console, resource, page, navigation, blank-render, and assertion results never block the Change or publication.

The Optimize wizard saves each person's current question and answers under GET|PATCH|DELETE /v1/orgs/{slug}/lollipop/projects/{project_id}/optimize-draft. The draft follows that person across browsers without becoming shared Project configuration. The server bounds every field and verifies that the selected Site and optional edit target still belong to the Project. Changing a completed goal requires confirmation before replacing its dependent outcome; Review links return to the exact question and then back to Review. The frequency step shows the selected Site's current approved-question × ready-source count, maximum provider charge, and monthly-allowance-then-prepaid model funding for a required stale-audit refresh. “Ask Wang to help me choose” first calls the unmetered /optimize-recommendation/estimate route and discloses one ordinary metered request. Only a separate confirmed action calls /optimize-recommendation; it uses approved Project/Site/audit evidence, returns an allowlisted answer with reason and confidence, and never inherits the first-audit exemption. Starting clears the draft only after creating an enabled optimization, freezing plan version 1, and immediately queueing its first durable Agent Cell run. Reviewed edits append another immutable plan version and explicitly do not start a run; Run now and the stored schedule remain the execution paths.

Each optimization stores one explicit target_site_id. That Site is enforced at the Project-context read and Change-write boundaries, so an optimization cannot widen itself to the Account's other Sites. Daily, weekly, fortnightly, and monthly runs are claimed durably; “After each publish” queues only after a verified Published release. Run now and recurring runs first check the selected Site's latest audit. Evidence older than 24 hours is refreshed through the ordinary authenticated Site-audit route with the last owner-confirmed buyer questions and normal repeat-audit funding; a Site without approved questions stops at the question-review step instead of inventing them. Every recurring run re-checks its human owner's current Project capability and uses a short-lived credential that is revoked immediately. A verified publish now freezes an outcome window for every newly published Change in that release, including its expected metric, direction, horizon, pre-release Site/audit reference, and first check time. Project context returns these windows to the selected-Site optimization. A report uses measured_plan_ids only for windows its evidence actually measures and plan_ids only for new draft Changes. The server rejects cross-Site or unpublished links, keeps inconclusive evidence marked inconclusive, and links the first next opportunity without executing or publishing it. Leaving Optimize or closing the browser disconnects only the live progress stream. Reopening Optimize reattaches to the retained run and reports queued, working, Waiting for you, complete, or failed state. Pending questions expose Send reply, and permission requests expose Allow once or Reject. Pause/resume and Run now are immediate lifecycle controls; Remove stops future work while retaining plan, run, and report history. The Agent Cell receives the exact structured report command, must place every report JSON value in a writable /tmp file instead of retrying brittle shell quoting, and is explicitly banned from using durable Changes as schema probes. Reports show the control-plane-assigned comparison period, measured outcome, before/now metric when available, supporting evidence, and the next useful measurement time when evidence is insufficient. Their customer-facing title is derived from the optimization and selected Site, so model-written database or platform identifiers cannot appear in the report or Feed label. The first accepted report atomically completes its run. A confused retry returns the original report receipt and a direct instruction to stop without adding another report or Feed event, and startup recovery closes a reported run left active by a control-plane restart. Verified Preview receipts are derived from completed Change executions; an optimization cannot invent them in its report.

Organization people

The dashboard's dedicated Billing → People page lists everyone with access to the current organization. Owners and admins can add a person by email and choose a role. Email identity is case-insensitive and stored in canonical lowercase, including when a previously removed member is added again with different casing. Removing membership does not delete the reusable account. Adding a person does not send an invitation email; if the address does not have a TellWang account yet, the person can sign up with that same address to claim the preassigned membership.

Workspace Feed

GET /v1/orgs/{slug}/feed returns the owner-facing workspace activity stream and a lifecycle summary for every non-destroyed Wok. Feed items cover customer email, signups, connected business sources, reviewable drafts, GEO audits, provisioning milestones, and connected domains. The overview object reports Published and Preview counts plus each Wok's current active, suspended, pending, or provisioning state. The dashboard uses this to keep sleeping Preview and in-progress setup visible instead of presenting only a flat event list.

Dismiss an item with POST /v1/orgs/{slug}/feed/dismiss {"ref":"…"}. Dismissal is organization-scoped and idempotent.

Deep copy: grounded site rebuilds

POST /v1/orgs/{slug}/storefront-platform/detect accepts {"source_url":"acme.com"}, normalizes a bare domain to HTTPS, and returns a bounded Shopify, Shopline, WooCommerce, or unknown observation with evidence and confidence. A confirmed Shopify result also includes its permanent myshopify.com identity and a stable evidence digest for the publicly detected classic or new customer-account mode. A committed migration cannot create its Preview until those discovery signals are locked. A confirmed Shopline result includes the permanent myshopline.com identity observed from the source domain or runtime. A confirmed WooCommerce result also includes its same-origin WordPress REST root, whether the site uses /wp-json/ or plain-permalink ?rest_route=/ discovery. Detection is a source probe, not merchant authorization or migration readiness. The Shopify account digest excludes dynamic page bytes, so an unchanged account mode has a repeatable receipt.

POST /v1/orgs/{slug}/site-clones captures bounded evidence from an existing site for a clean rebuild. It recursively expands same-origin sitemap indexes and balances the explicit page cap across sitemap groups. Raw mode captures up to 60 pages; render:true captures up to 30 post-JavaScript pages in the background. Each page is capped at 2 MiB and reports whether it was truncated. This is presentation ground truth, not a claim that the whole site, database, user accounts, inventory state, cart, payment flow, or checkout was imported.

⚠
Low-level capture boundary: these site-clone endpoints stop at capture, manifest/artifact reads, passive-asset rehosting, and cleanup. The committed Shopify journey composes separate connections, internal brokers, and the fixed worker for import, compile, Preview deployment, and parity. No low-level capture response is a one-to-one migration claim.

The dashboard exposes bounded Shopify, Shopline, and WooCommerce public capture plus committed Shopify or Shopline live_transition setup in the top-level Import workspace. A Shopify or Shopline journey can provision a journey-unique pair or select a fresh empty unassigned owned Preview, persist and recover its current action, and begin server-handled provider authorization. A Shopline journey securely stores its rotating Admin grant and app-owned Storefront token, then continues through provider-specific extraction and the shared capture, execution, Preview, evidence, parity, rollback, and handoff path. A detected WooCommerce source is directed to Tryout before journey creation. The three Shopify connections, fixed worker, compatibility runtime, internal Preview deploy bridge, deployment-bound browser and commerce evidence producer, fail-closed parity gate, and editable Wok handoff are integrated behind signed, lease-bound contracts. Merchant authorization, a complete route universe, browser evidence for every non-catalog route, locale-matched product and collection template evidence, a digest-bound catalog route set, app, account, and checkout evidence, independent QA, and owner review must still pass; neither a capture receipt nor a stored connection is a migration-ready claim.

Storefront connections and committed journeys

Organization Bearer routes expose safe connection metadata through GET /v1/orgs/{slug}/storefront-connections. Begin the browser-bound Shopify installation and full-migration OAuth journey with POST /v1/orgs/{slug}/storefront-connections/shopify/authorize, begin Shopline authorization through the exact assigned custom app or reviewed public app with POST /v1/orgs/{slug}/storefront-connections/shopline/authorize, provision the normal managed Storefront runtime with POST /v1/orgs/{slug}/storefront-connections/{connection_id}/shopify/storefront-runtime/managed, detect and bind the live store's classic or new customer-account mode to the exact Preview with PUT /v1/orgs/{slug}/storefront-connections/{connection_id}/shopify/customer-account, or reload its secret-free setup by account connection ID with GET /v1/orgs/{slug}/storefront-connections/{connection_id}/shopify/customer-account, WooCommerce read-only application authorization with POST /v1/orgs/{slug}/storefront-connections/woocommerce/authorize, or signed WordPress connector pairing with POST /v1/orgs/{slug}/storefront-connections/woocommerce/connector/authorize. The WooCommerce routes are not available for live migration. TellWang keeps the generated single-store install link in platform secrets. Its same-origin launch verifies the requested store and client before Shopify opens; Shopify returns to a signed installation callback that automatically continues into the exact full-migration.v1 grant. The authorization response includes the permission-contract version and SHA-256, and the current journey action discloses the complete scope set before approval. The matching public callback routes validate one-use state or challenge evidence before encrypted credential storage. Shopify also binds the initiating browser with signed HttpOnly cookies, then returns 303 to the validated relative return path with only the non-secret storefront_connection ID. At most ten unconsumed authorization states may exist per organization and provider; a capped start returns 429 with Retry-After: 60. One installed TellWang Shopify app/store pair may have one active or revoking TellWang organization owner. A callback from another organization fails before Shopify token exchange with CP_STOREFRONT_SHOPIFY_STORE_ALREADY_CONNECTED. Keep using the owning organization, or finish disconnect and provider revocation there before authorizing the store elsewhere. Emergency-disconnect a connection family with DELETE /v1/orgs/{slug}/storefront-connections/{connection_id}; this terminates migration leases, removes both reserved Shopify Wok environment bindings, scrubs stored credentials, and restarts every active linked Preview and Published Wok. The family reaches revoked only after every restart succeeds. Shopify-side app removal remains visible as provider_revocation_pending; the merchant must uninstall TellWang in Shopify Admin to finish provider-side cleanup. Shopify sends signed app/uninstalled and app/scopes_update events to POST /v1/storefront-connections/shopify/webhooks so the reconciler can scrub a revoked or scope-drifted connection family. Additional merchant-restricted Shopify apps may coexist with the primary app through the bounded platform-secret registry. Each app has a stable custom:<slug> identity, distinct credentials, and one Shopify-generated install link bound to one permanent *.myshopify.com store. TellWang selects that app only for its assigned store and preserves the issuing identity for callback, refresh, lifecycle, and revocation checks. Registry values never enter a merchant form, Wok environment, response, or log. No storefront-connection MCP tools ship in this slice.

/diag reports shopify_migration_oauth as healthy only when the managed app credentials, every configured custom-app assignment, exact HTTPS callback, and control-plane encryption key are available. Authorization and callback responses are non-cacheable and use a no-referrer policy. Shopify must return an expiring offline token with the exact full-migration scope set; the credential is retained only in its encrypted connection envelope.

Shopline uses the same connection boundary through either the exact store-bound custom app or the separately reviewed public app. Their signed install and OAuth callbacks live at GET /v1/storefront-connections/shopline/install and GET /v1/storefront-connections/shopline/callback. Signed lifecycle events post to POST /v1/storefront-connections/shopline/webhooks; required customer and merchant redaction events post to POST /v1/storefront-connections/shopline/compliance. Because current Shopline webhook versions are managed through the Admin API, TellWang verifies or creates the exact uninstall subscription during OAuth and fails the connection closed if that receipt is unavailable. shopline_migration_oauth and shopline_oauth_refresh report app configuration and ten-hour credential renewal health. TellWang stores the Admin grant and app-owned Storefront token encrypted and returns only secret-free connection metadata.

Before retaining a grant, TellWang verifies Shopify's immutable Shop ID and permanent domain through Admin GraphQL. Background renewal stays bound to that grant, and signed lifecycle events must match the stored Shop ID.

The Admin scopes are read_themes, read_products, read_product_listings, read_publications, read_online_store_navigation, read_online_store_pages, read_metaobjects, read_metaobject_definitions, read_markets, read_locales, read_translations, and read_legal_policies. The Storefront scopes are unauthenticated_read_product_listings, unauthenticated_read_product_inventory, unauthenticated_read_product_tags, unauthenticated_read_content, unauthenticated_read_metaobjects, unauthenticated_read_selling_plans, unauthenticated_read_checkouts, unauthenticated_write_checkouts, unauthenticated_read_customers, and unauthenticated_write_customers. The Storefront writes are shopper checkout and account operations. No Admin write, order, payment, domain, or traffic scope is accepted.

This is one Shopify app approval, not one generic credential. The broad OAuth token remains encrypted in the control plane. The migration worker receives only fixed operations for resolving the published MAIN theme, reading bounded theme-file pages, and verifying the same snapshot. TellWang also creates or reuses an app-owned public Storefront token inside the control plane, verifies its exact ten-scope contract, and stores it encrypted for the protected Wok server. The merchant does not install Headless or paste a token for this managed Storefront runtime; stores using newer Customer Accounts may still need Headless-channel public-client setup. The runtime connection reports auth_mode: managed_public_token. CP_STOREFRONT_SHOPIFY_MANAGED_RUNTIME_UNAVAILABLE means provisioning can be retried without another approval; CP_STOREFRONT_SHOPIFY_MANAGED_RUNTIME_INVALID means Shopify did not return the exact runtime contract; and CP_STOREFRONT_SHOPIFY_MANAGED_RUNTIME_NOT_EXTENDABLE means TellWang must publish a storefront-capable, extendable app version; retry later with the existing merchant approval. The control plane renews the rotating offline grant five minutes before access expiry and records a secret-free bounded retry schedule. The shopify_oauth_refresh diagnostic degrades for expired or near-expiry grants and renewal backlog. Transient renewal and managed runtime failures retry with the existing approval. A merchant reconnect is requested only after the offline grant is definitively revoked or expired. That path archives secret-free lineage, removes stale capture and execution evidence, and returns the same journey to source authorization. Any permission expansion requires a new approval. The PUT …/shopify/storefront-runtime private-token route exists only for MigrationTemplate 1.0.0 compatibility and is not part of the normal Import journey. The Customer Account row is mode-specific. The server probes the live journey's public /account route and binds a digest of that evidence. Classic mode reuses managed Storefront access, accepts no public client or OAuth URLs, and generates only a sealed Wok session key. New mode requires a public Headless Client ID, binds the exact Preview callback/origin/logout URLs, and verifies Authorization Code with PKCE S256 discovery. Its GET returns only secret-free setup metadata, including account_mode, auth_mode, and mode_verified. No Storefront token, buyer password, customer access token, or session key is returned.

Mode detection or discovery is setup evidence. Account login, logout, order history, and checkout are tested on Preview before launch.

Managed Storefront verification reads shop, navigation, product, inventory, tag, page, and blog data, then creates an empty cart and validates its HTTPS checkout URL. The signed Shopify Marketplace template requires unauthenticated_read_checkouts, unauthenticated_write_checkouts, unauthenticated_read_product_listings, unauthenticated_read_product_inventory, unauthenticated_read_product_tags, unauthenticated_read_content, unauthenticated_read_metaobjects, unauthenticated_read_selling_plans, unauthenticated_read_customers, and unauthenticated_write_customers. The managed token stays in protected server configuration. Safe retries reuse the same app-owned token and do not reopen Shopify approval.

POST /v1/orgs/{slug}/storefront-migration-journeys starts a committed Shopify or Shopline v1 journey with a stable Idempotency-Key, source URL, rights assertion, and either a new or existing Preview target. intent:"live_transition" follows capture, compilation, Preview, evidence, and parity. Shopify also accepts intent:"commerce_only": it binds the protected Storefront commerce configuration and returns page_strategy:"custom" without capturing, importing, or generating pages, routes, a runtime definition, or a launch. Its first Git snapshot installs any missing runtime baseline, records it, and makes the server and provider editable Wok source without replacing author-owned storefront-source/. A new target receives a server-owned journey-unique Wok name; an existing target must be active, empty, and unassigned. Completion accepts only the exact linked Preview returned by provisioning. Collection and item GET routes recover secret-free journey state. shopify-adapters/preflight refreshes the authenticated, root-owned adapter inventory and returns only required keys, availability, and accepted SHA-256 pins. Missing adapters remain platform-owned work. When a connected development store returns a password page, POST .../{id}/shopify-storefront-access accepts its Online Store password over HTTPS, exchanges it server-side for Shopify's temporary storefront session, including the cookie-bound authenticity-token form and updated essential session required by development stores, discards the raw password, seals the session to that organization, journey, connection, and exact store host, then restarts the same failed capture. It does not put the password in a URL, public receipt, Wok environment, or Wok Git. The dashboard supplies a private idempotency key so a successful network retry does not exchange the password again. Item resume, cancel, and current action begin/complete routes enforce server-owned transitions; deletion is allowed only after a terminal cleanup-eligible state. Shopline completion pins the exact encrypted connection and starts its server-owned source inventory and reference capture. A complete capture is promoted into the same immutable execution lineage used by Shopify; provider-specific receipts prevent cross-provider replay. The server rejects WooCommerce or unknown sources before journey creation; those sources remain available through public Tryout capture. Completing Shopify authorization accepts only an active same-organization connection for the canonical store, pins its secret-free digest, and creates one idempotent discovery capture plus a durable aggregate bound to the exact organization, Preview Wok, canonical source, Shopify connection digest, and authorization action. A sealed route universe can contain up to 20,000 routes; deterministic segments contain at most 20 routes each, with an independent bounded network budget. Journey reads retain the flat discovery fields and add aggregate_id, universe:{contract_version,route_count,route_set_sha256,complete}, segments:{segment_size,total,pending,running,complete,failed,captured_routes,failed_routes}, and coverage_complete. Coverage becomes complete only when the exact expected segments all succeed and their route total equals the sealed universe. Dashboard clients accept retained segment sizes from 1 through the 200-route capture ceiling so an older resumable journey remains operable after capture geometry changes. While discovery is pending, universe is absent; the API never emits an unversioned placeholder. Resume replaces only failed segment attempts. The top-level route_coverage object remains absent until route reconciliation produces its fixed coverage fields. reference_capture.started_at records capture creation and worker_job_started says whether the worker accepted it. reference_capture.updated_at is the latest bounded status check for the discovery capture; aggregate polling does not overwrite it, and clients must not describe it as a worker heartbeat. Pending, incomplete, and failed evidence is reported with MIGRATION_SHOPIFY_ROUTE_UNIVERSE_PENDING, MIGRATION_SHOPIFY_ROUTE_UNIVERSE_INCOMPLETE, MIGRATION_SHOPIFY_REFERENCE_SEGMENTS_PENDING, or MIGRATION_SHOPIFY_REFERENCE_SEGMENTS_FAILED. The editable Preview remains pending until every declared route segment succeeds. Commerce evidence, parity, and launch also require every declared adapter to succeed. Retained WooCommerce journeys cannot advance or resume. MCP exposes start_storefront_migration, list_storefront_migrations, get_storefront_migration, resume_storefront_migration, and cancel_storefront_migration. Action completion and delete remain REST-only. A direct clone deletion cannot remove reference evidence while its journey remains active. These merchant routes do not perform DNS cutover or rollback.

The semantic /diag storefront-migration check reports running and failed reference captures plus authorized imports still waiting for execution admission, alongside journey status counts. shopify_preview_adapter_ready counts exact adapter snapshots that can admit only an incomplete Preview, and shopify_template_previews_deployed counts those Previews with a retained deployment receipt. Neither count means launch-ready.

The broad Admin OAuth credential never passes through a journey response, migration worker, or Wok. A loopback-only internal relay verifies the exact organization, journey, execution, pinned connection ID and authorization digest, fixed theme operation, live lease, and fencing token before it runs the allowlisted Admin query. The control plane rotates the expiring offline token under encrypted storage. A second broker binds the managed Storefront runtime to the exact candidate_deploy fence. The internal Preview deploy route accepts only the signed gzip and canonical secret-free lineage for the current compile receipt, injects the sealed provider configuration itself, and validates the archive into a detached Wok Git worktree. It commits the exact editable storefront source, deploys an export of that commit, then fast-forwards canonical Wok Git only after runtime activation. The immutable receipt keeps separate compiler-package, Git-export, Wok-commit, and live-runtime digests. Visual definition and asset edits remain deployable while the generated server and commerce provider are protected before Git handoff. Failure restores the prior runtime, environment, and only the managed Git paths, preserving unrelated Wok edits. A successor execution can replace a prior generated storefront only when the same journey's active deployment receipt and exact Wok Git commit prove that no managed-path edit has occurred. It never changes the live Shopify theme or hostname. While the journey is active, direct frontend/app-server writes, edge-function changes, generic promotion, and custom-domain attach or verification return CP_STOREFRONT_MIGRATION_MUTATION_BLOCKED. Wok Git is the editable path because it runs the post-edit commerce gate. The lock ends when the journey is live, rolled back, cancelled, or failed. After that handoff, TellWang excludes runtime-package-manifest.json from deployment and carries the Wok's versioned server and provider. Runtime edits do not regenerate or re-sign the retired migration package and still pass release gates.

The admitted Shopify workflow imports the published MAIN theme, preserves its authorized DOM, classes, responsive CSS, passive assets, and reviewed JavaScript, and binds commerce to Shopify's APIs. Exact local scripts execute under checksum-bound signed review and a fixed same-origin browser policy; modules, workers, inline handlers, embedded external URLs, and unreviewed bytes block compilation. The browser policy blocks cross-origin requests from computed URLs. The fixed worker then captures the exact Preview under the same route universe. Its pinned gate compares desktop/mobile pixels, DOM landmarks, document height, scroll reach and effects, interactions, console errors, and network failures. Commerce receipts are required for product view, variant selection, cart add/update/remove, search, Customer Accounts, Shopify-hosted checkout handoff, and every discovered app or unknown dependency. Missing, duplicate, stale, wrong-deployment, malformed, or failed evidence blocks the report.

The source Shopify Online Store remains live while the migrated Wok runs at its Preview hostname. No endpoint publishes or replaces a Shopify theme, changes DNS, or moves shopper traffic. See the Storefront Import guide.

Use capture_profile:"quick" for a fixed two-route browser evidence sample: the canonical homepage plus one same-origin product detail page selected from bounded sitemap discovery or homepage links. The source must be the storefront homepage and max_pages is always 2. If no public product route is discoverable, the capture fails with CP_CLONE_CAPTURE_PRODUCT_ROUTE_NOT_FOUND instead of using an unrelated second page. The receipt exposes capture_profile:"quick" and route_selection:"home_and_product". This mode does not require a Wok, authorize a provider, connect commerce, generate pages, deploy, or change the source store.

Use capture_profile:"migration" when the rebuild needs browser evidence beyond HTML and text. The configured Crawlee/Playwright worker retains up to 20,000 bounded same-origin sitemap and anchor discoveries, then records up to 200 selected routes in either manifest contract (100 by default). Sitemap leaf groups are selected round-robin before anchors fill unused capacity. The manifest reports discovered, selected, captured, and failed counts separately, plus rendered DOM evidence, desktop/mobile screenshots, network observations, scroll traces, bounded non-navigating interaction outcomes, and live dependencies. Every bounded interaction, scroll-effect, network, and live-dependency stream includes observed/retained counts plus a completeness receipt; an incomplete receipt blocks parity instead of hiding truncation. Crawlee completes first, then the Browsertrix sibling receives the exact canonical final route URLs Crawlee captured with page-only scope. Its fixed driver permits only GET, HEAD, and OPTIONS, blocks WebSocket requests, and disables service workers. The sibling rejects missing or extra page records. The manifest binds the sorted route set with oracle.route_set_sha256, oracle.captured_routes, and oracle.read_only_policy:"safe-http-methods-no-websocket-v1". The Browsertrix WACZ is required. Missing, failed, route-mismatched, or policy-mismatched evidence fails the capture. A connected password-protected Shopify development store can carry only TellWang's exact-host temporary storefront session. It is sealed before durable job storage and is never passed as a command argument. Because the capture records request cookies for replay fidelity, the short-lived session may persist inside your private WACZ capture evidence until retention deletes it. It never appears in public receipts or generated storefront code. This is bounded capture evidence, not deployable source or one-to-one proof. cap_reached:true means routes were left unselected or bounded discovery evidence is incomplete. New migration captures use v2; v1 remains readable for retained jobs. Neither contract persists or continues a larger frontier. V2 carries a server-observed Shopify, WooCommerce, or unknown source identity and uses provider-neutral cart, checkout, account, search, extension, and API dependency labels. It still does not reconcile a complete provider inventory. Migration creation requires an Idempotency-Key, is asynchronous, cannot be combined with render:true, and never silently falls back. Its durable replay checks the originally requested URL, platform, Wok, and page bound before probing the source again. An identical retry can therefore recover the retained job while the storefront is offline; changed intent is rejected. New jobs persist the safe canonical URL after public redirects and retain a WooCommerce REST root when one was discovered. The successful handoff is capture_complete:true and migration_ready:false: the manifest is an implementation and comparison oracle, not deployable source or proof of functional parity.

Shopify acceptance uses parallel operation: keep acme.com on the original Shopify Online Store while every public route is built and compared in one immutable Wok Preview. Shopify checkout continues through its returned HTTPS checkout URL. The receipt and policy are Preview-only and set theme_action:"none". They cannot authorize DNS, theme publication, or shopper-traffic changes. Moving the hostname needs separate owner approval.

Managed RAG

RAG is an optional per-Wok API and durable worker, not another application contract to learn. Choose LangChain or LlamaIndex when enabling it; apps call the model gateway at /llm/v1/rag/{wok_id}/.... Vectors stay in the Wok's Postgres through pgvector, source and generated files stay in private Wok Storage, and jobs use the Wok's Redis queue. RAG accepts only anon, authenticated, and service_role Wok tokens. Trusted application roles and groups come from signed app_metadata, but application roles cannot impersonate those reserved Wok roles; anonymous callers can retrieve only material marked public.

A customer-facing retrieval or chat function authenticates to the model gateway with its injected TELLWANG_RAG_GATEWAY_KEY and forwards the caller's exact signed Wok bearer separately in X-Wok-Authorization. The gateway verifies organization ownership and preserves the identity used for document ACLs.

External messaging providers are application integrations, not TellWang primitives. A WeChat bot, for example, is built from ordinary editable resources inside a Wok: Edge Functions for callbacks and messages, Wok secrets for provider credentials, tables for application state, and the managed RAG API for grounded answers. The reference Wok acknowledges the provider webhook before longer grounded work continues as an Edge Function background task; durable event and delivery rows support recovery. Each visitor has a continuing, organization-visible service thread with bot and human attribution. Questions without a grounded answer enter the shared service inbox, where a Wok administrator can answer directly and separately approve a non-sensitive question and answer for later public RAG. Outgoing model and administrator replies are converted from Markdown to readable WeChat text before delivery. It may be installed as an immutable marketplace Wok release, but installation does not add provider-specific platform endpoints, MCP tools, or privileged credential paths.

Owners can drive these endpoints through a connected MCP client or Wang. The dashboard's Enterprise RAG capability generates an app-scoped prompt that covers RAG setup, governed collections, ingestion, document policy, grounded agents, generation, and insights. The app's Documents surface shows storage buckets, collections, each active indexed file, its governed metadata, and a signed action for the private source. Its Add documents action uploads approved files into a selected collection, requires an explicit public/internal/confidential/restricted access level, and shows parsing and indexing progress before reporting that the files are ready. The org-level Wang knowledge API is different: it holds a small plain-text memory for Wang itself, while app RAG is the governed vector corpus for application features.

Use Wok Storage's resumable upload flow before the manifest endpoint for very large corpora. The multipart /rag/uploads convenience route is capped at 100 files; MCP clients should keep each sequential browser-originated batch below 900 MiB so multipart overhead stays within the management proxy ceiling. Files use digest-bound content-addressed paths. A non-ASCII filename remains the visible title but receives a deterministic ASCII Storage key. Identical retries do not upload again and changed bytes cannot silently replace indexed content; the manifest route remains the scalable contract. Hybrid retrieval combines dense, full-text, and multilingual trigram rankings with reciprocal-rank fusion, then removes candidates below the absolute semantic and text gates. Meaningful embedded PDF pictures and charts are privately vision-described and indexed; one broken image stream is skipped without losing readable text, and the child result reports that failure. Standard Woks describe at most four pictures per PDF and high-throughput Woks at most eight. Those calls use the organization's included model allowance first, then prepaid credits; model 429/5xx responses receive bounded worker retries. An authorized visual hit carries its page, dimensions, media type, and a 15-minute signed preview suitable for an application channel's media upload. The Documents surface shows a Load more action instead of silently truncating a large collection. Disabling RAG closes its route and revokes its dedicated model key while keeping the corpus in the Wok for re-enable.

Marketplace Wok releases

A marketplace listing is a signed, immutable Wok release, not a prompt or Wang recipe. Installation applies its exact migrations, function module trees, frontend, portable Storage and Realtime declarations, managed RAG setup, and named configuration to an untouched Preview Wok. The buyer owns the result; no model participates and no later version installs automatically. The WeChat reference Wok keeps a continuing service transcript, hides internal citation labels, presents localized source names, answers every grounded part immediately, and places only the unsupported scope into its shared service inbox.

Storefront migration templates use a separate closed contract and never enter the ordinary Wok-release installer. The dedicated registry validates canonical MigrationTemplate v1 manifests, retains the manifest only, and moderates domain-separated Ed25519 signatures through the existing Marketplace keyring. Shopify and Shopline each have an exact TellWang-trusted workflow, dependency-only compatibility WokRelease, parity profile, and connection contract. Their identities and immutable digests are not interchangeable. Publication and every later read re-verify the complete provider-specific manifest.

Marketplace is a top-level dashboard destination beside Feed and Apps. The plus control in Feed and Apps, and the New app control on the Apps page, open the same choice: start an app build in chat or browse ready-made Woks in Marketplace.

An MCP-native agent reaches the same endpoints through list_marketplace_releases, get_marketplace_release, install_marketplace_release, and get_marketplace_installation. The install tool takes an optional idempotency_key and mints one per call when it is omitted; pass the same key to make a retried call replay one attempt instead of starting another. Gates live in the endpoint, not the tool: a production target, a Preview holding customer work, an unsigned or altered artifact, configuration names that do not match the signed declaration, and blank required values are all refused. build_skill generates an application from instructions and is not a route to a marketplace release.

Moving an installed app to a newer version

Installation needs an empty Preview Wok. Once you have edited the app you own, that requirement is exactly wrong, so upgrades are a separate operation with a three-way merge: the version you installed, the newer version, and your Wok as it is now. A file you never touched follows the release. A file the release did not change stays as you left it. A file both changed since installation stops the upgrade — nothing is written, and the receipt names every such path for you to answer.

Databases move forward only. A newer version may add migrations; it may not rewrite one your Wok already ran, because that statement's effects are already in your data. That refusal is not something a resolution can override — it belongs in the release. The same holds for a changed managed-RAG declaration, which needs a fresh Preview/Published pair for the same reason promotion refuses it. A clean upgrade re-runs the release's verification contract against the merged app, then records the new version as your Wok's base. Published is untouched until you promote, and promotion applies its own gates again. The MCP tools are plan_marketplace_upgrade, upgrade_marketplace_release, and get_marketplace_upgrade.

After the package tests and owner Preview approval, ordinary Wok promotion replays the signed release's portable bucket policies and managed-RAG declarations onto Published without copying staging rows or Storage objects. Anonymous bucket writes are create-only. A newly introduced RAG runtime and its model key are retired if a later promotion gate fails; a different RAG release version does not overwrite an existing runtime. Provider-specific behavior remains editable Wok code.

Brand voice

The dashboard's Brand voice tab compares a public website with current answers from Google AI Overview and ChatGPT Search. It returns the answer and citations from each available surface, a 0–100 drift score, likely causes, suggested site fixes, and a prompt Wang can use to implement those fixes. A higher score means the AI answers omit more of the website's prominent language; it does not claim sentiment or factual accuracy.

Audit log

Every state-changing call to TellWang writes a row to a tamper-evident, hash-chained audit log. Customers query their own org's chain:

Response shape: {entries:[{id, actor_kind, actor_id, action, target_kind, target_id, http_status, correlation_id, payload, created_at}], next_cursor}. Payload values that touch secrets (env values, key material) are stored as fingerprints — names + hashes only, never plaintext.

The dashboard Feed reads the org activity stream, while this per-Wok endpoint remains available to any authorized REST or MCP client.

Web analytics & session replay

Apps with first-party analytics enabled report cookieless pageviews, daily visitors, custom events, sources, campaigns, country/region, device class, browser language, privacy-safe clicked elements, conversion outcomes, aggregate click cells, and scroll depth. GET /v1/woks/{id}/analytics/web?days=7 returns traffic plus those aggregate breakdowns, including countries for all visitors and countries for visitors who clicked. Each demographic bucket counts distinct daily visitors, not cross-day identities. GET /v1/woks/{id}/analytics/heatmap?path=/&days=7 returns a normalized 20×30 click grid and ten scroll-depth buckets.

TellWang validates direct and Cloudflare-proxied client addresses before country and region are derived against a local database, then the raw IP is discarded. Referrers are reduced to an external hostname. Add data-tw-analytics="pricing-cta" to name an interactive element without sending its text or selector, and call window.twConversion("signup", "success") with an outcome of success, failure, or cancelled. Raw click coordinates, selectors, DOM text, input values, and full referrer URLs do not enter these aggregate datasets. Age and gender are not inferred or stored. IP geolocation by DB-IP.

TellWang operators can view aggregate analytics and build usage for active production Woks: cumulative Wang and Agent Cell execution time and tokens, the latest run, connected domains, and the same aggregate audience rollups. Every access is audit-logged. Queue time and customer-facing app LLM calls are excluded from build usage. Analytics is Wok-level, so platform traffic counts each Wok once even when several domains route to it. This view never exposes raw collection files, raw IP, age, gender, person profiles, or session replay.

Session replay is separate and off by default for each Wok. An owner or admin can enable it in the Analytics tab or with PATCH /v1/woks/{id}/analytics/session-replay and {"enabled":true,"capture_visible_text":true,"acknowledge_privacy":true}. Existing Woks default to masked text. Full-fidelity mode records ordinary visible page copy, layout attributes, and web fonts; form inputs remain masked, data-tw-mask protects selected text, data-tw-block excludes a sensitive subtree, and canvas stays off. The response separates the saved Wok preference from recording_available; TellWang records every eligible human session after that opt-in. Global Privacy Control and automated browsers stop the recorder; Do Not Track does not. Private lifecycle markers account for idle reading time even when the visitor does not click or type. Each upload is signed for one Wok, one unlinkable session, and the selected privacy mode. Public bootstrap and ingest are rate-limited; ingest redacts input values, event handlers, and URL queries/fragments again before owner-only storage capped per session, per Wok, and globally.

Wang uses list_session_replays to triage these summaries without reading raw DOM events, and configure_session_replay after an owner explicitly accepts the privacy behavior. Recordings are deleted after seven days. Verified custom domains serve the same complete collection and recorder-library route set as standard Wok hosts.

Wok internals — SQL, functions, realtime, scheduler, env

Once a Wok is provisioned, drive its full surface from the same Bearer-of-owning-org auth. Every endpoint is authorized server-side against the owning org — cross-org access returns 404 with no leak. Use REST directly or connect an MCP client from Build with an agent.

Frontend changes ship through git

Every plan gets the Wok's own git repository. git_snapshot returns a clone URL for the Preview Wok; edit the checkout with your normal tools, commit, and push — the push deploys frontend/ and functions/ through the authenticated release path and returns a receipt. Git pushes and browser_check hold a Preview activity lease while they run. A live-store Shopify migration can be snapshotted after Import installs its editable-source baseline. A completed or already-cancelled commerce_only / custom_build_ready journey may take its first snapshot without imported presentation when its exact verified runtime connection remains active. The owner-requested snapshot installs any missing baseline, records the platform version server-side, and hands storefront/server.js plus storefront/shopify-commerce-provider.mjs to the Wok as editable source while preserving storefront-source/. Existing Woks remain protected until their owner requests a new snapshot. Its receipt reports shopify_runtime_adopted, shopify_runtime_editable, and shopify_runtime_source_ready. Credentials stay sealed in Wok environment state and never enter Git. Imported baselines keep a small storefront-source/manifest.json and one HTML file per captured route; TellWang rebuilds the large runtime definition only inside the deployment artifact. The snapshot is serialized with migration work and ends active mechanical migration ownership. Later snapshots preserve Wok-owned runtime edits. Runtime and presentation changes travel through the same validation, Preview evidence, and promotion path. Run the checkout's applicable test suite, show the exact Preview and test summary to the owner, then promote with that approved receipt's pins. browser_check remains optional diagnosis.

SQL console

Edge functions

Functions receive the following env vars at runtime: SUPABASE_URL (the wok's PostgREST), SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, JWT_SECRET (the stack's JWT signing secret — the same one GoTrue signs with and PostgREST validates against), SUPABASE_DB_URL, REDIS_URL (per-wok Redis 7 container, AUTH via the wok's db password), and TELLWANG_FUNCTION_SCHEDULE_URL for delayed invocations. These are injected and platform-managed — set_env rejects them; read them with Deno.env.get(...). The Redis instance is bullmq-ready out of the box — see Functions → Redis + BullMQ for the canonical pattern.

Release receipt

GET /v1/woks/{id}/release answers what is live without reconstructing it from several tools. It returns the newest attempt, the current successful release, the previous rollback target, the Wok Git source commit, the shared release manifest, a SHA-256 digest of the deployed bytes, changed runtime surfaces, verification evidence, and publish/rollback approval identity. A newly activated deployment remains verifying; it cannot become succeeded until every required probe passes. The current release follows runtime activation order, so a delayed probe cannot make an older candidate replace newer live bytes in the receipt.

release_status=verified means the exact frontend tree, complete function-module tree, ordered tenant migration checksums, Wok Git source, and runtime artifact all match the manifest, and every effective changed surface has relevant passing evidence. Frontend/SSR changes need a browser or public-URL check, function changes need an invocation, and database changes need their declared postconditions. A normalized byte-identical frontend receipt is marked effective_noop:true and finishes without browser evidence only when an earlier non-no-op receipt already proved those exact live bytes. An unmarked empty surface list does not silently pass, and a no-op receipt cannot bless or supersede a failed verification. Promotion still compares Published with the full pinned Preview manifest, while requiring new evidence only for effective Published changes. A newer failed attempt is never skipped. External remote URLs are credential-scrubbed and compared with their last fetched tracking ref; Wok Git remains authoritative. A release whose required check never ran is recorded as unverified rather than failed: the content was deliberately retained and is still live, nothing reported a problem with it, and it can still accept the check it is waiting for. An explicit failed Preview deployment or verification remains failed with its evidence while the candidate stays available for diagnosis and revision; only a deliberate rollback changes Preview back. Browser checks require a completed navigation, visible rendered content, and every requested assertion to pass. Uncaught exceptions and console.error output stay visible for diagnosis, but inherited analytics or third-party script errors are warnings when the page still renders and every target assertion passes, and they do not revert the change. Browser checks are diagnostic: console output, navigation failure, a blank render, or a failed target assertion never fails, compensates, or blocks publication. A passing targeted check may still appear as a positive observation. Use element_attribute to verify exact DOM attributes such as a meta description, and request no_console_errors only when a clean console is itself part of the change. A page that never loaded, a failed check, a console-only check, and a check run with no content assertions record no negative evidence. Promotion may accept release_status=unverified after explicit owner approval when frontend browser evidence is the only missing signal; function, database, and context evidence still fail closed. Reading the receipt never waits out a release in progress: while a deploy or promotion still holds the Wok's release lock, the receipt returns release_in_progress:true and reports the alignment verdicts as unavailable rather than comparing a tree that is mid-write. The deployment history and statuses stay current; poll again once the release settles.

POST /v1/woks/{id}/releases/{deployment_id}/rollback creates a new audited rollback release from a source-linked successful deployment. It restores frontend and functions exactly, including removing functions absent from the target, and disables any enabled function schedule whose target disappeared. It never deletes history or reverses schema/data. Before mutation TellWang persists the current source and complete function-schedule set; a failed rollback replays both so partial code and dangling timers are not left live.

Publishing queues a server-owned job bound to the exact newest owner-approved Preview deployment, its artifact digest and its full manifest. The call returns a deployment id immediately; clients poll that receipt, and disconnecting does not cancel the release. Abandoned queued or building jobs are picked up again automatically under a database lock. The worker reconstructs code from the pinned Wok Git commit, preserves generated SEO files as exact snapshot bytes, reapplies the anon-key and analytics transforms that snapshots intentionally remove, and rechecks live Preview immediately before touching Published. TellWang rejects an older id, a mismatched digest, a newer attempt, a failed current attempt, or source, artifact, context or manifest drift. Published cannot verify unless its complete function tree, derived static frontend or source-backed storefront tree, migrations and declared surfaces match the pinned manifest. A terminal Shopify storefront carries its exact managed Git source to Published. When the Preview has an explicit editable-runtime handoff, promotion carries its versioned server and provider too; otherwise Published continues using the protected platform runtime. The retired migration attestation is never promoted. An empty frontend/ directory is not classified as a no-op. A failing browser check is diagnostic and does not restore or invalidate frontend. On Published, a failed function check restores functions and schedules only; on Preview, it leaves the failed candidate and evidence in place for fix-forward work. A source-backed Shopify SSR frontend has no static frontend/ tree, so a Published frontend-only verification failure replays the preceding verified Wok Git source through the validated app-server deploy path and probes the restored origin. Mixed Published frontend/function failures retain the surface-scoped path. Restore targets are preflighted from immutable Git and their live hashes are checked before compensation completes. Explicit no-op receipts never supply independent proof, supersession, or a runtime pin. A failed staging promotion creates a durable production release hold only after Published was actually mutated. TellWang keeps clone/fetch available, but a Git push cannot activate production under the old promotion approval. Repair staging and submit a new pinned release. Calling create-staging first proves the linked Preview's database and every rendered service are reachable. If its Compose runtime or network is missing, TellWang reconstructs the infrastructure from persisted state and verifies that application artifacts did not change before returning success. It can also restore a linked Preview's lost application schema from Published: TellWang replays Published's schema only, never production rows, and adopts existing ledger history only after the two application-schema fingerprints match exactly. A non-empty divergent Preview is preserved, and historical ledger rows remain append-only.

Realtime publication

Scheduler

Environment variables

Most common use: wire OAuth providers (Google, GitHub, Apple, Azure, Bitbucket, Discord, Facebook, LinkedIn, Notion, Slack, Spotify, Twitch, Twitter, Zoom) by setting GOTRUE_EXTERNAL_<PROVIDER>_ENABLED=true + _CLIENT_ID + _SECRET + _REDIRECT_URI. See Auth → Other providers. Google sign-in needs none of this — enable_google_login uses TellWang's own Google client. GOTRUE_RATE_LIMIT_HEADER is platform-managed: the edge overwrites its matching private header with the validated end-user address before proxying Auth, and a customer value cannot replace that boundary.

paste-dotenv.sh
curl -X POST https://tellwang.com/v1/woks/$WOK/env \
  -H "Authorization: Bearer $TELLWANG_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dotenv":"GOTRUE_EXTERNAL_GOOGLE_ENABLED=true\nGOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=...\nGOTRUE_EXTERNAL_GOOGLE_SECRET=...\nGOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=https://..."}'
curl -X POST https://tellwang.com/v1/woks/$WOK/restart \
  -H "Authorization: Bearer $TELLWANG_KEY"

Account, plans & model gateway

The control plane runs the customer onramp, plan tiers, and a metered model gateway — all under the same Bearer key you provision Woks with.

Plan changes are self-serve via the subscription checkout above. Plan overrides (PUT /v1/orgs/{slug}/plan), per-org quota overrides, and backfilling plan runtime defaults for existing Woks (POST /v1/orgs/{slug}/runtime-defaults) are reserved for TellWang support.

Prepaid credits

Top up once, debit silently per action. One USD-cents balance per org covers domain registrations and other per-call charges. Two top-up rails — Stripe Checkout (card) or Solana USDC (crypto). After the initial deposit there's no second click per buy.

On any paid action with an insufficient balance, the response is 402 {status:"insufficient_credits", balance_cents, deficit_cents, top_up_url} — the top_up_url is a pre-built Stripe Checkout covering exactly the deficit, so the agent or dashboard hands the customer one click to unblock the buy.

Payment gateways

If submission returns CP_BILLING_NOT_CONFIGURED, TellWang keeps the local profile pending but makes no claim that it reached Stripe. Contact support, then retry the same submission.

Domain registration

Buy a domain through Cloudflare Registrar with TellWang as the trustee. Registration starts at $5 USD; the quote returns the exact registration and renewal prices before purchase. Pre-flight failures (invalid name, unsupported TLD, unavailable name, cap exceeded) are free — no debit occurs until the buy succeeds. TellWang forwards each candidate directly to Cloudflare's availability check instead of maintaining its own syntax, TLD, or public-suffix gate. Cloudflare decides whether the candidate is valid, registrable, available, and supported through its Registrar API, and its quote determines standard or premium status plus the exact prices.

When connecting an owned hostname to a Wok, pass dns_mode:"tellwang" to create or claim its registrable root Cloudflare zone, publish the exact root, www, or other subdomain, and receive zone_domain plus the root's assigned nameservers. Connect each hostname separately; all reuse the same root zone, and only that root's nameservers change. Pass dns_mode:"external" to keep the current DNS provider and receive the ownership TXT plus direct A record. Nameserver delegation changes DNS hosting only; it does not transfer registration. Omitting the mode keeps automatic discovery.

Wang — the customer-facing agent

Wang is the agent layer described on How Wang works. Every plan includes its own hosted Agent Cell. Free includes one concurrent run and DeepSeek Flash; paid plans add DeepSeek Pro, Kimi, and higher limits. Private is available through the model gateway. Any signed-in member can also connect their own ChatGPT or Grok subscription as a per-person choice.

Wang chat persistence

The in-dashboard Wang chat keeps the conversation and run state on the server, so logging in from a fresh browser brings the thread back. TellWang relays the organization's Agent Cell into this same transcript on every plan, including tool progress and permission or question cards that need your reply. Agent turns use the selected model's context and the checkout's own AGENTS.md and TELLWANG.md. If a turn stops making progress, TellWang retires only that engine context with CP_AGENT_CELL_NO_PROGRESS; the next attempt starts clean with the recent TellWang thread restored, while completed Wok work and the durable transcript remain unchanged.

No per-call billing — chat history is metadata, not a paid action; LLM tokens are already metered on the sllm_ key.

Org instructions & knowledge base

Teach Wang about your business so it answers with your context instead of generic defaults. Telegram/Slack channels and connected MCP clients can consume this context; the dashboard prompt handoff does not run a model itself.

Retrieval uses typo-tolerant Postgres full-text search.

Inbound email — Wang can read it

Mail received on a domain attached to a Wok lands in that Wok's inbox; Wang can list and read it to summarize, extract, classify, or draft a reply.

Channels — Telegram & Slack

Connect a messaging bot so your team talks to Wang where they already are. The bot credential is yours (the @BotFather token / Slack bot token), stored encrypted; no platform-wide bot is involved. Inbound messages run a Wang turn grounded in this org's instructions + knowledge base, and the answer is posted back to the same chat.

Connect it from the dashboard's Channels tab, or via the connect_channel / list_channels / disconnect_channel MCP tools. Inbound messages run the same full Wang runtime selected for the organization. When a paid-plan run needs a sensitive approval or structured answer, the durable request is shown in the TellWang dashboard.

Key management

Generate and manage encryption keys, then encrypt, decrypt, and sign through your Wok — the private key material never leaves the control plane. Key types: aes-256-gcm (encrypt/decrypt), ed25519 and rsa-4096 (sign/verify). An ed25519 key's public key is a Solana address, so /sign is a remote signer for Solana transactions. Bearer-of-org; use $ORG_SLUG or me. See Key Management for worked examples.

Model gateway wire format

The model gateway is OpenAI-compatible. Any library that targets the OpenAI HTTP API works against https://tellwang.com/v1/llm/v1 with an sllm_ Bearer.