# Architecture This page walks through the moving parts so you have a mental model of where your code sits and what runs where. ## The big picture ```mermaid flowchart LR Dev["Your laptop
sinch CLI"] Platform["Sinch Functions Platform"] Fn["Your deployed Function"] VP["Voice Platform"] CP["Conversation Platform
(SMS, WhatsApp, etc.)"] Phone(["Phone network"]) Chat(["Messaging channels"]) Dev -- "deploy" --> Platform Platform -- "runs" --> Fn Phone -- "incoming call" --> VP Chat -- "inbound message" --> CP VP -- "ICE / ACE / PIE / DICE" --> Fn CP -- "webhook" --> Fn Fn -. "SDK calls
context.voice" .-> VP Fn -. "SDK calls
context.conversation" .-> CP ``` The CLI uploads your source and configuration to the Sinch Functions Platform. From there, the platform builds your function, runs it, and updates any callback URLs on your Voice or Conversation apps so inbound traffic reaches the new version. ## What happens when you deploy 1. You run `sinch functions deploy` from your project directory. 2. The CLI validates your project: - **Node:** typecheck, bundle with `tsup`, smoke-test. - **C#:** `dotnet build`, health-check locally. 3. The CLI packages the project into a zip and uploads it to the Sinch Functions Platform. 4. The platform builds and rolls out your function. If an identical build already exists, the build step is skipped and the existing artifact is reused. 5. Your function comes up at `https://fn-.functions.sinch.com`. 6. If your project's `sinch.json` declares a Voice App or Conversation App, the CLI updates that app's callback URL to point at the new function. ## What happens when a call arrives 1. A caller dials your Sinch phone number. 2. Sinch's voice platform receives the call and looks up the Voice App assigned to that number. 3. The Voice App sends an **ICE** (Incoming Call Event) callback to your function's URL. 4. Your function runs, builds a SVAML response, returns it. 5. Sinch interprets the SVAML and controls the call accordingly — plays audio, runs menus, connects legs, records, etc. 6. If the SVAML ran a menu, Sinch sends a **PIE** (Prompt Input Event) callback when the menu completes. You respond with the next SVAML step. 7. When the call ends, Sinch sends a **DICE** (Disconnected Call Event) callback. Your function can log or clean up. See [voice-callbacks](#) for the callback lifecycle in detail. ## What happens when a message arrives 1. A user sends an SMS or WhatsApp message to a number assigned to your Conversation App. 2. The Conversation platform posts a webhook to your function's URL. 3. Your function runs, decides what to do, and optionally sends a reply via `context.conversation.messages.send(...)`. ## What happens when you run `sinch functions dev` 1. The CLI starts your function locally — hot-reloading via `tsup` watch (Node) or `dotnet watch` (C#). 2. It opens a tunnel (Cloudflare Tunnel) that gives your local process a public URL. 3. It optionally updates your Voice App's callback URL to the tunnel URL so Sinch can reach your laptop directly. 4. When a real call hits the number, Sinch calls your laptop, and you see requests in real time via `sinch functions logs`. 5. Stop the dev server and the CLI reverts any callback URLs it touched. This means you can test against real Sinch traffic from your laptop, with no deploy loop. ## Where secrets live | Where | What | Who manages it | | --- | --- | --- | | OS keychain (`keytar`) | CLI login credentials — API keys for the Sinch platform | The CLI itself, via `sinch auth login` | | Your project's `.env` | Local development variables (dev loop only) | You, during `sinch dev` | | `sinch.json` → `variables` | Non-secret function config (e.g., feature flags, upstream URLs) | Checked into your repo | | `sinch.json` → `secrets` + `sinch secrets add` | Production secrets (e.g., ElevenLabs API key, OpenAI key) | You; stored encrypted in the platform, injected at runtime | See [configuration-secrets](#) for the full story of how each layer is resolved. ## Where your deployed function runs Deployed functions run in an isolated, managed runtime environment. The platform provides: - **Cache** — persistent and shared across invocations - **Blob storage** — durable and backed up - **SQLite database** — with automatic durable replication, so it survives restarts - **Per-function subdomain** — `https://fn-.functions.sinch.com` - **Auto-scaling** based on request volume - **Structured logging** streamed via `sinch functions logs` - **Pre-initialized SDK clients** for Voice, Conversation, SMS, Numbers (and Verification in C#) when the right environment variables are set You don't see any of this infrastructure from your code. You write a handler, the runtime takes care of the rest.