> For the complete documentation index, see [llms.txt](https://docs.concurrence.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.concurrence.com/developer-guide/platform-api/platform-sdk/quickstart.md).

# Quickstart

Common Platform SDK operations: agents, services, simulations, analytics, streaming, and entities.

This guide walks through common Platform SDK operations: listing agents, inspecting services, running voice simulations, pulling analytics, streaming conversation turns, opening a text-session WebSocket, and looking up entities.

For a complete runnable project with explicit setup, result verification, failure handling, and cleanup, start with [First Verified Conversation](/developer-guide/guides/first-verified-conversation.md). The examples below are an operation catalog.

## Prerequisites

{% hint style="info" %}
**Before You Begin**

1. [**Installed the SDK**](/developer-guide/platform-api/platform-sdk/installation.md) in your project.
2. [**Configured your credentials**](/developer-guide/platform-api/platform-sdk/configuration.md) with a valid API key and workspace ID.
   {% endhint %}

## Initialize the Client

```typescript
import 'dotenv/config'
import { AmigoClient } from '@amigo-ai/platform-sdk'

const client = new AmigoClient({
  apiKey: process.env.AMIGO_API_KEY!,
  workspaceId: process.env.AMIGO_WORKSPACE_ID!,
})
```

## Example 1: List Agents

Fetch the first page of agents in your workspace:

```typescript
const { items: agents } = await client.agents.list()

for (const agent of agents) {
  console.log(`Agent: ${agent.name} (ID: ${agent.id})`)
  console.log(`  Latest version: ${agent.latest_version ?? 'none'}`)
  console.log(`  Updated: ${agent.updated_at}`)
}
```

List responses are paginated: they carry `items`, `has_more`, and a `continuation_token`. Use `client.agents.listAutoPaging()` to iterate across pages automatically.

Retrieve a specific agent's version to see its full configuration:

```typescript
if (agents.length > 0) {
  const version = await client.agents.getVersion(agents[0].id, 'latest')
  console.log(`Identity: ${version.identity.name} (${version.identity.role})`)
  console.log(`Background: ${version.background}`)
}
```

## Example 2: Inspect a Service

Choose a configured test service explicitly. Later examples use this service for simulations and conversations, so inspect its data and integration permissions before continuing:

```typescript
const serviceId = process.env.AMIGO_SERVICE_ID
if (!serviceId) throw new Error('Set AMIGO_SERVICE_ID to your configured test service')
const service = await client.services.get(serviceId)

console.log(`Service: ${service.name}`)
console.log(`Channel: ${service.channel_type}`)
console.log(`Environment: ${service.environment}`)

// Check version sets
for (const [name, versionSet] of Object.entries(service.version_sets)) {
  console.log(`  Version set "${name}": agent v${versionSet.agent_version_number ?? 'unpinned'}`)
}
```

## Example 3: Run a Voice Simulation

Simulate a caller conversation to test your service behavior without making a real call:

```typescript
// Step 1: Start a simulation session
const { session_id, greeting } = await client.simulations.createSession({
  service_id: service.id,
  branch_name: 'release',
})

console.log(`Session started: ${session_id}`)
console.log(`Agent greeting: ${greeting}`)

// Step 2: Send a caller message and observe the agent response
const { observation, snapshot } = await client.simulations.step({
  session_id,
  caller_text: "Hi, I'd like to schedule an appointment",
})

console.log(`Agent response: ${observation.agent_text}`)
console.log(`Conversation state: ${snapshot.current_state.name}`)
console.log(`Is terminal: ${observation.is_terminal}`)

// Step 3: Continue the conversation
const { observation: obs2 } = await client.simulations.step({
  session_id,
  caller_text: 'Tomorrow at 2pm works for me',
})

console.log(`Agent: ${obs2.agent_text}`)

// Step 4: Delete the session when done
await client.simulations.deleteSession(session_id)
console.log('Session complete')
```

## Example 4: Pull Analytics

Check call metrics for the last 7 days:

```typescript
const stats = await client.analytics.getCalls({ days: 7 })

console.log(`Total calls: ${stats.total_calls}`)
console.log(`Avg duration: ${stats.avg_duration_seconds.toFixed(1)}s`)
console.log(`Period: ${stats.period_start} to ${stats.period_end}`)

// Daily breakdown
for (const day of stats.calls_by_date) {
  console.log(`  ${day.date}: ${day.count} calls`)
}
```

`client.analytics.getDashboard({ days: 7 })` returns a composite dashboard object with top KPIs and period-over-period deltas; its shape is not statically typed, so inspect the JSON before wiring it into typed code. Other analytics helpers include `getCallQuality`, `getEmotionTrends`, `getLatency`, `getToolPerformance`, and `getUsage`.

## Example 5: Stream a Text Conversation Turn

Send a turn to a text conversation and render the agent's response token by token. `streamTurn` targets the always-SSE turns endpoint (`POST /turns/stream`) and yields typed events from the `TurnStreamEvent` discriminated union (`token`, `thinking`, `tool_call_started`, `tool_call_completed`, `message`, `done`, `error`).

```typescript
const conversation = await client.conversations.create({ service_id: service.id })

const events = client.conversations.streamTurn(conversation.id, {
  message: "I'd like to schedule a follow-up appointment",
})

for await (const event of events) {
  switch (event.event) {
    case 'token':
      process.stdout.write(event.text)
      break
    case 'tool_call_started':
      console.log(`\n[tool: ${event.tool_name} started]`)
      break
    case 'tool_call_completed':
      console.log(`[tool: ${event.tool_name} ${event.succeeded ? 'ok' : 'failed'}]`)
      break
    case 'message':
      console.log(`\n[final: ${event.text}]`)
      break
    case 'done':
      console.log(`\n[done - ${event.turn_count} turns total]`)
      break
    case 'error':
      console.error(`\n[stream error: ${event.message}]`)
      break
  }
}
```

If you need the raw bytes instead, `client.conversations.createTurnStream()` returns the underlying `ReadableStream<Uint8Array>` of SSE frames. Turns are persisted on the conversation either way; fetch them later with `client.conversations.get(conversation.id)`.

## Example 6: Open a Public Text-Session WebSocket

The following example is for a trusted Node.js client connecting to the workspace-scoped session endpoint. The SDK helper supplies the authentication subprotocol rather than putting the key in the URL. For a browser application, follow [Serve an Agent From a Web App](/developer-guide/platform-api/conversations/serve-agent-from-web-app.md) and its scoped access flow; keep the workspace key in your backend.

{% hint style="warning" %}
The current SDK URL helper exposes a `conversationId` option and assumes tool events are enabled when omitted. The server ignores `conversation_id` and defaults `tool_events` to `false`. Until the helper matches the server contract, construct the URL directly as shown here and use the SDK only for `sessionConnectAuthProtocols`.
{% endhint %}

```typescript
import { sessionConnectAuthProtocols } from '@amigo-ai/platform-sdk'

const query = new URLSearchParams({
  service_id: service.id,
  entity_id: process.env.AMIGO_ENTITY_ID!, // a test entity selected explicitly (see Example 7)
  tool_events: 'true',
})
const workspaceId = process.env.AMIGO_WORKSPACE_ID!
const url = `wss://api.platform.amigo.ai/v1/${workspaceId}/sessions/connect?${query}`

const ws = new WebSocket(url, [...sessionConnectAuthProtocols(process.env.AMIGO_API_KEY!)])
let firstUserMessageSent = false

ws.addEventListener('message', (event) => {
  const frame = JSON.parse(event.data as string)
  switch (frame.event) {
    case 'session.created':
      console.log(`conversation ${frame.data.conversation_id}`)
      break
    case 'token':
      process.stdout.write(frame.data.text)
      break
    case 'message':
      console.log(`\nagent: ${frame.data.text}`)
      break
    case 'tool_call_started':
      console.log(`[tool ${frame.data.tool_name} started]`)
      break
    case 'done':
      // The first done event terminates the automatic opening agent turn.
      if (!firstUserMessageSent) {
        firstUserMessageSent = true
        ws.send(JSON.stringify({ type: 'user_text', text: 'Hello' }))
      }
      break
    case 'error':
      console.error(`${frame.data.code}: ${frame.data.message}`)
      break
  }
})
```

Wait for each turn's `done` or `error` event before sending the next `user_text`. The endpoint reconnects by the workspace, service, and entity combination; a `conversation_id` in the WebSocket URL is ignored. See [Sessions](/developer-guide/platform-api/platform-api/sessions.md) for all query parameters, frame shapes, timeouts, and close codes.

## Example 7: Look Up an Entity

Retrieve a patient or caller entity from the world model:

```typescript
const { entities } = await client.world.listEntities({ limit: 10 })

if (entities.length > 0) {
  const entity = entities[0]
  console.log(`Entity: ${entity.display_name ?? entity.entity_type}`)
  console.log(`Type: ${entity.entity_type}`)
  console.log(`Last seen: ${entity.last_event_at}`)
  console.log(`Event count: ${entity.event_count}`)
}
```

## Full Quickstart Script

Here is a complete runnable script that combines the agent-list, service-inspection, and analytics examples:

```typescript
import 'dotenv/config'
import { AmigoClient } from '@amigo-ai/platform-sdk'

async function main() {
  const client = new AmigoClient({
    apiKey: process.env.AMIGO_API_KEY!,
    workspaceId: process.env.AMIGO_WORKSPACE_ID!,
  })

  // 1. List agents
  const { items: agents } = await client.agents.list()
  console.log(`\n=== Agents (${agents.length}) ===`)
  for (const agent of agents) {
    console.log(`  ${agent.name} (v${agent.latest_version ?? '?'})`)
  }

  // 2. Inspect first service
  const { items: services } = await client.services.list()
  if (services.length > 0) {
    const svc = services[0]
    console.log(`\n=== Service: ${svc.name} ===`)
    console.log(`  Channel: ${svc.channel_type}`)
    console.log(`  Agent: ${svc.agent_name}`)
  }

  // 3. Call analytics
  const stats = await client.analytics.getCalls({ days: 7 })
  console.log('\n=== Analytics (7d) ===')
  console.log(`  Calls: ${stats.total_calls}`)
  console.log(`  Avg duration: ${stats.avg_duration_seconds.toFixed(1)}s`)

  console.log('\nDone!')
}

main().catch((error) => {
  console.error(error)
  process.exitCode = 1
})
```

## Next Steps

* [**Error Handling**](/developer-guide/platform-api/platform-sdk/error-handling.md)**.** Handle errors and edge cases.
* [**Agents**](/developer-guide/platform-api/workspaces/agents.md)**.** Deep dive into agent management.
* [**Simulation Coverage**](/developer-guide/platform-api/safety/simulation-coverage.md)**.** Full simulation coverage reference.
* [**Analytics & Observability**](/developer-guide/platform-api/safety/analytics.md)**.** Call analytics and quality metrics.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.concurrence.com/developer-guide/platform-api/platform-sdk/quickstart.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
