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.

TermWhat it is
AppA 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.
AgentA 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 templateA 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.

CapabilityWhat it gives youLearn more
Data & objectsA scoped object store: typed fields, relations, computed fields, saved views, semantic search, queries.Data & objects
Agent toolsFunctions the voice agent can call mid-call — declarative object.* CRUD, your own http endpoint, or a sandboxed JS handler.Agent tools
Dashboard UIReact pages that render inside the dashboard via a sandboxed iframe and the window.telenow bridge; menu items, slots, realtime, design tokens.Dashboard UI
AutomationEvent subscriptions, signed webhooks, platform-hosted inbound hooks, schedules, and durable multi-step workflows.Automation
Bundled agents & knowledgeReady-made agents, multi-agent teams, and knowledge bases that auto-attach to your agents.Bundled agents
External backend / RESTA scoped, app-key REST API for your own server (Data, Files, Agents, Campaigns, live-call stream) plus signed-request verification.External backends
Scopes & securityThe permission model: what your app asks for at install, and how the platform enforces it server-side.Scopes & permissions
Packaging & publishingHow to validate, package, upload privately, and submit to the marketplace.Packaging & distribution
Limits & quotasEvery 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.

TierWhere code runsHostingUse 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.
externalYour 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.
sandboxedTelenow'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.kindHow it runsWhat it needs
object.create / object.query / object.update / object.deleteDeclarative, in-core. No app code.Just a declared object (and a match field for update/delete).
httpPOSTs to your backend.A non-empty top-level base_url in the manifest (validated).
sandboxRuns in the hardened JS sandbox.The platform feature flag FEATURE_APP_SANDBOX enabled.

Consequences worth internalising:

  • An http tool works perfectly with "runtime": "declarative" as long as base_url is set — the http handler is what triggers the validator's "needs base_url" rule, not the tier string.
  • Setting "runtime": "external" does not make your object.* tools call out anywhere; they still run declaratively in-core.
  • Treat runtime as a label for humans and the marketplace. Get your handler.kind right and the base_url present, 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), and npx telenow build packages 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.telenow bridge; 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 like useObjects() 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 http tool call and event webhook the platform sends is signed with X-Telenow-Signature: sha256=<hex> (HMAC-SHA256 over the raw body). Your backend verifies it with verifySignature before 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 with npm 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 http tool calls and event webhooks). Bundled knowledge bases are created and embedded, and app_schedules rows 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_schedules are 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 build to 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.md and 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 external tier 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