Pinecall

Deployment Topologies

Embedded, standalone, or headless — pick the topology that fits your architecture.

The fundamental split#

Before topology, understand the two communication patterns:

1. Backend channels — phone, SIP, WhatsApp. These talk to your Node.js process via the SDK's WebSocket. Your code receives events through an in-process EventEmitter.

Backend channels flow

2. Browser channels — WebRTC and chat. The browser connects directly to voice.pinecall.io. Your backend's only job is minting short-lived tokens.

Browser channels — WebRTC token flow

This split is why some topologies support SSE event streaming and others don't — SSE requires the agent to be in the same process as your web server.

Topology 1: Embedded#

Agent runs inside your existing web app (Express, Next.js, Hono, Remix). The web server and the agent share a Node.js process.

Embedded topology

Pros:

  • SSE streaming works (you can build live dashboards)
  • One deployment unit — easy ops
  • Token endpoint is one route away from the agent

Cons:

  • The agent process restarts every time you deploy the web app
  • Web traffic and voice traffic share resources

When to use: small apps, dashboards that need live call event streaming, single-team projects.

Topology 2: Standalone#

Agent runs as a separate process from your web app. The web app handles HTTP, the agent process handles voice.

Standalone topology

Pros:

  • Independent deploys — restart the agent without touching the web app
  • Independent scaling — give the agent its own resources
  • Crash isolation — a web bug doesn't kill calls in flight

Cons:

  • No SSE — the web app can't stream events from the agent process directly. If you need live dashboards, the agent has to expose its own SSE endpoint or push to a shared bus (Redis, NATS).
  • Two deployments to manage

When to use: higher-traffic apps, when ops cares about independent scaling, when you want to avoid the "web deploy kills in-flight calls" problem.

Topology 3: Headless#

No web server at all. Just the agent. Use this when you only need phone/SIP/WhatsApp — no browser channels, no dashboards, no tokens to mint.

// agent/index.js — a complete production agent, no web server needed
import { Pinecall } from "@pinecall/sdk";

const pc = new Pinecall();

export const agent = pc.agent("support", {
  prompt: "You are a support agent for an online store...",
  llm: "openai/gpt-5-chat-latest",
  voice: "elevenlabs/sarah",
  stt: "deepgram/flux",
  language: "en",
  phoneNumber: "+13186330963",
  greeting: "Hi! How can I help?",
  tools: [lookupOrder, processReturn],
});

Run it with pinecall run agent/index.js for a polished boot banner and live transcript.

Pros:

  • Lowest possible complexity
  • No HTTP surface to attack or maintain
  • Easy to ship as a container, a systemd unit, or a serverless function

Cons:

  • No browser channels (no WebRTC, no chat) unless someone else mints tokens
  • No SSE
  • No dashboards from this process

When to use: IoT devices, intercoms, single-purpose phone bots, WhatsApp-only bots, scheduled outbound campaigns.

Comparison#

FeatureEmbeddedStandaloneHeadless
SSE (agent.stream())
WebRTC / Chat✅ (token from web app)❌ (or you build it)
Phone / SIP
WhatsApp
Outbound calls
Operational complexityMediumMediumLowest
Independent scaling
Crash isolationn/a

Which one should you pick?#

  • Just starting out — embedded. Get something running, split later if you need to.
  • You need browser channels and a dashboard — embedded.
  • You're scaling and ops cares — standalone.
  • You're shipping a fixed-purpose device or WhatsApp-only bot — headless.

Migration between topologies is cheap. The agent code is the same in all three. You're just choosing where to run it.

What's next#