# Agent

> Configure Astra, the workspace's AI phone agent: voice, greeting, jobs, business hours, routing — then publish it live.

Source: https://dev.ody.co/api/agent

Each workspace has one **AI agent** (shown as *Astra* in the app). It answers calls on the numbers routed to it and places [outbound AI calls](https://dev.ody.co/api/calls#place-an-ai-call). Changes are saved as a **draft** and only reach live calls after you **publish**.

## The agent object

- `id` *uuid*
- `name` *string* — What the agent calls itself on the phone.
- `greeting` *string | null* — The first sentence on every answered call.
- `tone` *string | null* — Free-text style guidance, for example `warm and concise`.
- `voice` *string | null* — `astra` (default), `luna`, `andromeda`, `celeste`, `albion`, `atrium`, `bond` or `orion`.
- `language` *string | null* — For example `en-US`.
- `instructions` *string | null* — Compiled instructions (read-only, built from the config and your knowledge).
- `status` *"draft" | "published"*
- `enabled` *boolean* — Master switch. When `false`, routed calls fall back to the team.
- `timezone` *string* — IANA timezone used for business hours.
- `businessHours` *object* — `{ mode: "always" }` or `{ mode: "scheduled", weekly: { mon: [{ start: "09:00", end: "17:00" }], … } }`. Days are `sun`–`sat`; times are 24-hour and `end` is exclusive.
- `inHoursAction` / `offHoursAction` *string* — Who answers during and outside business hours: `agent`, `voicemail`, `app` (ring the team) or `forward`.
- `jobs` *array of {name, instructions}* — The tasks the agent handles (for example "Book appointments", "Answer pricing questions").

**`GET /v1/api/agent`**

### Retrieve the agent

Returns the agent (`null` until one is created) and this cycle's AI credit usage.

**Scope:** `agent:manage`

**Returns** `{ agent, credits: { cycleId, used, included, remaining } | null }`.

cURL:

```bash
curl https://api.ody.co/v1/api/agent \
  -H "Authorization: Bearer $ODY_API_KEY"
```
TypeScript:

```ts
const { agent, credits } = await ody.agent.get();
```
Python:

```python
res = client.agent.get()
```

Response:

```json
{
  "agent": {
    "id": "0d9c…",
    "name": "Astra",
    "greeting": "Thanks for calling Acme Plumbing, this is Astra. How can I help?",
    "voice": "astra",
    "status": "published",
    "enabled": true,
    "timezone": "America/Chicago",
    "businessHours": { "mode": "scheduled", "weekly": { "mon": [{ "start": "08:00", "end": "18:00" }] } },
    "inHoursAction": "agent",
    "offHoursAction": "agent",
    "jobs": [{ "name": "Book appointments", "instructions": "Offer the next two open slots." }]
  },
  "credits": { "cycleId": "2026-10", "used": 1200, "included": 3000, "remaining": 1800 }
}
```

**`PATCH /v1/api/agent`**

### Update the agent

Creates the agent if there isn't one yet, otherwise updates the draft. Only the fields you send change. `jobs` is **replaced wholesale**. Send at least one field.

Changes don't reach live calls until you [publish](#publish-the-agent).

**Scope:** `agent:manage`

**Body:** any of `name`, `greeting`, `tone`, `voice`, `language`, `timezone`, `businessHours`, `inHoursAction`, `offHoursAction`, `enabled`, `jobs`. See the agent object above.

**Returns** `{ agent }`.

cURL:

```bash
curl -X PATCH https://api.ody.co/v1/api/agent \
  -H "Authorization: Bearer $ODY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "greeting": "Thanks for calling Acme Plumbing, this is Astra. How can I help?",
    "voice": "luna",
    "timezone": "America/Chicago",
    "offHoursAction": "agent",
    "jobs": [
      { "name": "Book appointments", "instructions": "Offer the next two open slots." },
      { "name": "Emergencies", "instructions": "For burst pipes, take the address and say a plumber will call back within 15 minutes." }
    ]
  }'
```
TypeScript:

```ts
await ody.agent.update({
  greeting: "Thanks for calling Acme Plumbing, this is Astra. How can I help?",
  voice: "luna",
  timezone: "America/Chicago",
  offHoursAction: "agent",
  jobs: [{ name: "Book appointments", instructions: "Offer the next two open slots." }],
});
```
Python:

```python
client.agent.update(
    greeting="Thanks for calling Acme Plumbing, this is Astra. How can I help?",
    voice="luna",
    timezone="America/Chicago",
    off_hours_action="agent",
    jobs=[{"name": "Book appointments", "instructions": "Offer the next two open slots."}],
)
```

**`POST /v1/api/agent/publish`**

### Publish the agent

Pushes the saved configuration live to the telephony layer. New calls use it within seconds. With a **test key**, publishing is simulated.

**Scope:** `agent:manage`

**Returns** `{ agent, simulated? }`. Returns `409` when the configuration is incomplete; the message says what's missing.

cURL:

```bash
curl -X POST https://api.ody.co/v1/api/agent/publish \
  -H "Authorization: Bearer $ODY_API_KEY"
```
TypeScript:

```ts
await ody.agent.publish();
```
Python:

```python
client.agent.publish()
```

> **Where the agent's knowledge comes from:**
What the agent *knows* (your services, prices, FAQs) comes from the workspace's knowledge sources: website pages and notes added under **Astra → Knowledge** in the app. Those aren't editable through the API yet.
