LanternDocs

Surfaces

A surface is a channel where people talk to an agent. Seven are wired: WhatsApp, iMessage, Slack, Discord, Telegram, voice and web chat. Replies go back on the channel the message came from.

In plain termsPut the agent where the conversation already happens instead of asking people to open a dashboard. Same agent and guardrails on every channel; only the doorway changes.

Available surfaces

WhatsApp

Two paths:

  • Personal (bridge) -- a Baileys-based bridge pairs with your own WhatsApp account by QR code. No Business account needed. Self-hosted only.
  • Business Cloud API -- the surface gateway has a WhatsApp Cloud API adapter for a dedicated business number.

To set up personal WhatsApp:

  1. Open Channels (/surfaces) and choose WhatsApp
  2. Select Personal (bridge)
  3. Scan the QR code with your WhatsApp app
  4. The bridge connects and your agent is now reachable via WhatsApp
Note: The bridge is a separate long-running process (port 3100). Start it with make run-whatsapp-bridge, or lantern dev, which starts it by default.

Bridge tenant env var

Set LANTERN_TENANT_ID to the tenant UUID the bridge runs under. LANTERN_DEFAULT_TENANT_ID is still read as a fallback. The iMessage bridge and bridge-core resolve it in that order. The macOS iMessage bridge is covered in Personal assistant.

Slack

The surface gateway (services/surface-gateway) has a Slack adapter for events and bot messages, and the control plane serves a slash-command endpoint at POST /v1/surfaces/slack/command. In production, unsigned slash commands are refused unless SLACK_SIGNING_SECRET is set. Configure the surface under Channels (POST /v1/surfaces with a surfaceId and displayName).

Discord

A Discord adapter ships in the surface gateway. Configure it under Channels with your bot credentials.

Telegram

Connect a Telegram bot to an agent:

  1. Create a bot via @BotFather on Telegram
  2. Add the bot token under Channels
  3. Assign the surface to an agent

Voice (Twilio + LiveKit)

Phone numbers route inbound calls to a Lantern agent. Two providers are supported:

  • Twilio -- TwiML webhooks for inbound PSTN calls. The control-plane verifies Twilio's webhook signature and replies with TwiML. SMS is also available on the same Twilio connector.
  • LiveKit -- realtime audio; the control-plane mints a short-lived join token and the audio loop runs in a separately-deployed LiveKit Agents worker (media last-mile).

Budget gating

Voice spend counts against the same agent_budgets as runs. A Twilio inbound call over a hard-fail budget is declined with <Reject> (no carrier cost). A LiveKit join token is refused with HTTP 402 (no token means no media). A flat cost estimate is recorded on connect; the provider's status callback at POST /v1/voice/calls/status/{provider} reconciles to actual duration cost when the call ends.

Voice API

MethodPathDescription
POST/v1/voice/numbersLink a phone number to an agent (provider + config)
GET/v1/voice/numbersList linked numbers
DELETE/v1/voice/numbers/{id}Unlink a number
GET/v1/voice/callsRecent calls with duration and cost
POST/v1/voice/tokenMint a short-lived LiveKit join token
POST/v1/voice/webhook/{provider}Inbound call webhook (Twilio TwiML or LiveKit JWT)
POST/v1/voice/calls/status/{provider}Call-end status callback — reconciles actual cost into budget rollup. Point Twilio's “call status changes” webhook here.

Env vars

VariablePurpose
LANTERN_VOICE_CALLER_IDE.164 caller-ID shown on outbound calls. Must be a Twilio verified number.
LANTERN_VOICE_SMS_HEADSUPon (default) — sends an SMS heads-up before the call so recipients recognize the number.
LANTERN_VOICE_CLONEOptional — 1 speaks outbound calls in the owner's cloned voice via ElevenLabs. Requires LANTERN_ELEVENLABS_API_KEY and LANTERN_ELEVENLABS_VOICE_ID.

Web Chat

Embed a chat widget on any website:

<!-- widget.js is served by the dashboard app; copy the exact snippet from /embed -->
<script src="http://localhost:3001/widget.js"
  data-api-key="YOUR_SCOPED_API_KEY"
  data-agent="your-agent-name"
  data-api-base="http://localhost:8080"
  data-theme="dark"
  data-position="bottom-right"
  async defer></script>

The widget uses the same /v1/sessions endpoints as the dashboard and streams replies over SSE. The API key is visible in the browser, so scope it to sessions and messages. The dashboard's /embed page generates the snippet.

REST API

Every agent is accessible via the REST API. See the API Reference for full details.

curl -X POST http://localhost:8080/v1/runs \
  -H "Authorization: Bearer $LANTERN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agentName": "my-agent", "input": {"topic": "quantum computing"}}'

Assigning surfaces to agents

Configure a surface once for the tenant, then point it at an agent:

  1. Set up the surface under Channels
  2. On the agent's page, open its Channels tab and enable the surfaces it should answer on
Warning: An agent answers only on surfaces assigned to it. A message on a channel the agent is not enabled for gets no reply.

Two-way communication

When a user sends a message:

  1. The surface gateway (or a bridge) receives the message
  2. It routes to the correct agent based on the surface configuration
  3. The agent runs with the message as input
  4. The response streams back through the same surface, in the same conversation or thread
Tip: Pair a schedule with the Slack connector to post a daily summary.