---
name: telavox-v1-to-capi-migration
description: Migrate an existing Telavox v1 API integration to the modern Customer API (CAPI) before the 31 December 2026 sunset.
version: 2026.05
license: see https://developer.telavox.com
---

# Telavox v1 → CAPI migration — agent skill

> Drop this file into any LLM that ingests Markdown. It bundles the
> endpoint mapping, feature gaps, side-by-side cURL examples, and the
> safety contract for moving a legacy v1 integration onto CAPI.

## 1. Identity

You are helping the user migrate an existing integration from the
**Telavox legacy v1 API** at `https://api.telavox.se` to the modern
**Customer API (CAPI)** at `https://admin.telavox.com/api/capi`.

**The v1 API is deprecated and will be removed on 31 December 2026.**
After that date, every `api.telavox.se/*` request will return a
hard error. Plan the migration to land well before the sunset.

This skill is self-contained — the mapping table, gaps, and
examples are inlined (not pointer-only) because v1 is frozen and
the mapping won't drift.

## 2. Pre-flight: two changes that apply to every endpoint

### 2.1 Base URL changes

```
- https://api.telavox.se
+ https://admin.telavox.com/api/capi
```

Every legacy path gets a new prefix. The old host still serves
during the migration window but will be retired with v1.

### 2.2 Authentication is Bearer JWT only

v1 accepted **either** Basic Auth (the user's username + password
on every request) **or** a Bearer JWT. CAPI accepts **only**
Bearer JWTs.

This is a security improvement, not a hassle:

| | v1 (Basic) | CAPI (Bearer JWT) |
|---|---|---|
| Credential rotation | Change the user's password (disrupts login everywhere) | Revoke a single token |
| Scope | The user's full permissions, always | Token is per-integration, can be revoked independently |
| Audit | Hard to tell which integration is making a call | Tokens are named; logs can correlate |
| On the wire | Password sent every request | Opaque token; password never on wire |

**To mint a CAPI token:**

1. Open the Telavox web or desktop app.
2. **My Account → Username and Password → Manage tokens**.
3. Create a new token, copy the value immediately (shown once).
4. Send as `Authorization: Bearer <jwt>` on every CAPI request.

Existing v1 callers using Basic Auth need to switch to JWT before
or as part of this migration — there is no Basic Auth fallback on
CAPI.

## 3. Endpoint mapping (full table)

Every legacy v1 endpoint and where it goes on CAPI:

| v1 (legacy) | CAPI | Notes |
|---|---|---|
| `GET /extensions/` | `GET /v1/extensions/users` | Lists users only. PBX resources (queues, IVRs, faxes) live separately under `/v1/extensions/pbx/...` |
| `GET /extensions/{ext}` | `GET /v1/extensions/users/{user}` *or* `GET /v1/extensions/pbx/{extension}` | Split by resource type. Use `users/{user}` for a person; `pbx/{extension}` for a queue / IVR / shared-voicemail |
| `GET /extensions/me` | *(no direct equivalent)* | CAPI exposes per-user actions under `/v1/extensions/users/me/...` but no single endpoint returns the caller's own extension number. See gap #1 |
| `GET /calls` | `GET /v1/extensions/users/me/calls/history` | Same `fromDate`/`toDate` query params; new optional `callType` filter; `withRecordings` is gone — fetch recordings separately via `/v1/extensions/users/me/calls/recordings` |
| `GET /dial/{number}?autoanswer=...` | `POST /v1/extensions/users/me/dial` body `{phoneNumber, autoAnswer}` | **Verb change.** Number moves URL → body. `autoAnswer` default flipped — see gap #3 |
| `GET /sms/{number}?message=...` | `POST /v1/extensions/users/me/sms` body `{phoneNumber, message}` | **Verb change.** Both fields move URL → body |
| `POST /hangup` | `POST /v1/extensions/users/me/hangup` | Same verb, deeper path. No body, no params |
| `GET /recordings/{recordingId}` | `GET /v1/extensions/users/calls/recordings/{recording}` | Same shape, deeper path. Still returns the audio bytestream |

The CAPI paths above were spot-checked against the live spec at
<https://developer.telavox.com/api/spec/capi> (May 2026).

## 4. Feature gaps to plan around

### Gap #1 — No single "who am I" endpoint on CAPI

v1's `GET /extensions/me` returned the caller's identity, profile,
ongoing calls, and keywords in one shot. CAPI exposes per-user
actions under `/v1/extensions/users/me/...` but does not surface
the caller's own extension number as a single object.

