> ## Documentation Index
> Fetch the complete documentation index at: https://slng.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# API examples

> Code samples for the SLNG Voice Agent API in JavaScript and Python. Create, list, update, test, and delete voice agents through the agent lifecycle.

Working code for the agent lifecycle. For prompt design, tool configuration, and template variables, see [Configuring voice agents](https://slng.mintlify.site/examples/agents-config.md).

## Placeholders

Every snippet below uses these placeholders. Replace them before running the code.

| Placeholder | Replace with |
| - | - |
| `SLNG_API_KEY` | An SLNG key from [app.slng.ai/api-keys](https://app.slng.ai/api-keys). Use it as the bearer token in the `Authorization` header. |
| `AGENT_ID` / `550e8400-e29b-41d4-a716-446655440000` | The agent's UUID returned by `POST /v1/agents` |
| `region: "eu-central"` | A Voice Agents logical region. See [Agent regions](https://slng.mintlify.site/voice-agents.md#agent-regions) |

## Create an agent

```javascript JavaScript theme={null}
const resp = await fetch("https://api.agents.slng.ai/v1/agents", {
  method: "POST",
  headers: {
    Authorization: "Bearer SLNG_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    schema_version: 2,
    tool_mode: "shared",
    name: "Appointment Reminder",
    system_prompt:
      "You are a friendly appointment reminder for {{clinic_name}}. " +
      "Confirm the patient upcoming visit or help them reschedule. " +
      "Keep responses to one or two sentences.",
    greeting: "Hi {{patient_name}}, this is a reminder from {{clinic_name}} about your upcoming appointment.",
    language: "en",
    region: "eu-central",
    models: {
      stt: "slng/deepgram/nova:3-en",
      llm: "groq/openai/gpt-oss-120b",
      tts: "slng/deepgram/aura:2-en",
      tts_voice: "aura-2-thalia-en",
    },
    tool_refs: [],
    mcp_refs: [],
    template_defaults: {
      clinic_name: "Downtown Health Clinic",
      patient_name: "there",
    },
  }),
});

const agent = await resp.json();
console.log(agent.id);
```

```python Python theme={null}
import requests

resp = requests.post(
    "https://api.agents.slng.ai/v1/agents",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
    json={
        "schema_version": 2,
        "tool_mode": "shared",
        "name": "Appointment Reminder",
        "system_prompt": (
            "You are a friendly appointment reminder for {{clinic_name}}. "
            "Confirm the patient upcoming visit or help them reschedule. "
            "Keep responses to one or two sentences."
        ),
        "greeting": "Hi {{patient_name}}, this is a reminder from {{clinic_name}} about your upcoming appointment.",
        "language": "en",
        "region": "eu-central",
        "models": {
            "stt": "slng/deepgram/nova:3-en",
            "llm": "groq/openai/gpt-oss-120b",
            "tts": "slng/deepgram/aura:2-en",
            "tts_voice": "aura-2-thalia-en",
        },
        "tool_refs": [],
        "mcp_refs": [],
        "template_defaults": {
            "clinic_name": "Downtown Health Clinic",
            "patient_name": "there",
        },
    },
)

agent = resp.json()
print(agent["id"])
```

```bash cURL theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "schema_version": 2,
    "tool_mode": "shared",
    "name": "Appointment Reminder",
    "system_prompt": "You are a friendly appointment reminder for {{clinic_name}}. Confirm the patient upcoming visit or help them reschedule. Keep responses to one or two sentences.",
    "greeting": "Hi {{patient_name}}, this is a reminder from {{clinic_name}} about your upcoming appointment.",
    "language": "en",
    "region": "eu-central",
    "models": {
      "stt": "slng/deepgram/nova:3-en",
      "llm": "groq/openai/gpt-oss-120b",
      "tts": "slng/deepgram/aura:2-en",
      "tts_voice": "aura-2-thalia-en"
    },
    "tool_refs": [],
    "mcp_refs": [],
    "template_defaults": {
      "clinic_name": "Downtown Health Clinic",
      "patient_name": "there"
    }
  }'
```

New agents use the shared organisation tool library. Create and publish tools separately, then add their pinned versions through `tool_refs`; see [Tools](https://slng.mintlify.site/examples/agents-config.md#tools).

## Test with a web session

Web sessions let you talk to your agent from a browser. No phone number or SIP trunk required. The response includes LiveKit credentials you can use with any [LiveKit client SDK](https://docs.livekit.io/client-sdk-js/).

```javascript JavaScript theme={null}
const resp = await fetch(
  `https://api.agents.slng.ai/v1/agents/${agent.id}/web-sessions`,
  {
    method: "POST",
    headers: {
      Authorization: "Bearer SLNG_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      arguments: { patient_name: "Maria", clinic_name: "Greenfield Family Medicine" },
    }),
  },
);

const session = await resp.json();
// session.livekit_url:   WebSocket URL to connect to
// session.livekit_token: access token for the room
// session.room_name:     LiveKit room name
// session.call_id:       use this to look up the call later
// session.max_session_seconds: how long the session stays open
```

```python Python theme={null}
resp = requests.post(
    f"https://api.agents.slng.ai/v1/agents/{agent['id']}/web-sessions",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
    json={
        "arguments": {"patient_name": "Maria", "clinic_name": "Greenfield Family Medicine"},
    },
)

session = resp.json()
# session["livekit_url"]:   WebSocket URL to connect to
# session["livekit_token"]: access token for the room
# session["room_name"]:     LiveKit room name
# session["call_id"]:       use this to look up the call later
# session["max_session_seconds"]: how long the session stays open
```

```bash cURL theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents/AGENT_ID/web-sessions \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "participant_name": "Test user",
    "arguments": {
      "patient_name": "Maria"
    }
  }'
```

Both fields are optional. `arguments` overrides `template_defaults` on the agent, and `participant_name` sets a display name in the LiveKit room. `max_session_seconds` is set by the server — it is not configurable per request — and is enforced for web sessions only; phone calls are not subject to it.

## Update an agent

PATCH updates only the fields you send. Use PUT if you want to replace the entire configuration.

Shared tool and MCP attachments need the complete agent document. Download it with `GET /v1/agents/{agent_id}/config`, edit `tool_refs` or `mcp_refs`, then send it with PUT. PATCH does not update attachments.

```javascript JavaScript theme={null}
const resp = await fetch(
  `https://api.agents.slng.ai/v1/agents/${agent.id}`,
  {
    method: "PATCH",
    headers: {
      Authorization: "Bearer SLNG_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      greeting: "Hello {{patient_name}}, thanks for picking up.",
      models: {
        stt: "slng/deepgram/nova:3-en",
        llm: "groq/openai/gpt-oss-120b",
        tts: "slng/deepgram/aura:2-en",
        tts_voice: "aura-2-thalia-en",
        llm_kwargs: { temperature: 0.3 },
      },
    }),
  },
);

const updated = await resp.json();
```

```python Python theme={null}
resp = requests.patch(
    f"https://api.agents.slng.ai/v1/agents/{agent['id']}",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
    json={
        "greeting": "Hello {{patient_name}}, thanks for picking up.",
        "models": {
            "stt": "slng/deepgram/nova:3-en",
            "llm": "groq/openai/gpt-oss-120b",
            "tts": "slng/deepgram/aura:2-en",
            "tts_voice": "aura-2-thalia-en",
            "llm_kwargs": {"temperature": 0.3},
        },
    },
)

updated = resp.json()
```

```bash cURL theme={null}
curl -X PATCH https://api.agents.slng.ai/v1/agents/AGENT_ID \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "greeting": "Hello {{patient_name}}, thanks for picking up.",
    "models": {
      "stt": "slng/deepgram/nova:3-en",
      "llm": "groq/openai/gpt-oss-120b",
      "tts": "slng/deepgram/aura:2-en",
      "tts_voice": "aura-2-thalia-en",
      "llm_kwargs": { "temperature": 0.3 }
    }
  }'
