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.
https://api.tellwang.com/v1 # control plane (Woks, resources)
https://<wok-id>.tellwang.com/rest/v1 # a Wok's data APIAuthentication
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 https://api.tellwang.com/v1/woks \
-H "Authorization: Bearer <api-key>"Conventions
- Idempotency: send an
Idempotency-Keyheader on writes. Successful responses are replayed for safe retries and never double-apply (or double-charge); failed responses are revalidated so a repaired target is not pinned behind an old error. - Errors: a stable envelope —
{ "error": { "code", "message", "hint", "correlation_id" } }.codeis the machine-readable identifier (classify on this);messageis human-prose;hintis the remediation (sometimes omitted on terse errors);correlation_idis always present — include it when filing a ticket. See Error codes for every code with per-code remediation, grouped by area. - Pagination: cursor-based via
?cursor=+limit; responses includenext_cursor. - Rate limits: per-token;
429withRetry-After.
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.
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" }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.
GET /v1/healthz— liveness only.200 {"status":"ok"}when TellWang process is running and able to serve. Doesn't say anything about the underlying systems. Use this for load-balancer health checks and CI smoke tests; sub-millisecond.GET /v1/diag— platform semantic health. Walks every platform subsystem and reports per-check status + evidence:
Use this when you want to know "is anything wrong, and what is it." Open (no auth) so the platform's status is queryable from outside. Top-level{ "status": "ok", "correlation_id": "4aaebbc7a83773d9", "checks": [ {"name":"email_mta_dns", "status":"ok", "detail":"mx.tellwang.com resolves directly to the configured mail origin"}, {"name":"function_schedules", "status":"ok", "detail":"12 schedule(s); every enabled target is deployed"}, {"name":"audit_alerts", "status":"ok", "detail":"no privileged-activity signal in the last hour"}, ... ] }statusis the aggregate acrosschecks(ok / degraded / down). Personal-model readiness appears aschatgpt_oauthandgrok_connection; these checks verify root-key availability without reading or exposing a member's credentials.lollipop_samplingvalidates the configured metasearch and, when paid backlink discovery is explicitly enabled, the Google Organic and backlink-index endpoints plus positive global and per-organization daily batch limits. It then reads the latest durable, tenant-free discovery outcome saved at discovery completion and shared by every control-plane process. A later audit-stage failure cannot preserve an older healthy result. A partial or unavailable run is degraded even if the endpoint URLs parse; missing, stale, unreadable, legacy-schema, or opposite-provider-mode evidence is unknown/degraded instead of being reported healthy. After paid mode is enabled or disabled, one audit must complete in the current mode before this check can become healthy. Public detail never exposes the provider-reported amount or tenant content.GET /v1/diag/wok/{id}— per-wok semantic health. Same shape, but checks scoped to one wok's stack: every container's running-state, postgres readiness, port reachability, replication slot health, and the latest runtime-heal artifact invariant. A missing-runtime repair recreates infrastructure from persisted state and must preserve source, project context, migration lineage, frontend, and functions;heal_artifact_integrityreports the proof or compensation result. Bearer-of-owning-org (or TellWang's bootstrap token); cross-org returns 404 with no leak. Use this in your customer's own dashboards or to debug "my wok stopped working."
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.
GET /v1/woks/{id}— single row:{id, host, url, status, created_at, updated_at}. Useful for "is this wok still mine + alive."GET /v1/woks— list active woks for the calling org.GET /v1/woks/{id}/connection— the wiring sheet. Returns everything@supabase/supabase-jsneeds:
Every Wok's stable service base is{ "wok_id": "acme-pos", "status": "ready", "url": "https://acme-pos.tellwang.com", // base URL for supabase-js "rest_url": "https://acme-pos.tellwang.com/rest/v1", "anon_key": "eyJhbGciOi...", // client-side JWT, RLS-bound "service_role_key": "eyJhbGciOi...", // SERVER-SIDE ONLY; bypasses RLS "functions_url": "https://acme-pos.tellwang.com/functions/v1", "realtime_url": "https://acme-pos.tellwang.com/realtime/v1", "storage_url": "https://acme-pos.tellwang.com/storage/v1", "auth_url": "https://acme-pos.tellwang.com/auth/v1", "rag_retrieve_url": "https://tellwang.com/v1/llm/v1/rag/acme-pos/retrieve", "rag_agent_url_template": "https://tellwang.com/v1/llm/v1/rag/acme-pos/agents/{slug}/chat", "redis_url": "redis://default:<dbpass>@redis:6379" // internal-only, edge fn use }https://<wok-id>.tellwang.com, with the 5 standard Supabase API path prefixes (/rest/v1,/auth/v1,/realtime/v1,/storage/v1,/functions/v1) routing transparently to the Wok's services. When a verified custom domain is bound, website paths on the platform hostname permanently redirect to that canonical domain; the service paths remain available. TellWang also aligns generated robots and sitemap URLs, canonical links, andog:urlwith the custom origin. Edge functions that returntext/event-streamare proxied unbuffered for SSE, and WebSocket Upgrade handshakes pass through the same functions route. TellWang fetches a Let's Encrypt cert on the first HTTPS hit via on-demand TLS (no pre-provisioning step). Keys are minted on-the-fly from the Wok's per-instance JWT secret; the secret never leaves TellWang.service_role_keybypasses RLS and must never reach a browser — wire it only into server-side processes (edge functions, your backend, CI).redis_urlis internal-only (no external access); edge functions read it asprocess.env.REDIS_URL, see Functions → Redis + BullMQ. When RAG is enabled, customer-facing functions receive a private model-gateway key and call the returned gateway URLs; see Functions → Managed RAG.POST /v1/woks/{id}/restart— graceful restart of every container in the wok's stack (postgres → gotrue → postgrest → realtime → storage → functions). Picks up env-var changes that PUT/POST/envwrote since the last restart. Idempotent (returns the same shape regardless of pre-state).POST /v1/woks/{id}/resume— reconcile asuspendedWok from its declared Compose stack and retained volumes, including recreating containers removed by host cleanup. 200 if already active; 409 if destroyed.POST /v1/woks/{id}/wake— start a Preview Wok that idled out and wait until its services answer. Preview Woks sleep after a few hours unused; any build request wakes one automatically, and this is the explicit lever when you want it awake before you look at it.POST /v1/orgs/{slug}/platform-problems— report a problem with the platform itself: a documented command that does not exist, a tool erroring through no fault of the call, a Wok or release stuck with no forward move, or docs that do not match reality. Agents reach it aslollipop report-platform-problem. Reports deduplicate by fingerprint, so repeated hits raise a count rather than adding rows, and TellWang attaches the Wok status, the last deployment error and the run's recent tool calls itself.GET /v1/orgs/{slug}/platform-problems— the sweep: open reports first, most-hit first.?status=anyincludes resolved ones.DELETE /v1/woks/{id}— tear down the stack + volumes and mark it destroyed. Deleting a production Wok also removes its linked staging Wok, so no preview stack is orphaned. Control-plane environment variables and secrets remain until the separate purge step; export anything you need before deleting.POST /v1/woksreturns only after the linked staging Wok is semantically ready and seeded: Postgres accepts SQL and the rendered REST/Auth/Functions/Storage listeners answer, together with Realtime when it is enabled. A fresh Preview copies Published's schema only, never rows, verifies the exact application-schema fingerprint, and then adopts the same immutable migration names and checksums append-only. It does not replay historical DDL during initial creation. A database-backed lease serializes same-ID lifecycle attempts, including stale recovery, so concurrent cleanup cannot remove the winning stack. The server bounds production plus automatic staging at 150 seconds; clients should allow 180 seconds. Network and mandatory-port reservation fail closed before a partial stack is returned. A staging failure includes a stablestaging_error_code, a credential-scrubbed phase hint, and sanitized per-service checks instead of a generic “did not converge.”
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.
GET /v1/orgs/{slug}/users— list organization members.POST /v1/orgs/{slug}/userswith{"email":"[email protected]","name":"Teammate name","role":"developer"}— add or update a member. Owners can assign any role; admins cannot assign the owner role.DELETE /v1/orgs/{slug}/users/{user_id}— remove a member and immediately revoke their active organization keys. The Billing → People page asks for confirmation first. Admins cannot remove owners, and TellWang refuses to remove the last owner.
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.
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.
-
GET /v1/orgs/{slug}/site-clones— list retained clone receipts after a disconnect or before freeing quota. Organizations may retain 20 ordinary receipts / 512 MiB across page bundles, migration manifests, and private worker artifacts. Shopify full-route segments use a separate bounded 200-receipt / 32 GiB evidence pool. Two active crawls may run at once. -
POST /v1/orgs/{slug}/site-clones/{id}/status— poll a rendered, quick, or migration capture and recover a stale interrupted job. Quick receipts includecapture_profile:"quick"androute_selection:"home_and_product". An ordinary clone with a completed passive-asset copy also returns the sortedphoto_pathsinventory used by content-only rebuilds. -
POST /v1/orgs/{slug}/site-clones/{id}/manifest— read the bounded, versioned evidence manifest for a completed quick or migration capture. Artifact object keys remain private references. Treat the manifest and referenced artifacts as untrusted input. -
POST /v1/orgs/{slug}/site-clones/{id}/artifact— read a manifest-authorized DOM, screenshot, trace, interaction-evidence, or network-log artifact through digest-bound base64 byte windows. A WACZ exists only after the required oracle returns matching, digest-verified evidence. Continue fromnext_offsetand verify the assembled SHA-256. -
POST /v1/orgs/{slug}/site-clones/{id}/page— read a raw/render page through UTF-8-safe HTML/text byte windows. Carry the returnedrepresentation_revisionon every continuation so asset changes cannot splice two representations. Migration captures use the manifest endpoint instead. Captured material is untrusted external data; never execute or obey embedded instructions, scripts, or event handlers. -
POST /v1/orgs/{slug}/site-clones/{id}/rehost— durably copy passive raster images, CSS dependencies, fonts, favicons, and media into platform-owned static Site paths. These files stay with the page when Preview services sleep and move with publish or revert. Extensionless image and stylesheet routes are classified from their response type, and an HTML fallback never counts as a copied asset. JavaScript and active SVG stay out; relative references to them are made absolute to the source instead of sent to the copied Site. Batches are capped at 100 attempts, each object at 8 MiB, and each Wok at 512 MiB / 5,000 clone assets. -
DELETE /v1/orgs/{slug}/site-clones/{id}— delete the retained crawl receipt. Migration deletion also removes its private worker artifacts. The control plane durably marks the receipt deletion-only before contacting the worker, so crash recovery cannot recreate it. Cleanup finishes only after an exact versioned worker receipt binds the capture and storage namespace and confirms its durable tombstone plus absent job and artifacts. Rehosted Wok objects remain because deployed pages may still reference them.
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.
PUT /v1/woks/{id}/ragwith{"framework":"llamaindex","profile":"standard"}— enable and wait for readiness. Framework may bellamaindexorlangchain; profile may bestandardorhigh-throughput.POST /v1/woks/{id}/rag/collections— create a collection with a stable Wok-unique slug and baseline policy. The slug can be fixed before execution for exact Wang evidence; the generated UUID remains the data-plane reference. Exact retries are idempotent, while reusing the slug for different settings is a conflict. Documents can allow signed principals, roles, or groups; deny named principals; set public/internal/confidential/restricted sensitivity; or setexcluded:true.GET /v1/woks/{id}/rag/collectionsandGET /v1/woks/{id}/rag/collections/{collection_id}/documents— inspect active revisions, document/chunk/visual counts, source versions, effective access policies, governed metadata, status, and errors with bounded cursor pagination.GET /v1/woks/{id}/rag/collections/{collection_id}/documents/{document_id}/accessmints a 15-minute signed URL for the active private source.POST /v1/woks/{id}/rag/collections/{collection_id}/documents/{document_id}/exclude— quarantine an indexed document without downloading it again. The completed job atomically activates an excluded zero-chunk revision and purges its prior RAG text and vectors; its private source file remains in Storage until separately deleted.POST /v1/woks/{id}/rag/ingestions— submit up to 1,000 existing Storage objects per atomic batch. Each object can carry up to 50 safe flat metadata keys and 16 KiB of scalar or non-empty scalar-list values for department, jurisdiction, document type, version, effective date, or tags. Metadata is versioned with the document and retrieval filters use exact containment after ACL enforcement. Successful later batches extend or update the active collection, so 1,000 is not a collection-size cap. The prior index remains live until the complete batch succeeds. Promotion retains one active membership snapshot plus compact revision metadata, while a failed batch discards candidate-only vectors. Excluded objects are never downloaded or embedded; excluded text ranges are removed before chunking. Promoting anexcluded:trueobject purges its older RAG text/vector revisions; delete the original Storage object separately if the source file must also be erased.POST /v1/woks/{id}/rag/agents— create a grounded customer-service agent with an optional structuredsouldefining its position, organization, mission, tone, conversational style, responsibilities, and boundaries.excluded_document_idscan block up to 500 active files for this agent only while keeping them available to other agents, generation, and insights. End-user chat uses the two-header model-gateway route at/llm/v1/rag/{wok_id}/agents/{slug}/chat. The visitor's exactquestionremains authoritative. Applications may send up to eight priormessageswith avisitor,assistant, orhumanrole. History helps with intent and continuity but is never evidence. Ingestion stores page-aware parent sections and bounded labels found in the source. Same-script questions search the exact contextual wording plus up to two matching indexed labels; cross-script questions keep the exact query and add one model-planned multilingual query. Dense, full-text, and trigram rankings are combined with reciprocal-rank fusion, then at most eight parent-aware passages reach the answer tool. Source labels help search but are not evidence. The answer model may request one bounded retry when no model rewrite was already spent. It treats a standalone topic label as a request to explain it and calls a strict tool with plain answer text, request-local source IDs, and the exact caller-specific scope that still needs a colleague. TellWang constructs citations itself, caps this channel answer call at 256 output tokens and 800 answer characters, and retries one malformed answer call. When part of a question needs a person, such as a specific plan or account detail, the response answers the rest and returnsneeds_human_followupandhuman_followup_scopefor the application. A separate strict verifier checks evidence, directness, source actors and certainty, represented-organization identity, and conversation continuity. A rejected draft receives one bounded repair and independent recheck. No domain-specific fallback substitutes a nearby fact for a missing answer. Visual evidence is prioritized only when requested. Anonymous chat is off unlessallow_anonymous:true, and even then only public passages are eligible.GET /v1/woks/{id}/rag/agents— list enabled agents with their exact corpora, excluded file IDs and stable paths, grounding policy, exposure, instructions, and escalation settings.GET /v1/woks/{id}/rag/agents/{slug}— inspect the enabled agent's collections, excluded file IDs/paths, and exact grounding, citation, anonymous-access, instructions, and escalation settings. Optional expected fields let an agent verify the collection set, source-path block list, and exposure setting.DELETE /v1/woks/{id}/rag/agents/{slug}— turn an agent off immediately. Re-saving the same slug re-enables it.POST /v1/woks/{id}/rag/generations— create Markdown, DOCX, PDF, CSV, or JSON drafts from an explicit non-empty document set. Every named file must exist and be readable, otherwise no partial draft is produced. Drafts stay under privaterag-results/generated/, inherit the strictest common source access, and default to a 50-call model budget (maximum 200). Direct app callers need signedrag_authorrole orrag-authorsgroup.POST /v1/woks/{id}/rag/insights— queue summary, comparison, classification, extraction, clustering, or trend work. Optional JSON Schema output must validate before success. A caller-selectedmax_model_callsis capped at 500 to prevent runaway corpus-wide spend; direct app callers need RAG author access.POST /v1/woks/{id}/rag/interview-projects— create a durable, industry-neutral Interview Processing project with a strict extraction schema, governed collections, and confidence threshold.POST /v1/woks/{id}/rag/interview-projects/{project_id}/process— process up to 100 selected interview documents as separate durable jobs. Every populated field needs an exact source quote; weak or incomplete evidence enters review instead of a report.GET /v1/woks/{id}/rag/interview-projects/{project_id}/recordsandPATCH /v1/woks/{id}/rag/interview-projects/{project_id}/records/{record_id}— inspect evidence and confidence, then approve, reject, or correct records against the same schema. Reviewer decisions are audited.POST /v1/woks/{id}/rag/interview-projects/{project_id}/reports— generate a private DOCX, PDF, or XLSX from approved records only. Counts and missingness are deterministic; qualitative findings cite approved record IDs and pass another support check.GET /v1/woks/{id}/rag/jobs/{job_id}— poll asynchronous work. For ingestion, only parent-job success means the new collection revision is active.GET /v1/woks/{id}/rag/jobs/by-key?kind=…&idempotency_key=…— resolve a parent job from the immutable key chosen before execution so Wang or another connected agent can verify terminal success without depending on a generated job ID.GET /v1/woks/{id}/rag/jobs/{job_id}/items— inspect cursor-paginated per-file outcomes and errors for a large ingestion or Interview Processing batch. Successful PDF items report indexedvisualsand skippedvisual_failurescounts.GET /v1/woks/{id}/rag/artifacts— list generated files and insight outputs durably with provenance and inherited policy.GET /v1/woks/{id}/rag/artifacts/{artifact_id}— policy-check and mint a 15-minute signed URL for a generated file.
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.
GET /v1/marketplace/catalog— public safe metadata for the newest published version of every release. Its customer-facing category supplies the Marketplace industry filters; technical capabilities remain separate.GET /v1/marketplace/releases/{release_slug}?version=1.4.1— public release detail with compatibility, file checksums, signing-key identity, and configuration declarations. It reads the stored validated manifest without opening the archive, and never returns package bytes or configuration values.GET /v1/orgs/{slug}/marketplace/migration-templates— authenticated catalog containing only exact signature-verified, TellWang-trusted Shopify and Shopline manifests. Any published record outside that registry makes the read fail closed. MCP tool:list_migration_templates.GET /v1/orgs/{slug}/marketplace/migration-templates/{template_slug}?version=<version>— trusted signed manifest detail. Shopify and Shopline publish independent immutable versions; the current Shopline template is1.0.2. A published template returnsstart_available:trueandstart_path:"/orgs/{slug}/storefront-migration-journeys". MCP tool:get_migration_template.POST /v1/marketplace/migration-templatesplus the bootstrap-onlyapprove,publish, andrejectroutes — TellWang's moderation for the dedicated manifest registry. Publish verifies the stored digest, signature/key identity, and complete provider-specific trust registry.POST /v1/orgs/{slug}/marketplace/installations— start an exact installation with anIdempotency-Key. Body:{"release_slug":"wechat-rag-bot","release_version":"1.4.7","wok_id":"…stg","configuration":{"NAME":"value"}}. The target must be the caller's linked Preview and may contain only TellWang's byte-exact untouched starter; live public database relations also count as work. Installs are serialized per Wok, heartbeat while active, and expose a failed receipt with safe detail. A crash-orphaned receipt can retry only while the Preview remains empty.GET /v1/orgs/{slug}/marketplace/installations/{installation_id}— read the durable install, integrity, deployment, and verification receipt.
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.
GET /v1/orgs/{slug}/marketplace/upgrades/plan?wok_id=&release_slug=&target_version=— the merge, computed and returned without touching the Wok. Shows which files follow the release, which stay yours, which migrations are new, and every conflict.POST /v1/orgs/{slug}/marketplace/upgrades— apply it, with anIdempotency-Key. Body:{"release_slug":"…","target_version":"1.1.0","wok_id":"…stg","configuration":{},"resolutions":{}}. Conflicts return409 CP_WOK_RELEASE_UPGRADE_CONFLICTand aconflictedreceipt; retry withresolutionsmapping each path toupstreamorcustomer.GET /v1/orgs/{slug}/marketplace/upgrades/{upgrade_id}— the durable receipt:applying,applied,conflicted, orfailed.
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.
POST /v1/orgs/{slug}/brand-voice/scan— body{"domain":"example.com","brand_name":"Example"}. The domain must resolve to a public HTTPS site. TellWang reads up to six pages through the same private-network protections as the site audit, asks both live AI surfaces, and returns only observations actually received.- The matching MCP tool is
scan_brand_voice. Provider credentials remain in the platform secrets backend; the response never includes them.GET /v1/diagreports whether both observation providers are configured.
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:
GET /v1/audit-log— list entries for the calling org, newest-first, cursor-paginated. Query params:limit— 1..200 (default 100).cursor— opaque cursor returned asnext_cursorfrom the previous page.action— exact match on action string, e.g.wok.exec_sql,wok.env.set,wok.frontend.deploy.actor_kind— one ofoperator|bearer|internal|system.target_kind— e.g.wok,llm_key,email_domain.since/until— RFC3339 timestamps.
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.
GET /v1/woks/{id}/analytics/sessions?since_hours=24&limit=100&cursor=...— cursor-paginated recording summaries after a server-side time filter. Rows include entry URL, duration, viewport, event count, completeness, client-error co-occurrence, and rage/dead-click signals. Requires the build capability.GET /v1/woks/{id}/analytics/sessions/{sid}— rrweb events for the dashboard player plus the recording'scapture_visible_textpolicy. Requires the build capability.PATCH /v1/woks/{id}/analytics/session-replay— enable or disable recording and selectcapture_visible_text. Owner/admin only; enabling requires the privacy acknowledgement.
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
POST /v1/woks/{id}/exec_sql— body{"sql":"<your-sql>", "no_pgrst_reload":false}. Runs in your wok's db container viapsql; returns{stdout, stderr, exit_code}. Auto-appendsNOTIFY pgrst, 'reload schema'on success so PostgREST picks up new tables immediately (opt-out viano_pgrst_reload). Body cap 1 MiB; stdout/stderr capped at 1 MiB.
Edge functions
POST /v1/woks/{id}/functions/{name}— body{"code":"<index.ts>","files":{"lib/helper.ts":"<source>"}}.filesis optional and contains local modules relative to the function directory; the complete tree is capped at 256 KiB. Name^[a-z][a-z0-9-]{0,30}$. On public invocation, the shared edge overwritesX-TellWang-Client-IPwith the validated end-user address before the function runs. Cloudflare forwarding headers are accepted only from Cloudflare's published networks; direct and DNS-only domains fall back to the socket peer. Use that private header for abuse controls instead of trusting caller-supplied forwarding headers. Returns 201 with the row +invoke_urlyou can curl immediately. 503CP_FUNCTIONS_NOT_ENABLEDwhile Functions are still being enabled on the Wok; TellWang enables them automatically, so retry shortly.GET /v1/woks/{id}/functions— lists each fn as{name, code_bytes, code_sha256, module_count, invoke_url, created_at, updated_at}(omits source bodies).GET /v1/woks/{id}/functions/{name}— returnscodeplus the localfilesmap so you can pull the complete deployed function.DELETE /v1/woks/{id}/functions/{name}— idempotent; missing returns 204.POST /v1/woks/{id}/triggers· body{table, event, function_name}— wires a DB trigger thatpg_notifys on INSERT/UPDATE/DELETE and dispatches to your function.
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
PUT /v1/woks/{id}/realtime/tables/{schema}/{name}— adds the table to thesupabase_realtimepublication. Idempotent.GET /v1/woks/{id}/realtime/tables— returns{tables:[{schema, table}], publication}.DELETE /v1/woks/{id}/realtime/tables/{schema}/{name}— drops the table from the publication.GET /v1/woks/{id}/realtime/status— reports wal_level + slot health.
Scheduler
POST /v1/woks/{id}/scheduler/jobs— body{name, schedule, command}. Schedule = cron expression (0 3 * * *) or interval (30 seconds). Command = any SQL, runs inside your wok's db. Returns 201 with the cron job_id.GET /v1/woks/{id}/scheduler/jobs— lists each as{job_id, name, schedule, command, active}.DELETE /v1/woks/{id}/scheduler/jobs/{name}— unschedule. Idempotent.POST /v1/woks/{id}/function-schedules— body{name, function_name, every_seconds, payload?, enabled?}. TellWang queues the Edge Function every 60–86,400 seconds with a fresh Wok-scoped service-role credential in the request headers; credentials are never persisted inpayload. A tick coalesces while the same schedule is pending or running.GET /v1/woks/{id}/function-schedules— lists run count, last status/error, and next invocation.DELETE /v1/woks/{id}/function-schedules/{name}— removes the recurring invocation without deleting the function.POST /v1/woks/{id}/function-invocations— schedules one deployed function for an RFC3339run_at. Owner build Bearers and the same Wok's service-role key are accepted. Body{function_name, run_at, payload?, idempotency_key}.GET /v1/woks/{id}/function-invocations— lists the latest 100 one-time and recurring queued invocations, attempts, status, error code, and terminal result. The dispatcher runs one invocation per Wok and eight globally. A 90-second wall-clock termination returnsCP_FUNCTION_INVOCATION_WALL_CLOCKand is not retried.
Environment variables
PUT /v1/woks/{id}/env/{name}— body{value}. Name^[A-Z][A-Z0-9_]{0,63}$. Encrypted at rest under the TellWang's key store (AES-256-GCM envelope). 204 on success. Applied to the Wok's Auth and Functions services, which TellWang restarts on the next change.POST /v1/woks/{id}/env— bulk import. Body is one of{"vars":{"NAME1":"v1","NAME2":"v2"}}or{"dotenv":"NAME1=v1\nNAME2=v2"}. Up to 200 names per call; all names validated against the regex BEFORE any write (atomic — one bad name fails the whole batch with the offender list in the error envelope). Single database transaction, so a network failure mid-batch never leaves a half-applied state. Dotenv parser tolerates# comments,export NAME=valshell-prefix, and matching surrounding single/double quotes. Does NOT auto-restart the wok stack — POST/restartafterward if you need the new values live immediately (the per-var PUT path auto-restarts; the bulk path does not).GET /v1/woks/{id}/env— returns{vars:[{name, created_at, updated_at}]}. Values are NEVER returned (write-only).DELETE /v1/woks/{id}/env/{name}— unset. Idempotent.
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.
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.
POST /v1/signupstarts verified signup; it creates no account until the email code and official Twilio Verify phone code both pass. The dashboard also offers a privacy route: choose a Wallet Standard-compatible Solana wallet such as MetaMask or Phantom, sign a one-use message, then send at least $1 USDC by QR code, wallet link, or copied address. The full confirmed amount becomes workspace credit. Existing accounts can sign in by password, emailed code, or passkey.POST /v1/account/password/codeemails the signed-in person a purpose-bound six-digit code;POST /v1/account/passwordconsumes that code while changing the password and closes other sessions. Sign-in and signup codes cannot authorize this action. The/v1/passkeysand/v1/passkeys/register/*routes list, add, and remove passkeys; Lollipop and TellWang use separate trusted WebAuthn relying parties for their product domains. All public auth steps are rate-limited, and the optionalinvite_codegate applies to both signup routes.GET /v1/plans— the public catalog for Free, Pro, Scale, Scale + HA, and Enterprise. The response includes display copy, monthly price, the private server size of each paid plan (`server`: RAM, vCPU, disk) and the app quota that server holds, Agent Cell concurrency, runtime defaults, and a sharedusageblock with final model, Functions, SMS, Storage, Email, and domain rates. App limits are 1 / 1 / 5 / 5 / 10; each live app includes its linked Preview. Database standby and redundant REST begin with Scale + HA. Lollipop's public homepage projects the catalog's current numeric plan limits into its pricing chart and does not keep a separate fallback price list.GET /v1/orgs— organizations the signed-in human belongs to, including their role, current organization, and plan.POST /v1/orgs/new— create a named organization and become its owner. Body{name}accepts 1–80 Unicode characters. Your first owned organization is free; another requires ownership of a paid organization, with a 20-organization account cap. Send one stableIdempotency-Keyper logical attempt so a lost response can be retried without a duplicate. The dashboard does this automatically and exposes the action in the desktop workspace menu and as New org on mobile; the mobile Orgs list can reopen an organization when the first switch fails.POST /v1/orgs/{slug}/token— switch a signed-in human into an organization they belong to by minting a fresh organization-bound session key. Call this after/orgs/new; if switching fails after creation succeeded, retry this token request without creating the organization again.GET /v1/orgs/{slug}/plan— your plan, its entitlements, and Woks used against the limit.POST /v1/llm-keys— mint a model-gateway key; the requested grant is capped at your plan. The REST body and MCPmint_llm_keyschema acceptprivate,deepseek-v4-flash,deepseek-v4-pro, and paid-plankimi-k2.7-code. The current meter consumes the organization-wide included allowance when completions finish, so/topupreportsnot_requiredinstead of duplicating that allowance onto a key.GETlists key usage, included tokens left, and the published token-type rates;DELETErevokes. The old per-key/checkouttoken bundle returns 410CP_LLM_CHECKOUT_RETIRED; usage beyond included allowances uses organization prepaid credits. Point any OpenAI-compatible client at/v1/llm/v1/chat/completions. Passstream: truefor SSE streaming responses (see Streaming) — token metering happens after the stream closes, off the finalusagechunk.GET /v1/llm-keys/{prefix}/billing— the Stripe-credit ledger for a key, to reconcile a purchase against the meter.POST /v1/orgs/{slug}/email/domain— attach a sending domain (e.g.mail.acme.com). Returns the DKIM / SPF / MX records to publish, or auto-publishes them when TellWang manages the apex zone.GET /v1/orgs/{slug}/email/domainspolls live status;DELETE /v1/orgs/{slug}/email/domain/{domain}revokes the provider domain before removing the local row, releasing its provider slot without deleting inbox mail. See Email → Bring your own domain.POST /v1/orgs/{slug}/billing/checkout/subscription— buy apro,scale, orscale_hafixed-price subscription through card-only Stripe Checkout. The hosted checkout accepts active Stripe promotion codes, with Stripe enforcing validity, expiry, redemption limits, and the discounted invoice. Checkout collects the subscription payment method. Usage beyond the included allowances is paid from prepaid credits. Canonical Stripe verification and the durable reservation still bind the exact purchased plan safely.POST /v1/orgs/{slug}/billing/subscription/cancel— an Owner, Admin, or Billing member can schedule the exact current Stripe subscription to end at its period boundary. Send{"cancel_at_period_end":true}with anIdempotency-Key. TellWang verifies the Stripe customer and subscription before changing it. The paid plan remains active through the returnedcurrent_period_end, while new metered usage switches to prepaid credits immediately. At expiry the organization moves to Free. Existing Woks are not deleted, but an organization above Free's one-Wok limit cannot create another until it deletes Woks or upgrades.POST /v1/orgs/{slug}/billing/subscription/change— an Owner, Admin, or Billing member moves the active subscription to another paid plan. Send{"plan":"scale"}with anIdempotency-Key. Stripe charges the prorated difference for the rest of the period at once; if that payment fails, the plan does not change. A plan whose server cannot hold the organization's published apps is refused before any charge, with the plan that fits named in the message.POST /v1/orgs/{slug}/billing/checkout/postpaid— returnsCP_POSTPAID_DISABLED. Usage beyond the included allowances is paid from prepaid credits.GET /v1/orgs/{slug}/billing/subscriptionreportspostpaid_enabled:falseand keeps historical usage-charge states visible.
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.
GET /v1/orgs/{slug}/credits— current balance, recent ledger entries, both rails' status.POST /v1/orgs/{slug}/credits/topup— body{amount_usd, success_url?, cancel_url?}. Returns a Stripe Checkout URL; on payment the balance lands within ~5s via the same webhook plumbing the LLM top-up uses. Per-session cap $5000.GET /v1/orgs/{slug}/credits/crypto-deposit— returns TellWang's Solana USDC token account address + the per-org memo string (tw:org:<slug>). Send any USDC amount with the memo attached; the watcher credits ~15-45s after confirmation. Idempotent on tx signature.
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
POST /v1/orgs/{slug}/projects/{project}/payments/kyc— saves the real legal identity for one customer-facing Project and immediately creates that Project's Stripe-managed Connect account. Stripe collects the official KYC, gives the client a full Stripe Dashboard, assumes connected-account payment-loss responsibility, and charges processing fees to that account. TellWang creates card checkouts as direct charges in the Project's Stripe account. The account slug remains only the authorization container. Success returns{project_id, account_id, onboarding_url, expires_at}, which proves Stripe received the submission. The onboarding URL is single-use; open it immediately.POST /v1/orgs/{slug}/projects/{project}/payments/onboarding-link— creates a fresh link for that Project when onboarding was interrupted or the first link expired.GET /v1/orgs/{slug}/projects/{project}/payments/balance— reports only that Project's collected totals pluscharges_enabled,payouts_enabled, anddetails_submitted. Projects in one account do not share payment identity or a connected account.GET|POST /v1/orgs/{slug}/projects/{project}/payment-gateways— lists or creates gateways owned by that Project. A supplied Wok must be linked to the selected Project; unmapped legacy gateways fail closed for card payments. Before verification, each card, USDC, or x402 intent reserves its amount for 45 minutes against the $1,000 total cap and $600 card sub-cap. Checkout returnsexpires_at; x402 verification must echo the no-store requirements response'spayment_id. Settlement rechecks the cap and commits payment state with the lifetime counter in one transaction.
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.
POST /v1/orgs/{slug}/domains/check— body{names:[], expected_max_price?}. Returns a per-name quote:{ok, name, tier, billed_usd, renewal_price_usd?, reason?}. Always check before buy so you know what you'll be charged. Max 20 names per call.POST /v1/orgs/{slug}/domains/buy— body{name, expected_max_price?, auto_renew?, privacy?, registrant_contact?}. Silent debit from the org's prepaid credit balance, then registers via CF, then upserts the row. Returns{status:"active"|"pending"|"failed", domain_row, debit_cents, balance_remaining}. On insufficient credits returns 402 withtop_up_url(see above). On CF-register failure post-debit, the credit is auto-refunded.POST /v1/orgs/{slug}/domains/attach— body{domain}. Attach a domain already in TellWang's Cloudflare account (no registrar round-trip) so the org can manage its DNS without a fresh registration. Attach, purchase, and claim share one canonical authority. Existing conflicts are rejected before Cloudflare is touched, and the database closes cross-surface write races.GET /v1/orgs/{slug}/domains— list owned domains.GET /v1/orgs/{slug}/domains/{name}— one domain's local row + a live CF re-fetch (auto-syncs the zone_id when CF surfaces one we don't have yet).GET /v1/orgs/{slug}/domains/{name}/seo— read Google Search Console status for a domain owned, claimed, or connected to the org.POST /v1/orgs/{slug}/domains/{name}/seo— register the domain and submit its sitemap. Managed DNS verifies automatically. External DNS returnsstatus:"connection_required"with the exact TXT record instead of failing; add it and call again.GET /v1/orgs/{slug}/domains/{name}/dns— list zone records.POST /v1/orgs/{slug}/domains/{name}/dns— body{type, name, content, ttl?, proxied?, priority?, comment?}. Create A / AAAA / CNAME / MX / NS / TXT / CAA / SRV / PTR / DS / HTTPS / SVCB records.PATCH /v1/orgs/{slug}/domains/{name}/dns/{id}— update record.DELETE /v1/orgs/{slug}/domains/{name}/dns/{id}— delete record.
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.
- In-dashboard Chat — open tellwang.com/dashboard. Each organization gets its own Agent Cell, with an isolated human-bound worker for every active thread. The dashboard streams the same durable run and approval requests; it never receives an Agent Cell credential.
- Channels — connect a Telegram or Slack bot in the dashboard's Channels tab and your team talks to Wang from the chat app they already use. See Channels below.
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.
GET | PUT /v1/orgs/{slug}/wang/model— read or select the plan-aware Wang catalog. Free sees DeepSeek Flash; paid plans also see DeepSeek Pro and Kimi. Account-verified ChatGPT and subscription-backed Grok Build belong to the signed-in member, not the organization, so selecting either personal provider never spends a teammate's account. Private is available through the model gateway.- App-building model rule — Create app, Edit app, every app-focused chat, and their app-build follow-ups require DeepSeek, Kimi, connected ChatGPT, or connected Grok. The run request may carry the dashboard's closed-vocabulary
capability; TellWang persists it only for model suitability and continuity, never as authorization. A Private app-build submission returnsCP_WANG_APP_MODEL_REQUIREDbefore its prompt or run is stored. Every hosted Agent Cell key is also bound to a private or coding model scope; Private keeps read access but cannot cross the server-side build boundary through MCP, the TellWang CLI, or Git push. POST /v1/orgs/{slug}/wang/providers/chatgpt/connect— begin ChatGPT device sign-in. Follow the returned verification link and enter its short code; pollPOST …/connect/{attempt_id}until connected. Wang checks automatically, explains that completion may take a few seconds to arrive, and offers Check now after the member finishes in ChatGPT. While sign-in is pending, Cancel connection stops polling and invalidates the code.DELETE …/providers/chatgptcancels that pending attempt or removes the encrypted connection and returns the member to the organization model.POST /v1/orgs/{slug}/wang/providers/grok/connect— begin official Grok device sign-in. Follow the returnedaccounts.x.ailink and enter the short code; pollPOST …/connect/{attempt_id}until connected. TellWang checks automatically and offers Check now. While sign-in is pending, Cancel connection stops polling, invalidates the code, and retires the isolated sign-in runtime. The official client's OAuth state is encrypted in the control plane, refreshed in an isolated one-shot container, and never projected into an Agent Cell.DELETE …/providers/grokcancels that pending attempt or removes the encrypted connection.GET /v1/orgs/{slug}/wang/chat— returns the last 200 owner-visible messages oldest-first as{messages:[{id, role, content?, run_id?, display_kind?, has_image?, author_email?, author_name?, tool_calls_json?, tool_call_id?, tool_name?, created_at}]}. Human messages carry their speaker identity in a group conversation. The response includes typed reasoning activity, public narration, and the explicitly published final answer; the unpublished final-answer candidate remains hidden. A screenshot-bearing user message hashas_image:true; its image bytes stay out of the transcript response. Role is one ofuser|assistant|tool.POST /v1/orgs/{slug}/wang/chat— append one. Body matches the OpenAI message shape:{role, content?, tool_calls?, tool_call_id?, name?}. Content cap 200 KiB. Returns 201 with the inserted row.GET /v1/orgs/{slug}/wang/chat?thread_id={id}— return the last 200 owner-visible messages. Agent reasoning is stored asdisplay_kind:"activity"for the collapsed Thinking accordion and public model text asdisplay_kind:"narration"for ordinary assistant messages. The independently accepted final answer is a separate published row. The unpublished final-answer placeholder remains private.DELETE /v1/orgs/{slug}/wang/chat— clear all messages for the org. Returns 204.GET | POST /v1/orgs/{slug}/wang/threads— list or create organization-level chats. Rows include a participant count and anarchivedflag. Older conversations appear under Archived chats; continuing one returns it to the current list. No transcript is deleted. A new thread may include an optionalwok_idas its focused starting context.PATCH …/threads/{id}changes or clears that focus; it never limits the chat to one Wok, and every action still authorizes its explicit target.GET | POST | DELETE /v1/orgs/{slug}/wang/threads/{id}/members— manage the chat as a private Slack-style group. Add existing organization members, list the people who can read and reply, remove someone, or leave. Adding someone to a chat never grants organization access.POST /v1/orgs/{slug}/wang/runs— submit a human-attributed message to the organization's durable Agent Cell queue. Omitruntime_versionor send3. The optional screenshot must be a fully decodable base64 JPEG, PNG, or WebP data URL no larger than 700 KB, 4096 px on either edge, or 2 megapixels; invalid images returnCP_INVALID_BODYinstead of being silently dropped. Image decoding is concurrency-bounded and rate-limited per organization;CP_RATE_LIMITEDincludesRetry-After. Free and Pro allow one concurrent worker; Scale and Scale + HA allow four; Enterprise allows eight. Free includes DeepSeek Flash and 1M model tokens monthly; paid plans add DeepSeek Pro and Kimi. A member may also select connected ChatGPT or Grok; either subscription connection applies only to that member's runs and allowance. Each chat has one active driver, while additional teammate messages queue oldest-first instead of failing when Wang is already working. For Wok-focused work, an exact owned Wok named in the current or most recent thread request becomes that run's focus, maps to Preview, and gets a retained Git checkout before the Agent Cell starts; the organization chat itself remains unbound. A personal-provider worker advertises only the exact provider model to the Agent Cell. Switching models replaces that thread's worker and engine context while preserving its checkout and TellWang transcript. The response saysrunningorqueued, includes the queue position or execution start time, and exposesrequires_coding_modelso refreshed clients preserve app-build suitability. Retired versions1/2return 410CP_RUNTIME_RETIRED. An assistant turn ending does not automatically finish the run: TellWang checks the user's goal against Wang's answer and secret-free tool ledger, and the run succeeds only when the work is complete. A turn that asks routine permission without any successful edit, mutation, or verification continues instead; genuine blockers must use the durable request mechanism. An explicit request to execute a named tool ortellwangcommand requires at least one successful tool record, so a pasted command cannot be treated as an observed result. Agentreasoningparts stream into the collapsed Thinking accordion, whiletextparts stream as ordinary Wang narration outside it; both remain classified on failed or cancelled runs. If completion cannot be confirmed, the run fails closed and publishes no final answer. The accepted final answer is published once, separately from narration, and commits atomically withstatus=done.GET …/runs?thread_id={thread-id}restores the active stopwatch, completed duration, submitter names, queued messages, and coding-model requirement after refresh;GET …/runs/{id}/imagereturns an attached screenshot only to someone who can open that run's chat, with private, no-store caching, and chat history fetches it only when the reader chooses View screenshot;GET …/runs/{id}/eventsstreams reasoning activity, public narration, the accepted final answer, safe tool targets and truthful tool states, status, queue changes, and approval/question requests;DELETEcancels the active or queued turn.- Managed DNS completion — the secret-free tool ledger includes only revalidated operational labels, never raw results. A managed-zone one-shot verification with a future
next_check_afterderivesexternal_wait:"managed_dns_propagation", even when the domain was connected in an earlier run. After reporting the truthful pending-activation state, Wang callslollipop finish-run; TellWang validates that server-derived state and ends the run without injecting another completion turn. External DNS that still needs customer action and ordinary unfinished work remain incomplete. POST /v1/wang/agent-cell/finish— backing endpoint forlollipop finish-run. It accepts only an authenticated Agent Cell whose active run already has a supported, server-derived terminal wait state. It records the accepted exit; an unsupported or ambiguous exit returnsCP_AGENT_CELL_FINISH_UNAVAILABLE.- Thinking boundary — when a run needs another Agent Cell turn, TellWang records the continuation note as durable
activityfor the collapsed Thinking accordion. The Agent Cell's echo of the user's turn is hidden, so customer prompts and system guidance never become public narration. preview_selectiononPOST /v1/orgs/{slug}/wang/runs— optionally carries version1, the focused or linked Previewwok_id, and 1–20 bounded semantic element targets (tag, optionalid,classes,role,name,type, andselector). TellWang validates the locator grammar and thread/Wok relationship, persists the selection separately from visible chat text and embeddings, and gives it to the Agent Cell as distinctly labeled, bounded untrusted data. Invalid selections returnCP_INVALID_BODY.POST /v1/orgs/{slug}/wang/runs/{id}/handoff— accept or decline an offered Kimi continuation. Acceptance sends the work to a third-party model. The successor keeps the source run's validated screenshot and semantic Preview selection in separately stored fields so “the selected element” stays grounded; raw locator data does not appear in the visible continuation message or embeddings.GET | POST | DELETE /v1/orgs/{slug}/agent-cell— read, ensure, or stop the organization's cell on any plan.GET …/agent-cell/requests?run_id=…lists pending interactions;POST …/requests/{id}/replyanswers them.GET | POST | DELETE /v1/orgs/{slug}/engineering-pilot— private Scale-plan engineering pilot lifecycle and dispatcher health. A named owner/admin remains the approval authority, configures the Delivery Ed25519 public key, and may rotate the one-time-displayedepd_key atPOST …/dispatcher-key. That credential is rejected by ordinary TellWang APIs and is accepted only byPOST …/tickets. First machine admission also requires a five-minute, one-use grant signed by the separate Delivery trust root and bound to the exact organization, admitted/guarded issue revision, configured repository and base, spec/planning/graph digests, enabledENGINEERING_ADMITTEDdelivery-admitedge, and durable request digest. Exact replay returns the original ticket after expiry; changed evidence conflicts. Admission is capped at eight open tickets and ten machine admissions per hour.GET | POST …/ticketslists or queues bounded tickets that move through fresh-context Builder, Reviewer, and QA Agent Cell turns before stopping for human review. Only Builder receives the repository-limited GitHub credential and egress. Reviewer and QA receive neither and must emit the exact read-only checkout evidence marker; generic shell calls and failed Git commands do not count. An initial prose-only answer gets one bounded corrective turn, then fails closed. The dispatcher trusts a numbered PR URL only from successful shell evidence, rejects comparison links, and verifies through GitHub that the proposal is open, draft, unmerged, and maps the exact ticket branch to the ticket's pinned base branch.POST …/tickets/{id}/approve|rejectrecords that decision. The pilot never merges, deploys, or receives production, funds, or credential access. TellWang installs the repository-limited GitHub credential asengineering-pilot-github-token; it is never returned by this API.
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.
- Instructions — a markdown blob Wang always follows (tone, naming conventions, approval policy, "always provision in region X").
GET / PUT / DELETE /v1/orgs/{slug}/wang/instructions(PUT body{body}, 20 KB cap). Appended to Wang's base persona; it never overrides the safety / boundary-authz rules. - Knowledge base — documents Wang retrieves per question.
GET /v1/orgs/{slug}/wang/knowledge(list, bodies omitted),POST(add{title, body}; 100 KB/doc, 200 docs/org),DELETE …/wang/knowledge/{id}, andGET | POST …/wang/knowledge/search?q=(full-text-ranked top matches). Retrieved per-query via thesearch_knowledgeMCP tool.
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.
GET /v1/woks/{id}/inbox— list received messages (bodies omitted;{id, from, to, subject, read, received_at}).GET …/inbox/{message_id}— fullbody_text+body_html, attachment metadata, and durable read state.PATCH …/inbox/{message_id}with{read:true|false}updates that state without changing the retained message.GET …/originaldownloads the exact retained.eml;GET …/attachments/{index}downloads one decoded attachment without exposing the account key in a URL.DELETE …/inbox/{message_id}— idempotent.- Wang reaches these through the
list_inbox+read_emailMCP tools.set_email_forwardingadds durable, metered forwarding with readable attachments, an exactoriginal_message.eml, and original SMTP-envelope headers;get_email_forwardingreports retry health andremove_email_forwardingdisables it. GET /v1/woks/{wok_id}/email-handlerreads the initial approved inbound automation, its draft/enabled/paused/failed state, exact message-field permissions, safe-test receipt, and retained test/live history.POSTsaves the deployed function, bounded sender/recipient/subject filters, permitted fields, and lifecycle state.POST …/email-handler/testchecks the exact draft against an owned Inbox message or safe sample without invoking the function or causing an external side effect; Enable requires that unchanged receipt.DELETEremoves the rule without deleting the function, Inbox messages, or prior receipts. Setting, testing, pausing, resuming, and deleting require build permission.GET /v1/woks/{id}/email-forwardingreturns destination, enabled-since time, pending/failed counts, last success, and active delivery rows with recipient, attempt count, retry time, stable error code, and a safe diagnostic. It never returns the message body or raw provider error.GET /v1/email/domainsreturns independent receiving and sending states for each email domain, the required inbound MX, sending DNS records, detected-publication flags, and bounded recovery guidance. Stored provider errors are not exposed.POST /v1/email/sendaccepts optional ownedwok_id, Inboxreply_to_message_id, and Base64attachmentswith filename and optionalcontent_type(or compatibility aliascontentType). The complete encoded message is capped at 40 MB. Attachment bytes remain in the durable provider outbox and idempotency identity until delivery settles. A dashboard reply stores one durable sent copy in the same reservation transaction as its idempotent billing receipt; message detail returns those sent replies without relying on a provider payload that is cleared after delivery.GET /v1/orgs/{slug}/billing/usage/auditsreturns completed claimed pre-account and Site-audit receipts with Site, time, serving model, and charging terms. Included rows name Pre-account audit or First Site audit and show $0.00; paid repeats retain the dollar charge for successful answer checks and their model-funding terms.GET /v1/orgs/{slug}/billing/usage/emailreturns the current month's received, sent, and forwarded delivery-unit rows with Site, quantity, charge state, and durable receipt. Received mail is marked not charged, and no forwarding row is represented as model-credit usage.
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.
GET /v1/orgs/{slug}/channels— list connected channels (kind,token_fingerprint,webhook_url; never the token).PUT /v1/orgs/{slug}/channels/{kind}— connect/rotate.kindistelegramorslack. Body{token, signing_secret?}(signing_secretrequired for Slack). For Telegram we callsetWebhookfor you and return the bot@username; for Slack we return thewebhook_urlto set as the Event Subscriptions Request URL.DELETE /v1/orgs/{slug}/channels/{kind}— disconnect (TelegramdeleteWebhookfirst), 204.- Inbound (provider-called, public):
POST /v1/channels/telegram/{secret}andPOST /v1/channels/slack/{secret}. Authenticated by the random per-channel secret in the path, plus Telegram'sX-Telegram-Bot-Api-Secret-Tokenheader / Slack's HMAC request-signature.
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.
POST /v1/orgs/{slug}/kms/keys— create{name, type}. Returns metadata only (name, type, version, fingerprint, public key for asymmetric); the material is never returned.GET /v1/orgs/{slug}/kms/keyslists;GET …/kms/keys/{name}reads one;DELETEis idempotent.POST /v1/orgs/{slug}/kms/keys/{name}/rotate— new version becomes current; older versions are retained so prior ciphertext and signatures still resolve.POST /v1/orgs/{slug}/kms/keys/{name}/import— bring your own key.aes-256-gcm:{material_b64}(32 bytes).ed25519:{secret_key}(asolana-keygenid.json array or a base58 secret key) or{seed_b64}.rsa-4096:{private_key_pem}. The response echoes the derived address so you can confirm it.PUT /v1/orgs/{slug}/kms/keys/{name}/state—{state}enable or disable a key.POST …/kms/keys/{name}/encrypt—{plaintext_b64, aad_b64?}→{ciphertext}.…/decryptreverses it.…/generate-data-keyreturns a fresh data key plus its wrapped form for envelope-encrypting large payloads locally.POST …/kms/keys/{name}/sign—{message_b64}→{signature, signature_b64, version}(theed25519signature is base58, ready for a Solana transaction).…/verifytakes{message_b64, signature}→{valid}.
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.
POST /v1/llm/v1/chat/completions— OpenAI-compatible model gateway. Every plan acceptsprivate,deepseek-v4-flash, anddeepseek-v4-pro; paid plans also acceptkimi-k2.7-code. Private and Kimi support text andimage_urlcontent blocks; DeepSeek is text-only. Private never sends a failed request to an external fallback. Usage beyond the included allowances is paid from prepaid credits. The request count is an included abuse allowance rather than a priced overage meter: paid plans and Free with prepaid credit or preserved paid key value continue after the included count while token admission remains the spend boundary. Without enough prepaid credit, fresh overage returns 402. BYOK remains provider-paid and bypasses this charge.CP_LLM_CONCURRENCY_LIMITEDasks the caller to wait for an admitted completion;CP_LLM_REQUESTS_EXHAUSTEDmeans Free exhausted the included request count without usage funding. On success the response carriesX-LLM-Tokens-Remaining+X-LLM-Requests-Remaining.- Streaming — pass
stream: true. The gateway returns SSE (Content-Type: text/event-stream) and force-injectsstream_options.include_usage = trueon the upstream so the finaldata: {"usage":{...}}chunk arrives for post-stream meter debit.X-Accel-Buffering: nosuppresses proxy buffering so chunks land at upstream latency. Valid chunks pass through unchanged; when a private provider omits the required string ID on a streamed tool call, TellWang supplies a stable opaque ID so OpenAI-compatible clients can continue. After a client disconnect, a TellWang-funded call stops forwarding and is still metered accurately from its final usage; BYOK keeps ordinary client cancellation. GET /v1/llm/v1/models— OpenAI-spec, plan-aware discovery; returns{object:"list", data:[{id, object:"model", created, owned_by}]}. Free lists Private and both DeepSeek ids; paid plans also list Kimi.