--- title: Migrating from V2 to V3 | API Docs description: Step-by-step guide for upgrading your integration from the Linq V2 API to V3. --- V3 is a full redesign — not a patch release. The core change is a shift from **synchronous** responses to an **asynchronous** model: the API accepts your request immediately and returns a `trace_id`, while webhooks tell you what happened. Along the way, the message structure, authentication header, endpoint paths, and error shape all changed. This guide walks through every breaking change and new capability. ## Why migrate? | You want to… | V2 | V3 | | ---------------------------------------- | ---------- | ------------------------------- | | Know when messages actually fail | ❌ | ✅ `message.failed` webhook | | Know exactly when messages are delivered | ❌ | ✅ `message.delivered` webhook | | Debug issues quickly | ❌ | ✅ `trace_id` everywhere | | Choose message protocols | ❌ | ✅ `preferred_service: iMessage` | | Send confetti/effects | ❌ | ✅ 12 effects | | Use custom emoji reactions | ❌ | ✅ Any emoji | | Send Office docs, ZIP files | ❌ | ✅ 18 document types | | Know when group names/icons change | ❌ | ✅ Group metadata webhooks | | Reply to specific messages | ⚠️ Limited | ✅ Full threading | | Send voice memos | ❌ | ✅ Voice memo API | --- ## Quick migration checklist - [ ] Replace `X-LINQ-INTEGRATION-TOKEN` header with `Authorization: Bearer ` - [ ] Update all base paths from `/api/partner/v2/` to `/api/partner/v3/` - [ ] Convert message body: `text`/`attachments` → `parts` array - [ ] Parse `success` boolean and log the `trace_id` on every response - [ ] Update webhook handlers for the new payload structure; use `event_id` for deduplication - [ ] Switch to the presigned upload flow for attachments - [ ] Register webhook subscriptions programmatically (see [Webhook Subscriptions](/guides/webhooks/subscriptions/index.md)) --- ## Authentication The token value stays the same — only the header name changes. | | V2 | V3 | | ------ | ----------------------------------- | ------------------------------- | | Header | `X-LINQ-INTEGRATION-TOKEN: ` | `Authorization: Bearer ` | Terminal window ``` # V2 curl -H "X-LINQ-INTEGRATION-TOKEN: $LINQ_API_KEY" ... # V3 curl -H "Authorization: Bearer $LINQ_API_KEY" ... ``` See [Authentication](/getting-started/authentication/index.md) for full details. --- ## Sending messages ### Endpoint path The flat `/v2/chat_messages` endpoint is gone. V3 nests messages under the chat resource: | Operation | V2 | V3 | | ------------ | ------------------------ | ---------------------------------- | | Send message | `POST /v2/chat_messages` | `POST /v3/chats/{chatId}/messages` | ### Message structure V2 used top-level `text` and `attachments` fields. V3 uses a unified `parts` array where each part has an explicit `type`. **V2 request body:** ``` { "chat_id": "chat-uuid", "text": "Hello, world!", "attachments": [{ "url": "https://example.com/image.jpg" }] } ``` **V3 request body:** ``` { "message": { "parts": [ { "type": "text", "value": "Hello, world!" }, { "type": "media", "attachment_id": "att-uuid" } ] } } ``` The `chat_id` moves from the body to the URL path. Message content is wrapped in a `message` object. Attachments must be pre-uploaded and referenced by `attachment_id` — see [Attachments](#attachments) below. See [Sending Messages](/guides/messaging/sending-messages/index.md) and the [Send Message](/api/resources/chats/subresources/messages/methods/send/index.md) API reference for the full schema. --- ## Response format V3 success responses return the resource directly — there is no `data` wrapper or `success` field on success. **V2 response:** ``` { "data": { "chat_message": { "id": "msg-uuid", "text": "Hello" } }, "status": 200 } ``` **V3 success response (send message):** ``` { "chat_id": "chat-uuid", "message": { "id": "msg-uuid", "delivery_status": "pending", "service": null, "parts": [...], } } ``` **V3 error response:** ``` { "success": false, "error": { "status": 400, "code": 1005, "message": "invalid chatId format: must be a valid UUID" }, "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736" } ``` Key changes: - `success: false` and `trace_id` appear in **error responses only** — not in the success body - `trace_id` on successful requests is returned in the `X-Trace-ID` **response header**; log it for every request - `service` is `null` on the initial response; it is confirmed via the `message.delivered` webhook for iMessage and RCS — SMS does not produce a delivery receipt --- ## Async processing and trace IDs V2 was synchronous — you waited for a result. V3 is asynchronous: 1. The API accepts your request and returns a `message_id` in the body plus a `trace_id` in the `X-Trace-ID` response header immediately. 2. Processing happens in the background. 3. Webhooks notify you of the outcome: `message.sent` → `message.delivered` or `message.failed`. This means **silent failures are gone**. Any failure will produce a `message.failed` webhook with error details. Always log the `trace_id` — it’s how you correlate an API request with its webhook events and is the first thing support will ask for. See [Webhooks](/guides/webhooks/index.md) and [Debugging](/guides/platform/debugging/index.md) for more. --- ## Error handling V3 uses structured error responses with numeric codes. **V2 error:** ``` { "error": "Invalid chat_id", "status": 400 } ``` **V3 error:** ``` { "success": false, "error": { "status": 400, "code": 1005, "message": "invalid chatId format: must be a valid UUID" }, "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736" } ``` Update your error handling to read `error.code` (numeric) rather than parsing the `error` string. See the [Errors](/error/index.md) guide for the full code reference. --- ## Webhooks V3 webhook payloads have a new structure with versioning and deduplication support. **V2 payload:** ``` { "event": "message.sent", "data": { "chat_message": { "id": "msg-uuid" } } } ``` **V3 payload:** ``` { "api_version": "v3", "event_type": "message.sent", "event_id": "550e8400-e29b-41d4-a716-446655440000", "created_at": "2025-11-23T17:30:00Z", "trace_id": "abc123def456", "data": { "message_id": "msg-uuid", "service": "iMessage" } } ``` Key differences: - `event_type` replaces `event` - `event_id` is a stable UUID per event — use it for deduplication; webhooks are delivered at-least-once with up to 10 retries over \~25 minutes - `trace_id` links the event back to the originating API request - `data` shape changed — update your payload destructuring - Register and manage subscriptions via the API — see [Webhook Subscriptions](/guides/webhooks/subscriptions/index.md) **New events in V3:** | Event | Description | | ------------------------------- | ----------------------------------- | | `message.delivered` | Explicit delivery confirmation | | `message.failed` | Delivery failure with error details | | `chat.group_name_updated` | Group name was changed | | `chat.group_icon_updated` | Group icon was changed | | `chat.group_name_update_failed` | Group name update failed | | `chat.group_icon_update_failed` | Group icon update failed | See the [Webhook Events](/guides/webhooks/events/index.md) guide for the full event reference. --- ## Attachments V2 accepted a direct URL in the message body. V3 uses a two-step presigned upload flow. **Step 1 — Request an upload URL:** Terminal window ``` curl -X POST https://api.linqapp.com/api/partner/v3/attachments \ -H "Authorization: Bearer $LINQ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filename": "document.pdf", "content_type": "application/pdf", "size_bytes": 1024000 }' ``` **Step 2 — Upload to the presigned S3 URL:** Terminal window ``` curl -X PUT "https://uploads.linqapp.com/..." \ -H "Content-Type: application/pdf" \ --data-binary @document.pdf ``` **Step 3 — Reference the `attachment_id` in your message:** ``` { "message": { "parts": [{ "type": "media", "attachment_id": "att-uuid" }] } } ``` V3 also expands supported document types from 2 to 18, including Word, Excel, PowerPoint, Pages, Numbers, Keynote, PDF, TXT, RTF, CSV, HTML, ePub, ZIP, and `.ics` files. See the [Attachments](/guides/messaging/attachments/index.md) guide for the full list and size limits. --- ## Group chats V3 simplifies group creation by combining it with the initial message, and adds explicit participant management endpoints. **V2 creation:** ``` POST /api/partner/v2/chats { "phone_numbers": ["+12025550001", "+12025550002"], "display_name": "My Group" } ``` **V3 creation:** ``` POST /api/partner/v3/chats { "from": "+12025550100", "to": ["+12025550001", "+12025550002"], "message": { "parts": [{ "type": "text", "value": "Welcome to the group!" }] } } ``` **New participant management endpoints:** | Operation | V3 Path | | --------------------- | ---------------------------------------- | | Add participants | `POST /v3/chats/{chatId}/participants` | | Remove participants | `DELETE /v3/chats/{chatId}/participants` | | Leave group chat | `POST /v3/chats/{chatId}/leave` | | Update group metadata | `PUT /v3/chats/{chatId}` | See the [Group Chats](/guides/chats/group-chats/index.md) guide for details. --- ## Not supported yet The following V2 features are not yet available in V3. ### Contacts API V2 included a full contacts management API (`GET/POST/PUT/PATCH/DELETE /v2/contacts`). V3 does not currently have a contacts API. If your integration relies on creating or managing contacts via V2, you will need to continue using V2 for this or handle contact management outside of the Linq API for now. ### Phone number forwarding V2 exposed `PUT /v2/phone_numbers/{id}` to update a number’s forwarding configuration. This is not yet available in V3. --- ## Full endpoint reference **V2 → V3 path changes:** | Operation | V2 | V3 | | --------------------- | ------------------------------------------------ | -------------------------------------------- | | List chats | `GET /v2/chats` | `GET /v3/chats` | | Create chat | `POST /v2/chats` | `POST /v3/chats` | | Get chat | `GET /v2/chats/{id}` | `GET /v3/chats/{chatId}` | | Mark as read | `PUT /v2/chats/{id}/mark_as_read` | `POST /v3/chats/{chatId}/read` | | Share contact card | `POST /v2/chats/{id}/share_contact` | `POST /v3/chats/{chatId}/share_contact_card` | | Start typing | `POST /v2/chats/{id}/start_typing` | `POST /v3/chats/{chatId}/typing` | | Stop typing | `DELETE /v2/chats/{id}/stop_typing` | `DELETE /v3/chats/{chatId}/typing` | | List messages | `GET /v2/chats/{id}/chat_messages` | `GET /v3/chats/{chatId}/messages` | | Send message | `POST /v2/chats/{id}/chat_messages` | `POST /v3/chats/{chatId}/messages` | | Get message | `GET /v2/chats/{id}/chat_messages/{msgId}` | `GET /v3/messages/{messageId}` | | Edit message | `POST /v2/chats/{id}/chat_messages/{msgId}/edit` | `PATCH /v3/messages/{messageId}` | | Delete message | `DELETE /v2/chats/{id}/chat_messages/{msgId}` | `DELETE /v3/messages/{messageId}` | | Add/remove reaction | `POST /v2/chat_messages/{id}/reactions` | `POST /v3/messages/{messageId}/reactions` | | List phone numbers | `GET /v2/phone_numbers` | `GET /v3/phone_numbers` | | Webhook subscriptions | `/v2/webhook_subscriptions` | `/v3/webhook-subscriptions` | | iMessage availability | `POST /v2/i_message_availability/check` | `POST /v3/chats/{chatId}/capability` | **New in V3 (no V2 equivalent):** | Operation | V3 Path | | ----------------------- | ---------------------------------------- | | Update chat metadata | `PUT /v3/chats/{chatId}` | | Add participants | `POST /v3/chats/{chatId}/participants` | | Remove participants | `DELETE /v3/chats/{chatId}/participants` | | Leave group chat | `POST /v3/chats/{chatId}/leave` | | Send voice memo | `POST /v3/chats/{chatId}/voicememo` | | Get thread | `GET /v3/messages/{messageId}/thread` | | Upload attachment | `POST /v3/attachments` | | Get attachment metadata | `GET /v3/attachments/{attachmentId}` | --- ## New V3 features These capabilities have no V2 equivalent. **[Protocol selection](/guides/messaging/protocol-selection/index.md)** — Use `preferred_service` on any message to target a specific channel (`iMessage`, `RCS`, or `SMS`). Useful for iMessage-only features or compliance requirements. **[Message effects](/guides/messaging/message-effects/index.md)** — Attach iMessage screen effects (confetti, fireworks, lasers, sparkles) or bubble effects (slam, loud, gentle, invisible ink) via the `effect` object. **[Text decorations](/guides/messaging/sending-messages#text-decorations/index.md)** — Apply bold, italic, strikethrough, underline, and animated styles to character ranges within a text part. iMessage only. **[Threaded replies](/guides/messaging/sending-messages#replying-to-messages/index.md)** — Reply to a specific message using `reply_to: { message_id, part_index }`. **[Custom reactions](/guides/messaging/reactions/index.md)** — V2 supported the six standard iMessage tapbacks. V3 adds custom emoji reactions on top of those. **[Voice memos](/guides/messaging/voice-memos/index.md)** — Send audio messages as iMessage voice memo bubbles via `POST /v3/chats/{chatId}/voicememo`. **[Participant management](/guides/chats/group-chats/index.md)** — Add and remove participants from existing group chats, and leave a group, via dedicated endpoints. **[Rich link previews](/guides/messaging/rich-link-previews/index.md)** — Send a `link` part to render a rich preview card on iMessage and RCS. **[Presigned attachment uploads](/guides/messaging/attachments/index.md)** — Upload files via a presigned S3 URL and reference them by `attachment_id`. Supports 18 document types vs. 2 in V2.