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

# How do I migrate from API v1?

> What changed between the v1 and v2 Klipy APIs, and how to move an existing integration over.

<Warning>
  v1 (`https://api.klipy.ai/api/v1`) is deprecated in favor of v2. It continues to work today with no functional changes, and there's no fixed shutdown date yet — but new integrations should start on v2, and existing ones should plan to move over.
</Warning>

## What changed

### API keys

v1 keys (`klipy_pk_<id>`) and v2 keys (`klipy_live_<random>`) are **different formats and are not interchangeable** — a v1 key does not authenticate against `/api/v2/*`, and a v2 key does not authenticate against `/api/v1/*`. You'll need to issue new v2 keys; see [Issuing API keys](/docs/api/v2/issuing-api-keys).

Two other differences worth knowing before you migrate:

* **Scopes are required.** v1 keys were issued with full (`ALL`) access. v2 has no `ALL` scope — you choose exactly which `resource:action` scopes a key needs at creation time.
* **Access level is explicit.** v2 keys are either organization-wide or bound to a single user, chosen at creation. v1 had no equivalent concept.

### Resource naming

The v1 `people` resource is called `contacts` in v2 — same underlying object, new name:

| v1             | v2             |
| -------------- | -------------- |
| `people`       | `contacts`     |
| `companies`    | `companies`    |
| `interactions` | `interactions` |

### New in v2

v2 covers the full CRM object model, not just the three resources v1 exposed:

* **New resources:** deals, pipelines, tasks, notes, segments, meetings, recordings, bookings.
* **Relationship sub-resources:** link/unlink contacts and companies on a deal, records on a note, members on a segment, and single deal/company associations on a meeting. See [Introduction](/docs/api/v2/introduction#relationship-sub-resources).
* **Batch-create:** `POST /{resource}/batch` for up to 100 items in one request, on every resource that supports creation.
* **Idempotency:** every `POST`/`PATCH` accepts an `Idempotency-Key` header so retries are safe.

### Recordings API

The `GET /recordings` and `GET /recordings/{id}` endpoints provide access to meeting transcripts, not stored video. The fields differ from earlier approaches:

* **`has_transcript`** — boolean. `true` if a transcript exists for this recording; `false` if transcription is still in progress, or if the meeting produced no audio (e.g., notetaker was removed before any audio captured).
* **`transcript_url`** — string or null. When `has_transcript` is `true`, this is a short-lived (approximately 5 minutes) single-purpose tokenized HTTPS GET link that returns the transcript as JSON. When `has_transcript` is `false`, this field is `null`. Do not hardcode the URL; always fetch it from the response and follow the returned link. Once the link expires (\~5 minutes), requests to that URL return `404`; the link may be fetched multiple times while valid. To retrieve an expired token, call `GET /recordings/{id}` again to obtain a fresh one. The `/transcripts/download` endpoint is rate limited; exceeding limits returns `429` with a `Retry-After` header.
* **`recording_url` and `video_status` are deprecated static fields.** Klipy no longer stores playable meeting video. The Recall.ai provider retains raw media for a limited window; Klipy retains transcripts as structured records for long-term access.

<Warning>
  `recording_url` and `video_status` are deprecated and will be removed in v3. Both fields are retained on v2 for backward compatibility but always return a fixed value: `recording_url` is always `null`, and `video_status` is always `"skipped"` (a pre-existing member of the original enum — no new value is introduced). Do not rely on either field for anything other than the fixed placeholder value; use `has_transcript` and `transcript_url` instead.
</Warning>

Discovery workflow: `GET /recordings?limit=...` to list recordings and check `has_transcript`, then `GET /recordings/{id}` to retrieve `transcript_url` for transcripts that exist.

### What didn't change

* **Field naming.** Both v1 and v2 use `snake_case` JSON field names.
* **Envelope shape.** Both use the same `{ object, data, meta }` pattern for single-resource responses and cursor-based `page_info` for lists.
* **Rate limits.** Both are 200 req/min per key, 1000 req/min per organization.

## Migration checklist

<Steps>
  <Step title="Issue a v2 key">
    Create a new key at **[Settings → API](https://app.klipy.ai/settings/api)** with the scopes your integration needs. See [Issuing API keys](/docs/api/v2/issuing-api-keys).
  </Step>

  <Step title="Update the base URL">
    Change requests from `https://api.klipy.ai/api/v1` to `https://api.klipy.ai/api/v2`.
  </Step>

  <Step title="Rename `people` calls to `contacts`">
    Update any request path or reference from `/people` to `/contacts`. The request/response shape for the equivalent operations is otherwise the same.
  </Step>

  <Step title="Switch the auth header value">
    Swap the v1 key for the new v2 key in your `X-Klipy-Api-Key` or `Authorization: Bearer` header — the header names themselves are unchanged.
  </Step>

  <Step title="Test, then retire the v1 key">
    Once traffic is confirmed on v2, revoke the v1 key from the same settings page.
  </Step>
</Steps>

## Related topics

* [Introduction](/docs/api/v2/introduction) — full v2 concepts: envelope, scopes, batch, idempotency, relationships.
* [Issuing API keys](/docs/api/v2/issuing-api-keys) — the v2 key lifecycle.