```

## Duplicate an agent

Use duplication when you want to copy an existing agent configuration as-is, including prompts, models, tools, template defaults, and selected region.

The request contract:

* `name` is required. The Dashboard pre-fills `<Name> Copy`, but the API expects an explicit name.
* The inbound connection is never inherited. Pass `target_sip_inbound_trunk_id` to attach one to the copy — this is only accepted when the source agent has inbound telephony, and the trunk must differ from the source agent's inbound trunk.
* The outbound connection is inherited within your organisation unless you override it with `target_sip_outbound_trunk_id` (only accepted when the source agent has outbound telephony).

The duplicate does not copy call history.

After duplicating an agent:

* Reconnect inbound routing if the duplicate should receive calls.
* Verify the outbound trunk before dispatching calls.
* Test the duplicate with a web session or a test call.

```javascript JavaScript theme={null}
const duplicated = await fetch(
  `https://api.agents.slng.ai/v1/agents/${agent.id}/duplicate`,
  {
    method: "POST",
    headers: {
      Authorization: "Bearer SLNG_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: `${agent.name} Copy`,
    }),
  },
).then((r) => r.json());

console.log(duplicated.id);
```

```python Python theme={null}
duplicated = requests.post(
    f"https://api.agents.slng.ai/v1/agents/{agent['id']}/duplicate",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
    json={
        "name": f"{agent['name']} Copy",
    },
).json()

