# How do I put a VARTA voice agent inside my own app, instead of on the phone network?

The sessions API is the integration point -- your native client captures its own audio, transcribes it with its own speech recogniser, and sends the text to POST /v1/sessions/{id}/turn one turn at a time. There is no mobile SDK; this page is the pattern you wire the calls yourself against.


You put a VARTA agent inside a native app the same way you'd hold any conversation
through the API: open a session, send it transcribed text one turn at a time, and play
back the audio it returns. **There is no mobile SDK** -- no iOS or Android package that
does audio capture, transcription, playback and session bookkeeping for you. Every
piece between the microphone and `POST /v1/sessions/{id}/turn` is code you write and
own.

## Why this is the sessions API, not the calls API

`POST /v1/calls` places a real telephone call over a SIP trunk. An in-app agent never
touches the phone network -- the caller's voice already reaches your client over
whatever transport your app uses. The right primitive is a **session**: the same
conversational runtime `/v1/calls` uses underneath, opened directly, with your client
supplying transcribed text instead of a phone call supplying audio to a trunk. See
[Sessions](/docs/api/sessions) for the full reference.

## The call sequence

1. Open a session when the in-app voice flow starts.

```bash
curl -X POST "$VARTA_BASE_URL/sessions" \
  -H "Authorization: Bearer $VARTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "ag_412", "customer_name": "Rahul"}'
```

> **Agent ids are numeric and studio-assigned.** `ag_412` above is the shape the API
> actually issues: `/v1` strips the `ag_` prefix and parses the rest as an integer
> (`backend/app/api/v1/_ids.py:56-61`), so an author-chosen slug like
> `ag_cod_confirm` is rejected as malformed before any lookup happens. Use the id the
> studio gave your agent.

2. Your app captures the user's speech from the device microphone and transcribes it
   -- with whatever speech-recognition stack you've already integrated, on-device or
   cloud. VARTA does not do speech recognition on this path; it consumes text you
   already transcribed.
3. Send that text as a turn, along with whatever confidence/telemetry your recogniser
   can supply.

```bash
curl -X POST "$VARTA_BASE_URL/sessions/se_9021/turn" \
  -H "Authorization: Bearer $VARTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "I want to check my order status", "stt_confidence": 0.94, "stt_provider": "your_recognizer"}'
```

4. The response carries the agent's reply text, a pre-synthesised `audio_url` (or
   `cache_hit: true` if that phrasing was already cached), the layer that decided the
   reply, and the turn's cost. Play `audio_url` back through your app; repeat steps 2-4
   for each turn.
5. When the user leaves the flow or ends the conversation, close it out.

```bash
curl -X POST "$VARTA_BASE_URL/sessions/se_9021/end" \
  -H "Authorization: Bearer $VARTA_API_KEY"
```

A browser-based voice widget embedded on a web page is the same pattern in a web
client instead of a native one -- and it is not hypothetical: it ships as the fourth
runnable example, [Browser voice widget](/docs/examples), complete with the
key-holding proxy that keeps your API token out of the page. The browser
captures and transcribes audio, and sends text to the identical
`POST /v1/sessions/{id}/turn` endpoint. Nothing about the API changes between a native
app and a browser tab -- only which client owns the microphone.

## What you still have to build

- **Audio capture** -- microphone permission, recording, and (usually) voice-activity
  detection to know when the user has stopped talking, in your app's native layer.
- **Speech recognition** -- an on-device or cloud STT integration that turns captured
  audio into the `text` this API expects. VARTA does not provide one for this path.
- **Audio playback** -- fetching and playing `audio_url`, including handling the case
  where a turn arrives with no fresh audio because it was a cache hit.
- **Session lifecycle in your app** -- opening a session when the voice flow starts,
  persisting `session_id` for the duration of that flow, and calling
  `POST /v1/sessions/{id}/end` when it's done, including on an unclean exit (app
  backgrounded or killed mid-conversation).
- **Reconnect/resume handling** -- if your app loses connectivity mid-session, deciding
  whether to resume the same session or open a new one is a decision this API leaves to
  your client.
