# Moving from v1

v1 (`/v1/external`) still works. Every v1 response carries a `Deprecation` header with the deprecation date (2 November 2026) and a `Link` to this page. No shutdown date has been set. When one is, v1 responses add a `Sunset` header.

New integrations should use v2. Existing ones can move one flow at a time, because a v1 credential and a v2 key are both organization keys.

## What changed

| | v1 | v2 |
| --- | --- | --- |
| Prefix | `/v1/external/...` | `/v2/...` |
| Agent in the path | `:agentId` or `:slug` | Always `agt_...`. A slug is only a filter |
| Conversation | `conversationId`, a deal id or `id` | One object, a case: `cse_...` |
| Lists | `{ data, limit, offset, hasMore }` | `{ object: "list", data, hasMore, nextCursor }` with `limit` and `cursor` |
| Errors | Mixed shapes | RFC 9457 `application/problem+json` with a stable `code` and `requestId` |
| Webhook signature | `X-Lelemon-Timestamp` and `X-Lelemon-Signature` | `Lelemon-Signature: t=...,v1=...` |
| Webhook setup | Configured by Lelemon | `POST /v2/webhook-endpoints` |
| Events | Six v1 events | A [catalog](/webhooks/events) |
| Idempotency | Not supported | `Idempotency-Key` on every `POST` |

## Route map

| v1 | v2 |
| --- | --- |
| `GET /agents`, `GET /agents/{agentId}` | `GET /v2/agents`, `GET /v2/agents/{id}` |
| `POST /agent-templates/{templateId}/instantiate` | `POST /v2/agents` with `fromTemplate` |
| `PATCH /agents/{agentId}` | `PATCH /v2/agents/{id}`. Send `expectedVersion` to avoid overwriting a newer version |
| `POST /agents/{agentId}/activate`, `/pause` | `POST /v2/agents/{id}/activate`, `/pause` |
| `GET /agents/{agentId}/prompt-versions`, `.../restore` | `GET /v2/agents/{id}/versions`, `.../{versionId}/restore` |
| `POST /actions`, `GET /actions`, `DELETE /actions/{slug}` | `POST /v2/actions`, `GET /v2/actions`, `DELETE /v2/actions/{id}`. The `variables` of an action have the same place in v2, with `source`, `variable` and `field` and English names for the variables (`conversacion.id` is `case.id`) |
| `GET /actions/authorization` | `GET /v2/actions/authorization` |
| `PUT /agents/{agentId}/actions/{slug}` | `PUT /v2/agents/{id}/tools/{toolId}` |
| `POST /agents/{slug}/skills` and the rest | `/v2/agents/{id}/skills` |
| `POST /knowledge/collections`, `PUT /knowledge/documents` | `/v2/knowledge-collections` and `/v2/knowledge-collections/{id}/documents` |
| `PUT /agents/{agentId}/knowledge/{collectionId}` | `PUT /v2/agents/{id}/knowledge-collections/{collectionId}` |
| `POST /agents/{slug}/conversations` | `POST /v2/cases` |
| `POST /conversations/{id}/messages` | `POST /v2/cases/{id}/messages` with `author: "contact"` |
| `POST /conversations/{id}/send` | `POST /v2/cases/{id}/messages` with `author: "team"` |
| `POST /conversations/{id}/notas` | `POST /v2/cases/{id}/messages` with `visibility: "internal"`, or `POST /v2/cases/{id}/notes` |
| `POST /conversations/{id}/derivar` | `POST /v2/cases/{id}/move` with `pipelineId` or `stageId`. To hand the case to a person, `POST /v2/cases/{id}/escalate` |
| `PUT /conversations/{id}/campos` | `PATCH /v2/cases/{id}` with `fields` |
| `GET /conversations/{id}/historial` | `GET /v2/cases?contactId=...` |
| `GET /conversations/{id}/adjuntos` | `/v2/cases/{id}/attachments` |
| `POST /conversations/{id}/resolve` | `POST /v2/cases/{id}/close` |
| `GET /pipelines`, `GET /pipelines/{id}` | `/v2/pipelines`, with `/stages`, `/fields` and `/routing-rules` as resources |
| `PUT /pipelines/{id}/fields/options` | `PATCH /v2/pipelines/{id}/fields/{fieldId}` |
| `PATCH /pipelines/{id}` with `settings` | `settings` on `PATCH /v2/pipelines/{id}`: `autoClose`, `businessHours`, `waitThresholds`, `askFor`, `timezone`, `stageOnTakeControl` and `stageOnHandoff`. The names are in English and each block replaces the whole block |
| `PATCH /pipelines/{id}/stages/{stageId}` with `isTerminal`, `closingOutcome`, `statusType`, `defaultNextStageId`, `transitions` or `config` | The same route in v2 with `closes`, `closingOutcome`, `statusType`, `nextStageId`, `transitions` and `config` (`agentMode`, `followUp`, durations and `delayMinutes`) |
| `PUT`/`DELETE /pipelines/{id}/stages/{stageId}/source/whatsapp` | `whatsappPhoneNumberId` on `PATCH /v2/pipelines/{id}/stages/{stageId}`; `null` releases the number |
| `GET`/`PUT /pipelines/{id}/respuestas-rapidas` | `quickReplies` on `PATCH /v2/pipelines/{id}`, which replaces the whole list |
| `GET /metrics/conversations` | `GET /v2/case-metrics`, paginated with `cursor`. `aiSeconds` is `agentSeconds`, `resolvedByAi` is `resolvedByAgent` and `closedBy: "ai"` is `"agent"` |
| `POST /events` | `POST /v2/contact-events` |
| `GET /scheduling/agendas` | `GET /v2/scheduling/agendas`. A slug becomes the `agd_…` id |
| `GET /scheduling/availability?agenda=slug` | `GET /v2/scheduling/availability?agendaId=agd_…`. Slots are `{ start, end }` |
| `POST /scheduling/meetings` | `POST /v2/scheduling/meetings` with `agendaId` and `start`. Also `GET`, `/cancel` and `/reschedule`, and the events `meeting.scheduled`, `meeting.rescheduled` and `meeting.canceled` |
| `GET /miembros/disponibilidad?email=` | `GET /v2/members/{id}/availability`. Find the `mbr_` id in `GET /v2/members`. Needs `members:read` |
| `PUT /miembros/disponibilidad` | `PUT /v2/members/{id}/availability` with `status` `available` or `away`. Needs `members:write` |
| `POST /triggers`, `GET /triggers`, `PATCH /triggers/{id}` | `/v2/triggers` |
| `POST /agents/{slug}/runs` | `POST /v2/agents/{id}/runs`, with `actor` instead of the signed `pedidoPor` and `limits` instead of `topes` |
| `GET /runs/{id}` | `GET /v2/runs/{id}`, and `GET /v2/runs` to list |
| `POST /runs/{id}/cancel` | `POST /v2/runs/{id}/cancel` |
| `POST /runs/{id}/answer` | `POST /v2/runs/{id}/answer` with `answer` and an optional `actor` instead of the signed `respondidoPor` |

Check the [API reference](/api/v2) for the exact body of each v2 route.

## Move in this order

1. Create a key and rebuild your flow, using `?dryRun=true` where a route accepts it.
2. Replace your webhook receiver: [verify the new signature](/webhooks/verify) and handle events by their new types.
3. Switch reads, then writes. Keep sending `Idempotency-Key` from the first write.
4. Create a live key and cut over one flow at a time.

The v1 documentation is still available under [v1 (legacy)](/legacy/v1).