print(duplicated["id"])
```

```bash cURL theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents/AGENT_ID/duplicate \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Appointment Reminder Copy"
  }'
```

## Version history and restore

Every save — create, update, restore, import — appends an immutable version to the agent's history. Versions can't be edited or deleted; the only mutable part is an optional label. Restoring is a two-step preview-then-accept flow, so you can review exactly which fields will change before anything is applied.

| Endpoint | Purpose |
| - | - |
| `GET /v1/agents/{agent_id}/versions` | List versions, newest first (paginated with `page` and `page_size`) |
| `GET /v1/agents/{agent_id}/versions/{n}` | Fetch one version, including its full config document |
| `GET /v1/agents/{agent_id}/versions/{n}/config` | Download the version's config document as a file |
| `POST /v1/agents/{agent_id}/versions/{n}/restore/preview` | Preview a restore: which fields change, plus the hashes needed to accept |
| `POST /v1/agents/{agent_id}/versions/{n}/restore/accept` | Apply a previewed restore |
| `PATCH /v1/agents/{agent_id}/versions/{n}` | Set or clear the version's label |

### Browse the history

```bash cURL theme={null}
curl "https://api.agents.slng.ai/v1/agents/AGENT_ID/versions?page=1&page_size=20" \
  -H "Authorization: Bearer SLNG_API_KEY"
```

Each item records what changed and where it came from:

```json theme={null}
{
  "items": [
    {
      "id": "8b6d2f1a-0c4e-4d7b-9a52-3f0e6c1d9b7e",
      "voice_agent_id": "550e8400-e29b-41d4-a716-446655440000",
      "version_number": 9,
      "config_schema_version": 2,
      "config_hash": "d1f8…",
      "code_dependency_hash": null,
      "changed_fields": ["system_prompt", "models"],
      "source": "update",
      "restored_from_version": null,
      "actor_type": "client",
      "label": null,
      "created_at": "2026-08-01T09:30:00Z"
    }
  ],
  "meta": { "page": 1, "page_size": 20, "total": 9, "pages": 1 }
}
```

### Preview a restore

```bash cURL theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents/AGENT_ID/versions/4/restore/preview \
  -H "Authorization: Bearer SLNG_API_KEY"
```

The preview compares version 4 against the current configuration and returns the diff plus the hashes that authorize the accept step (`preparation.config` and `candidate` — the full config document that would be applied — are trimmed here for brevity):

```json theme={null}
{
  "state": "ready",
  "restore_kind": "exact",
  "target_version": 4,
  "target_version_id": "1f9c7a3e-6b2d-4e8f-a0c5-7d4b9e2f8a1c",
  "current_version": 9,
  "current_version_id": "8b6d2f1a-0c4e-4d7b-9a52-3f0e6c1d9b7e",
  "current_config_hash": "d1f8…",
  "target_config_hash": "07ac…",
  "candidate_config_hash": "9b1d…",
  "acceptance_hash": "3f2c…",
  "changed_fields": ["system_prompt", "models"],
  "issues": [],
  "preparation": {
    "state": "ready",
    "candidate_hash": "9b1d…",
    "resource_hash": "77aa…",
    "dependency_hash": null
  }
}
```

While the platform is still preparing the restore candidate, the preview returns `202` with `"state": "preparing"` and a `Retry-After` header — retry the preview until `state` is `ready`. The version's name is not restored by default; pass `{"restore_historical_name": true}` in the preview body to include it (and pass the same value again on accept — the acceptance hash binds the name policy).

### Accept the restore

Send back the hashes from the preview:

```bash cURL theme={null}
curl -X POST https://api.agents.slng.ai/v1/agents/AGENT_ID/versions/4/restore/accept \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "acceptance_hash": "3f2c…",
    "candidate_hash": "9b1d…",
    "resource_hash": "77aa…",
    "dependency_hash": null
  }'
