App platform overview
App platform overview
The Telenow App Platform lets you build installable apps for the Telenow voice-AI product — think of a Shopify app or a WordPress plugin, but for the Telenow dashboard and the voice agent that talks to your callers.
An app can add data tables, new dashboard pages, tools the voice agent calls mid-conversation, automations, ready-made agents, and knowledge — all from a single declarative file. You can keep an app private to your own organisation, or publish it to the marketplace for any Telenow org to install.
This page is the map. It explains what an app is, what it can do, how the pieces fit together, and where to go next. The platform works the same whether you are a solo developer wiring up a single clinic or an international team shipping a global CRM — the SDK, manifest, and APIs are identical.
New here? Start with What you can build for the every-possibility overview, then Build your first app. When you start hitting real data, read Limits & quotas.
🤖 Building with an AI assistant? Give it the App-Building Skill file — one self-contained document with the whole framework, the exact rules, and every reference an LLM needs to build a correct Telenow app in one shot. Paste its URL (or contents) into ChatGPT, Claude, Cursor, or any coding assistant, and tell it to follow it. It's also the fastest way for a new human developer to get the full picture.
App vs agent vs agent-template
These three words sound similar but mean different things. Get this straight first and the rest is easy.
| Term | What it is |
|---|---|
| App | A versioned bundle you install into an org. It contributes data objects, agent tools, dashboard UI, automations, and more. This is what you build and what this doc set is about. |
| Agent | A live, configured voice agent in an org (a system prompt + models + voice + tools). Agents place and answer calls. Apps can provide tools and ship templates that build agents, but an agent is its own thing. |
| Agent template | A ready-made agent recipe an app ships in its manifest (agents[]). When an admin clicks "Create agent", the template is turned into a real agent, auto-bound to the app's tools. It is a blueprint, not a running agent. |
So: you build an app; the app can bundle agent templates; an admin turns a template into a real agent.
What an app can do — capability map
Everything an app contributes is declared in its manifest. Here is the full surface, with the page that covers each in depth. For the outcome-oriented "every possibility" tour, see What you can build.
| Capability | What it gives you | Learn more |
|---|---|---|
| Data & objects | A scoped object store: typed fields, relations, computed fields, saved views, semantic search, queries. | Data & objects |
| Agent tools | Functions the voice agent can call mid-call — declarative object.* CRUD, your own http endpoint, or a sandboxed JS handler. | Agent tools |
| Dashboard UI | React pages that render inside the dashboard via a sandboxed iframe and the window.telenow bridge; menu items, slots, realtime, design tokens. | Dashboard UI |
| Automation | Event subscriptions, signed webhooks, platform-hosted inbound hooks, schedules, and durable multi-step workflows. | Automation |
| Bundled agents & knowledge | Ready-made agents, multi-agent teams, and knowledge bases that auto-attach to your agents. | Bundled agents |
| External backend / REST | A scoped, app-key REST API for your own server (Data, Files, Agents, Campaigns, live-call stream) plus signed-request verification. | External backends |
| Scopes & security | The permission model: what your app asks for at install, and how the platform enforces it server-side. | Scopes & permissions |
| Packaging & publishing | How to validate, package, upload privately, and submit to the marketplace. | Packaging & distribution |
| Limits & quotas | Every hard cap and rate limit (rows, blobs, schedules, workflows, proxy size, …). | Limits & quotas |
The manifest IS the app
There is one file at the heart of every app: telenow.app.json, the manifest. It is a declarative description of everything your app contributes. The platform reads it and gives each declaration effect — for a declarative app, no code of yours runs at all.
// telenow.app.json — the whole app, declared
{
"id": "clinic-crm",
"version": "2.1.2",
"name": "Doctor CRM",
"runtime": "declarative",
"category": "crm",
"icon": "stethoscope",
"blurb": "A full clinic CRM: patients, appointments, and visit logs.",
"scopes": ["objects:patient", "objects:appointment", "calls:read"],
"objects": [ /* your data types */ ],
"tools": [ /* what the agent can call */ ],
"ui": { "entry": "ui/index.tsx", "pages": [ /* dashboard pages */ ] },
"events": [ /* automations */ ],
"agents": [ /* ready-made agents */ ]
}
Because the manifest is declarative, the platform can validate it, version it, and enforce its scopes before anything runs. Every field is documented in the Manifest reference.
The recurring example throughout these docs is the clinic-crm ("Doctor CRM") app shipped in the SDK — a declarative CRM with patient / appointment / visit / lead objects, eight tools, five UI pages, bundled agents, a knowledge base, workflows, and an inbound hook. The skeleton above is an abridged view of its real manifest, sdk/examples/doctor-crm/telenow.app.json (the actual file declares all 11 scopes and fills in every block shown here as /* … */).
Runtime tiers
An app declares a runtime in its manifest. This describes where your tool handlers run.
| Tier | Where code runs | Hosting | Use when |
|---|---|---|---|
| declarative (default) | Nowhere — the platform runs object CRUD, tools, UI, and automations for you. | None. | You can model your logic as object reads/writes. Start here. |
| external | Your own server. http tools POST to your base_url; you verify signatures and use the app-key REST API. | Your backend. | You need custom server logic or to call your existing systems. |
| sandboxed | Telenow's hardened JS sandbox (sandbox handler — pure compute, no host/data/network). | None. | You need a bit of computation but no hosting (vetted apps). |
Decision guide: if your tool is "create/find/update/delete a record", use declarative — no hosting, no signatures, nothing to deploy. If your tool needs to call your own system or do real work on a server you control, use external. If you just need pure computation (formatting, math) with no I/O, use sandboxed.
runtime is advisory — handlers decide, not the tier
This is the part that trips people up: runtime is a declaration of intent / catalog metadata, not a switch that gates execution. The manifest validator does not check runtime against an allowed-values list — an absent value defaults to declarative, and a typo (say "runtime": "externl") is silently kept. It only describes the app in the catalog.
What actually decides how a tool runs is the individual tool's handler.kind, dispatched per tool at call time:
handler.kind | How it runs | What it needs |
|---|---|---|
object.create / object.query / object.update / object.delete | Declarative, in-core. No app code. | Just a declared object (and a match field for update/delete). |
http | POSTs to your backend. | A non-empty top-level base_url in the manifest (validated). |
sandbox | Runs in the hardened JS sandbox. | The platform feature flag FEATURE_APP_SANDBOX enabled. |
Consequences worth internalising:
- An
httptool works perfectly with"runtime": "declarative"as long asbase_urlis set — thehttphandler is what triggers the validator's "needsbase_url" rule, not the tier string. - Setting
"runtime": "external"does not make yourobject.*tools call out anywhere; they still run declaratively in-core. - Treat
runtimeas a label for humans and the marketplace. Get yourhandler.kindright and thebase_urlpresent, and the tier string is cosmetic.
One app mixes everything at once
There is no "pick one tier" rule. A single installed app can simultaneously ship: a set of declarative object.* objects and tools, an http tool that reaches your backend, a sandbox tool for pure compute, a React dashboard, and events/schedules/workflows. The clinic-crm example is mostly declarative but could add an http tool to call an external lab system without changing anything about its objects. Mix freely — the platform dispatches each piece on its own merits.
How it fits together — architecture
A few ideas tie the whole platform together.
- Manifest-driven. The manifest is the single source of truth. The CLI validates it with
npx telenow validate(the same checks the server runs at upload), andnpx telenow buildpackages it. - Sandboxed React UI. Your dashboard pages are a React bundle that renders in a sandboxed iframe on an opaque origin — it has no dashboard cookies, no tokens, and no API keys. The dashboard injects a
window.telenowbridge; every call (read data, list agents, place a call) is relayed to the parent and performed under the signed-in user, scoped to your app and org, and enforced server-side. React hooks likeuseObjects()wrap the bridge. - Tenant + app scoped data. Your object store is automatically isolated to
(org, app). You cannot read another org's data, and another app cannot read yours. - Signed webhooks / HMAC. Every
httptool call and event webhook the platform sends is signed withX-Telenow-Signature: sha256=<hex>(HMAC-SHA256 over the raw body). Your backend verifies it withverifySignaturebefore trusting anything. - App-key REST. External backends authenticate to the REST API with an app key bound to one
(org, app)— so calls are automatically scoped and can never reach another tenant.
// In the dashboard UI — no API key, relayed under the signed-in user
import { useObjects, useTelenowContext } from 'telenow/react';
export default function App() {
const { page } = useTelenowContext();
const { data, loading, create } = useObjects('appointment');
if (loading) return <p>Loading…</p>;
return <Calendar events={data} onBook={(a) => create(a)} />;
}
// On your own backend — app key + signature verification
import { verifySignature, DataClient } from 'telenow';
const db = new DataClient('https://api.telenow.ai', process.env.TELENOW_APP_KEY!);
// verify X-Telenow-Signature against the RAW body before trusting a tool call
The npm package is
telenow(unscoped). Install it withnpm install telenow, Node 18+, zero runtime dependencies.
See it all in one map: What you can build lists every outcome and the scopes it needs.
Install & scopes at a glance
Every capability that touches sensitive data or actions is gated by a scope you declare in the manifest. When an org installs your app, it sees exactly what the app is asking for and consents to it.
"scopes": [
"objects:patient", // read/write the patient object type
"calls:read", // read call history + receive live call events
"calls:initiate", // place outbound calls
"whatsapp:send" // send WhatsApp messages
]
Scopes are frozen at install. If a later version of your app adds a scope, the org must re-consent before upgrading. The bridge's can() and useUser() help you gate UI, but real enforcement always happens server-side. The full list and the security model live in Scopes & permissions.
Install & uninstall lifecycle
Knowing what happens to your app's data across install, upgrade, and uninstall matters once real records exist.
- Install. The org consents to the manifest's scopes; the install gets a fresh signing secret (used to HMAC-sign outbound
httptool calls and event webhooks). Bundled knowledge bases are created and embedded, andapp_schedulesrows are created for your declared schedules. - Upgrade (re-install a newer version). The install is re-pinned to the new version. The granted scopes are re-pinned from the new version's manifest (adding scopes requires re-consent), and settings the new version no longer declares are scrubbed (including a key that became
secret, so stale plaintext can't linger). Schedules are reconciled to the new manifest — new keys start one interval out, dropped keys are removed. The signing secret is preserved on re-install. - Uninstall (default). Your dashboard pages and sidebar menu items disappear immediately. By default your objects, blobs, and bundled KBs are KEPT — a later re-install restores them, and the signing secret is preserved.
app_schedulesare always stopped, whether or not you delete data. - Uninstall with
?deleteData=true. This permanently purges the app's records (app_objects), deletes its blob storage, and makes its bundled KBs unreachable (they no longer appear in agent retrieval or search). This is irreversible — a later re-install starts empty.
# Keep data (default) — pages vanish, records and blobs are retained for re-install
DELETE /api/orgs/:orgId/apps/clinic-crm
# Permanently delete everything the app stored
DELETE /api/orgs/:orgId/apps/clinic-crm?deleteData=true
App keys and bindings cascade away with the install either way. The uninstall confirmation in the dashboard shows how many records "delete all data" would remove.
Distribution: private or marketplace
You build the same way regardless of how you ship.
- Private to your org. Run
npx telenow buildto produce<appId>-<version>.telenow.zip, then upload it under Apps → Upload app zip. Only your org can install it. Perfect for internal tools and customer-specific builds. A private upload does not require a README or screenshots. - Published to the marketplace. Submit the same package for review and publish it so any Telenow org can discover and install it. Marketplace review additionally requires a
README.mdand at least one screenshot for the listing (a private upload does not). The marketplace channel only moves forward in version, and publishers get cross-org adoption analytics.
Packaging, versioning, the review checklist, and publishing are covered in Packaging & distribution.
Who it's for & prerequisites
This platform is for developers who want to extend Telenow — agencies building for clients, SaaS teams adding a voice layer, or in-house developers automating their own calling. You do not need to be a Rust or voice-AI expert.
Prerequisites:
- Node 18+ and npm to run the CLI and build the React UI.
- Basic React if you want dashboard pages (you can ship an app with no UI at all).
- Your own backend (optional) — only if you choose the
externaltier for custom server logic.
That's it. A fully functional, hosting-free app needs nothing more than the manifest and the telenow package. Developers everywhere use the exact same tools, regardless of market.
Next
- What you can build — the every-possibility overview, organised by outcome.
- Build your first app — CLI scaffold → dev preview → build → upload.
- Manifest reference — every field of
telenow.app.json. - Limits & quotas — every hard cap and rate limit.
- Scopes & permissions and Packaging & distribution.