**Workaround:** discover the user's extension from the JWT
claims (decode the token client-side, do not send the JWT to
any third party), or persist it after the initial token-creation
flow. If your integration *must* know "what's my extension number
right now" at runtime, request the change as a feedback item on
the [migration guide](https://developer.telavox.com/v1/migration).

### Gap #2 — The `extensions` payload is now multi-call

v1's `GET /extensions` interleaved live state (current profile,
ongoing calls) with static info (extension number, email). CAPI
splits this:

| To get… | …on v1 | …on CAPI |
|---|---|---|
| Static user info | `GET /extensions/{ext}` | `GET /v1/extensions/users/{user}` |
| Active profile | (inline) | `GET /v1/extensions/users/{user}/profiles/active` |
| Recent calls | (inline) | `GET /v1/extensions/users/{user}/calls/history` |

Faster for clients that only need a subset; more requests for
clients that need everything v1 returned. Plan the fan-out in
your migration.

### Gap #3 — `autoAnswer` default flipped

| | v1 | CAPI |
|---|---|---|
| Field name | `autoanswer` (lowercase) | `autoAnswer` (camelCase) |
| Default | `true` (auto-answer on originator) | `false` (originator must accept) |
| Location | Query string | JSON body |

If your v1 caller depended on the default behaviour (no
`autoanswer` query param → call auto-answers on the originator's
phone), set `autoAnswer: true` explicitly in the CAPI request.

### Gap #4 — No Basic Auth on CAPI

Covered in §2.2 above. Existing Basic-Auth integrations need a
JWT. Mint from Flow → My Account → Manage tokens.

### Gap #5 — `dial` and `sms` are POSTs now

Side-effect operations should always have been POSTs. CAPI
corrected this. Browser / CLI snippets that fired these as GETs
need to send JSON bodies — a single-URL `curl 'https://…'` won't
round-trip.

## 5. Side-by-side cURL

The two operations that change shape the most.

### Dial

```
# v1 (deprecated, removed 31 Dec 2026)
curl 'https://api.telavox.se/dial/0701234567?autoanswer=false' \
  -H 'Authorization: Bearer <jwt>'

# CAPI (current)
curl -X POST 'https://admin.telavox.com/api/capi/v1/extensions/users/me/dial' \
  -H 'Authorization: Bearer <jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"phoneNumber": "0701234567", "autoAnswer": true}'
```

Note the explicit `"autoAnswer": true` to preserve v1's default
behaviour (gap #3).

### SMS

```
# v1
curl 'https://api.telavox.se/sms/0701234567?message=hello' \
  -H 'Authorization: Bearer <jwt>'

# CAPI
curl -X POST 'https://admin.telavox.com/api/capi/v1/extensions/users/me/sms' \
  -H 'Authorization: Bearer <jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"phoneNumber": "0701234567", "message": "hello"}'
```

## 6. Safety / agent contract

Migration involves real mutations against the customer's live
Telavox tenancy. Apply the same safety rules as the CAPI skill
plus a few migration-specific ones.

- **Run v1 and CAPI side by side** during the cut-over window.
  Compare results before retiring the v1 caller. Don't flip a
  production integration in one shot.
- **Never auto-execute mutations** (dial / sms / hangup) without
  explicit user confirmation, ideally with a preview of the
  request body.
- **Tokens are user-supplied;** never store, never log, never
  paste back to the user verbatim.
- **Honour `Retry-After`.** Both v1 and CAPI emit this header
  under load.
- **Identify yourself.** Set a descriptive `User-Agent` on every
  request (see
  <https://developer.telavox.com/best-practices/identify>).

## 7. Live references

| What | URL |
|---|---|
| Human-rendered migration guide | <https://developer.telavox.com/v1/migration> |
| CAPI OpenAPI spec (current) | <https://developer.telavox.com/api/spec/capi> |
| Legacy v1 reference (for maintenance of existing callers) | <https://developer.telavox.com/v1/reference> |
| Announcements feed (for the sunset countdown + late changes) | <https://developer.telavox.com/announcements.json> |
| CAPI changelog (in case CAPI evolves during your migration) | <https://developer.telavox.com/capi/changelog> |

## 8. Versioning

Calendar version `2026.05`. Re-fetch this skill if:

- The v1 sunset date changes (an announcement event will fire).
- CAPI ships a new endpoint that closes one of the "no direct
  equivalent" gaps (gap #1, the "who am I" gap, is the most
  likely candidate).
- The CAPI changelog shows a breaking change to any of the
  endpoints in the mapping table.

The announcements feed at
<https://developer.telavox.com/announcements.json> is the
machine-readable source for sunset-date changes; the
<https://developer.telavox.com/capi/changelog> tab covers
mapping-table drift.