```

`acceptance_hash` comes from the top level of the preview; `candidate_hash`, `resource_hash`, and `dependency_hash` come from its `preparation` object. If the agent changed between preview and accept, the accept fails with a conflict — run the preview again. On success the response is the restored agent, and the `X-Agent-Version-Created` header reports whether a new version was appended (`false` means the restore was a no-op because nothing differed).

### Label a version

Labels are the only mutable part of a version. Set one to mark a known-good configuration, or send `null` to clear it:

```bash cURL theme={null}
curl -X PATCH https://api.agents.slng.ai/v1/agents/AGENT_ID/versions/4 \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "label": "prod-baseline" }'
```

## Export and import agent configs

`GET /v1/agents/{agent_id}/config` downloads the agent's canonical config document — a portable JSON file with everything needed to recreate the agent. Secrets are never included. To download a historical snapshot instead, use `GET /v1/agents/{agent_id}/versions/{n}/config` from the section above.

```bash cURL theme={null}
curl https://api.agents.slng.ai/v1/agents/AGENT_ID/config \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -o agent-config.json
```

`POST /v1/agents/import` creates a new agent from such a document — a download followed by an import round-trips exactly. Pass the optional `sip_outbound_trunk_id` query parameter to attach an outbound trunk to the imported agent.

```bash cURL theme={null}
curl -X POST "https://api.agents.slng.ai/v1/agents/import?sip_outbound_trunk_id=TRUNK_ID" \
  -H "Authorization: Bearer SLNG_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @agent-config.json
```

## List and inspect agents

```javascript JavaScript theme={null}
// List all agents
const agents = await fetch("https://api.agents.slng.ai/v1/agents", {
  headers: { Authorization: "Bearer SLNG_API_KEY" },
}).then((r) => r.json());

for (const a of agents) {
  console.log(`${a.name} (${a.id})`);
}

// Get a single agent and check its template variables
const agent = await fetch(`https://api.agents.slng.ai/v1/agents/${agents[0].id}`, {
  headers: { Authorization: "Bearer SLNG_API_KEY" },
}).then((r) => r.json());

console.log(agent.template_variables);
// { clinic_name: { required: true, default: "Downtown Health Clinic" }, ... }
```

```python Python theme={null}
# List all agents
agents = requests.get(
    "https://api.agents.slng.ai/v1/agents",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
).json()

for a in agents:
    print(f"{a['name']} ({a['id']})")

# Get a single agent and check its template variables
agent = requests.get(
    f"https://api.agents.slng.ai/v1/agents/{agents[0]['id']}",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
).json()

print(agent["template_variables"])
# {"clinic_name": {"required": true, "default": "Downtown Health Clinic"}, ...}
```

## Delete an agent

Returns `204 No Content` on success.

```javascript JavaScript theme={null}
await fetch(`https://api.agents.slng.ai/v1/agents/${agent.id}`, {
  method: "DELETE",
  headers: { Authorization: "Bearer SLNG_API_KEY" },
});
```

```python Python theme={null}
requests.delete(
    f"https://api.agents.slng.ai/v1/agents/{agent['id']}",
    headers={"Authorization": "Bearer SLNG_API_KEY"},
)
```

```bash cURL theme={null}
curl -X DELETE https://api.agents.slng.ai/v1/agents/AGENT_ID \
  -H "Authorization: Bearer SLNG_API_KEY"
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.