diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b7a9d22..babe609 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,7 +26,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
- node-version: '22'
+ node-version: '24'
- name: Set up pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
@@ -53,7 +53,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
- node-version: '22'
+ node-version: '24'
- name: Set up pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml
index e5d0eb5..edbb9ff 100644
--- a/.github/workflows/publish-npm.yml
+++ b/.github/workflows/publish-npm.yml
@@ -26,7 +26,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
with:
- node-version: '20'
+ node-version: '24'
- name: Set up pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
diff --git a/.stats.yml b/.stats.yml
index 1fd2991..c7c071b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 41
+configured_endpoints: 45
diff --git a/api.md b/api.md
index 69a44ac..3924645 100644
--- a/api.md
+++ b/api.md
@@ -146,6 +146,20 @@ Methods:
- client.availableNumber.retrieve({ ...params }) -> AvailableNumberRetrieveResponse
+# PaymentRequests
+
+Types:
+
+- PaymentRequest
+- PaymentRequestListResponse
+
+Methods:
+
+- client.paymentRequests.create({ ...params }) -> PaymentRequest
+- client.paymentRequests.retrieve(paymentRequestID) -> PaymentRequest
+- client.paymentRequests.list({ ...params }) -> PaymentRequestListResponse
+- client.paymentRequests.cancel(paymentRequestID) -> PaymentRequest
+
# WebhookEvents
Types:
diff --git a/package.json b/package.json
index b636cac..d181517 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
"standardwebhooks": "^1.0.0"
},
"devDependencies": {
- "@arethetypeswrong/cli": "^0.17.0",
+ "@arethetypeswrong/cli": "^0.18.0",
"@swc/core": "^1.3.102",
"@swc/jest": "^0.2.29",
"@types/jest": "^29.4.0",
diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json
index 836b132..9e94b3d 100644
--- a/packages/mcp-server/package.json
+++ b/packages/mcp-server/package.json
@@ -38,7 +38,6 @@
"@valtown/deno-http-worker": "^0.0.21",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
- "deno": "^2.9.1",
"express": "^5.1.0",
"fuse.js": "^7.1.0",
"minisearch": "^7.2.0",
diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts
index 6d64422..5d357f4 100644
--- a/packages/mcp-server/src/code-tool-worker.ts
+++ b/packages/mcp-server/src/code-tool-worker.ts
@@ -138,6 +138,10 @@ const fuse = new Fuse(
'client.phoneNumbers.list',
'client.phoneNumbers.update',
'client.availableNumber.retrieve',
+ 'client.paymentRequests.cancel',
+ 'client.paymentRequests.create',
+ 'client.paymentRequests.list',
+ 'client.paymentRequests.retrieve',
'client.webhookEvents.list',
'client.webhookSubscriptions.create',
'client.webhookSubscriptions.delete',
diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts
index fd519a9..e3dcb89 100644
--- a/packages/mcp-server/src/code-tool.ts
+++ b/packages/mcp-server/src/code-tool.ts
@@ -136,6 +136,7 @@ const localDenoHandler = async ({
const workerPath = getWorkerPath();
const client = reqContext.client;
+ const baseURLHostname = new URL(client.baseURL).hostname;
const { code } = args as { code: string };
let denoPath: string;
@@ -187,10 +188,7 @@ const localDenoHandler = async ({
runFlags: [
`--node-modules-dir=manual`,
`--allow-read=${allowRead}`,
- // Bare --allow-net: the worker transport is a unix socket in os.tmpdir() whose
- // random path we can't predict, and modern Deno gates that socket under --allow-net.
- // A host-scoped `--allow-net=` excludes it and crashes every run.
- `--allow-net`,
+ `--allow-net=${baseURLHostname}`,
// Allow environment variables because instantiating the client will try to read from them,
// even though they are not set.
'--allow-env',
diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts
index 80f4cb8..235beb6 100644
--- a/packages/mcp-server/src/local-docs-search.ts
+++ b/packages/mcp-server/src/local-docs-search.ts
@@ -69,16 +69,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## create\n\n`client.chats.create(from: string, message: { parts: text_part | media_part | link_part | object[]; effect?: message_effect; idempotency_key?: string; preferred_service?: service_type; reply_to?: reply_to; }, to: string[]): { chat: object; }`\n\n**post** `/v3/chats`\n\nCreate a new chat with specified participants and send an initial message.\nThe initial message is required when creating a chat.\n\n## Message Effects\n\nYou can add iMessage effects to make your messages more expressive. Effects are\noptional and can be either screen effects (full-screen animations) or bubble effects\n(message bubble animations).\n\n**Screen Effects:** `confetti`, `fireworks`, `lasers`, `sparkles`, `celebration`,\n`hearts`, `love`, `balloons`, `happy_birthday`, `echo`, `spotlight`\n\n**Bubble Effects:** `slam`, `loud`, `gentle`, `invisible`\n\nOnly one effect type can be applied per message.\n\n## Inline Text Decorations (iMessage only)\n\nUse the `text_decorations` array on a text part to apply styling and animations to character ranges.\n\nEach decoration specifies a `range: [start, end)` and exactly one of `style` or `animation`.\n\n**Styles:** `bold`, `italic`, `strikethrough`, `underline`\n**Animations:** `big`, `small`, `shake`, `nod`, `explode`, `ripple`, `bloom`, `jitter`\n\n```json\n{\n \"type\": \"text\",\n \"value\": \"Hello world\",\n \"text_decorations\": [\n { \"range\": [0, 5], \"style\": \"bold\" },\n { \"range\": [6, 11], \"animation\": \"shake\" }\n ]\n}\n```\n\n**Note:** Style ranges (bold, italic, etc.) may overlap, but animation ranges must not overlap with other animations or styles. Text decorations only render for iMessage recipients.\nFor SMS/RCS, text decorations are not applied.\n\n## First-Message Link Restriction\n\nTo protect sender deliverability, the **first outbound message** of a new chat cannot be a link.\nThe request is rejected with `400` (error code `1005`) when:\n\n- The message contains a `link` part (explicit rich-preview link), or\n- Any `text` part contains a URL.\n\nThis rule applies only to `POST /v3/chats`. Follow-up messages on an existing chat\n(`POST /v3/chats/{chatId}/messages`) are not subject to this restriction.\n\n\n### Parameters\n\n- `from: string`\n Sender phone number in E.164 format. Must be a phone number that the\nauthenticated partner has permission to send from.\n\n\n- `message: { parts: { type: 'text'; value: string; text_decorations?: text_decoration[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]; effect?: { name?: string; type?: 'screen' | 'bubble'; }; idempotency_key?: string; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; }`\n Message content container. Groups all message-related fields together,\nseparating the \"what\" (message content) from the \"where\" (routing fields like from/to).\n\n - `parts: { type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]`\n Array of message parts. Each part can be text, media, or link.\nParts are displayed in order. Text and media can be mixed freely,\nbut a `link` part must be the only part in the message.\n\n**Rich Link Previews:**\n- Use a `link` part to send a URL with a rich preview card\n- A `link` part must be the **only** part in the message\n- To send a URL as plain text (no preview), use a `text` part instead\n\n**Supported Media:**\n- Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp\n- Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp\n- Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr\n- Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm\n- Contact & Calendar: .vcf, .ics\n\n**Audio:**\n- Audio files (.m4a, .mp3, .aac, .caf, .wav, .aiff, .amr) are fully supported as media parts\n- To send audio as an **iMessage voice memo bubble** (inline playback UI), use the dedicated\n `/v3/chats/{chatId}/voicememo` endpoint instead\n\n**Validation Rules:**\n- A `link` part must be the **only** part in the message. It cannot be combined\n with text or media parts.\n- Consecutive text parts are not allowed. Text parts must be separated by\n media parts. For example, [text, text] is invalid, but [text, media, text] is valid.\n- Maximum of **100 parts** total.\n- Media parts using a public `url` (downloaded by the server on send) are\n capped at **40**. Parts using `attachment_id` or presigned URLs\n are exempt from this sub-limit. For bulk media sends exceeding 40 files,\n pre-upload via `POST /v3/attachments` and reference by `attachment_id` or `download_url`.\n\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n iMessage effect to apply to this message (screen or bubble effect)\n - `idempotency_key?: string`\n Optional idempotency key for this message.\nUse this to prevent duplicate sends of the same message.\n\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n Messaging service type\n - `reply_to?: { message_id: string; part_index?: number; }`\n Reply to another message to create a threaded conversation\n\n- `to: string[]`\n Array of recipient handles (phone numbers in E.164 format or email addresses).\nFor individual chats, provide one recipient. For group chats, provide multiple.\n\n\n### Returns\n\n- `{ chat: { id: string; display_name: string; handles: object[]; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }; is_group: boolean; message: object; service: 'iMessage' | 'SMS' | 'RCS'; }; }`\n Response for creating a new chat with an initial message\n\n - `chat: { id: string; display_name: string; handles: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }; is_group: boolean; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: object | object | object | { app: object; layout: object; reactions: reaction[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; sent_at: string; delivered_at?: string; effect?: object; from_handle?: object; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: object; service?: 'iMessage' | 'SMS' | 'RCS'; }; service: 'iMessage' | 'SMS' | 'RCS'; }`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst chat = await client.chats.create({\n from: '+12052535597',\n message: { parts: [{ type: 'text', value: 'Hello! How can I help you today?' }] },\n to: ['+12052532136'],\n});\n\nconsole.log(chat);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.New',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.Chat)\n}\n',
- },
python: {
method: 'chats.create',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nchat = client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(chat.chat)',
},
+ go: {
+ method: 'client.Chats.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.Chat)\n}\n',
+ },
typescript: {
method: 'client.chats.create',
example:
@@ -105,16 +105,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list_chats\n\n`client.chats.listChats(cursor?: string, from?: string, limit?: number, to?: string): { id: string; created_at: string; display_name: string; handles: chat_handle[]; health_status: object; is_archived: boolean; is_group: boolean; updated_at: string; group_chat_icon?: string; service?: service_type; }`\n\n**get** `/v3/chats`\n\nRetrieves a paginated list of chats for the authenticated partner.\n\n**Filtering:**\n- If `from` is provided, returns chats for that specific phone number\n- If `from` is omitted, returns chats across all phone numbers owned by the partner\n- If `to` is provided, only returns chats where the specified handle is a participant\n\n**Pagination:**\n- Use `limit` to control page size (default: 20, max: 100)\n- The response includes `next_cursor` for fetching the next page\n- When `next_cursor` is `null`, there are no more results to fetch\n- Pass the `next_cursor` value as the `cursor` parameter for the next request\n\n**Example pagination flow:**\n1. First request: `GET /v3/chats?from=%2B12223334444&limit=20`\n2. Response includes `next_cursor: \"20\"` (more results exist)\n3. Next request: `GET /v3/chats?from=%2B12223334444&limit=20&cursor=20`\n4. Response includes `next_cursor: null` (no more results)\n\n\n### Parameters\n\n- `cursor?: string`\n Pagination cursor from the previous response's `next_cursor` field.\nOmit this parameter for the first page of results.\n\n\n- `from?: string`\n Phone number to filter chats by. Returns chats made from this phone number.\nMust be in E.164 format (e.g., `+13343284472`). The `+` is automatically URL-encoded by HTTP clients.\nIf omitted, returns chats across all phone numbers owned by the partner.\n\n\n- `limit?: number`\n Maximum number of chats to return per page\n\n- `to?: string`\n Filter chats by a participant handle. Only returns chats where this handle is a participant.\nCan be an E.164 phone number (e.g., `+13343284472`) or an email address (e.g., `user@example.com`).\nFor phone numbers, the `+` is automatically URL-encoded by HTTP clients.\n\n\n### Returns\n\n- `{ id: string; created_at: string; display_name: string; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }; is_archived: boolean; is_group: boolean; updated_at: string; group_chat_icon?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `created_at: string`\n - `display_name: string`\n - `handles: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]`\n - `health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }`\n - `is_archived: boolean`\n - `is_group: boolean`\n - `updated_at: string`\n - `group_chat_icon?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\n// Automatically fetches more pages as needed.\nfor await (const chat of client.chats.listChats()) {\n console.log(chat);\n}\n```",
perLanguage: {
- go: {
- method: 'client.Chats.ListChats',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Chats.ListChats(context.TODO(), linqgo.ChatListChatsParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
- },
python: {
method: 'chats.list_chats',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npage = client.chats.list_chats()\npage = page.chats[0]\nprint(page.id)',
},
+ go: {
+ method: 'client.Chats.ListChats',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Chats.ListChats(context.TODO(), linqgo.ChatListChatsParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
+ },
typescript: {
method: 'client.chats.listChats',
example:
@@ -140,16 +140,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## retrieve\n\n`client.chats.retrieve(chatId: string): { id: string; created_at: string; display_name: string; handles: chat_handle[]; health_status: object; is_archived: boolean; is_group: boolean; updated_at: string; group_chat_icon?: string; service?: service_type; }`\n\n**get** `/v3/chats/{chatId}`\n\nRetrieve a chat by its unique identifier.\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ id: string; created_at: string; display_name: string; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }; is_archived: boolean; is_group: boolean; updated_at: string; group_chat_icon?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `created_at: string`\n - `display_name: string`\n - `handles: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]`\n - `health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL' | 'OPTED_OUT'; updated_at: string; }`\n - `is_archived: boolean`\n - `is_group: boolean`\n - `updated_at: string`\n - `group_chat_icon?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst chat = await client.chats.retrieve('550e8400-e29b-41d4-a716-446655440000');\n\nconsole.log(chat);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.Get(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.ID)\n}\n',
- },
python: {
method: 'chats.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nchat = client.chats.retrieve(\n "550e8400-e29b-41d4-a716-446655440000",\n)\nprint(chat.id)',
},
+ go: {
+ method: 'client.Chats.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.Get(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.ID)\n}\n',
+ },
typescript: {
method: 'client.chats.retrieve',
example:
@@ -175,16 +175,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update\n\n`client.chats.update(chatId: string, display_name?: string, group_chat_icon?: string): { chat_id?: string; status?: string; }`\n\n**put** `/v3/chats/{chatId}`\n\nUpdate chat properties such as display name and group chat icon.\n\nListen for `chat.group_name_updated`, `chat.group_icon_updated`,\n`chat.group_name_update_failed`, or `chat.group_icon_update_failed`\nwebhook events to confirm the outcome.\n\n\n### Parameters\n\n- `chatId: string`\n\n- `display_name?: string`\n New display name for the chat (group chats only)\n\n- `group_chat_icon?: string`\n URL of an image to set as the group chat icon (group chats only)\n\n### Returns\n\n- `{ chat_id?: string; status?: string; }`\n\n - `chat_id?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst chat = await client.chats.update('550e8400-e29b-41d4-a716-446655440000');\n\nconsole.log(chat);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Update',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.Update(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatUpdateParams{\n\t\t\tDisplayName: linqgo.String("Team Discussion"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.ChatID)\n}\n',
- },
python: {
method: 'chats.update',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nchat = client.chats.update(\n chat_id="550e8400-e29b-41d4-a716-446655440000",\n display_name="Team Discussion",\n)\nprint(chat.chat_id)',
},
+ go: {
+ method: 'client.Chats.Update',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchat, err := client.Chats.Update(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatUpdateParams{\n\t\t\tDisplayName: linqgo.String("Team Discussion"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.ChatID)\n}\n',
+ },
typescript: {
method: 'client.chats.update',
example:
@@ -208,16 +208,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## mark_as_read\n\n`client.chats.markAsRead(chatId: string): void`\n\n**post** `/v3/chats/{chatId}/read`\n\nMark all messages in a chat as read.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.markAsRead('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e')\n```",
perLanguage: {
- go: {
- method: 'client.Chats.MarkAsRead',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.MarkAsRead(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'chats.mark_as_read',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.chats.mark_as_read(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)',
},
+ go: {
+ method: 'client.Chats.MarkAsRead',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.MarkAsRead(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.chats.markAsRead',
example:
@@ -243,16 +243,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## leave_chat\n\n`client.chats.leaveChat(chatId: string): { message?: string; status?: string; trace_id?: string; }`\n\n**post** `/v3/chats/{chatId}/leave`\n\nRemoves your phone number from a group chat. Once you leave, you will no longer receive messages from the group and all interaction endpoints (send message, typing, mark read, etc.) will return 409.\n\nA `participant.removed` webhook will fire once the leave has been processed.\n\n**Supported**\n- iMessage group chats with 4 or more active participants (including yourself)\n\n**Not supported**\n- DM (1-on-1) chats — use the chat directly to continue the conversation\n\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ message?: string; status?: string; trace_id?: string; }`\n\n - `message?: string`\n - `status?: string`\n - `trace_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.chats.leaveChat('550e8400-e29b-41d4-a716-446655440000');\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.LeaveChat',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.LeaveChat(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
- },
python: {
method: 'chats.leave_chat',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.chats.leave_chat(\n "550e8400-e29b-41d4-a716-446655440000",\n)\nprint(response.trace_id)',
},
+ go: {
+ method: 'client.Chats.LeaveChat',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.LeaveChat(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
+ },
typescript: {
method: 'client.chats.leaveChat',
example:
@@ -277,16 +277,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## share_contact_card\n\n`client.chats.shareContactCard(chatId: string): void`\n\n**post** `/v3/chats/{chatId}/share_contact_card`\n\nShare your contact information (Name and Photo Sharing) with a chat.\n\n**Note:** A contact card must be configured before sharing. You can set up your contact card via the [Contact Card API](#tag/Contact-Card) or on the [Linq dashboard](https://dashboard.linqapp.com/contact-cards).\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.shareContactCard('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e')\n```",
perLanguage: {
- go: {
- method: 'client.Chats.ShareContactCard',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.ShareContactCard(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'chats.share_contact_card',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.chats.share_contact_card(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)',
},
+ go: {
+ method: 'client.Chats.ShareContactCard',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.ShareContactCard(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.chats.shareContactCard',
example:
@@ -313,16 +313,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## send_voicememo\n\n`client.chats.sendVoicememo(chatId: string, attachment_id?: string, voice_memo_url?: string): { voice_memo: object; }`\n\n**post** `/v3/chats/{chatId}/voicememo`\n\nSend an audio file as an **iMessage voice memo bubble** to all participants in a chat.\nVoice memos appear with iMessage's native inline playback UI, unlike regular audio\nattachments sent via media parts which appear as downloadable files.\n\n**Supported audio formats:**\n- MP3 (audio/mpeg)\n- M4A (audio/x-m4a, audio/mp4)\n- AAC (audio/aac)\n- CAF (audio/x-caf) - Core Audio Format\n- WAV (audio/wav)\n- AIFF (audio/aiff, audio/x-aiff)\n- AMR (audio/amr)\n\n\n### Parameters\n\n- `chatId: string`\n\n- `attachment_id?: string`\n Reference to a voice memo file pre-uploaded via `POST /v3/attachments`.\nThe file is already stored, so sends using this ID skip the download step.\n\nEither `voice_memo_url` or `attachment_id` must be provided, but not both.\n\n\n- `voice_memo_url?: string`\n URL of the voice memo audio file. Must be a publicly accessible HTTPS URL.\n\nEither `voice_memo_url` or `attachment_id` must be provided, but not both.\n\n\n### Returns\n\n- `{ voice_memo: { id: string; chat: { id: string; handles: chat_handle[]; is_active: boolean; is_group: boolean; service: service_type; }; created_at: string; from: string; status: string; to: string[]; voice_memo: { id: string; filename: string; mime_type: string; size_bytes: number; url: string; duration_ms?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }; }`\n Response for sending a voice memo to a chat\n\n - `voice_memo: { id: string; chat: { id: string; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; is_active: boolean; is_group: boolean; service: 'iMessage' | 'SMS' | 'RCS'; }; created_at: string; from: string; status: string; to: string[]; voice_memo: { id: string; filename: string; mime_type: string; size_bytes: number; url: string; duration_ms?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.chats.sendVoicememo('f19ee7b8-8533-4c5c-83ec-4ef8d6d1ddbd');\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.SendVoicememo',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.SendVoicememo(\n\t\tcontext.TODO(),\n\t\t"f19ee7b8-8533-4c5c-83ec-4ef8d6d1ddbd",\n\t\tlinqgo.ChatSendVoicememoParams{\n\t\t\tVoiceMemoURL: linqgo.String("https://example.com/voice-memo.m4a"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.VoiceMemo)\n}\n',
- },
python: {
method: 'chats.send_voicememo',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.chats.send_voicememo(\n chat_id="f19ee7b8-8533-4c5c-83ec-4ef8d6d1ddbd",\n voice_memo_url="https://example.com/voice-memo.m4a",\n)\nprint(response.voice_memo)',
},
+ go: {
+ method: 'client.Chats.SendVoicememo',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.SendVoicememo(\n\t\tcontext.TODO(),\n\t\t"f19ee7b8-8533-4c5c-83ec-4ef8d6d1ddbd",\n\t\tlinqgo.ChatSendVoicememoParams{\n\t\t\tVoiceMemoURL: linqgo.String("https://example.com/voice-memo.m4a"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.VoiceMemo)\n}\n',
+ },
typescript: {
method: 'client.chats.sendVoicememo',
example:
@@ -348,16 +348,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## add\n\n`client.chats.participants.add(chatId: string, handle: string): { message?: string; status?: string; trace_id?: string; }`\n\n**post** `/v3/chats/{chatId}/participants`\n\nAdd a new participant to an existing group chat.\n\n**Requirements:**\n- Group chats only (3+ existing participants)\n- New participant must support the same messaging service as the group\n- Cross-service additions not allowed (e.g., can't add RCS-only user to iMessage group)\n- For cross-service scenarios, create a new chat instead\n\n\n### Parameters\n\n- `chatId: string`\n\n- `handle: string`\n Phone number (E.164 format) or email address of the participant to add\n\n### Returns\n\n- `{ message?: string; status?: string; trace_id?: string; }`\n\n - `message?: string`\n - `status?: string`\n - `trace_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.chats.participants.add('550e8400-e29b-41d4-a716-446655440000', { handle: '+12052499136' });\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Participants.Add',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.Participants.Add(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatParticipantAddParams{\n\t\t\tHandle: "+12052499136",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
- },
python: {
method: 'chats.participants.add',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.chats.participants.add(\n chat_id="550e8400-e29b-41d4-a716-446655440000",\n handle="+12052499136",\n)\nprint(response.trace_id)',
},
+ go: {
+ method: 'client.Chats.Participants.Add',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.Participants.Add(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatParticipantAddParams{\n\t\t\tHandle: "+12052499136",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
+ },
typescript: {
method: 'client.chats.participants.add',
example:
@@ -383,16 +383,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## remove\n\n`client.chats.participants.remove(chatId: string, handle: string): { message?: string; status?: string; trace_id?: string; }`\n\n**delete** `/v3/chats/{chatId}/participants`\n\nRemove a participant from an existing group chat.\n\n**Requirements:**\n- Group chats only\n- Must have 3+ participants after removal\n\n\n### Parameters\n\n- `chatId: string`\n\n- `handle: string`\n Phone number (E.164 format) or email address of the participant to remove\n\n### Returns\n\n- `{ message?: string; status?: string; trace_id?: string; }`\n\n - `message?: string`\n - `status?: string`\n - `trace_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst participant = await client.chats.participants.remove('550e8400-e29b-41d4-a716-446655440000', { handle: '+12052499136' });\n\nconsole.log(participant);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Participants.Remove',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tparticipant, err := client.Chats.Participants.Remove(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatParticipantRemoveParams{\n\t\t\tHandle: "+12052499136",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", participant.TraceID)\n}\n',
- },
python: {
method: 'chats.participants.remove',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nparticipant = client.chats.participants.remove(\n chat_id="550e8400-e29b-41d4-a716-446655440000",\n handle="+12052499136",\n)\nprint(participant.trace_id)',
},
+ go: {
+ method: 'client.Chats.Participants.Remove',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tparticipant, err := client.Chats.Participants.Remove(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatParticipantRemoveParams{\n\t\t\tHandle: "+12052499136",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", participant.TraceID)\n}\n',
+ },
typescript: {
method: 'client.chats.participants.remove',
example:
@@ -410,23 +410,23 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'post',
summary: 'Start typing indicator',
description:
- "Send a typing indicator to show that someone is typing in the chat.\n\n## Behavior & Limitations\n\nTyping indicators are best-effort signals with the following limitations:\n\n- **Active conversations only:** The recipient must have sent or received a message\n in this chat within the **last 5 minutes**. If the chat is inactive, the request is\n still accepted (`204`) but the indicator will not reach the recipient's device.\n\n- **No delivery guarantee:** Even for active chats, a `204` response only indicates\n the request was accepted for processing.\n\n- **Group chats not supported:** Attempting to start a typing indicator in a group chat\n will return a `403` error.\n",
+ 'Send a typing indicator to show that someone is typing in the chat.\n\n## Behavior\n\nTyping indicators are best-effort signals that behave as follows:\n\n- **iMessage chats only:** Typing indicators are only supported for iMessage chats.\n Requests for RCS or SMS chats are accepted (`204`) but no indicator is delivered.\n\n- **Send a message first for reliable delivery:** Typing indicators are best-effort.\n If you have not sent a message in this chat recently (roughly the **last 5 minutes**),\n a typing indicator may not reach the recipient — the request is still accepted (`204`),\n but delivery is not deterministic. Once you have sent a message in the chat, typing\n indicators reliably reach the recipient.\n\n- **No delivery guarantee:** Even for active chats, a `204` response only indicates\n the request was accepted for processing.\n\n- **Group chats not supported:** Attempting to start a typing indicator in a group chat\n will return a `403` error.\n\n## Duration & keeping it visible\n\n- A single call shows the indicator for about **85–90 seconds**, then it clears\n automatically.\n\n- To keep it visible longer, call this endpoint again every **60 seconds**. Each call\n refreshes the indicator so it stays visible continuously.\n\n- Sending a message clears the indicator.\n\n- To resume typing after sending a message, call this endpoint again.\n\n- Incoming messages do not affect the indicator.\n\n## Recipient re-opening the chat\n\nIf the recipient brings their messaging app to the foreground while the chat has an\nunread message, their device clears any showing typing indicator. Calling this endpoint\nagain on its own may not bring it back. To make it reappear, either send a message, or\ncall `DELETE /v3/chats/{chatId}/typing` (stop) and then call start typing again.\n\n## Recommended usage\n\nCall this endpoint when composing begins, call it again every 60 seconds while\ncomposing, and send the message to clear the indicator. To clear the indicator without\nsending a message, call `DELETE /v3/chats/{chatId}/typing`.\n',
stainlessPath: '(resource) chats.typing > (method) start',
qualified: 'client.chats.typing.start',
params: ['chatId: string;'],
markdown:
- "## start\n\n`client.chats.typing.start(chatId: string): void`\n\n**post** `/v3/chats/{chatId}/typing`\n\nSend a typing indicator to show that someone is typing in the chat.\n\n## Behavior & Limitations\n\nTyping indicators are best-effort signals with the following limitations:\n\n- **Active conversations only:** The recipient must have sent or received a message\n in this chat within the **last 5 minutes**. If the chat is inactive, the request is\n still accepted (`204`) but the indicator will not reach the recipient's device.\n\n- **No delivery guarantee:** Even for active chats, a `204` response only indicates\n the request was accepted for processing.\n\n- **Group chats not supported:** Attempting to start a typing indicator in a group chat\n will return a `403` error.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.typing.start('550e8400-e29b-41d4-a716-446655440000')\n```",
+ "## start\n\n`client.chats.typing.start(chatId: string): void`\n\n**post** `/v3/chats/{chatId}/typing`\n\nSend a typing indicator to show that someone is typing in the chat.\n\n## Behavior\n\nTyping indicators are best-effort signals that behave as follows:\n\n- **iMessage chats only:** Typing indicators are only supported for iMessage chats.\n Requests for RCS or SMS chats are accepted (`204`) but no indicator is delivered.\n\n- **Send a message first for reliable delivery:** Typing indicators are best-effort.\n If you have not sent a message in this chat recently (roughly the **last 5 minutes**),\n a typing indicator may not reach the recipient — the request is still accepted (`204`),\n but delivery is not deterministic. Once you have sent a message in the chat, typing\n indicators reliably reach the recipient.\n\n- **No delivery guarantee:** Even for active chats, a `204` response only indicates\n the request was accepted for processing.\n\n- **Group chats not supported:** Attempting to start a typing indicator in a group chat\n will return a `403` error.\n\n## Duration & keeping it visible\n\n- A single call shows the indicator for about **85–90 seconds**, then it clears\n automatically.\n\n- To keep it visible longer, call this endpoint again every **60 seconds**. Each call\n refreshes the indicator so it stays visible continuously.\n\n- Sending a message clears the indicator.\n\n- To resume typing after sending a message, call this endpoint again.\n\n- Incoming messages do not affect the indicator.\n\n## Recipient re-opening the chat\n\nIf the recipient brings their messaging app to the foreground while the chat has an\nunread message, their device clears any showing typing indicator. Calling this endpoint\nagain on its own may not bring it back. To make it reappear, either send a message, or\ncall `DELETE /v3/chats/{chatId}/typing` (stop) and then call start typing again.\n\n## Recommended usage\n\nCall this endpoint when composing begins, call it again every 60 seconds while\ncomposing, and send the message to clear the indicator. To clear the indicator without\nsending a message, call `DELETE /v3/chats/{chatId}/typing`.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.typing.start('550e8400-e29b-41d4-a716-446655440000')\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Typing.Start',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.Typing.Start(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'chats.typing.start',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.chats.typing.start(\n "550e8400-e29b-41d4-a716-446655440000",\n)',
},
+ go: {
+ method: 'client.Chats.Typing.Start',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.Typing.Start(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.chats.typing.start',
example:
@@ -444,23 +444,23 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'delete',
summary: 'Stop typing indicator',
description:
- 'Stop the typing indicator for the chat.\n\nTyping indicators are automatically stopped when a message is sent, so calling\nthis endpoint after sending a message is unnecessary.\n\nSee the `POST` endpoint above for behavior details and limitations.\n\n**Note:** Group chats are not supported and will return a `403` error.\n',
+ 'Immediately clears the typing indicator for the chat, without sending a message.\n\nThe typing indicator also clears automatically when you send a message, or about\n85–90 seconds after the last `POST /v3/chats/{chatId}/typing` (start typing) request.\n\nSee the start typing endpoint (`POST /v3/chats/{chatId}/typing`) above for behavior\ndetails.\n\n**Note:** Group chats are not supported and will return a `403` error.\n',
stainlessPath: '(resource) chats.typing > (method) stop',
qualified: 'client.chats.typing.stop',
params: ['chatId: string;'],
markdown:
- "## stop\n\n`client.chats.typing.stop(chatId: string): void`\n\n**delete** `/v3/chats/{chatId}/typing`\n\nStop the typing indicator for the chat.\n\nTyping indicators are automatically stopped when a message is sent, so calling\nthis endpoint after sending a message is unnecessary.\n\nSee the `POST` endpoint above for behavior details and limitations.\n\n**Note:** Group chats are not supported and will return a `403` error.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.typing.stop('550e8400-e29b-41d4-a716-446655440000')\n```",
+ "## stop\n\n`client.chats.typing.stop(chatId: string): void`\n\n**delete** `/v3/chats/{chatId}/typing`\n\nImmediately clears the typing indicator for the chat, without sending a message.\n\nThe typing indicator also clears automatically when you send a message, or about\n85–90 seconds after the last `POST /v3/chats/{chatId}/typing` (start typing) request.\n\nSee the start typing endpoint (`POST /v3/chats/{chatId}/typing`) above for behavior\ndetails.\n\n**Note:** Group chats are not supported and will return a `403` error.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.chats.typing.stop('550e8400-e29b-41d4-a716-446655440000')\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Typing.Stop',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.Typing.Stop(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'chats.typing.stop',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.chats.typing.stop(\n "550e8400-e29b-41d4-a716-446655440000",\n)',
},
+ go: {
+ method: 'client.Chats.Typing.Stop',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Chats.Typing.Stop(context.TODO(), "550e8400-e29b-41d4-a716-446655440000")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.chats.typing.stop',
example:
@@ -490,16 +490,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## send\n\n`client.chats.messages.send(chatId: string, message: { parts: text_part | media_part | link_part | object[]; effect?: message_effect; idempotency_key?: string; preferred_service?: service_type; reply_to?: reply_to; }): { chat_id: string; message: sent_message; }`\n\n**post** `/v3/chats/{chatId}/messages`\n\nSend a message to an existing chat. Use this endpoint when you already have\na chat ID and want to send additional messages to it.\n\n## Message Effects\n\nYou can add iMessage effects to make your messages more expressive. Effects are\noptional and can be either screen effects (full-screen animations) or bubble effects\n(message bubble animations).\n\n**Screen Effects:** `confetti`, `fireworks`, `lasers`, `sparkles`, `celebration`,\n`hearts`, `love`, `balloons`, `happy_birthday`, `echo`, `spotlight`\n\n**Bubble Effects:** `slam`, `loud`, `gentle`, `invisible`\n\nOnly one effect type can be applied per message.\n\n## Inline Text Decorations (iMessage only)\n\nUse the `text_decorations` array on a text part to apply styling and animations to character ranges.\n\nEach decoration specifies a `range: [start, end)` and exactly one of `style` or `animation`.\n\n**Styles:** `bold`, `italic`, `strikethrough`, `underline`\n**Animations:** `big`, `small`, `shake`, `nod`, `explode`, `ripple`, `bloom`, `jitter`\n\n```json\n{\n \"type\": \"text\",\n \"value\": \"Hello world\",\n \"text_decorations\": [\n { \"range\": [0, 5], \"style\": \"bold\" },\n { \"range\": [6, 11], \"animation\": \"shake\" }\n ]\n}\n```\n\n**Note:** Style ranges (bold, italic, etc.) may overlap, but animation ranges must not overlap with other animations or styles. Text decorations only render for iMessage recipients.\nFor SMS/RCS, text decorations are not applied.\n\n\n### Parameters\n\n- `chatId: string`\n\n- `message: { parts: { type: 'text'; value: string; text_decorations?: text_decoration[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]; effect?: { name?: string; type?: 'screen' | 'bubble'; }; idempotency_key?: string; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; }`\n Message content container. Groups all message-related fields together,\nseparating the \"what\" (message content) from the \"where\" (routing fields like from/to).\n\n - `parts: { type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]`\n Array of message parts. Each part can be text, media, or link.\nParts are displayed in order. Text and media can be mixed freely,\nbut a `link` part must be the only part in the message.\n\n**Rich Link Previews:**\n- Use a `link` part to send a URL with a rich preview card\n- A `link` part must be the **only** part in the message\n- To send a URL as plain text (no preview), use a `text` part instead\n\n**Supported Media:**\n- Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp\n- Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp\n- Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr\n- Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm\n- Contact & Calendar: .vcf, .ics\n\n**Audio:**\n- Audio files (.m4a, .mp3, .aac, .caf, .wav, .aiff, .amr) are fully supported as media parts\n- To send audio as an **iMessage voice memo bubble** (inline playback UI), use the dedicated\n `/v3/chats/{chatId}/voicememo` endpoint instead\n\n**Validation Rules:**\n- A `link` part must be the **only** part in the message. It cannot be combined\n with text or media parts.\n- Consecutive text parts are not allowed. Text parts must be separated by\n media parts. For example, [text, text] is invalid, but [text, media, text] is valid.\n- Maximum of **100 parts** total.\n- Media parts using a public `url` (downloaded by the server on send) are\n capped at **40**. Parts using `attachment_id` or presigned URLs\n are exempt from this sub-limit. For bulk media sends exceeding 40 files,\n pre-upload via `POST /v3/attachments` and reference by `attachment_id` or `download_url`.\n\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n iMessage effect to apply to this message (screen or bubble effect)\n - `idempotency_key?: string`\n Optional idempotency key for this message.\nUse this to prevent duplicate sends of the same message.\n\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n Messaging service type\n - `reply_to?: { message_id: string; part_index?: number; }`\n Reply to another message to create a threaded conversation\n\n### Returns\n\n- `{ chat_id: string; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: text_part_response | media_part_response | link_part_response | object[]; sent_at: string; delivered_at?: string; effect?: message_effect; from_handle?: chat_handle; preferred_service?: service_type; reply_to?: reply_to; service?: service_type; }; }`\n Response for sending a message to a chat\n\n - `chat_id: string`\n - `message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; sent_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.chats.messages.send('550e8400-e29b-41d4-a716-446655440000', { message: { parts: [{ type: 'text', value: 'Hello, world!' }] } });\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Messages.Send',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.Messages.Send(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatMessageSendParams{\n\t\t\tMessage: linqgo.MessageContentParam{\n\t\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\t\tValue: "Hello, world!",\n\t\t\t\t\t},\n\t\t\t\t}},\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ChatID)\n}\n',
- },
python: {
method: 'chats.messages.send',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.chats.messages.send(\n chat_id="550e8400-e29b-41d4-a716-446655440000",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello, world!",\n }]\n },\n)\nprint(response.chat_id)',
},
+ go: {
+ method: 'client.Chats.Messages.Send',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Chats.Messages.Send(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatMessageSendParams{\n\t\t\tMessage: linqgo.MessageContentParam{\n\t\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\t\tValue: "Hello, world!",\n\t\t\t\t\t},\n\t\t\t\t}},\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ChatID)\n}\n',
+ },
typescript: {
method: 'client.chats.messages.send',
example:
@@ -525,16 +525,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list\n\n`client.chats.messages.list(chatId: string, cursor?: string, limit?: number): { id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: message_effect; from?: string; from_handle?: chat_handle; parts?: text_part_response | media_part_response | link_part_response | object[]; preferred_service?: service_type; read_at?: string; reply_to?: reply_to; sent_at?: string; service?: service_type; }`\n\n**get** `/v3/chats/{chatId}/messages`\n\nRetrieve messages from a specific chat with pagination support.\n\n\n### Parameters\n\n- `chatId: string`\n\n- `cursor?: string`\n Pagination cursor from previous next_cursor response\n\n- `limit?: number`\n Maximum number of messages to return\n\n### Returns\n\n- `{ id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from?: string; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; parts?: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; read_at?: string; reply_to?: { message_id: string; part_index?: number; }; sent_at?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `chat_id: string`\n - `created_at: string`\n - `delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'`\n - `is_delivered: boolean`\n - `is_from_me: boolean`\n - `is_read: boolean`\n - `updated_at: string`\n - `delivered_at?: string`\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n - `from?: string`\n - `from_handle?: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }`\n - `parts?: { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { id: string; filename: string; mime_type: string; reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; size_bytes: number; type: 'media'; url: string; } | { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: { handle: object; is_me: boolean; type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker'; custom_emoji?: string; sticker?: { file_name?: string; height?: number; mime_type?: string; url?: string; width?: number; }; }[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]`\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n - `read_at?: string`\n - `reply_to?: { message_id: string; part_index?: number; }`\n - `sent_at?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.chats.messages.list('550e8400-e29b-41d4-a716-446655440000')) {\n console.log(message);\n}\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Messages.List',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Chats.Messages.List(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatMessageListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
- },
python: {
method: 'chats.messages.list',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npage = client.chats.messages.list(\n chat_id="550e8400-e29b-41d4-a716-446655440000",\n)\npage = page.messages[0]\nprint(page.id)',
},
+ go: {
+ method: 'client.Chats.Messages.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Chats.Messages.List(\n\t\tcontext.TODO(),\n\t\t"550e8400-e29b-41d4-a716-446655440000",\n\t\tlinqgo.ChatMessageListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
+ },
typescript: {
method: 'client.chats.messages.list',
example:
@@ -552,24 +552,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'post',
summary: 'Request location sharing',
description:
- "Send a location sharing request to a contact. They will receive an iMessage\nprompt asking them to share their location.\n\nLocation requests only work in **1:1 iMessage chats** (Apple limitation).\nAttempting to request location in a group chat, or in an SMS or RCS chat,\nreturns `409` (Operation not supported on this chat's service type).\n",
+ 'Request a contact in a chat to share their location. They receive an iMessage\nprompt and must accept before any location is available; once they do, read their\nlocation coordinates with `GET /v3/chats/{chatId}/location`.\n\nThe request is delivered asynchronously. The endpoint returns immediately with\n`{ "success": true, "message": "Location request sent" }` and does not return\ncoordinates.\n\nLocation requests only work in **1:1 iMessage chats** (Apple limitation):\n\n- Group chats (any service) return `409` with code `2016`\n (`GroupChatNotSupported`).\n- 1:1 SMS and RCS chats return `409` with code `2017`\n (`ChatServiceNotSupported`).\n',
stainlessPath: '(resource) chats.location > (method) request',
qualified: 'client.chats.location.request',
params: ['chatId: string;'],
response: '{ message: string; success: boolean; }',
markdown:
- "## request\n\n`client.chats.location.request(chatId: string): { message: string; success: boolean; }`\n\n**post** `/v3/chats/{chatId}/location/request`\n\nSend a location sharing request to a contact. They will receive an iMessage\nprompt asking them to share their location.\n\nLocation requests only work in **1:1 iMessage chats** (Apple limitation).\nAttempting to request location in a group chat, or in an SMS or RCS chat,\nreturns `409` (Operation not supported on this chat's service type).\n\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ message: string; success: boolean; }`\n\n - `message: string`\n - `success: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst locationRequestResponse = await client.chats.location.request('975d0776-bd17-4273-8337-f346b4c661b0');\n\nconsole.log(locationRequestResponse);\n```",
+ '## request\n\n`client.chats.location.request(chatId: string): { message: string; success: boolean; }`\n\n**post** `/v3/chats/{chatId}/location/request`\n\nRequest a contact in a chat to share their location. They receive an iMessage\nprompt and must accept before any location is available; once they do, read their\nlocation coordinates with `GET /v3/chats/{chatId}/location`.\n\nThe request is delivered asynchronously. The endpoint returns immediately with\n`{ "success": true, "message": "Location request sent" }` and does not return\ncoordinates.\n\nLocation requests only work in **1:1 iMessage chats** (Apple limitation):\n\n- Group chats (any service) return `409` with code `2016`\n (`GroupChatNotSupported`).\n- 1:1 SMS and RCS chats return `409` with code `2017`\n (`ChatServiceNotSupported`).\n\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ message: string; success: boolean; }`\n\n - `message: string`\n - `success: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from \'@linqapp/sdk\';\n\nconst client = new LinqAPIV3();\n\nconst locationRequestResponse = await client.chats.location.request(\'975d0776-bd17-4273-8337-f346b4c661b0\');\n\nconsole.log(locationRequestResponse);\n```',
perLanguage: {
- go: {
- method: 'client.Chats.Location.Request',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tlocationRequestResponse, err := client.Chats.Location.Request(context.TODO(), "975d0776-bd17-4273-8337-f346b4c661b0")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", locationRequestResponse.Message)\n}\n',
- },
python: {
method: 'chats.location.request',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nlocation_request_response = client.chats.location.request(\n "975d0776-bd17-4273-8337-f346b4c661b0",\n)\nprint(location_request_response.message)',
},
+ go: {
+ method: 'client.Chats.Location.Request',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tlocationRequestResponse, err := client.Chats.Location.Request(context.TODO(), "975d0776-bd17-4273-8337-f346b4c661b0")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", locationRequestResponse.Message)\n}\n',
+ },
typescript: {
method: 'client.chats.location.request',
example:
@@ -587,25 +587,25 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'get',
summary: 'Get location data',
description:
- 'Retrieve the current location for contacts sharing with you in a chat.\n\nThe response is wrapped in the standard `{ "success": true, "data": ... }` envelope —\nthe body is **not** a bare GeoJSON document. `data` is a\n[GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) `FeatureCollection` with a\n`Feature` for each participant actively sharing their location.\n\nWorks for both 1:1 and group chats. In group chats, `data.features` contains a separate\nfeature for each participant who is sharing. Each feature\'s `properties.handle` identifies the user.\n\nReturns an empty `data.features` array if no one is sharing or no location data is available yet.\n',
+ 'Retrieve the current location for contacts sharing with you in a chat.\n\nThe response is wrapped in the standard `{ "success": true, "data": ... }` envelope —\nthe body is **not** a bare GeoJSON document. `data` is a\n[GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) `FeatureCollection` with a\n`Feature` for each participant actively sharing their location.\n\nWorks for both 1:1 and group chats. In group chats, `data.features` contains a separate\nfeature for each participant who is sharing. Each feature\'s `properties.handle` identifies the user.\n\nReturns an empty `data.features` array if no one is sharing or no location data is\navailable yet. If sharing started but this stays empty, see the **Location Sharing**\noverview.\n\nPoll this endpoint to track a moving contact. `properties.updated_at`\nreflects when each participant\'s location was last updated. There is no\ncoordinate-update webhook. See the **Location Sharing** overview for polling\nguidance.\n',
stainlessPath: '(resource) chats.location > (method) retrieve',
qualified: 'client.chats.location.retrieve',
params: ['chatId: string;'],
response:
"{ data: { features: { geometry: object; properties: object; type: 'Feature'; }[]; type: 'FeatureCollection'; }; success: boolean; }",
markdown:
- "## retrieve\n\n`client.chats.location.retrieve(chatId: string): { data: object; success: boolean; }`\n\n**get** `/v3/chats/{chatId}/location`\n\nRetrieve the current location for contacts sharing with you in a chat.\n\nThe response is wrapped in the standard `{ \"success\": true, \"data\": ... }` envelope —\nthe body is **not** a bare GeoJSON document. `data` is a\n[GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) `FeatureCollection` with a\n`Feature` for each participant actively sharing their location.\n\nWorks for both 1:1 and group chats. In group chats, `data.features` contains a separate\nfeature for each participant who is sharing. Each feature's `properties.handle` identifies the user.\n\nReturns an empty `data.features` array if no one is sharing or no location data is available yet.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ data: { features: { geometry: object; properties: object; type: 'Feature'; }[]; type: 'FeatureCollection'; }; success: boolean; }`\n\n - `data: { features: { geometry: { coordinates: number[]; type: 'Point'; }; properties: { handle: string; address?: string; locality?: string; updated_at?: string; }; type: 'Feature'; }[]; type: 'FeatureCollection'; }`\n - `success: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst getChatLocationResponse = await client.chats.location.retrieve('975d0776-bd17-4273-8337-f346b4c661b0');\n\nconsole.log(getChatLocationResponse);\n```",
+ "## retrieve\n\n`client.chats.location.retrieve(chatId: string): { data: object; success: boolean; }`\n\n**get** `/v3/chats/{chatId}/location`\n\nRetrieve the current location for contacts sharing with you in a chat.\n\nThe response is wrapped in the standard `{ \"success\": true, \"data\": ... }` envelope —\nthe body is **not** a bare GeoJSON document. `data` is a\n[GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) `FeatureCollection` with a\n`Feature` for each participant actively sharing their location.\n\nWorks for both 1:1 and group chats. In group chats, `data.features` contains a separate\nfeature for each participant who is sharing. Each feature's `properties.handle` identifies the user.\n\nReturns an empty `data.features` array if no one is sharing or no location data is\navailable yet. If sharing started but this stays empty, see the **Location Sharing**\noverview.\n\nPoll this endpoint to track a moving contact. `properties.updated_at`\nreflects when each participant's location was last updated. There is no\ncoordinate-update webhook. See the **Location Sharing** overview for polling\nguidance.\n\n\n### Parameters\n\n- `chatId: string`\n\n### Returns\n\n- `{ data: { features: { geometry: object; properties: object; type: 'Feature'; }[]; type: 'FeatureCollection'; }; success: boolean; }`\n\n - `data: { features: { geometry: { coordinates: number[]; type: 'Point'; }; properties: { handle: string; address?: string; locality?: string; updated_at?: string; }; type: 'Feature'; }[]; type: 'FeatureCollection'; }`\n - `success: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst getChatLocationResponse = await client.chats.location.retrieve('975d0776-bd17-4273-8337-f346b4c661b0');\n\nconsole.log(getChatLocationResponse);\n```",
perLanguage: {
- go: {
- method: 'client.Chats.Location.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgetChatLocationResponse, err := client.Chats.Location.Get(context.TODO(), "975d0776-bd17-4273-8337-f346b4c661b0")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", getChatLocationResponse.Data)\n}\n',
- },
python: {
method: 'chats.location.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nget_chat_location_response = client.chats.location.retrieve(\n "975d0776-bd17-4273-8337-f346b4c661b0",\n)\nprint(get_chat_location_response.data)',
},
+ go: {
+ method: 'client.Chats.Location.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgetChatLocationResponse, err := client.Chats.Location.Get(context.TODO(), "975d0776-bd17-4273-8337-f346b4c661b0")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", getChatLocationResponse.Data)\n}\n',
+ },
typescript: {
method: 'client.chats.location.retrieve',
example:
@@ -623,7 +623,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'post',
summary: 'Send a message (auto-selected from-number)',
description:
- 'Send a message to one or more recipients **without supplying a `from`\nnumber**. Linq resolves both the sending line and the target chat for you,\nthen returns exactly which line was used, which chat the message landed in,\nwhether a new chat was created, and every resulting message id.\n\nThis fuses "create chat" and "send message" behind a single\nmessage-centric resource. Provide only the recipients (`to`) and the\n`message`; the platform decides the rest.\n\n## How the from-number and chat are chosen\n\n- **Reuse** — if a chat with exactly these recipients already exists and the\n line it lives on is healthy, the message is sent into that chat on its\n existing line (`from_selection.reason = reused_active_chat`).\n- **New** — if no such chat exists, a new chat is created on the best\n available line (`from_selection.reason = new_best_number`).\n- **Failover** — if a matching chat exists but its line has been flagged, a\n **new** chat is created on a fresh best line and the flagged chat is\n abandoned (`from_selection.reason = failover_flagged`,\n `previous_chat_id` set). If you supply `continuation_message`, that\n text is sent as the single message INSTEAD of `message` (useful as a\n fresh-number-appropriate opener). Exactly one message is sent either way.\n\nRecipients (`to`) are an order-independent set: a single handle is a direct\nchat, multiple handles a group chat.\n\n## Differences from POST /v3/chats\n\n- The first message **may contain a link** (including for a newly created\n chat). Note: sending a link as the very first message on a freshly\n selected line can elevate that line\'s flagging risk — it is allowed, not\n recommended.\n- Voice memos are **not** supported here. To send an iMessage voice-memo\n bubble, use `POST /v3/chats/{chatId}/voicememo` with a known chat id.\n\n## Service preference, effects, decorations\n\nSet `message.preferred_service` (`iMessage` | `RCS` | `SMS`), `message.effect`,\nand per-part `text_decorations` exactly as on the other send endpoints.\n\nAlways responds `202 Accepted` — chat creation is incidental to the send.\n',
+ 'Send a message to one or more recipients **without supplying a `from`\nnumber**. Linq resolves both the sending line and the target chat for you,\nthen returns exactly which line was used, which chat the message landed in,\nwhether a new chat was created, and every resulting message id.\n\nThis fuses "create chat" and "send message" behind a single\nmessage-centric resource. Provide only the recipients (`to`) and the\n`message`; the platform decides the rest.\n\n## How the from-number and chat are chosen\n\n- **Reuse** — if a chat with exactly these recipients already exists on a\n line that can still send, the message is sent into that chat on its\n existing line (`from_selection.reason = reused_active_chat`). The\n most-recently-active such chat wins; chats stranded on flagged lines\n (e.g. by an earlier failover) are skipped.\n- **New** — if no such chat exists, a new chat is created on the best\n available line (`from_selection.reason = new_best_number`).\n- **Failover** — if matching chats exist but none is on a line that can\n send, a **new** chat is created on a fresh best line and the flagged chat\n is abandoned (`from_selection.reason = failover_flagged`,\n `previous_chat_id` set). If you supply `continuation_message`, that\n text is sent as the single message INSTEAD of `message` (useful as a\n fresh-number-appropriate opener). Exactly one message is sent either way.\n\nRecipients (`to`) are an order-independent set: a single handle is a direct\nchat, multiple handles a group chat.\n\n## Differences from POST /v3/chats\n\n- The first message **may contain a link** (including for a newly created\n chat). Note: sending a link as the very first message on a freshly\n selected line can elevate that line\'s flagging risk — it is allowed, not\n recommended.\n- Voice memos are **not** supported here. To send an iMessage voice-memo\n bubble, use `POST /v3/chats/{chatId}/voicememo` with a known chat id.\n\n## Service preference, effects, decorations\n\nSet `message.preferred_service` (`iMessage` | `RCS` | `SMS`), `message.effect`,\nand per-part `text_decorations` exactly as on the other send endpoints.\n\nAlways responds `202 Accepted` — chat creation is incidental to the send.\n',
stainlessPath: '(resource) messages > (method) create',
qualified: 'client.messages.create',
params: [
@@ -635,18 +635,18 @@ const EMBEDDED_METHODS: MethodEntry[] = [
response:
"{ chat_id: string; created_new_chat: boolean; from: string; from_selection: { reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged'; reused_existing_chat: boolean; }; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; is_group: boolean; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: text_part_response | media_part_response | link_part_response | object[]; sent_at: string; delivered_at?: string; effect?: message_effect; from_handle?: chat_handle; preferred_service?: service_type; reply_to?: reply_to; service?: service_type; }; service: 'iMessage' | 'SMS' | 'RCS'; previous_chat_id?: string; }",
markdown:
- "## create\n\n`client.messages.create(message: { parts: text_part | media_part | link_part | object[]; effect?: message_effect; idempotency_key?: string; preferred_service?: service_type; reply_to?: reply_to; }, to: string[], continuation_message?: { text: string; }, Idempotency-Key?: string): { chat_id: string; created_new_chat: boolean; from: string; from_selection: object; handles: chat_handle[]; is_group: boolean; message: sent_message; service: service_type; previous_chat_id?: string; }`\n\n**post** `/v3/messages`\n\nSend a message to one or more recipients **without supplying a `from`\nnumber**. Linq resolves both the sending line and the target chat for you,\nthen returns exactly which line was used, which chat the message landed in,\nwhether a new chat was created, and every resulting message id.\n\nThis fuses \"create chat\" and \"send message\" behind a single\nmessage-centric resource. Provide only the recipients (`to`) and the\n`message`; the platform decides the rest.\n\n## How the from-number and chat are chosen\n\n- **Reuse** — if a chat with exactly these recipients already exists and the\n line it lives on is healthy, the message is sent into that chat on its\n existing line (`from_selection.reason = reused_active_chat`).\n- **New** — if no such chat exists, a new chat is created on the best\n available line (`from_selection.reason = new_best_number`).\n- **Failover** — if a matching chat exists but its line has been flagged, a\n **new** chat is created on a fresh best line and the flagged chat is\n abandoned (`from_selection.reason = failover_flagged`,\n `previous_chat_id` set). If you supply `continuation_message`, that\n text is sent as the single message INSTEAD of `message` (useful as a\n fresh-number-appropriate opener). Exactly one message is sent either way.\n\nRecipients (`to`) are an order-independent set: a single handle is a direct\nchat, multiple handles a group chat.\n\n## Differences from POST /v3/chats\n\n- The first message **may contain a link** (including for a newly created\n chat). Note: sending a link as the very first message on a freshly\n selected line can elevate that line's flagging risk — it is allowed, not\n recommended.\n- Voice memos are **not** supported here. To send an iMessage voice-memo\n bubble, use `POST /v3/chats/{chatId}/voicememo` with a known chat id.\n\n## Service preference, effects, decorations\n\nSet `message.preferred_service` (`iMessage` | `RCS` | `SMS`), `message.effect`,\nand per-part `text_decorations` exactly as on the other send endpoints.\n\nAlways responds `202 Accepted` — chat creation is incidental to the send.\n\n\n### Parameters\n\n- `message: { parts: { type: 'text'; value: string; text_decorations?: text_decoration[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]; effect?: { name?: string; type?: 'screen' | 'bubble'; }; idempotency_key?: string; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; }`\n Message content container. Groups all message-related fields together,\nseparating the \"what\" (message content) from the \"where\" (routing fields like from/to).\n\n - `parts: { type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]`\n Array of message parts. Each part can be text, media, or link.\nParts are displayed in order. Text and media can be mixed freely,\nbut a `link` part must be the only part in the message.\n\n**Rich Link Previews:**\n- Use a `link` part to send a URL with a rich preview card\n- A `link` part must be the **only** part in the message\n- To send a URL as plain text (no preview), use a `text` part instead\n\n**Supported Media:**\n- Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp\n- Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp\n- Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr\n- Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm\n- Contact & Calendar: .vcf, .ics\n\n**Audio:**\n- Audio files (.m4a, .mp3, .aac, .caf, .wav, .aiff, .amr) are fully supported as media parts\n- To send audio as an **iMessage voice memo bubble** (inline playback UI), use the dedicated\n `/v3/chats/{chatId}/voicememo` endpoint instead\n\n**Validation Rules:**\n- A `link` part must be the **only** part in the message. It cannot be combined\n with text or media parts.\n- Consecutive text parts are not allowed. Text parts must be separated by\n media parts. For example, [text, text] is invalid, but [text, media, text] is valid.\n- Maximum of **100 parts** total.\n- Media parts using a public `url` (downloaded by the server on send) are\n capped at **40**. Parts using `attachment_id` or presigned URLs\n are exempt from this sub-limit. For bulk media sends exceeding 40 files,\n pre-upload via `POST /v3/attachments` and reference by `attachment_id` or `download_url`.\n\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n iMessage effect to apply to this message (screen or bubble effect)\n - `idempotency_key?: string`\n Optional idempotency key for this message.\nUse this to prevent duplicate sends of the same message.\n\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n Messaging service type\n - `reply_to?: { message_id: string; part_index?: number; }`\n Reply to another message to create a threaded conversation\n\n- `to: string[]`\n Recipient handles (E.164 phone numbers or email addresses). One handle\nis a direct chat; multiple handles a group chat. Order-independent — the\nset identifies the chat.\n\n\n- `continuation_message?: { text: string; }`\n Text-only fallback that **replaces** `message` ONLY on the failover branch —\nwhen a chat with these recipients already existed but its line was flagged,\nso a new chat is created on a fresh line. On that branch this text is sent as\nthe single message instead of `message` (the recipient is on a new number, so\nyou typically want a fresh-number-appropriate opener rather than the original\ncontent). Ignored otherwise (a healthy reuse, or genuine first contact).\nCarries no parts, media, or effects — exactly one message is ever sent.\n\n - `text: string`\n The replacement message text, sent as the single message on failover.\n\n- `Idempotency-Key?: string`\n\n### Returns\n\n- `{ chat_id: string; created_new_chat: boolean; from: string; from_selection: { reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged'; reused_existing_chat: boolean; }; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; is_group: boolean; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: text_part_response | media_part_response | link_part_response | object[]; sent_at: string; delivered_at?: string; effect?: message_effect; from_handle?: chat_handle; preferred_service?: service_type; reply_to?: reply_to; service?: service_type; }; service: 'iMessage' | 'SMS' | 'RCS'; previous_chat_id?: string; }`\n Result of an auto-from send. Self-describing: which line was used, which\nchat the message landed in, whether a new chat was created, and the\nresulting message id(s).\n\n\n - `chat_id: string`\n - `created_new_chat: boolean`\n - `from: string`\n - `from_selection: { reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged'; reused_existing_chat: boolean; }`\n - `handles: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]`\n - `is_group: boolean`\n - `message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; sent_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n - `service: 'iMessage' | 'SMS' | 'RCS'`\n - `previous_chat_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst message = await client.messages.create({\n message: { parts: [{ type: 'text', value: 'Hi! Thanks for reaching out — how can we help?' }] },\n to: ['+14155559876'],\n});\n\nconsole.log(message);\n```",
+ "## create\n\n`client.messages.create(message: { parts: text_part | media_part | link_part | object[]; effect?: message_effect; idempotency_key?: string; preferred_service?: service_type; reply_to?: reply_to; }, to: string[], continuation_message?: { text: string; }, Idempotency-Key?: string): { chat_id: string; created_new_chat: boolean; from: string; from_selection: object; handles: chat_handle[]; is_group: boolean; message: sent_message; service: service_type; previous_chat_id?: string; }`\n\n**post** `/v3/messages`\n\nSend a message to one or more recipients **without supplying a `from`\nnumber**. Linq resolves both the sending line and the target chat for you,\nthen returns exactly which line was used, which chat the message landed in,\nwhether a new chat was created, and every resulting message id.\n\nThis fuses \"create chat\" and \"send message\" behind a single\nmessage-centric resource. Provide only the recipients (`to`) and the\n`message`; the platform decides the rest.\n\n## How the from-number and chat are chosen\n\n- **Reuse** — if a chat with exactly these recipients already exists on a\n line that can still send, the message is sent into that chat on its\n existing line (`from_selection.reason = reused_active_chat`). The\n most-recently-active such chat wins; chats stranded on flagged lines\n (e.g. by an earlier failover) are skipped.\n- **New** — if no such chat exists, a new chat is created on the best\n available line (`from_selection.reason = new_best_number`).\n- **Failover** — if matching chats exist but none is on a line that can\n send, a **new** chat is created on a fresh best line and the flagged chat\n is abandoned (`from_selection.reason = failover_flagged`,\n `previous_chat_id` set). If you supply `continuation_message`, that\n text is sent as the single message INSTEAD of `message` (useful as a\n fresh-number-appropriate opener). Exactly one message is sent either way.\n\nRecipients (`to`) are an order-independent set: a single handle is a direct\nchat, multiple handles a group chat.\n\n## Differences from POST /v3/chats\n\n- The first message **may contain a link** (including for a newly created\n chat). Note: sending a link as the very first message on a freshly\n selected line can elevate that line's flagging risk — it is allowed, not\n recommended.\n- Voice memos are **not** supported here. To send an iMessage voice-memo\n bubble, use `POST /v3/chats/{chatId}/voicememo` with a known chat id.\n\n## Service preference, effects, decorations\n\nSet `message.preferred_service` (`iMessage` | `RCS` | `SMS`), `message.effect`,\nand per-part `text_decorations` exactly as on the other send endpoints.\n\nAlways responds `202 Accepted` — chat creation is incidental to the send.\n\n\n### Parameters\n\n- `message: { parts: { type: 'text'; value: string; text_decorations?: text_decoration[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]; effect?: { name?: string; type?: 'screen' | 'bubble'; }; idempotency_key?: string; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; }`\n Message content container. Groups all message-related fields together,\nseparating the \"what\" (message content) from the \"where\" (routing fields like from/to).\n\n - `parts: { type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { type: 'media'; attachment_id?: string; url?: string; } | { type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; type: 'imessage_app'; fallback_text?: string; interactive?: boolean; url?: string; }[]`\n Array of message parts. Each part can be text, media, or link.\nParts are displayed in order. Text and media can be mixed freely,\nbut a `link` part must be the only part in the message.\n\n**Rich Link Previews:**\n- Use a `link` part to send a URL with a rich preview card\n- A `link` part must be the **only** part in the message\n- To send a URL as plain text (no preview), use a `text` part instead\n\n**Supported Media:**\n- Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp\n- Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp\n- Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr\n- Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm\n- Contact & Calendar: .vcf, .ics\n\n**Audio:**\n- Audio files (.m4a, .mp3, .aac, .caf, .wav, .aiff, .amr) are fully supported as media parts\n- To send audio as an **iMessage voice memo bubble** (inline playback UI), use the dedicated\n `/v3/chats/{chatId}/voicememo` endpoint instead\n\n**Validation Rules:**\n- A `link` part must be the **only** part in the message. It cannot be combined\n with text or media parts.\n- Consecutive text parts are not allowed. Text parts must be separated by\n media parts. For example, [text, text] is invalid, but [text, media, text] is valid.\n- Maximum of **100 parts** total.\n- Media parts using a public `url` (downloaded by the server on send) are\n capped at **40**. Parts using `attachment_id` or presigned URLs\n are exempt from this sub-limit. For bulk media sends exceeding 40 files,\n pre-upload via `POST /v3/attachments` and reference by `attachment_id` or `download_url`.\n\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n iMessage effect to apply to this message (screen or bubble effect)\n - `idempotency_key?: string`\n Optional idempotency key for this message.\nUse this to prevent duplicate sends of the same message.\n\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n Messaging service type\n - `reply_to?: { message_id: string; part_index?: number; }`\n Reply to another message to create a threaded conversation\n\n- `to: string[]`\n Recipient handles (E.164 phone numbers or email addresses). One handle\nis a direct chat; multiple handles a group chat. Order-independent — the\nset identifies the chat.\n\n\n- `continuation_message?: { text: string; }`\n Text-only fallback that **replaces** `message` ONLY on the failover branch —\nwhen a chat with these recipients already existed but its line was flagged,\nso a new chat is created on a fresh line. On that branch this text is sent as\nthe single message instead of `message` (the recipient is on a new number, so\nyou typically want a fresh-number-appropriate opener rather than the original\ncontent). Ignored otherwise (a healthy reuse, or genuine first contact).\nCarries no parts, media, or effects — exactly one message is ever sent.\n\n - `text: string`\n The replacement message text, sent as the single message on failover.\n\n- `Idempotency-Key?: string`\n\n### Returns\n\n- `{ chat_id: string; created_new_chat: boolean; from: string; from_selection: { reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged'; reused_existing_chat: boolean; }; handles: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]; is_group: boolean; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: text_part_response | media_part_response | link_part_response | object[]; sent_at: string; delivered_at?: string; effect?: message_effect; from_handle?: chat_handle; preferred_service?: service_type; reply_to?: reply_to; service?: service_type; }; service: 'iMessage' | 'SMS' | 'RCS'; previous_chat_id?: string; }`\n Result of an auto-from send. Self-describing: which line was used, which\nchat the message landed in, whether a new chat was created, and the\nresulting message id(s).\n\n\n - `chat_id: string`\n - `created_new_chat: boolean`\n - `from: string`\n - `from_selection: { reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged'; reused_existing_chat: boolean; }`\n - `handles: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }[]`\n - `is_group: boolean`\n - `message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; sent_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n - `service: 'iMessage' | 'SMS' | 'RCS'`\n - `previous_chat_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst message = await client.messages.create({\n message: { parts: [{ type: 'text', value: 'Hi! Thanks for reaching out — how can we help?' }] },\n to: ['+14155559876'],\n});\n\nconsole.log(message);\n```",
perLanguage: {
- go: {
- method: 'client.Messages.New',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.New(context.TODO(), linqgo.MessageNewParams{\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hi! Thanks for reaching out — how can we help?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+14155559876"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ChatID)\n}\n',
- },
python: {
method: 'messages.create',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nmessage = client.messages.create(\n message={\n "parts": [{\n "type": "text",\n "value": "Hi! Thanks for reaching out — how can we help?",\n }]\n },\n to=["+14155559876"],\n)\nprint(message.chat_id)',
},
+ go: {
+ method: 'client.Messages.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.New(context.TODO(), linqgo.MessageNewParams{\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hi! Thanks for reaching out — how can we help?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+14155559876"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ChatID)\n}\n',
+ },
typescript: {
method: 'client.messages.create',
example:
@@ -673,16 +673,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list_messages_thread\n\n`client.messages.listMessagesThread(messageId: string, cursor?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: message_effect; from?: string; from_handle?: chat_handle; parts?: text_part_response | media_part_response | link_part_response | object[]; preferred_service?: service_type; read_at?: string; reply_to?: reply_to; sent_at?: string; service?: service_type; }`\n\n**get** `/v3/messages/{messageId}/thread`\n\nRetrieve all messages in a conversation thread. Given any message ID in the thread,\nreturns the originator message and all replies in chronological order.\n\nIf the message is not part of a thread, returns just that single message.\n\nSupports pagination and configurable ordering.\n\n\n### Parameters\n\n- `messageId: string`\n\n- `cursor?: string`\n Pagination cursor from previous next_cursor response\n\n- `limit?: number`\n Maximum number of messages to return\n\n- `order?: 'asc' | 'desc'`\n Sort order for messages (asc = oldest first, desc = newest first)\n\n### Returns\n\n- `{ id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from?: string; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; parts?: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; read_at?: string; reply_to?: { message_id: string; part_index?: number; }; sent_at?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `chat_id: string`\n - `created_at: string`\n - `delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'`\n - `is_delivered: boolean`\n - `is_from_me: boolean`\n - `is_read: boolean`\n - `updated_at: string`\n - `delivered_at?: string`\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n - `from?: string`\n - `from_handle?: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }`\n - `parts?: { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { id: string; filename: string; mime_type: string; reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; size_bytes: number; type: 'media'; url: string; } | { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: { handle: object; is_me: boolean; type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker'; custom_emoji?: string; sticker?: { file_name?: string; height?: number; mime_type?: string; url?: string; width?: number; }; }[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]`\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n - `read_at?: string`\n - `reply_to?: { message_id: string; part_index?: number; }`\n - `sent_at?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\n// Automatically fetches more pages as needed.\nfor await (const message of client.messages.listMessagesThread('69a37c7d-af4f-4b5e-af42-e28e98ce873a')) {\n console.log(message);\n}\n```",
perLanguage: {
- go: {
- method: 'client.Messages.ListMessagesThread',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Messages.ListMessagesThread(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageListMessagesThreadParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
- },
python: {
method: 'messages.list_messages_thread',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npage = client.messages.list_messages_thread(\n message_id="69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n)\npage = page.messages[0]\nprint(page.id)',
},
+ go: {
+ method: 'client.Messages.ListMessagesThread',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Messages.ListMessagesThread(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageListMessagesThreadParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n',
+ },
typescript: {
method: 'client.messages.listMessagesThread',
example:
@@ -709,16 +709,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## retrieve\n\n`client.messages.retrieve(messageId: string): { id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: message_effect; from?: string; from_handle?: chat_handle; parts?: text_part_response | media_part_response | link_part_response | object[]; preferred_service?: service_type; read_at?: string; reply_to?: reply_to; sent_at?: string; service?: service_type; }`\n\n**get** `/v3/messages/{messageId}`\n\nRetrieve a specific message by its ID. This endpoint returns the full message\ndetails including text, attachments, reactions, and metadata.\n\n\n### Parameters\n\n- `messageId: string`\n\n### Returns\n\n- `{ id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from?: string; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; parts?: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; read_at?: string; reply_to?: { message_id: string; part_index?: number; }; sent_at?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `chat_id: string`\n - `created_at: string`\n - `delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'`\n - `is_delivered: boolean`\n - `is_from_me: boolean`\n - `is_read: boolean`\n - `updated_at: string`\n - `delivered_at?: string`\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n - `from?: string`\n - `from_handle?: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }`\n - `parts?: { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { id: string; filename: string; mime_type: string; reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; size_bytes: number; type: 'media'; url: string; } | { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: { handle: object; is_me: boolean; type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker'; custom_emoji?: string; sticker?: { file_name?: string; height?: number; mime_type?: string; url?: string; width?: number; }; }[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]`\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n - `read_at?: string`\n - `reply_to?: { message_id: string; part_index?: number; }`\n - `sent_at?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst message = await client.messages.retrieve('69a37c7d-af4f-4b5e-af42-e28e98ce873a');\n\nconsole.log(message);\n```",
perLanguage: {
- go: {
- method: 'client.Messages.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.Get(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ID)\n}\n',
- },
python: {
method: 'messages.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nmessage = client.messages.retrieve(\n "69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n)\nprint(message.id)',
},
+ go: {
+ method: 'client.Messages.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.Get(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ID)\n}\n',
+ },
typescript: {
method: 'client.messages.retrieve',
example:
@@ -743,16 +743,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## delete\n\n`client.messages.delete(messageId: string): void`\n\n**delete** `/v3/messages/{messageId}`\n\nDeletes a message from the Linq API only. This does NOT unsend or remove the message\nfrom the actual chat — recipients will still see the message.\n\n\n### Parameters\n\n- `messageId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.messages.delete('69a37c7d-af4f-4b5e-af42-e28e98ce873a')\n```",
perLanguage: {
- go: {
- method: 'client.Messages.Delete',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Messages.Delete(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'messages.delete',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.messages.delete(\n "69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n)',
},
+ go: {
+ method: 'client.Messages.Delete',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Messages.Delete(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.messages.delete',
example:
@@ -784,16 +784,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## add_reaction\n\n`client.messages.addReaction(messageId: string, operation: 'add' | 'remove', type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker', custom_emoji?: string, part_index?: number): { message?: string; status?: string; trace_id?: string; }`\n\n**post** `/v3/messages/{messageId}/reactions`\n\nAdd or remove emoji reactions to messages. Reactions let users express\ntheir response to a message without sending a new message.\n\n**Supported Reactions:**\n- love ❤️\n- like 👍\n- dislike 👎\n- laugh 😂\n- emphasize ‼️\n- question ❓\n- custom - any emoji (use `custom_emoji` field to specify)\n\n\n### Parameters\n\n- `messageId: string`\n\n- `operation: 'add' | 'remove'`\n Whether to add or remove the reaction\n\n- `type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker'`\n Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question.\nCustom emoji reactions have type \"custom\" with the actual emoji in the custom_emoji field.\nSticker reactions have type \"sticker\" with sticker attachment details in the sticker field.\n\n\n- `custom_emoji?: string`\n Custom emoji string. Required when type is \"custom\".\n\n\n- `part_index?: number`\n Optional index of the message part to react to.\nIf not provided, reacts to the entire message (part 0).\n\n\n### Returns\n\n- `{ message?: string; status?: string; trace_id?: string; }`\n\n - `message?: string`\n - `status?: string`\n - `trace_id?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.messages.addReaction('69a37c7d-af4f-4b5e-af42-e28e98ce873a', { operation: 'add', type: 'love' });\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Messages.AddReaction',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n\t"github.com/linq-team/linq-go/shared"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Messages.AddReaction(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageAddReactionParams{\n\t\t\tOperation: linqgo.MessageAddReactionParamsOperationAdd,\n\t\t\tType: shared.ReactionTypeLove,\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
- },
python: {
method: 'messages.add_reaction',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.messages.add_reaction(\n message_id="69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n operation="add",\n type="love",\n)\nprint(response.trace_id)',
},
+ go: {
+ method: 'client.Messages.AddReaction',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n\t"github.com/linq-team/linq-go/shared"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Messages.AddReaction(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageAddReactionParams{\n\t\t\tOperation: linqgo.MessageAddReactionParamsOperationAdd,\n\t\t\tType: shared.ReactionTypeLove,\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.TraceID)\n}\n',
+ },
typescript: {
method: 'client.messages.addReaction',
example:
@@ -820,16 +820,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update\n\n`client.messages.update(messageId: string, text: string, part_index?: number): { id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: message_effect; from?: string; from_handle?: chat_handle; parts?: text_part_response | media_part_response | link_part_response | object[]; preferred_service?: service_type; read_at?: string; reply_to?: reply_to; sent_at?: string; service?: service_type; }`\n\n**patch** `/v3/messages/{messageId}`\n\nEdit the text content of a specific part of a previously sent message.\n\n**Note:** A message can be edited up to 5 times, and only within 15 minutes of when it was originally sent.\n\n\n### Parameters\n\n- `messageId: string`\n\n- `text: string`\n New text content for the message part\n\n- `part_index?: number`\n Index of the message part to edit. Defaults to 0.\n\n### Returns\n\n- `{ id: string; chat_id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_delivered: boolean; is_from_me: boolean; is_read: boolean; updated_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from?: string; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; parts?: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; read_at?: string; reply_to?: { message_id: string; part_index?: number; }; sent_at?: string; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n - `id: string`\n - `chat_id: string`\n - `created_at: string`\n - `delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'`\n - `is_delivered: boolean`\n - `is_from_me: boolean`\n - `is_read: boolean`\n - `updated_at: string`\n - `delivered_at?: string`\n - `effect?: { name?: string; type?: 'screen' | 'bubble'; }`\n - `from?: string`\n - `from_handle?: { id: string; handle: string; joined_at: string; service: 'iMessage' | 'SMS' | 'RCS'; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }`\n - `parts?: { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'text'; value: string; text_decorations?: { range: number[]; animation?: 'big' | 'small' | 'shake' | 'nod' | 'explode' | 'ripple' | 'bloom' | 'jitter'; style?: 'bold' | 'italic' | 'strikethrough' | 'underline'; }[]; } | { id: string; filename: string; mime_type: string; reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; size_bytes: number; type: 'media'; url: string; } | { reactions: { handle: chat_handle; is_me: boolean; type: reaction_type; custom_emoji?: string; sticker?: object; }[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: { handle: object; is_me: boolean; type: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | 'custom' | 'sticker'; custom_emoji?: string; sticker?: { file_name?: string; height?: number; mime_type?: string; url?: string; width?: number; }; }[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]`\n - `preferred_service?: 'iMessage' | 'SMS' | 'RCS'`\n - `read_at?: string`\n - `reply_to?: { message_id: string; part_index?: number; }`\n - `sent_at?: string`\n - `service?: 'iMessage' | 'SMS' | 'RCS'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst message = await client.messages.update('69a37c7d-af4f-4b5e-af42-e28e98ce873a', { text: 'This is the edited message content' });\n\nconsole.log(message);\n```",
perLanguage: {
- go: {
- method: 'client.Messages.Update',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.Update(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageUpdateParams{\n\t\t\tText: "This is the edited message content",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ID)\n}\n',
- },
python: {
method: 'messages.update',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nmessage = client.messages.update(\n message_id="69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n text="This is the edited message content",\n part_index=0,\n)\nprint(message.id)',
},
+ go: {
+ method: 'client.Messages.Update',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmessage, err := client.Messages.Update(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageUpdateParams{\n\t\t\tText: "This is the edited message content",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", message.ID)\n}\n',
+ },
typescript: {
method: 'client.messages.update',
example:
@@ -862,16 +862,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update_app_card\n\n`client.messages.updateAppCard(messageId: string, layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }, fallback_text?: string, interactive?: boolean, url?: string): { chat_id: string; message: sent_message; }`\n\n**post** `/v3/messages/{messageId}/update`\n\nReplaces a previously delivered `imessage_app` card on the recipient's screen with new\ncontent, instead of posting a new bubble (like a game move redrawing the board).\n\nThe update is delivered as a **new message** with its own id and delivery lifecycle\n(`message.sent` / `message.delivered` / `message.failed` webhooks fire for the new id).\nTo update the card again, reference the message id returned by this call.\n\nConstraints:\n- The referenced message must be an `imessage_app` card sent by you (`400` otherwise —\n inbound cards cannot be updated).\n- The referenced card must already be delivered (`409` otherwise — retry after the\n `message.delivered` webhook for it).\n- The app identity (`team_id`, `bundle_id`, name) is inherited from the original card and\n cannot change; only `url`, `fallback_text`, and `layout` are replaced.\n- iMessage-only, like all app cards.\n- Concurrent updates against the same card are not serialized server-side; the last one\n delivered wins on the recipient's screen. Serialize updates by always referencing the\n message id returned by the previous call.\n\n\n### Parameters\n\n- `messageId: string`\n\n- `layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }`\n Visible layout of the card. At least one of\n`caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be\nset, otherwise the card renders as an empty bubble.\n\n`image_url` displays a preview image at the top of the card. The image renders on the\nrecipient's card whether or not they have your app installed. The small icon beside the\ncaption is the app's own icon and is not settable here.\n\n`* Note - requires a trusted chat w/ inbound activity`\n\n`image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle\nbeneath it). They only appear when `image_url` is set — without an image there is nothing to\noverlay — so setting either without `image_url` is rejected.\n\n - `caption?: string`\n Primary label, top-left and bold.\n - `image_subtitle?: string`\n Text shown below `image_title`, overlaid on the card image. Requires `image_url`.\n - `image_title?: string`\n Bold text overlaid on the card image. Requires `image_url` (rejected without it).\n - `image_url?: string`\n URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.\n - `subcaption?: string`\n Secondary label, below `caption` on the left.\n - `trailing_caption?: string`\n Label shown top-right.\n - `trailing_subcaption?: string`\n Label shown below `trailing_caption`, on the right.\n\n- `fallback_text?: string`\n Text shown on surfaces that cannot render the card (notifications, lock screen). Defaults\nto the caption when omitted.\n\n\n- `interactive?: boolean`\n Whether the updated card renders as your app's interactive balloon for recipients who\nhave your iMessage app installed. `true` (default) lets your installed extension draw its\nlive view; `false` always shows the static `layout` card. Recipients without your app\nalways see the static card regardless of this flag.\n\nDefaults to `true` when omitted — it is **not** inherited from the original card. To keep a\ncard static across updates, re-send `interactive: false` on each update.\n\n\n- `url?: string`\n URL the recipient's app opens when they tap the updated card.\n\n\n### Returns\n\n- `{ chat_id: string; message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: text_part_response | media_part_response | link_part_response | object[]; sent_at: string; delivered_at?: string; effect?: message_effect; from_handle?: chat_handle; preferred_service?: service_type; reply_to?: reply_to; service?: service_type; }; }`\n Response for sending a message to a chat\n\n - `chat_id: string`\n - `message: { id: string; created_at: string; delivery_status: 'pending' | 'queued' | 'sent' | 'delivered' | 'received' | 'read' | 'failed'; is_read: boolean; parts: { reactions: reaction[]; type: 'text'; value: string; text_decorations?: text_decoration[]; } | { id: string; filename: string; mime_type: string; reactions: reaction[]; size_bytes: number; type: 'media'; url: string; } | { reactions: reaction[]; type: 'link'; value: string; } | { app: { bundle_id: string; name: string; team_id: string; app_store_id?: number; }; layout: { caption?: string; image_subtitle?: string; image_title?: string; image_url?: string; subcaption?: string; trailing_caption?: string; trailing_subcaption?: string; }; reactions: object[]; type: 'imessage_app'; url: string; fallback_text?: string; }[]; sent_at: string; delivered_at?: string; effect?: { name?: string; type?: 'screen' | 'bubble'; }; from_handle?: { id: string; handle: string; joined_at: string; service: service_type; is_me?: boolean; left_at?: string; status?: 'active' | 'left' | 'removed'; }; preferred_service?: 'iMessage' | 'SMS' | 'RCS'; reply_to?: { message_id: string; part_index?: number; }; service?: 'iMessage' | 'SMS' | 'RCS'; }`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst response = await client.messages.updateAppCard('69a37c7d-af4f-4b5e-af42-e28e98ce873a', { layout: {} });\n\nconsole.log(response);\n```",
perLanguage: {
- go: {
- method: 'client.Messages.UpdateAppCard',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Messages.UpdateAppCard(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageUpdateAppCardParams{\n\t\t\tLayout: linqgo.MessageUpdateAppCardParamsLayout{\n\t\t\t\tCaption: linqgo.String("Score: 2 – 1"),\n\t\t\t},\n\t\t\tFallbackText: linqgo.String("Score update"),\n\t\t\tURL: linqgo.String("https://app.example.com/card?game=7f3a&move=2"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ChatID)\n}\n',
- },
python: {
method: 'messages.update_app_card',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.messages.update_app_card(\n message_id="69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n layout={\n "caption": "Score: 2 – 1"\n },\n fallback_text="Score update",\n url="https://app.example.com/card?game=7f3a&move=2",\n)\nprint(response.chat_id)',
},
+ go: {
+ method: 'client.Messages.UpdateAppCard',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Messages.UpdateAppCard(\n\t\tcontext.TODO(),\n\t\t"69a37c7d-af4f-4b5e-af42-e28e98ce873a",\n\t\tlinqgo.MessageUpdateAppCardParams{\n\t\t\tLayout: linqgo.MessageUpdateAppCardParamsLayout{\n\t\t\t\tCaption: linqgo.String("Score: 2 – 1"),\n\t\t\t},\n\t\t\tFallbackText: linqgo.String("Score update"),\n\t\t\tURL: linqgo.String("https://app.example.com/card?game=7f3a&move=2"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ChatID)\n}\n',
+ },
typescript: {
method: 'client.messages.updateAppCard',
example:
@@ -896,18 +896,18 @@ const EMBEDDED_METHODS: MethodEntry[] = [
response:
"{ attachment_id: string; download_url: string; expires_at: string; http_method: 'PUT'; required_headers: object; upload_url: string; }",
markdown:
- '## create\n\n`client.attachments.create(content_type: string, filename: string, size_bytes: number): { attachment_id: string; download_url: string; expires_at: string; http_method: \'PUT\'; required_headers: object; upload_url: string; }`\n\n**post** `/v3/attachments`\n\n**This endpoint is optional.** You can send media by simply providing a URL in your\nmessage\'s media part — no pre-upload required. Use this endpoint only when you want\nto upload a file ahead of time for reuse or latency optimization.\n\nReturns a presigned upload URL and a permanent `attachment_id` you can reference\nin future messages.\n\n## Step 1: Request an upload URL\n\nCall this endpoint with file metadata:\n\n```json\nPOST /v3/attachments\n{\n "filename": "photo.jpg",\n "content_type": "image/jpeg",\n "size_bytes": 1024000\n}\n```\n\nThe response includes an `upload_url` (valid for 15 minutes) and a permanent `attachment_id`.\n\n## Step 2: Upload the file\n\nMake a PUT request to the `upload_url` with the raw file bytes as the request body.\nYou **must** include all headers from `required_headers` exactly as returned — the presigned URL\nis signed with these values and S3 will reject the upload if they don\'t match.\n\nThe request body is the binary file content — **not** JSON, **not** multipart form data.\nThe file must equal `size_bytes` bytes (the value you declared in step 1).\n\n```bash\ncurl -X PUT "" \\\n -H "Content-Type: image/jpeg" \\\n -H "Content-Length: 1024000" \\\n --data-binary @photo.jpg\n```\n\n## Step 3: Send a message with the attachment\n\nReference the `attachment_id` in a media part. The ID never expires — use it in as many messages as you want.\n\n```json\nPOST /v3/chats\n{\n "from": "+15559876543",\n "to": ["+15551234567"],\n "message": {\n "parts": [\n { "type": "media", "attachment_id": "" }\n ]\n }\n}\n```\n\n## When to use this instead of a URL in the media part\n\n- Sending the same file to multiple recipients (avoids re-downloading each time)\n- Large files where you want to separate upload from message send\n- Latency-sensitive sends where the file should already be stored\n\nIf you just need to send a file once, skip all of this and pass a `url` directly in the media part instead.\n\n**File Size Limit:** 100MB\n\n**Unsupported Types:** WebP, SVG, FLAC, OGG, and executable files are explicitly rejected.\n\n\n### Parameters\n\n- `content_type: string`\n Supported MIME types for file attachments and media URLs.\n\n**Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon\n\n**Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp\n\n**Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr\n\n**Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip\n\n**Transcoded on delivery:**\n- `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.\n\n**Deprecated (accepted but transcoded):**\n- `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.\n- `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.\n- `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.\n- `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.\n\n**Unsupported:** FLAC, OGG, and executable files are explicitly rejected.\n\n\n- `filename: string`\n Name of the file to upload\n\n- `size_bytes: number`\n Size of the file in bytes (max 100MB)\n\n### Returns\n\n- `{ attachment_id: string; download_url: string; expires_at: string; http_method: \'PUT\'; required_headers: object; upload_url: string; }`\n\n - `attachment_id: string`\n - `download_url: string`\n - `expires_at: string`\n - `http_method: \'PUT\'`\n - `required_headers: object`\n - `upload_url: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from \'@linqapp/sdk\';\n\nconst client = new LinqAPIV3();\n\nconst attachment = await client.attachments.create({\n content_type: \'image/jpeg\',\n filename: \'photo.jpg\',\n size_bytes: 1024000,\n});\n\nconsole.log(attachment);\n```',
+ '## create\n\n`client.attachments.create(content_type: string, filename: string, size_bytes: number): { attachment_id: string; download_url: string; expires_at: string; http_method: \'PUT\'; required_headers: object; upload_url: string; }`\n\n**post** `/v3/attachments`\n\n**This endpoint is optional.** You can send media by simply providing a URL in your\nmessage\'s media part — no pre-upload required. Use this endpoint only when you want\nto upload a file ahead of time for reuse or latency optimization.\n\nReturns a presigned upload URL and a permanent `attachment_id` you can reference\nin future messages.\n\n## Step 1: Request an upload URL\n\nCall this endpoint with file metadata:\n\n```json\nPOST /v3/attachments\n{\n "filename": "photo.jpg",\n "content_type": "image/jpeg",\n "size_bytes": 1024000\n}\n```\n\nThe response includes an `upload_url` (valid for 15 minutes) and a permanent `attachment_id`.\n\n## Step 2: Upload the file\n\nMake a PUT request to the `upload_url` with the raw file bytes as the request body.\nYou **must** include all headers from `required_headers` exactly as returned — the presigned URL\nis signed with these values and S3 will reject the upload if they don\'t match.\n\nThe request body is the binary file content — **not** JSON, **not** multipart form data.\nThe file must equal `size_bytes` bytes (the value you declared in step 1).\n\n```bash\ncurl -X PUT "" \\\n -H "Content-Type: image/jpeg" \\\n -H "Content-Length: 1024000" \\\n --data-binary @photo.jpg\n```\n\n## Step 3: Send a message with the attachment\n\nReference the `attachment_id` in a media part. The ID never expires — use it in as many messages as you want.\n\n```json\nPOST /v3/chats\n{\n "from": "+15559876543",\n "to": ["+15551234567"],\n "message": {\n "parts": [\n { "type": "media", "attachment_id": "" }\n ]\n }\n}\n```\n\n## When to use this instead of a URL in the media part\n\n- Sending the same file to multiple recipients (avoids re-downloading each time)\n- Large files where you want to separate upload from message send\n- Latency-sensitive sends where the file should already be stored\n\nIf you just need to send a file once, skip all of this and pass a `url` directly in the media part instead.\n\n**File Size Limit:** 100MB\n\n**Unsupported Types:** WebP, SVG, FLAC, OGG, and executable files are explicitly rejected.\n\n\n### Parameters\n\n- `content_type: string`\n Supported MIME types for file attachments and media URLs.\n\n**Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon\n\n**Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp\n\n**Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr\n\n**Wallet passes:** application/vnd.apple.pkpass\n\n**Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip\n\n**Transcoded on delivery:**\n- `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.\n\n**Deprecated (accepted but transcoded):**\n- `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.\n- `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.\n- `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.\n- `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.\n\n**Unsupported:** FLAC, OGG, and executable files are explicitly rejected.\n\n\n- `filename: string`\n Name of the file to upload\n\n- `size_bytes: number`\n Size of the file in bytes (max 100MB)\n\n### Returns\n\n- `{ attachment_id: string; download_url: string; expires_at: string; http_method: \'PUT\'; required_headers: object; upload_url: string; }`\n\n - `attachment_id: string`\n - `download_url: string`\n - `expires_at: string`\n - `http_method: \'PUT\'`\n - `required_headers: object`\n - `upload_url: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from \'@linqapp/sdk\';\n\nconst client = new LinqAPIV3();\n\nconst attachment = await client.attachments.create({\n content_type: \'image/jpeg\',\n filename: \'photo.jpg\',\n size_bytes: 1024000,\n});\n\nconsole.log(attachment);\n```',
perLanguage: {
- go: {
- method: 'client.Attachments.New',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tattachment, err := client.Attachments.New(context.TODO(), linqgo.AttachmentNewParams{\n\t\tContentType: linqgo.SupportedContentTypeImageJpeg,\n\t\tFilename: "photo.jpg",\n\t\tSizeBytes: 1024000,\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", attachment.AttachmentID)\n}\n',
- },
python: {
method: 'attachments.create',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nattachment = client.attachments.create(\n content_type="image/jpeg",\n filename="photo.jpg",\n size_bytes=1024000,\n)\nprint(attachment.attachment_id)',
},
+ go: {
+ method: 'client.Attachments.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tattachment, err := client.Attachments.New(context.TODO(), linqgo.AttachmentNewParams{\n\t\tContentType: linqgo.SupportedContentTypeImageJpeg,\n\t\tFilename: "photo.jpg",\n\t\tSizeBytes: 1024000,\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", attachment.AttachmentID)\n}\n',
+ },
typescript: {
method: 'client.attachments.create',
example:
@@ -934,16 +934,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## retrieve\n\n`client.attachments.retrieve(attachmentId: string): { id: string; content_type: supported_content_type; created_at: string; filename: string; size_bytes: number; status: 'pending' | 'complete' | 'failed'; download_url?: string; }`\n\n**get** `/v3/attachments/{attachmentId}`\n\nRetrieve metadata for a specific attachment including file\ninformation, and URLs for downloading.\n\n`status`: (**deprecated** — will be removed in a future API version)\n\n\n### Parameters\n\n- `attachmentId: string`\n\n### Returns\n\n- `{ id: string; content_type: string; created_at: string; filename: string; size_bytes: number; status: 'pending' | 'complete' | 'failed'; download_url?: string; }`\n\n - `id: string`\n - `content_type: string`\n - `created_at: string`\n - `filename: string`\n - `size_bytes: number`\n - `status: 'pending' | 'complete' | 'failed'`\n - `download_url?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst attachment = await client.attachments.retrieve('abc12345-1234-5678-9abc-def012345678');\n\nconsole.log(attachment);\n```",
perLanguage: {
- go: {
- method: 'client.Attachments.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tattachment, err := client.Attachments.Get(context.TODO(), "abc12345-1234-5678-9abc-def012345678")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", attachment.ID)\n}\n',
- },
python: {
method: 'attachments.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nattachment = client.attachments.retrieve(\n "abc12345-1234-5678-9abc-def012345678",\n)\nprint(attachment.id)',
},
+ go: {
+ method: 'client.Attachments.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tattachment, err := client.Attachments.Get(context.TODO(), "abc12345-1234-5678-9abc-def012345678")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", attachment.ID)\n}\n',
+ },
typescript: {
method: 'client.attachments.retrieve',
example:
@@ -967,17 +967,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## delete\n\n`client.attachments.delete(attachmentId: string): void`\n\n**delete** `/v3/attachments/{attachmentId}`\n\nPermanently delete an attachment owned by the authenticated partner.\n\n### Parameters\n\n- `attachmentId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.attachments.delete('abc12345-1234-5678-9abc-def012345678')\n```",
perLanguage: {
- go: {
- method: 'client.Attachments.Delete',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Attachments.Delete(context.TODO(), "abc12345-1234-5678-9abc-def012345678")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'attachments.delete',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.attachments.delete(\n "abc12345-1234-5678-9abc-def012345678",\n)',
},
- typescript: {
+ go: {
+ method: 'client.Attachments.Delete',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Attachments.Delete(context.TODO(), "abc12345-1234-5678-9abc-def012345678")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
+ typescript: {
method: 'client.attachments.delete',
example:
"import LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3({\n apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted\n});\n\nawait client.attachments.delete('abc12345-1234-5678-9abc-def012345678');",
@@ -1001,16 +1001,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list\n\n`client.phonenumbers.list(): { phone_numbers: object[]; }`\n\n**get** `/v3/phonenumbers`\n\n**Deprecated.** Use `GET /v3/phone_numbers` instead.\n\n\n### Returns\n\n- `{ phone_numbers: { id: string; phone_number: string; capabilities?: { mms: boolean; sms: boolean; voice: boolean; }; country_code?: string; type?: string; }[]; }`\n\n - `phone_numbers: { id: string; phone_number: string; capabilities?: { mms: boolean; sms: boolean; voice: boolean; }; country_code?: string; type?: string; }[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst phonenumbers = await client.phonenumbers.list();\n\nconsole.log(phonenumbers);\n```",
perLanguage: {
- go: {
- method: 'client.Phonenumbers.List',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphonenumbers, err := client.Phonenumbers.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phonenumbers.PhoneNumbers)\n}\n',
- },
python: {
method: 'phonenumbers.list',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nphonenumbers = client.phonenumbers.list()\nprint(phonenumbers.phone_numbers)',
},
+ go: {
+ method: 'client.Phonenumbers.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphonenumbers, err := client.Phonenumbers.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phonenumbers.PhoneNumbers)\n}\n',
+ },
typescript: {
method: 'client.phonenumbers.list',
example:
@@ -1032,20 +1032,20 @@ const EMBEDDED_METHODS: MethodEntry[] = [
stainlessPath: '(resource) phone_numbers > (method) list',
qualified: 'client.phoneNumbers.list',
response:
- "{ phone_numbers: { id: string; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]; }",
+ "{ phone_numbers: { id: string; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]; }",
markdown:
- "## list\n\n`client.phoneNumbers.list(): { phone_numbers: object[]; }`\n\n**get** `/v3/phone_numbers`\n\nReturns all phone numbers assigned to the authenticated partner.\nUse this endpoint to discover which phone numbers are available for\nuse as the `from` field when creating a chat, listing chats, or sending a voice memo.\n\n\n### Returns\n\n- `{ phone_numbers: { id: string; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]; }`\n\n - `phone_numbers: { id: string; health_status: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst phoneNumbers = await client.phoneNumbers.list();\n\nconsole.log(phoneNumbers);\n```",
+ "## list\n\n`client.phoneNumbers.list(): { phone_numbers: object[]; }`\n\n**get** `/v3/phone_numbers`\n\nReturns all phone numbers assigned to the authenticated partner.\nUse this endpoint to discover which phone numbers are available for\nuse as the `from` field when creating a chat, listing chats, or sending a voice memo.\n\n\n### Returns\n\n- `{ phone_numbers: { id: string; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]; }`\n\n - `phone_numbers: { id: string; phone_number: string; reputation: { doc_url: string; status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL'; }; forwarding_number?: string; }[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst phoneNumbers = await client.phoneNumbers.list();\n\nconsole.log(phoneNumbers);\n```",
perLanguage: {
- go: {
- method: 'client.PhoneNumbers.List',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphoneNumbers, err := client.PhoneNumbers.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phoneNumbers.PhoneNumbers)\n}\n',
- },
python: {
method: 'phone_numbers.list',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nphone_numbers = client.phone_numbers.list()\nprint(phone_numbers.phone_numbers)',
},
+ go: {
+ method: 'client.PhoneNumbers.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphoneNumbers, err := client.PhoneNumbers.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phoneNumbers.PhoneNumbers)\n}\n',
+ },
typescript: {
method: 'client.phoneNumbers.list',
example:
@@ -1071,16 +1071,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update\n\n`client.phoneNumbers.update(phoneNumberId: string, forwarding_number: string): { id: string; forwarding_number: string; phone_number: string; }`\n\n**put** `/v3/phone_numbers/{phoneNumberId}`\n\nUpdates the forwarding number for a phone number. The forwarding number is where inbound calls will be forwarded to.\n\nPass an empty string to clear the forwarding number.\n\n\n### Parameters\n\n- `phoneNumberId: string`\n\n- `forwarding_number: string`\n The forwarding number in E.164 format. Set to null or empty string to clear.\n\n\n### Returns\n\n- `{ id: string; forwarding_number: string; phone_number: string; }`\n\n - `id: string`\n - `forwarding_number: string`\n - `phone_number: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst phoneNumber = await client.phoneNumbers.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { forwarding_number: '+12025559999' });\n\nconsole.log(phoneNumber);\n```",
perLanguage: {
- go: {
- method: 'client.PhoneNumbers.Update',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphoneNumber, err := client.PhoneNumbers.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\tlinqgo.PhoneNumberUpdateParams{\n\t\t\tForwardingNumber: linqgo.String("+12025559999"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phoneNumber.ID)\n}\n',
- },
python: {
method: 'phone_numbers.update',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nphone_number = client.phone_numbers.update(\n phone_number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n forwarding_number="+12025559999",\n)\nprint(phone_number.id)',
},
+ go: {
+ method: 'client.PhoneNumbers.Update',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tphoneNumber, err := client.PhoneNumbers.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\tlinqgo.PhoneNumberUpdateParams{\n\t\t\tForwardingNumber: linqgo.String("+12025559999"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", phoneNumber.ID)\n}\n',
+ },
typescript: {
method: 'client.phoneNumbers.update',
example:
@@ -1098,24 +1098,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [
httpMethod: 'get',
summary: 'Get an available sending number',
description:
- 'Returns the best available line (E.164) to send from, applying smart\nnumber assignment. Optionally pass `to` recipients to make the choice\n"sticky" — reusing the line an existing chat with those recipients is\nalready on. Without `to`, the best healthy line is chosen.\n\nThis is advisory: it does not reserve the line or change selection state.\nPass the returned `phone_number` as `from` when you create the chat to\nguarantee the same line.\n\nAlso returns `vcf_url`: a time-limited link to a vCard (`.vcf`) for the\nchosen line, carrying its contact card (name/photo) with the chosen\nnumber as the primary `TEL` and the partner\'s other healthy lines as\nbackups. Share it with recipients so they can save the line as a contact.\n',
+ 'Returns the best available line (E.164) to send from, applying smart\nnumber assignment. Optionally pass `to` recipients to make the choice\n"sticky" — reusing the line an existing chat with those recipients is\nalready on. Without `to`, the best available line is chosen, always\npreferring lines with a healthier reputation.\n\nThis does not reserve the line. Without `to`, the least-recently-used\navailable line is returned — suggestions and your own sends (including\nan explicit `from` on chat creation) both count as use, so successive\ncalls cycle through your available lines and traffic spreads evenly.\nPass the returned `phone_number` as `from` when you create the chat to\nguarantee the same line.\n\nAlso returns `vcf_url`: a time-limited link to a vCard (`.vcf`) for the\nchosen line, carrying its contact card (name/photo) with the chosen\nnumber as the primary `TEL` and the partner\'s other available lines as\nbackups. Share it with recipients so they can save the line as a contact.\n',
stainlessPath: '(resource) available_number > (method) retrieve',
qualified: 'client.availableNumber.retrieve',
params: ['to?: string[];'],
response: '{ phone_number: string; vcf_url: string; }',
markdown:
- "## retrieve\n\n`client.availableNumber.retrieve(to?: string[]): { phone_number: string; vcf_url: string; }`\n\n**get** `/v3/available_number`\n\nReturns the best available line (E.164) to send from, applying smart\nnumber assignment. Optionally pass `to` recipients to make the choice\n\"sticky\" — reusing the line an existing chat with those recipients is\nalready on. Without `to`, the best healthy line is chosen.\n\nThis is advisory: it does not reserve the line or change selection state.\nPass the returned `phone_number` as `from` when you create the chat to\nguarantee the same line.\n\nAlso returns `vcf_url`: a time-limited link to a vCard (`.vcf`) for the\nchosen line, carrying its contact card (name/photo) with the chosen\nnumber as the primary `TEL` and the partner's other healthy lines as\nbackups. Share it with recipients so they can save the line as a contact.\n\n\n### Parameters\n\n- `to?: string[]`\n Recipient handles (E.164 or email) the message is destined for. When\nprovided, an existing chat with these recipients makes the choice\nsticky. Repeat the parameter for multiple recipients.\n\n\n### Returns\n\n- `{ phone_number: string; vcf_url: string; }`\n The line smart number assignment selected, plus a shareable vCard.\n\n - `phone_number: string`\n - `vcf_url: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst availableNumber = await client.availableNumber.retrieve();\n\nconsole.log(availableNumber);\n```",
+ "## retrieve\n\n`client.availableNumber.retrieve(to?: string[]): { phone_number: string; vcf_url: string; }`\n\n**get** `/v3/available_number`\n\nReturns the best available line (E.164) to send from, applying smart\nnumber assignment. Optionally pass `to` recipients to make the choice\n\"sticky\" — reusing the line an existing chat with those recipients is\nalready on. Without `to`, the best available line is chosen, always\npreferring lines with a healthier reputation.\n\nThis does not reserve the line. Without `to`, the least-recently-used\navailable line is returned — suggestions and your own sends (including\nan explicit `from` on chat creation) both count as use, so successive\ncalls cycle through your available lines and traffic spreads evenly.\nPass the returned `phone_number` as `from` when you create the chat to\nguarantee the same line.\n\nAlso returns `vcf_url`: a time-limited link to a vCard (`.vcf`) for the\nchosen line, carrying its contact card (name/photo) with the chosen\nnumber as the primary `TEL` and the partner's other available lines as\nbackups. Share it with recipients so they can save the line as a contact.\n\n\n### Parameters\n\n- `to?: string[]`\n Recipient handles (E.164 or email) the message is destined for. When\nprovided, an existing chat with these recipients makes the choice\nsticky. Repeat the parameter for multiple recipients.\n\n\n### Returns\n\n- `{ phone_number: string; vcf_url: string; }`\n The line smart number assignment selected, plus a shareable vCard.\n\n - `phone_number: string`\n - `vcf_url: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst availableNumber = await client.availableNumber.retrieve();\n\nconsole.log(availableNumber);\n```",
perLanguage: {
- go: {
- method: 'client.AvailableNumber.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tavailableNumber, err := client.AvailableNumber.Get(context.TODO(), linqgo.AvailableNumberGetParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", availableNumber.PhoneNumber)\n}\n',
- },
python: {
method: 'available_number.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\navailable_number = client.available_number.retrieve()\nprint(available_number.phone_number)',
},
+ go: {
+ method: 'client.AvailableNumber.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tavailableNumber, err := client.AvailableNumber.Get(context.TODO(), linqgo.AvailableNumberGetParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", availableNumber.PhoneNumber)\n}\n',
+ },
typescript: {
method: 'client.availableNumber.retrieve',
example:
@@ -1127,6 +1127,168 @@ const EMBEDDED_METHODS: MethodEntry[] = [
},
},
},
+ {
+ name: 'create',
+ endpoint: '/v3/payment_requests',
+ httpMethod: 'post',
+ summary: 'Create a payment request',
+ description:
+ "Creates a payment request and returns a `checkout_url` the recipient\nopens to pay with Apple Pay or card. Funds settle directly to your\nconnected Stripe account. A payment request is independent of any chat;\nto associate one with a chat for your records, store the chat id in\n`metadata`. Requires your connected account to be `charges_enabled`\n(returns `403` otherwise).\n\nSet `mode: subscription` with a recurring `price_id` from your connected\nStripe account to start an **auto-renewing subscription** instead of a\none-time charge — the recipient pays the first invoice at checkout and\nthe response's `stripe` object carries the customer and subscription ids\nfor the ongoing lifecycle in your own Stripe account. See the\n*Subscriptions* section of the tag overview.\n\nIn either mode, pass `customer_id` to attach the request to an\n**existing Customer** on your connected account instead of creating a\nnew one — see *Pre-created customers* in the tag overview.\n",
+ stainlessPath: '(resource) payment_requests > (method) create',
+ qualified: 'client.paymentRequests.create',
+ params: [
+ 'amount?: number;',
+ 'currency?: string;',
+ 'customer_id?: string;',
+ 'description?: string;',
+ 'from?: string;',
+ 'metadata?: object;',
+ "mode?: 'payment' | 'subscription';",
+ 'payer_handle?: string;',
+ 'price_id?: string;',
+ 'quantity?: number;',
+ "rail?: 'stripe' | 'natural';",
+ 'trial_end?: string;',
+ 'trial_period_days?: number;',
+ 'Idempotency-Key?: string;',
+ ],
+ response:
+ "{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }",
+ markdown:
+ "## create\n\n`client.paymentRequests.create(amount?: number, currency?: string, customer_id?: string, description?: string, from?: string, metadata?: object, mode?: 'payment' | 'subscription', payer_handle?: string, price_id?: string, quantity?: number, rail?: 'stripe' | 'natural', trial_end?: string, trial_period_days?: number, Idempotency-Key?: string): { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: object; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: object; trial_end?: string; updated_at?: string; }`\n\n**post** `/v3/payment_requests`\n\nCreates a payment request and returns a `checkout_url` the recipient\nopens to pay with Apple Pay or card. Funds settle directly to your\nconnected Stripe account. A payment request is independent of any chat;\nto associate one with a chat for your records, store the chat id in\n`metadata`. Requires your connected account to be `charges_enabled`\n(returns `403` otherwise).\n\nSet `mode: subscription` with a recurring `price_id` from your connected\nStripe account to start an **auto-renewing subscription** instead of a\none-time charge — the recipient pays the first invoice at checkout and\nthe response's `stripe` object carries the customer and subscription ids\nfor the ongoing lifecycle in your own Stripe account. See the\n*Subscriptions* section of the tag overview.\n\nIn either mode, pass `customer_id` to attach the request to an\n**existing Customer** on your connected account instead of creating a\nnew one — see *Pre-created customers* in the tag overview.\n\n\n### Parameters\n\n- `amount?: number`\n Amount to charge, in the currency's minor units (e.g. cents). Must be\nat least the payment provider's minimum (50 for `usd`). Required in\n`payment` mode; must be omitted in `subscription` mode (the amount\ncomes from the price).\n\n\n- `currency?: string`\n Three-letter ISO 4217 currency code. Only `usd` is currently\nsupported. Required in `payment` mode; must be omitted in\n`subscription` mode (the currency comes from the price).\n\n\n- `customer_id?: string`\n Optional id of an **existing Customer** on your connected Stripe\naccount (`cus_...`) to attach this request to, instead of a new\nCustomer being created. In `payment` mode the charge lands on that\ncustomer's payment history; in `subscription` mode the subscription\nis created on them. The customer must exist (and not be deleted) on\nyour connected account.\n\n\n- `description?: string`\n Optional description shown to the recipient at checkout.\n\n- `from?: string`\n Required for `rail: natural`. The line the request is sent from, in\nE.164 format. Must be a phone number your organization owns.\n\n\n- `metadata?: object`\n Optional key/value metadata (up to 49 keys) echoed back on retrieval\nand on `payment.*` webhooks, and stamped on the Stripe objects we\ncreate on your connected account (the PaymentIntent, and in\nsubscription mode the Subscription and any Customer created for\nyou — a customer you pass via `customer_id` is never modified) —\nuse it to correlate a request with your own records (e.g. a chat\nid). Keys starting with `linq_` are reserved.\n\n\n- `mode?: 'payment' | 'subscription'`\n `payment` (default) collects a one-time charge for `amount` +\n`currency`. `subscription` starts an auto-renewing subscription from\na recurring `price_id` on your connected Stripe account: the\nrecipient pays the first invoice at checkout and Stripe renews it\nautomatically from then on.\n\n- `payer_handle?: string`\n Required for `rail: natural`. The payer to bill, in E.164 format.\n\n\n- `price_id?: string`\n Subscription mode only (required there): id of an **active recurring\nPrice** on your connected Stripe account (`price_...`). If you sell\nthrough Stripe Payment Links today, pass the same price the link was\nbuilt from to get the native iMessage checkout for it.\n\n\n- `quantity?: number`\n Subscription mode only — units of the price to subscribe to.\n\n- `rail?: 'stripe' | 'natural'`\n Payment rail. `stripe` (default) is the direct-charge flow that\nsettles to your connected Stripe account. `natural` collects through\nthe Natural custodial wallet; it requires `from` + `payer_handle` and\nthat your organization has completed Natural merchant onboarding.\n\n- `trial_end?: string`\n Subscription mode only — end the free trial at a fixed timestamp\n(must be in the future) instead of a day count. Mutually exclusive\nwith `trial_period_days`.\n\n\n- `trial_period_days?: number`\n Subscription mode only — start with a free trial of this many days.\nThe recipient's card is still collected at checkout (Apple Pay or\ncard), saved to the subscription, and first charged when the trial\nends. Mutually exclusive with `trial_end`.\n\n\n- `Idempotency-Key?: string`\n\n### Returns\n\n- `{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }`\n\n - `id: string`\n - `amount: number`\n - `checkout_url: string`\n - `created_at: string`\n - `currency: string`\n - `mode: 'payment' | 'subscription'`\n - `object: string`\n - `status: 'requested' | 'succeeded' | 'canceled' | 'expired'`\n - `description?: string`\n - `expires_at?: string`\n - `interval?: 'day' | 'week' | 'month' | 'year'`\n - `interval_count?: number`\n - `metadata?: object`\n - `natural?: { payment_request_id?: string; transaction_id?: string; }`\n - `paid_at?: string`\n - `price_id?: string`\n - `quantity?: number`\n - `rail?: 'stripe' | 'natural'`\n - `stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }`\n - `trial_end?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst paymentRequest = await client.paymentRequests.create();\n\nconsole.log(paymentRequest);\n```",
+ perLanguage: {
+ python: {
+ method: 'payment_requests.create',
+ example:
+ 'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npayment_request = client.payment_requests.create(\n amount=497,\n currency="usd",\n description="Coffee with Ava",\n metadata={\n "order_id": "order_8675309"\n },\n)\nprint(payment_request.id)',
+ },
+ go: {
+ method: 'client.PaymentRequests.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpaymentRequest, err := client.PaymentRequests.New(context.TODO(), linqgo.PaymentRequestNewParams{\n\t\tAmount: linqgo.Int(497),\n\t\tCurrency: linqgo.String("usd"),\n\t\tDescription: linqgo.String("Coffee with Ava"),\n\t\tMetadata: map[string]string{\n\t\t\t"order_id": "order_8675309",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", paymentRequest.ID)\n}\n',
+ },
+ typescript: {
+ method: 'client.paymentRequests.create',
+ example:
+ "import LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3({\n apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted\n});\n\nconst paymentRequest = await client.paymentRequests.create({\n amount: 497,\n currency: 'usd',\n description: 'Coffee with Ava',\n metadata: { order_id: 'order_8675309' },\n});\n\nconsole.log(paymentRequest.id);",
+ },
+ http: {
+ example:
+ 'curl https://api.linqapp.com/api/partner/v3/payment_requests \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \\\n -d \'{\n "amount": 497,\n "currency": "usd",\n "customer_id": "cus_QAbCdEfGhIjKlMn",\n "description": "Coffee with Ava",\n "from": "+12025550123",\n "metadata": {\n "order_id": "order_8675309"\n },\n "payer_handle": "+12025550199",\n "price_id": "price_1QAbCdEfGhIjKlMn",\n "trial_period_days": 14\n }\'',
+ },
+ },
+ },
+ {
+ name: 'retrieve',
+ endpoint: '/v3/payment_requests/{paymentRequestId}',
+ httpMethod: 'get',
+ summary: 'Get a payment request',
+ description: "Returns a payment request's status and details.\n",
+ stainlessPath: '(resource) payment_requests > (method) retrieve',
+ qualified: 'client.paymentRequests.retrieve',
+ params: ['paymentRequestId: string;'],
+ response:
+ "{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }",
+ markdown:
+ "## retrieve\n\n`client.paymentRequests.retrieve(paymentRequestId: string): { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: object; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: object; trial_end?: string; updated_at?: string; }`\n\n**get** `/v3/payment_requests/{paymentRequestId}`\n\nReturns a payment request's status and details.\n\n\n### Parameters\n\n- `paymentRequestId: string`\n\n### Returns\n\n- `{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }`\n\n - `id: string`\n - `amount: number`\n - `checkout_url: string`\n - `created_at: string`\n - `currency: string`\n - `mode: 'payment' | 'subscription'`\n - `object: string`\n - `status: 'requested' | 'succeeded' | 'canceled' | 'expired'`\n - `description?: string`\n - `expires_at?: string`\n - `interval?: 'day' | 'week' | 'month' | 'year'`\n - `interval_count?: number`\n - `metadata?: object`\n - `natural?: { payment_request_id?: string; transaction_id?: string; }`\n - `paid_at?: string`\n - `price_id?: string`\n - `quantity?: number`\n - `rail?: 'stripe' | 'natural'`\n - `stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }`\n - `trial_end?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst paymentRequest = await client.paymentRequests.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(paymentRequest);\n```",
+ perLanguage: {
+ python: {
+ method: 'payment_requests.retrieve',
+ example:
+ 'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npayment_request = client.payment_requests.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(payment_request.id)',
+ },
+ go: {
+ method: 'client.PaymentRequests.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpaymentRequest, err := client.PaymentRequests.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", paymentRequest.ID)\n}\n',
+ },
+ typescript: {
+ method: 'client.paymentRequests.retrieve',
+ example:
+ "import LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3({\n apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted\n});\n\nconst paymentRequest = await client.paymentRequests.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(paymentRequest.id);",
+ },
+ http: {
+ example:
+ 'curl https://api.linqapp.com/api/partner/v3/payment_requests/$PAYMENT_REQUEST_ID \\\n -H "Authorization: Bearer $LINQ_API_V3_API_KEY"',
+ },
+ },
+ },
+ {
+ name: 'list',
+ endpoint: '/v3/payment_requests',
+ httpMethod: 'get',
+ summary: 'List payment requests',
+ description:
+ 'Lists your payment requests, newest first, for reconciliation. Paginate\nwith `limit` + `offset`; `has_more` indicates whether another page exists.\n',
+ stainlessPath: '(resource) payment_requests > (method) list',
+ qualified: 'client.paymentRequests.list',
+ params: [
+ 'limit?: number;',
+ 'offset?: number;',
+ "status?: 'requested' | 'succeeded' | 'canceled' | 'expired';",
+ ],
+ response:
+ "{ data: { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: object; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: object; trial_end?: string; updated_at?: string; }[]; has_more: boolean; object: 'list'; }",
+ markdown:
+ "## list\n\n`client.paymentRequests.list(limit?: number, offset?: number, status?: 'requested' | 'succeeded' | 'canceled' | 'expired'): { data: payment_request[]; has_more: boolean; object: 'list'; }`\n\n**get** `/v3/payment_requests`\n\nLists your payment requests, newest first, for reconciliation. Paginate\nwith `limit` + `offset`; `has_more` indicates whether another page exists.\n\n\n### Parameters\n\n- `limit?: number`\n Max results to return (default 20, max 100).\n\n- `offset?: number`\n Number of results to skip.\n\n- `status?: 'requested' | 'succeeded' | 'canceled' | 'expired'`\n Filter by lifecycle status.\n\n### Returns\n\n- `{ data: { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: object; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: object; trial_end?: string; updated_at?: string; }[]; has_more: boolean; object: 'list'; }`\n\n - `data: { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }[]`\n - `has_more: boolean`\n - `object: 'list'`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst paymentRequests = await client.paymentRequests.list();\n\nconsole.log(paymentRequests);\n```",
+ perLanguage: {
+ python: {
+ method: 'payment_requests.list',
+ example:
+ 'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npayment_requests = client.payment_requests.list()\nprint(payment_requests.data)',
+ },
+ go: {
+ method: 'client.PaymentRequests.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpaymentRequests, err := client.PaymentRequests.List(context.TODO(), linqgo.PaymentRequestListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", paymentRequests.Data)\n}\n',
+ },
+ typescript: {
+ method: 'client.paymentRequests.list',
+ example:
+ "import LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3({\n apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted\n});\n\nconst paymentRequests = await client.paymentRequests.list();\n\nconsole.log(paymentRequests.data);",
+ },
+ http: {
+ example:
+ 'curl https://api.linqapp.com/api/partner/v3/payment_requests \\\n -H "Authorization: Bearer $LINQ_API_V3_API_KEY"',
+ },
+ },
+ },
+ {
+ name: 'cancel',
+ endpoint: '/v3/payment_requests/{paymentRequestId}/cancel',
+ httpMethod: 'post',
+ summary: 'Cancel a payment request',
+ description:
+ 'Cancels an unpaid payment request: the underlying payment intent is\ncanceled and the request moves to `canceled`. A request that is already\npaid, canceled, or expired returns 409.\n',
+ stainlessPath: '(resource) payment_requests > (method) cancel',
+ qualified: 'client.paymentRequests.cancel',
+ params: ['paymentRequestId: string;'],
+ response:
+ "{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }",
+ markdown:
+ "## cancel\n\n`client.paymentRequests.cancel(paymentRequestId: string): { id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: object; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: object; trial_end?: string; updated_at?: string; }`\n\n**post** `/v3/payment_requests/{paymentRequestId}/cancel`\n\nCancels an unpaid payment request: the underlying payment intent is\ncanceled and the request moves to `canceled`. A request that is already\npaid, canceled, or expired returns 409.\n\n\n### Parameters\n\n- `paymentRequestId: string`\n\n### Returns\n\n- `{ id: string; amount: number; checkout_url: string; created_at: string; currency: string; mode: 'payment' | 'subscription'; object: string; status: 'requested' | 'succeeded' | 'canceled' | 'expired'; description?: string; expires_at?: string; interval?: 'day' | 'week' | 'month' | 'year'; interval_count?: number; metadata?: object; natural?: { payment_request_id?: string; transaction_id?: string; }; paid_at?: string; price_id?: string; quantity?: number; rail?: 'stripe' | 'natural'; stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }; trial_end?: string; updated_at?: string; }`\n\n - `id: string`\n - `amount: number`\n - `checkout_url: string`\n - `created_at: string`\n - `currency: string`\n - `mode: 'payment' | 'subscription'`\n - `object: string`\n - `status: 'requested' | 'succeeded' | 'canceled' | 'expired'`\n - `description?: string`\n - `expires_at?: string`\n - `interval?: 'day' | 'week' | 'month' | 'year'`\n - `interval_count?: number`\n - `metadata?: object`\n - `natural?: { payment_request_id?: string; transaction_id?: string; }`\n - `paid_at?: string`\n - `price_id?: string`\n - `quantity?: number`\n - `rail?: 'stripe' | 'natural'`\n - `stripe?: { customer_id?: string; payment_intent_id?: string; subscription_id?: string; }`\n - `trial_end?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst paymentRequest = await client.paymentRequests.cancel('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(paymentRequest);\n```",
+ perLanguage: {
+ python: {
+ method: 'payment_requests.cancel',
+ example:
+ 'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\npayment_request = client.payment_requests.cancel(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(payment_request.id)',
+ },
+ go: {
+ method: 'client.PaymentRequests.Cancel',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpaymentRequest, err := client.PaymentRequests.Cancel(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", paymentRequest.ID)\n}\n',
+ },
+ typescript: {
+ method: 'client.paymentRequests.cancel',
+ example:
+ "import LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3({\n apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted\n});\n\nconst paymentRequest = await client.paymentRequests.cancel('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(paymentRequest.id);",
+ },
+ http: {
+ example:
+ 'curl https://api.linqapp.com/api/partner/v3/payment_requests/$PAYMENT_REQUEST_ID/cancel \\\n -X POST \\\n -H "Authorization: Bearer $LINQ_API_V3_API_KEY"',
+ },
+ },
+ },
{
name: 'list',
endpoint: '/v3/webhook-events',
@@ -1140,16 +1302,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list\n\n`client.webhookEvents.list(): { doc_url: 'https://docs.linqapp.com/guides/webhooks/events'; events: webhook_event_type[]; }`\n\n**get** `/v3/webhook-events`\n\nReturns all available webhook event types that can be subscribed to.\nUse this endpoint to discover valid values for the `subscribed_events`\nfield when creating or updating webhook subscriptions.\n\n\n### Returns\n\n- `{ doc_url: 'https://docs.linqapp.com/guides/webhooks/events'; events: string[]; }`\n\n - `doc_url: 'https://docs.linqapp.com/guides/webhooks/events'`\n - `events: string[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst webhookEvents = await client.webhookEvents.list();\n\nconsole.log(webhookEvents);\n```",
perLanguage: {
- go: {
- method: 'client.WebhookEvents.List',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookEvents, err := client.WebhookEvents.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookEvents.DocURL)\n}\n',
- },
python: {
method: 'webhook_events.list',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nwebhook_events = client.webhook_events.list()\nprint(webhook_events.doc_url)',
},
+ go: {
+ method: 'client.WebhookEvents.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookEvents, err := client.WebhookEvents.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookEvents.DocURL)\n}\n',
+ },
typescript: {
method: 'client.webhookEvents.list',
example:
@@ -1176,16 +1338,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## create\n\n`client.webhookSubscriptions.create(subscribed_events: string[], target_url: string, phone_numbers?: string[]): { id: string; created_at: string; is_active: boolean; signing_secret: string; subscribed_events: webhook_event_type[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n\n**post** `/v3/webhook-subscriptions`\n\nCreate a new webhook subscription to receive events at a target URL.\nUpon creation, a signing secret is generated for verifying webhook\nauthenticity. **Store this secret securely — it cannot be retrieved later.**\n\n**Phone Number Filtering:**\n- Optionally specify `phone_numbers` to only receive events for specific lines\n- If omitted, events from all phone numbers are delivered (default behavior)\n- Use multiple subscriptions with different `phone_numbers` to route different lines to different endpoints\n- Each `target_url` can only be used once per account. To route different\n lines to different destinations, use a unique URL per subscription\n (e.g., append a query parameter: `https://example.com/webhook?line=1`)\n\n**Webhook Delivery:**\n- Events are sent via HTTP POST to the target URL\n- Each request includes [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks) headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) for signature verification\n- Legacy `X-Webhook-*` headers are also sent for backwards compatibility (deprecated)\n- See [Verifying Webhook Signatures](https://docs.linqapp.com/guides/webhooks#verifying-webhook-signatures) for verification details\n- Failed deliveries (5xx, 429, network errors) are retried up to 10 times over ~25 minutes with exponential backoff\n- Client errors (4xx except 429) are not retried\n\n\n### Parameters\n\n- `subscribed_events: string[]`\n List of event types to subscribe to\n\n- `target_url: string`\n URL where webhook events will be sent. Must be HTTPS.\n\n- `phone_numbers?: string[]`\n Optional list of phone numbers to filter events for. Only events originating from these phone numbers will be delivered to this subscription. If omitted or empty, events from all phone numbers are delivered. Phone numbers must be in E.164 format.\n\n### Returns\n\n- `{ id: string; created_at: string; is_active: boolean; signing_secret: string; subscribed_events: string[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n Response returned when creating a webhook subscription. Includes the signing secret which is only shown once.\n\n - `id: string`\n - `created_at: string`\n - `is_active: boolean`\n - `signing_secret: string`\n - `subscribed_events: string[]`\n - `target_url: string`\n - `updated_at: string`\n - `phone_numbers?: string[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst webhookSubscription = await client.webhookSubscriptions.create({ subscribed_events: ['message.sent', 'message.delivered', 'message.read'], target_url: 'https://webhooks.example.com/linq/events' });\n\nconsole.log(webhookSubscription);\n```",
perLanguage: {
- go: {
- method: 'client.WebhookSubscriptions.New',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.New(context.TODO(), linqgo.WebhookSubscriptionNewParams{\n\t\tSubscribedEvents: []linqgo.WebhookEventType{linqgo.WebhookEventTypeMessageSent, linqgo.WebhookEventTypeMessageDelivered, linqgo.WebhookEventTypeMessageRead},\n\t\tTargetURL: "https://webhooks.example.com/linq/events",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
- },
python: {
method: 'webhook_subscriptions.create',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nwebhook_subscription = client.webhook_subscriptions.create(\n subscribed_events=["message.sent", "message.delivered", "message.read"],\n target_url="https://webhooks.example.com/linq/events",\n)\nprint(webhook_subscription.id)',
},
+ go: {
+ method: 'client.WebhookSubscriptions.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.New(context.TODO(), linqgo.WebhookSubscriptionNewParams{\n\t\tSubscribedEvents: []linqgo.WebhookEventType{linqgo.WebhookEventTypeMessageSent, linqgo.WebhookEventTypeMessageDelivered, linqgo.WebhookEventTypeMessageRead},\n\t\tTargetURL: "https://webhooks.example.com/linq/events",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
+ },
typescript: {
method: 'client.webhookSubscriptions.create',
example:
@@ -1211,16 +1373,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## list\n\n`client.webhookSubscriptions.list(): { subscriptions: webhook_subscription[]; }`\n\n**get** `/v3/webhook-subscriptions`\n\nRetrieve all webhook subscriptions for the authenticated partner.\nReturns a list of active and inactive subscriptions with their\nconfiguration and status.\n\n\n### Returns\n\n- `{ subscriptions: { id: string; created_at: string; is_active: boolean; subscribed_events: webhook_event_type[]; target_url: string; updated_at: string; phone_numbers?: string[]; }[]; }`\n\n - `subscriptions: { id: string; created_at: string; is_active: boolean; subscribed_events: string[]; target_url: string; updated_at: string; phone_numbers?: string[]; }[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst webhookSubscriptions = await client.webhookSubscriptions.list();\n\nconsole.log(webhookSubscriptions);\n```",
perLanguage: {
- go: {
- method: 'client.WebhookSubscriptions.List',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscriptions, err := client.WebhookSubscriptions.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscriptions.Subscriptions)\n}\n',
- },
python: {
method: 'webhook_subscriptions.list',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nwebhook_subscriptions = client.webhook_subscriptions.list()\nprint(webhook_subscriptions.subscriptions)',
},
+ go: {
+ method: 'client.WebhookSubscriptions.List',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscriptions, err := client.WebhookSubscriptions.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscriptions.Subscriptions)\n}\n',
+ },
typescript: {
method: 'client.webhookSubscriptions.list',
example:
@@ -1247,16 +1409,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## retrieve\n\n`client.webhookSubscriptions.retrieve(subscriptionId: string): { id: string; created_at: string; is_active: boolean; subscribed_events: webhook_event_type[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n\n**get** `/v3/webhook-subscriptions/{subscriptionId}`\n\nRetrieve details for a specific webhook subscription including its\ntarget URL, subscribed events, and current status.\n\n\n### Parameters\n\n- `subscriptionId: string`\n\n### Returns\n\n- `{ id: string; created_at: string; is_active: boolean; subscribed_events: string[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n\n - `id: string`\n - `created_at: string`\n - `is_active: boolean`\n - `subscribed_events: string[]`\n - `target_url: string`\n - `updated_at: string`\n - `phone_numbers?: string[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst webhookSubscription = await client.webhookSubscriptions.retrieve('b2c3d4e5-f6a7-8901-bcde-f23456789012');\n\nconsole.log(webhookSubscription);\n```",
perLanguage: {
- go: {
- method: 'client.WebhookSubscriptions.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.Get(context.TODO(), "b2c3d4e5-f6a7-8901-bcde-f23456789012")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
- },
python: {
method: 'webhook_subscriptions.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nwebhook_subscription = client.webhook_subscriptions.retrieve(\n "b2c3d4e5-f6a7-8901-bcde-f23456789012",\n)\nprint(webhook_subscription.id)',
},
+ go: {
+ method: 'client.WebhookSubscriptions.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.Get(context.TODO(), "b2c3d4e5-f6a7-8901-bcde-f23456789012")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
+ },
typescript: {
method: 'client.webhookSubscriptions.retrieve',
example:
@@ -1289,16 +1451,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update\n\n`client.webhookSubscriptions.update(subscriptionId: string, is_active?: boolean, phone_numbers?: string[], subscribed_events?: string[], target_url?: string): { id: string; created_at: string; is_active: boolean; subscribed_events: webhook_event_type[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n\n**put** `/v3/webhook-subscriptions/{subscriptionId}`\n\nUpdate an existing webhook subscription. You can modify the target URL,\nsubscribed events, or activate/deactivate the subscription.\n\n**Note:** The signing secret cannot be changed via this endpoint.\n\n\n### Parameters\n\n- `subscriptionId: string`\n\n- `is_active?: boolean`\n Activate or deactivate the subscription\n\n- `phone_numbers?: string[]`\n Updated list of phone numbers to filter events for. Set to a non-empty array to filter events to specific phone numbers. Set to an empty array or null to remove the filter and receive events from all phone numbers. Phone numbers must be in E.164 format.\n\n- `subscribed_events?: string[]`\n Updated list of event types to subscribe to\n\n- `target_url?: string`\n New target URL for webhook events\n\n### Returns\n\n- `{ id: string; created_at: string; is_active: boolean; subscribed_events: string[]; target_url: string; updated_at: string; phone_numbers?: string[]; }`\n\n - `id: string`\n - `created_at: string`\n - `is_active: boolean`\n - `subscribed_events: string[]`\n - `target_url: string`\n - `updated_at: string`\n - `phone_numbers?: string[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst webhookSubscription = await client.webhookSubscriptions.update('b2c3d4e5-f6a7-8901-bcde-f23456789012');\n\nconsole.log(webhookSubscription);\n```",
perLanguage: {
- go: {
- method: 'client.WebhookSubscriptions.Update',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.Update(\n\t\tcontext.TODO(),\n\t\t"b2c3d4e5-f6a7-8901-bcde-f23456789012",\n\t\tlinqgo.WebhookSubscriptionUpdateParams{\n\t\t\tTargetURL: linqgo.String("https://webhooks.example.com/linq/events"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
- },
python: {
method: 'webhook_subscriptions.update',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nwebhook_subscription = client.webhook_subscriptions.update(\n subscription_id="b2c3d4e5-f6a7-8901-bcde-f23456789012",\n target_url="https://webhooks.example.com/linq/events",\n)\nprint(webhook_subscription.id)',
},
+ go: {
+ method: 'client.WebhookSubscriptions.Update',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\twebhookSubscription, err := client.WebhookSubscriptions.Update(\n\t\tcontext.TODO(),\n\t\t"b2c3d4e5-f6a7-8901-bcde-f23456789012",\n\t\tlinqgo.WebhookSubscriptionUpdateParams{\n\t\t\tTargetURL: linqgo.String("https://webhooks.example.com/linq/events"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", webhookSubscription.ID)\n}\n',
+ },
typescript: {
method: 'client.webhookSubscriptions.update',
example:
@@ -1322,16 +1484,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## delete\n\n`client.webhookSubscriptions.delete(subscriptionId: string): void`\n\n**delete** `/v3/webhook-subscriptions/{subscriptionId}`\n\nDelete a webhook subscription.\n\n### Parameters\n\n- `subscriptionId: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nawait client.webhookSubscriptions.delete('b2c3d4e5-f6a7-8901-bcde-f23456789012')\n```",
perLanguage: {
- go: {
- method: 'client.WebhookSubscriptions.Delete',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.WebhookSubscriptions.Delete(context.TODO(), "b2c3d4e5-f6a7-8901-bcde-f23456789012")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'webhook_subscriptions.delete',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.webhook_subscriptions.delete(\n "b2c3d4e5-f6a7-8901-bcde-f23456789012",\n)',
},
+ go: {
+ method: 'client.WebhookSubscriptions.Delete',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.WebhookSubscriptions.Delete(context.TODO(), "b2c3d4e5-f6a7-8901-bcde-f23456789012")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.webhookSubscriptions.delete',
example:
@@ -1356,16 +1518,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## check_imessage\n\n`client.capability.checkIMessage(address: string, from?: string): { address: string; available: boolean; }`\n\n**post** `/v3/capability/check_imessage`\n\nCheck whether a recipient address (phone number or email) is reachable via iMessage.\n\n\n### Parameters\n\n- `address: string`\n The recipient phone number or email address to check\n\n- `from?: string`\n Optional sender phone number. If omitted, an available phone from your pool is used automatically.\n\n### Returns\n\n- `{ address: string; available: boolean; }`\n\n - `address: string`\n - `available: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst handleCheckResponse = await client.capability.checkIMessage({ address: '+15551234567' });\n\nconsole.log(handleCheckResponse);\n```",
perLanguage: {
- go: {
- method: 'client.Capability.CheckIMessage',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\thandleCheckResponse, err := client.Capability.CheckIMessage(context.TODO(), linqgo.CapabilityCheckIMessageParams{\n\t\tHandleCheck: linqgo.HandleCheckParam{\n\t\t\tAddress: "+15551234567",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", handleCheckResponse.Address)\n}\n',
- },
python: {
method: 'capability.check_i_message',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nhandle_check_response = client.capability.check_i_message(\n address="+15551234567",\n)\nprint(handle_check_response.address)',
},
+ go: {
+ method: 'client.Capability.CheckIMessage',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\thandleCheckResponse, err := client.Capability.CheckIMessage(context.TODO(), linqgo.CapabilityCheckIMessageParams{\n\t\tHandleCheck: linqgo.HandleCheckParam{\n\t\t\tAddress: "+15551234567",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", handleCheckResponse.Address)\n}\n',
+ },
typescript: {
method: 'client.capability.checkIMessage',
example:
@@ -1390,16 +1552,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## check_rcs\n\n`client.capability.checkRCS(address: string, from?: string): { address: string; available: boolean; }`\n\n**post** `/v3/capability/check_rcs`\n\nCheck whether a recipient address (phone number) supports RCS messaging.\n\n\n### Parameters\n\n- `address: string`\n The recipient phone number or email address to check\n\n- `from?: string`\n Optional sender phone number. If omitted, an available phone from your pool is used automatically.\n\n### Returns\n\n- `{ address: string; available: boolean; }`\n\n - `address: string`\n - `available: boolean`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst handleCheckResponse = await client.capability.checkRCS({ address: '+15551234567' });\n\nconsole.log(handleCheckResponse);\n```",
perLanguage: {
- go: {
- method: 'client.Capability.CheckRCS',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\thandleCheckResponse, err := client.Capability.CheckRCS(context.TODO(), linqgo.CapabilityCheckRCSParams{\n\t\tHandleCheck: linqgo.HandleCheckParam{\n\t\t\tAddress: "+15551234567",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", handleCheckResponse.Address)\n}\n',
- },
python: {
method: 'capability.check_RCS',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nhandle_check_response = client.capability.check_RCS(\n address="+15551234567",\n)\nprint(handle_check_response.address)',
},
+ go: {
+ method: 'client.Capability.CheckRCS',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\thandleCheckResponse, err := client.Capability.CheckRCS(context.TODO(), linqgo.CapabilityCheckRCSParams{\n\t\tHandleCheck: linqgo.HandleCheckParam{\n\t\t\tAddress: "+15551234567",\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", handleCheckResponse.Address)\n}\n',
+ },
typescript: {
method: 'client.capability.checkRCS',
example:
@@ -1420,16 +1582,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
stainlessPath: '(resource) webhooks > (method) unwrap',
qualified: 'client.webhooks.unwrap',
perLanguage: {
- go: {
- method: 'client.Webhooks.Unwrap',
- example:
- 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Webhooks.Unwrap(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
- },
python: {
method: 'webhooks.unwrap',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nclient.webhooks.unwrap()',
},
+ go: {
+ method: 'client.Webhooks.Unwrap',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Webhooks.Unwrap(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n',
+ },
typescript: {
method: 'client.webhooks.unwrap',
example:
@@ -1452,16 +1614,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## retrieve\n\n`client.contactCard.retrieve(phone_number?: string): { contact_cards: object[]; }`\n\n**get** `/v3/contact_card`\n\nReturns the contact card for a specific phone number, or all contact cards for the\nauthenticated partner if no `phone_number` is provided.\n\n\n### Parameters\n\n- `phone_number?: string`\n E.164 phone number to filter by. If omitted, all my cards for the partner are returned.\n\n### Returns\n\n- `{ contact_cards: { first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }[]; }`\n\n - `contact_cards: { first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }[]`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst contactCard = await client.contactCard.retrieve();\n\nconsole.log(contactCard);\n```",
perLanguage: {
- go: {
- method: 'client.ContactCard.Get',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcontactCard, err := client.ContactCard.Get(context.TODO(), linqgo.ContactCardGetParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", contactCard.ContactCards)\n}\n',
- },
python: {
method: 'contact_card.retrieve',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\ncontact_card = client.contact_card.retrieve()\nprint(contact_card.contact_cards)',
},
+ go: {
+ method: 'client.ContactCard.Get',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcontactCard, err := client.ContactCard.Get(context.TODO(), linqgo.ContactCardGetParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", contactCard.ContactCards)\n}\n',
+ },
typescript: {
method: 'client.contactCard.retrieve',
example:
@@ -1488,16 +1650,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## create\n\n`client.contactCard.create(first_name: string, phone_number: string, image_url?: string, last_name?: string): { first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }`\n\n**post** `/v3/contact_card`\n\nCreates a contact card for a phone number. This endpoint is intended for initial, one-time setup only.\n\nThe contact card is stored in an inactive state first. Once it's applied successfully,\nit is activated and `is_active` is returned as `true`. On failure, `is_active` is `false`.\n\n**Note:** To update an existing contact card after setup, use `PATCH /v3/contact_card` instead.\n\n\n### Parameters\n\n- `first_name: string`\n First name for the contact card. Required.\n\n- `phone_number: string`\n E.164 phone number to associate the contact card with\n\n- `image_url?: string`\n Profile image URL for the contact card.\n\n- `last_name?: string`\n Last name for the contact card. Optional.\n\n### Returns\n\n- `{ first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }`\n\n - `first_name: string`\n - `is_active: boolean`\n - `phone_number: string`\n - `image_url?: string`\n - `last_name?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst setContactCard = await client.contactCard.create({ first_name: 'Acme', phone_number: '+15551234567' });\n\nconsole.log(setContactCard);\n```",
perLanguage: {
- go: {
- method: 'client.ContactCard.New',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tsetContactCard, err := client.ContactCard.New(context.TODO(), linqgo.ContactCardNewParams{\n\t\tFirstName: "Acme",\n\t\tPhoneNumber: "+15551234567",\n\t\tImageURL: linqgo.String("https://cdn.linqapp.com/contact-card/example.jpg"),\n\t\tLastName: linqgo.String("Support"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", setContactCard.FirstName)\n}\n',
- },
python: {
method: 'contact_card.create',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nset_contact_card = client.contact_card.create(\n first_name="Acme",\n phone_number="+15551234567",\n image_url="https://cdn.linqapp.com/contact-card/example.jpg",\n last_name="Support",\n)\nprint(set_contact_card.first_name)',
},
+ go: {
+ method: 'client.ContactCard.New',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tsetContactCard, err := client.ContactCard.New(context.TODO(), linqgo.ContactCardNewParams{\n\t\tFirstName: "Acme",\n\t\tPhoneNumber: "+15551234567",\n\t\tImageURL: linqgo.String("https://cdn.linqapp.com/contact-card/example.jpg"),\n\t\tLastName: linqgo.String("Support"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", setContactCard.FirstName)\n}\n',
+ },
typescript: {
method: 'client.contactCard.create',
example:
@@ -1524,16 +1686,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [
markdown:
"## update\n\n`client.contactCard.update(phone_number: string, first_name?: string, image_url?: string, last_name?: string): { first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }`\n\n**patch** `/v3/contact_card`\n\nPartially updates an existing active contact card for a phone number.\n\nFetches the current active contact card and merges the provided fields.\nOnly fields present in the request body are updated; omitted fields retain their existing values.\n\nRequires an active contact card to exist for the phone number.\n\n\n### Parameters\n\n- `phone_number: string`\n E.164 phone number of the contact card to update\n\n- `first_name?: string`\n Updated first name. If omitted, the existing value is kept.\n\n- `image_url?: string`\n Updated profile image URL. If omitted, the existing image is kept.\n\n- `last_name?: string`\n Updated last name. If omitted, the existing value is kept.\n\n### Returns\n\n- `{ first_name: string; is_active: boolean; phone_number: string; image_url?: string; last_name?: string; }`\n\n - `first_name: string`\n - `is_active: boolean`\n - `phone_number: string`\n - `image_url?: string`\n - `last_name?: string`\n\n### Example\n\n```typescript\nimport LinqAPIV3 from '@linqapp/sdk';\n\nconst client = new LinqAPIV3();\n\nconst setContactCard = await client.contactCard.update({ phone_number: '+15551234567' });\n\nconsole.log(setContactCard);\n```",
perLanguage: {
- go: {
- method: 'client.ContactCard.Update',
- example:
- 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tsetContactCard, err := client.ContactCard.Update(context.TODO(), linqgo.ContactCardUpdateParams{\n\t\tPhoneNumber: "+15551234567",\n\t\tFirstName: linqgo.String("John"),\n\t\tImageURL: linqgo.String("https://cdn.linqapp.com/contact-card/example.jpg"),\n\t\tLastName: linqgo.String("Doe"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", setContactCard.FirstName)\n}\n',
- },
python: {
method: 'contact_card.update',
example:
'import os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\nset_contact_card = client.contact_card.update(\n phone_number="+15551234567",\n first_name="John",\n image_url="https://cdn.linqapp.com/contact-card/example.jpg",\n last_name="Doe",\n)\nprint(set_contact_card.first_name)',
},
+ go: {
+ method: 'client.ContactCard.Update',
+ example:
+ 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tsetContactCard, err := client.ContactCard.Update(context.TODO(), linqgo.ContactCardUpdateParams{\n\t\tPhoneNumber: "+15551234567",\n\t\tFirstName: linqgo.String("John"),\n\t\tImageURL: linqgo.String("https://cdn.linqapp.com/contact-card/example.jpg"),\n\t\tLastName: linqgo.String("Doe"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", setContactCard.FirstName)\n}\n',
+ },
typescript: {
method: 'client.contactCard.update',
example:
@@ -1549,14 +1711,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [
const EMBEDDED_READMES: { language: string; content: string }[] = [
{
- language: 'go',
+ language: 'python',
content:
- '# Linq API V3 Go API Library\n\n
\n\nThe Linq API V3 Go library provides convenient access to the [Linq API V3 REST API](https://docs.linqapp.com)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)\n[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/linq-team/linq-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/linq-team/linq-go@v0.26.0\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("LINQ_API_V3_API_KEY")\n\t)\n\tchat, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.Chat)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chats.New(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/linq-team/linq-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Chats.ListChatsAutoPaging(context.TODO(), linqgo.ChatListChatsParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tchat := iter.Current()\n\tfmt.Printf("%+v\\n", chat)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Chats.ListChats(context.TODO(), linqgo.ChatListChatsParams{})\nfor page != nil {\n\tfor _, chat := range page.Chats {\n\t\tfmt.Printf("%+v\\n", chat)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\tFrom: "+12052535597",\n\tMessage: linqgo.MessageContentParam{\n\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t},\n\t\t}},\n\t},\n\tTo: []string{"+12052532136"},\n})\nif err != nil {\n\tvar apierr *linqgo.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v3/chats": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chats.New(\n\tctx,\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := linqgo.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chats.New(\n\tcontext.TODO(),\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchat, err := client.Chats.New(\n\tcontext.TODO(),\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chat)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/linq-team/linq-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n',
+ '# Linq API V3 Python API library\n\n\n[)](https://pypi.org/project/linq-python/)\n\nThe Linq API V3 Python library provides convenient access to the Linq API V3 REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)\n[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [docs.linqapp.com](https://docs.linqapp.com). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install linq-python\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\n\nchat = client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(chat.chat)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `LINQ_API_V3_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncLinqAPIV3` instead of `LinqAPIV3` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom linq import AsyncLinqAPIV3\n\nclient = AsyncLinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat = await client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\n print(chat.chat)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install linq-python[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom linq import DefaultAioHttpClient\nfrom linq import AsyncLinqAPIV3\n\nasync def main() -> None:\n async with AsyncLinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat = await client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\n print(chat.chat)\n\nasyncio.run(main())\n```\n\n\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Linq API V3 API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\nall_chats = []\n# Automatically fetches more pages as needed.\nfor chat in client.chats.list_chats():\n # Do something with chat here\n all_chats.append(chat)\nprint(all_chats)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom linq import AsyncLinqAPIV3\n\nclient = AsyncLinqAPIV3()\n\nasync def main() -> None:\n all_chats = []\n # Iterate through items across all pages, issuing requests as needed.\n async for chat in client.chats.list_chats():\n all_chats.append(chat)\n print(all_chats)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.chats.list_chats()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.chats)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.chats.list_chats()\n\nprint(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..."\nfor chat in first_page.chats:\n print(chat.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\nchat = client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(chat.message)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `linq.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `linq.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `linq.APIError`.\n\n```python\nimport linq\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\ntry:\n client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\nexcept linq.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept linq.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept linq.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom linq import LinqAPIV3\n\n# Configure the default for all requests:\nclient = LinqAPIV3(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\n```\n\n### Timeouts\n\nBy default requests time out after 1 minute. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom linq import LinqAPIV3\n\n# Configure the default for all requests:\nclient = LinqAPIV3(\n # 20 seconds (default is 1 minute)\n timeout=20.0,\n)\n\n# More granular control:\nclient = LinqAPIV3(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `LINQ_API_V3_LOG` to `info`.\n\n```shell\n$ export LINQ_API_V3_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\nresponse = client.chats.with_raw_response.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chats.create()` would have returned\nprint(chat.chat)\n```\n\nThese methods return an [`APIResponse`](https://github.com/linq-team/linq-python/tree/main/src/linq/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/linq-team/linq-python/tree/main/src/linq/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chats.with_streaming_response.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom linq import LinqAPIV3, DefaultHttpxClient\n\nclient = LinqAPIV3(\n # Or use the `LINQ_API_V3_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom linq import LinqAPIV3\n\nwith LinqAPIV3() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/linq-team/linq-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport linq\nprint(linq.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n',
},
{
- language: 'python',
+ language: 'go',
content:
- '# Linq API V3 Python API library\n\n\n[)](https://pypi.org/project/linq-python/)\n\nThe Linq API V3 Python library provides convenient access to the Linq API V3 REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)\n[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [docs.linqapp.com](https://docs.linqapp.com). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install linq-python\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\n\nchat = client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(chat.chat)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `LINQ_API_V3_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncLinqAPIV3` instead of `LinqAPIV3` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom linq import AsyncLinqAPIV3\n\nclient = AsyncLinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat = await client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\n print(chat.chat)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install linq-python[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom linq import DefaultAioHttpClient\nfrom linq import AsyncLinqAPIV3\n\nasync def main() -> None:\n async with AsyncLinqAPIV3(\n api_key=os.environ.get("LINQ_API_V3_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat = await client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\n print(chat.chat)\n\nasyncio.run(main())\n```\n\n\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Linq API V3 API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\nall_chats = []\n# Automatically fetches more pages as needed.\nfor chat in client.chats.list_chats():\n # Do something with chat here\n all_chats.append(chat)\nprint(all_chats)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom linq import AsyncLinqAPIV3\n\nclient = AsyncLinqAPIV3()\n\nasync def main() -> None:\n all_chats = []\n # Iterate through items across all pages, issuing requests as needed.\n async for chat in client.chats.list_chats():\n all_chats.append(chat)\n print(all_chats)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.chats.list_chats()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.chats)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.chats.list_chats()\n\nprint(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..."\nfor chat in first_page.chats:\n print(chat.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\nchat = client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(chat.message)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `linq.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `linq.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `linq.APIError`.\n\n```python\nimport linq\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\n\ntry:\n client.chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n )\nexcept linq.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept linq.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept linq.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom linq import LinqAPIV3\n\n# Configure the default for all requests:\nclient = LinqAPIV3(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\n```\n\n### Timeouts\n\nBy default requests time out after 1 minute. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom linq import LinqAPIV3\n\n# Configure the default for all requests:\nclient = LinqAPIV3(\n # 20 seconds (default is 1 minute)\n timeout=20.0,\n)\n\n# More granular control:\nclient = LinqAPIV3(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chats.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `LINQ_API_V3_LOG` to `info`.\n\n```shell\n$ export LINQ_API_V3_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom linq import LinqAPIV3\n\nclient = LinqAPIV3()\nresponse = client.chats.with_raw_response.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chats.create()` would have returned\nprint(chat.chat)\n```\n\nThese methods return an [`APIResponse`](https://github.com/linq-team/linq-python/tree/main/src/linq/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/linq-team/linq-python/tree/main/src/linq/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chats.with_streaming_response.create(\n from_="+12052535597",\n message={\n "parts": [{\n "type": "text",\n "value": "Hello! How can I help you today?",\n }]\n },\n to=["+12052532136"],\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom linq import LinqAPIV3, DefaultHttpxClient\n\nclient = LinqAPIV3(\n # Or use the `LINQ_API_V3_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom linq import LinqAPIV3\n\nwith LinqAPIV3() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/linq-team/linq-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport linq\nprint(linq.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n',
+ '# Linq API V3 Go API Library\n\n
\n\nThe Linq API V3 Go library provides convenient access to the [Linq API V3 REST API](https://docs.linqapp.com)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Linq API V3 MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[](https://cursor.com/en-US/install-mcp?name=%40linqapp%2Fsdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBsaW5xYXBwL3Nkay1tY3AiXSwiZW52Ijp7IkxJTlFfQVBJX1YzX0FQSV9LRVkiOiJNeSBBUEkgS2V5IiwiTElOUV9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19)\n[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40linqapp%2Fsdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40linqapp%2Fsdk-mcp%22%5D%2C%22env%22%3A%7B%22LINQ_API_V3_API_KEY%22%3A%22My%20API%20Key%22%2C%22LINQ_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/linq-team/linq-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/linq-team/linq-go@v0.26.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/linq-team/linq-go"\n\t"github.com/linq-team/linq-go/option"\n)\n\nfunc main() {\n\tclient := linqgo.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("LINQ_API_V3_API_KEY")\n\t)\n\tchat, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chat.Chat)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chats.New(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/linq-team/linq-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Chats.ListChatsAutoPaging(context.TODO(), linqgo.ChatListChatsParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tchat := iter.Current()\n\tfmt.Printf("%+v\\n", chat)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Chats.ListChats(context.TODO(), linqgo.ChatListChatsParams{})\nfor page != nil {\n\tfor _, chat := range page.Chats {\n\t\tfmt.Printf("%+v\\n", chat)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chats.New(context.TODO(), linqgo.ChatNewParams{\n\tFrom: "+12052535597",\n\tMessage: linqgo.MessageContentParam{\n\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t},\n\t\t}},\n\t},\n\tTo: []string{"+12052532136"},\n})\nif err != nil {\n\tvar apierr *linqgo.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v3/chats": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chats.New(\n\tctx,\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := linqgo.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chats.New(\n\tcontext.TODO(),\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchat, err := client.Chats.New(\n\tcontext.TODO(),\n\tlinqgo.ChatNewParams{\n\t\tFrom: "+12052535597",\n\t\tMessage: linqgo.MessageContentParam{\n\t\t\tParts: []linqgo.MessageContentPartUnionParam{{\n\t\t\t\tOfText: &linqgo.TextPartParam{\n\t\t\t\t\tType: linqgo.TextPartTypeText,\n\t\t\t\t\tValue: "Hello! How can I help you today?",\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t\tTo: []string{"+12052532136"},\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chat)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/linq-team/linq-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n',
},
{
language: 'typescript',
diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts
index b2e5e3d..53412f3 100644
--- a/packages/mcp-server/src/methods.ts
+++ b/packages/mcp-server/src/methods.ts
@@ -190,6 +190,30 @@ export const sdkMethods: SdkMethod[] = [
httpMethod: 'get',
httpPath: '/v3/available_number',
},
+ {
+ clientCallName: 'client.paymentRequests.create',
+ fullyQualifiedName: 'paymentRequests.create',
+ httpMethod: 'post',
+ httpPath: '/v3/payment_requests',
+ },
+ {
+ clientCallName: 'client.paymentRequests.retrieve',
+ fullyQualifiedName: 'paymentRequests.retrieve',
+ httpMethod: 'get',
+ httpPath: '/v3/payment_requests/{paymentRequestId}',
+ },
+ {
+ clientCallName: 'client.paymentRequests.list',
+ fullyQualifiedName: 'paymentRequests.list',
+ httpMethod: 'get',
+ httpPath: '/v3/payment_requests',
+ },
+ {
+ clientCallName: 'client.paymentRequests.cancel',
+ fullyQualifiedName: 'paymentRequests.cancel',
+ httpMethod: 'post',
+ httpPath: '/v3/payment_requests/{paymentRequestId}/cancel',
+ },
{
clientCallName: 'client.webhookEvents.list',
fullyQualifiedName: 'webhookEvents.list',
diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts
index c5c8a9f..121f803 100644
--- a/packages/mcp-server/src/server.ts
+++ b/packages/mcp-server/src/server.ts
@@ -28,7 +28,7 @@ export const newMcpServer = async ({
new McpServer(
{
name: 'linqapp_sdk_api',
- version: '0.28.0',
+ version: '0.28.2',
},
{
instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }),
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a588c59..4463f97 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,8 +15,8 @@ importers:
version: 1.0.0
devDependencies:
'@arethetypeswrong/cli':
- specifier: ^0.17.0
- version: 0.17.0
+ specifier: ^0.18.0
+ version: 0.18.4
'@swc/core':
specifier: ^1.3.102
version: 1.4.16
@@ -101,9 +101,6 @@ importers:
cors:
specifier: ^2.8.5
version: 2.8.5
- deno:
- specifier: ^2.9.1
- version: 2.9.1
express:
specifier: ^5.1.0
version: 5.2.1
@@ -219,20 +216,20 @@ packages:
}
hasBin: true
- '@arethetypeswrong/cli@0.17.0':
+ '@arethetypeswrong/cli@0.18.4':
resolution:
{
- integrity: sha512-xSMW7bfzVWpYw5JFgZqBXqr6PdR0/REmn3DkxCES5N0JTcB0CVgbIynJCvKBFmXaPc3hzmmTrb7+yPDRoOSZdA==,
+ integrity: sha512-kNWo6LTzGAuLYPpJ7Sgo63whSUeeSuKMlYx6IBgzs4ONEG807gW4hSSENvpeCHzO2H2wIzG5EFl0OKBbqGBAyA==,
}
- engines: { node: '>=18' }
+ engines: { node: '>=20' }
hasBin: true
- '@arethetypeswrong/core@0.17.0':
+ '@arethetypeswrong/core@0.18.4':
resolution:
{
- integrity: sha512-FHyhFizXNetigTVsIhqXKGYLpazPS5YNojEPpZEUcBPt9wVvoEbNIvG+hybuBR+pjlRcbyuqhukHZm1fr+bDgA==,
+ integrity: sha512-M5F0ePyN6h2Z6XxRiyIPqjGbltotXLjR0CKA0uKspsDu0QmgTNYvRb4RSQPMUs2ZXZHCCYpbaZbFbYOXLxCjUA==,
}
- engines: { node: '>=18' }
+ engines: { node: '>=20' }
'@babel/code-frame@7.28.6':
resolution:
@@ -504,6 +501,12 @@ packages:
integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==,
}
+ '@braidai/lang@1.1.2':
+ resolution:
+ {
+ integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==,
+ }
+
'@cloudflare/cabidela@0.2.4':
resolution:
{
@@ -531,38 +534,6 @@ packages:
}
engines: { node: '>=12' }
- '@deno/darwin-arm64@2.9.1':
- resolution: {integrity: sha512-aIRpWGuy8CDFKsxVqq//77ftRGnkxvvah0qqAgTVTFV0L5f7PQEzspBmvuxPZzHJS86tcwiCXqRLlt+BY8SqtQ==}
- cpu: [arm64]
- os: [darwin]
-
- '@deno/darwin-x64@2.9.1':
- resolution: {integrity: sha512-a3OiVR+uKnJRy9U+ByAHgqQQG1WSXe3udl76/ZMTuQM32GT8qiJLKQPx5QjpGDVFqaxWU64JNtpGv383/wVoRQ==}
- cpu: [x64]
- os: [darwin]
-
- '@deno/linux-arm64-glibc@2.9.1':
- resolution: {integrity: sha512-D/ye7zmd3uzl2eB/k25+gEepqJEOl6/xrmKA06pgyfyOSjePUfPHYDs/kvIZ0P97Fu/M/HdH3+OzC8ZQiiVDww==}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@deno/linux-x64-glibc@2.9.1':
- resolution: {integrity: sha512-6lYd+mnFXPguzTQiPkFgxQIUijIQtRH5oYhsT4aKIET3tuJh/8YlaSoqCtSK8DQIpyJPrLwdUlSpOaSHdsEr8w==}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@deno/win32-arm64@2.9.1':
- resolution: {integrity: sha512-lEqIMBHzrcXjmNIEhte5wKyM07BgJqqytae0q/9cgwXVvtm7JPGQOzVx6VYLWJ8H4XazqVWGViB6mDi/r0yWQQ==}
- cpu: [arm64]
- os: [win32]
-
- '@deno/win32-x64@2.9.1':
- resolution: {integrity: sha512-U0LZnDMUObQ6oVgDk1yAc3IcckFL33801EEoK5r/JLNEY/fxZIH5ib5edXj3E5oVNxa+b3z8sF/89qnSp/n+Yg==}
- cpu: [x64]
- os: [win32]
-
'@eslint-community/eslint-utils@4.4.0':
resolution:
{
@@ -951,6 +922,12 @@ packages:
integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==,
}
+ '@loaderkit/resolve@1.0.6':
+ resolution:
+ {
+ integrity: sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==,
+ }
+
'@modelcontextprotocol/sdk@1.27.1':
resolution:
{
@@ -2005,10 +1982,6 @@ packages:
}
engines: { node: '>=0.10.0' }
- deno@2.9.1:
- resolution: {integrity: sha512-2nzFWNVGtg4W4BmCpYJE9bTRPHcqdpfV+NJ5+xe6nqtaiSMtzr2NwFkhMtWjyLboNh6FsEEESk5TYNyBkHJ96g==}
- hasBin: true
-
depd@2.0.0:
resolution:
{
@@ -2407,6 +2380,12 @@ packages:
integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==,
}
+ fflate@0.8.3:
+ resolution:
+ {
+ integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==,
+ }
+
file-entry-cache@8.0.0:
resolution:
{
@@ -3273,11 +3252,12 @@ packages:
integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==,
}
- lru-cache@10.4.3:
+ lru-cache@11.5.2:
resolution:
{
- integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==,
+ integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==,
}
+ engines: { node: 20 || >=22 }
lru-cache@5.1.1:
resolution:
@@ -4746,23 +4726,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@arethetypeswrong/cli@0.17.0':
+ '@arethetypeswrong/cli@0.18.4':
dependencies:
- '@arethetypeswrong/core': 0.17.0
+ '@arethetypeswrong/core': 0.18.4
chalk: 4.1.2
cli-table3: 0.6.5
commander: 10.0.1
marked: 9.1.6
marked-terminal: 7.2.1(marked@9.1.6)
- semver: 7.7.1
+ semver: 7.7.3
- '@arethetypeswrong/core@0.17.0':
+ '@arethetypeswrong/core@0.18.4':
dependencies:
'@andrewbranch/untar.js': 1.0.3
+ '@loaderkit/resolve': 1.0.6
cjs-module-lexer: 1.4.1
- fflate: 0.8.2
- lru-cache: 10.4.3
- semver: 7.7.1
+ fflate: 0.8.3
+ lru-cache: 11.5.2
+ semver: 7.7.3
typescript: 5.6.1-rc
validate-npm-package-name: 5.0.1
@@ -4955,6 +4936,8 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
+ '@braidai/lang@1.1.2': {}
+
'@cloudflare/cabidela@0.2.4': {}
'@colors/colors@1.5.0':
@@ -4966,24 +4949,6 @@ snapshots:
dependencies:
'@cspotcode/source-map-consumer': 0.8.0
- '@deno/darwin-arm64@2.9.1':
- optional: true
-
- '@deno/darwin-x64@2.9.1':
- optional: true
-
- '@deno/linux-arm64-glibc@2.9.1':
- optional: true
-
- '@deno/linux-x64-glibc@2.9.1':
- optional: true
-
- '@deno/win32-arm64@2.9.1':
- optional: true
-
- '@deno/win32-x64@2.9.1':
- optional: true
-
'@eslint-community/eslint-utils@4.4.0(eslint@9.39.1)':
dependencies:
eslint: 9.39.1
@@ -5385,6 +5350,10 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15
+ '@loaderkit/resolve@1.0.6':
+ dependencies:
+ '@braidai/lang': 1.1.2
+
'@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)':
dependencies:
'@hono/node-server': 1.19.11(hono@4.12.5)
@@ -6039,15 +6008,6 @@ snapshots:
deepmerge@4.3.1: {}
- deno@2.9.1:
- optionalDependencies:
- '@deno/darwin-arm64': 2.9.1
- '@deno/darwin-x64': 2.9.1
- '@deno/linux-arm64-glibc': 2.9.1
- '@deno/linux-x64-glibc': 2.9.1
- '@deno/win32-arm64': 2.9.1
- '@deno/win32-x64': 2.9.1
-
depd@2.0.0: {}
detect-newline@3.1.0: {}
@@ -6293,6 +6253,8 @@ snapshots:
fflate@0.8.2: {}
+ fflate@0.8.3: {}
+
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@@ -6911,7 +6873,7 @@ snapshots:
jest-util: 29.7.0
natural-compare: 1.4.0
pretty-format: 29.7.0
- semver: 7.7.1
+ semver: 7.7.3
transitivePeerDependencies:
- supports-color
@@ -7043,7 +7005,7 @@ snapshots:
lodash.merge@4.6.2: {}
- lru-cache@10.4.3: {}
+ lru-cache@11.5.2: {}
lru-cache@5.1.1:
dependencies:
@@ -7827,7 +7789,7 @@ snapshots:
yargs@16.2.0:
dependencies:
cliui: 7.0.4
- escalade: 3.1.1
+ escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 04bb5de..3bf38b6 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -2,7 +2,6 @@ packages:
- 'packages/*'
onlyBuiltDependencies:
- '@swc/core'
- - 'deno'
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
- '@linqapp/sdk'
diff --git a/src/client.ts b/src/client.ts
index 8d8c1b7..601e097 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -67,6 +67,13 @@ import {
MessagesListMessagesPagination,
ReplyTo,
} from './resources/messages';
+import {
+ PaymentRequest,
+ PaymentRequestCreateParams,
+ PaymentRequestListParams,
+ PaymentRequestListResponse,
+ PaymentRequests,
+} from './resources/payment-requests';
import {
PhoneNumberListResponse,
PhoneNumberUpdateParams,
@@ -1166,6 +1173,121 @@ export class LinqAPIV3 {
*
*/
availableNumber: API.AvailableNumber = new API.AvailableNumber(this);
+ /**
+ * Request a payment from a recipient over iMessage. You create a payment
+ * request, send its `checkout_url` to the recipient, and they pay with Apple
+ * Pay or card. Funds settle **directly to your own Stripe account** — Linq
+ * never holds the money.
+ *
+ * ## How it works
+ *
+ * 1. **Create** a payment request with an amount and currency. You get back a
+ * `checkout_url` and a `status` of `requested`.
+ * 2. **Send** the `checkout_url` to the recipient as a `link` message part so
+ * it arrives as a tappable card (see *Sending the link* below).
+ * 3. The recipient **pays** on the hosted checkout (Apple Pay App Clip on a
+ * supported iPhone, web checkout everywhere else).
+ * 4. You receive a **`payment.succeeded`** webhook and the request's `status`
+ * becomes `succeeded`. Requests you don't collect eventually `expire`.
+ *
+ * ## Connected accounts (Stripe Standard, direct charges)
+ *
+ * Agent Pay runs on **Stripe Connect Standard accounts** using **direct
+ * charges**: the charge is created on *your* connected account and **you are
+ * the merchant of record**. That means the money, the payout schedule, the
+ * customer relationship, and the compliance surface are all yours — Linq
+ * orchestrates the request and the checkout but is never in the funds flow.
+ *
+ * **Refunds, disputes, and chargebacks are handled by you, in your own Stripe
+ * Dashboard.** Because charges settle directly to your account, Linq has no
+ * custody of the funds and cannot issue refunds or contest disputes on your
+ * behalf — and there is no refund/dispute endpoint in this API by design. Use
+ * the Stripe Dashboard (or the Stripe API on your own account) for the money
+ * lifecycle after a payment succeeds.
+ *
+ * ## Getting set up
+ *
+ * Open **Agent Pay** in your Linq dashboard
+ * (`https://zero.linqapp.com/organization/payments`), click **Connect Stripe**,
+ * and complete Stripe's onboarding (business details + a bank account). When
+ * your account reaches `charges_enabled`, request creation unlocks; until you
+ * connect Stripe, `POST /v3/payment_requests` returns `403`. You can keep
+ * collecting even while Stripe finishes background verification.
+ *
+ * ## Subscriptions
+ *
+ * Set `mode: subscription` on `POST /v3/payment_requests` to start an
+ * **auto-renewing subscription** instead of a one-time charge. Instead of an
+ * amount, you pass a `price_id` — an active **recurring Price** on your
+ * connected Stripe account (create one in your Stripe Dashboard under
+ * Product catalog; if you sell through Stripe Payment Links today, reuse the
+ * price your link is built from). The recipient pays the first invoice at
+ * the same checkout, and their payment method is saved to the subscription
+ * for automatic renewals.
+ *
+ * The division of labor is deliberate: **Linq handles the first payment,
+ * your Stripe account handles the rest.** The request reaches `succeeded`
+ * when the first invoice is paid; from then on the subscription lives
+ * entirely on your connected account. The response's `stripe` object gives
+ * you the join keys — `customer_id` and `subscription_id` — so renewals,
+ * plan changes, dunning, and cancellation are managed with your own Stripe
+ * Dashboard/API and your own Stripe webhooks. Your `metadata` is stamped on
+ * the Customer and Subscription, so correlating in either direction is
+ * trivial. There are no renewal webhooks from Linq by design.
+ *
+ * ### Free trials
+ *
+ * Add `trial_period_days` (or a fixed `trial_end` timestamp) to start the
+ * subscription with a free trial. The checkout still collects the
+ * recipient's payment method — the pay sheet shows "$0 due today" with the
+ * first charge date — and saves it to the subscription; Stripe bills it
+ * automatically when the trial ends. The request reaches `succeeded` when
+ * the card is collected, and the response carries `trial_end`. If the trial
+ * would end without a payment method on file, the subscription cancels
+ * rather than generating unpayable invoices. Trial lifecycle after checkout
+ * (extending, ending early) is managed in your own Stripe account via
+ * `stripe.subscription_id`.
+ *
+ * A subscription request you cancel (or that expires unpaid) cancels the
+ * incomplete Stripe subscription — nothing lingers on your account.
+ *
+ * ## Pre-created customers
+ *
+ * By default each request stands alone: payment mode attaches no Customer,
+ * and subscription mode creates a fresh one. If you already manage
+ * Customers on your connected account, pass their id as `customer_id`
+ * (`cus_...`) on create — in payment mode the charge lands on that
+ * customer's payment history, and in subscription mode the subscription is
+ * created on them instead of on a new Customer. The id must reference an
+ * existing, non-deleted customer on your connected account or the request
+ * fails with `400`. We never modify a customer you pass — no metadata is
+ * stamped on it.
+ *
+ * ## Sending the link
+ *
+ * Deliver the `checkout_url` as a **`link` message part** via
+ * `POST /v3/chats/{chatId}/messages` — it renders as a rich card with your
+ * branding (title, amount, image) instead of a bare URL, which converts far
+ * better. A `link` part must be the only part in the message. See
+ * [Rich Link Previews](/guides/messaging/sending-messages).
+ *
+ * On a supported iPhone the link opens an **Apple Pay App Clip** — a native,
+ * no-install checkout sheet. Everywhere else (Android, desktop, iPhones
+ * without the App Clip yet) the same URL opens the web checkout, so the link
+ * always works. The App Clip experience for your payment links is registered
+ * automatically by Linq and refreshed whenever you update your Agent Pay
+ * branding; a newly registered experience can take up to ~24 hours to
+ * activate on Apple's side, during which links open the web checkout.
+ *
+ * ## Webhooks
+ *
+ * Subscribe to payment lifecycle events to reconcile server-side rather than
+ * polling: `payment.succeeded`, `payment.canceled`, and `payment.expired`.
+ * Each event carries the payment request id, amount, currency, and your
+ * `metadata`. See [Webhooks](/guides/webhooks).
+ *
+ */
+ paymentRequests: API.PaymentRequests = new API.PaymentRequests(this);
/**
* Webhook Subscriptions allow you to receive real-time notifications when events
* occur on your account.
@@ -1451,6 +1573,7 @@ LinqAPIV3.Attachments = Attachments;
LinqAPIV3.Phonenumbers = Phonenumbers;
LinqAPIV3.PhoneNumbers = PhoneNumbers;
LinqAPIV3.AvailableNumber = AvailableNumber;
+LinqAPIV3.PaymentRequests = PaymentRequests;
LinqAPIV3.WebhookEvents = WebhookEvents;
LinqAPIV3.WebhookSubscriptions = WebhookSubscriptions;
LinqAPIV3.Capability = Capability;
@@ -1529,6 +1652,14 @@ export declare namespace LinqAPIV3 {
type AvailableNumberRetrieveParams as AvailableNumberRetrieveParams,
};
+ export {
+ PaymentRequests as PaymentRequests,
+ type PaymentRequest as PaymentRequest,
+ type PaymentRequestListResponse as PaymentRequestListResponse,
+ type PaymentRequestCreateParams as PaymentRequestCreateParams,
+ type PaymentRequestListParams as PaymentRequestListParams,
+ };
+
export {
WebhookEvents as WebhookEvents,
type WebhookEventType as WebhookEventType,
diff --git a/src/resources/attachments.ts b/src/resources/attachments.ts
index 8d42298..3958713 100644
--- a/src/resources/attachments.ts
+++ b/src/resources/attachments.ts
@@ -321,6 +321,8 @@ export class Attachments extends APIResource {
* **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff,
* audio/aac, audio/midi, audio/amr
*
+ * **Wallet passes:** application/vnd.apple.pkpass
+ *
* **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf,
* text/csv, text/html, text/calendar, text/xml, application/json,
* application/msword,
@@ -379,6 +381,7 @@ export type SupportedContentType =
| 'audio/midi'
| 'audio/amr'
| 'application/pdf'
+ | 'application/vnd.apple.pkpass'
| 'text/plain'
| 'text/markdown'
| 'text/vcard'
@@ -455,6 +458,8 @@ export interface AttachmentRetrieveResponse {
* **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff,
* audio/aac, audio/midi, audio/amr
*
+ * **Wallet passes:** application/vnd.apple.pkpass
+ *
* **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf,
* text/csv, text/html, text/calendar, text/xml, application/json,
* application/msword,
@@ -524,6 +529,8 @@ export interface AttachmentCreateParams {
* **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff,
* audio/aac, audio/midi, audio/amr
*
+ * **Wallet passes:** application/vnd.apple.pkpass
+ *
* **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf,
* text/csv, text/html, text/calendar, text/xml, application/json,
* application/msword,
diff --git a/src/resources/available-number.ts b/src/resources/available-number.ts
index 2575c16..f20a16c 100644
--- a/src/resources/available-number.ts
+++ b/src/resources/available-number.ts
@@ -18,15 +18,18 @@ export class AvailableNumber extends APIResource {
* Returns the best available line (E.164) to send from, applying smart number
* assignment. Optionally pass `to` recipients to make the choice "sticky" —
* reusing the line an existing chat with those recipients is already on. Without
- * `to`, the best healthy line is chosen.
+ * `to`, the best available line is chosen, always preferring lines with a
+ * healthier reputation.
*
- * This is advisory: it does not reserve the line or change selection state. Pass
- * the returned `phone_number` as `from` when you create the chat to guarantee the
- * same line.
+ * This does not reserve the line. Without `to`, the least-recently-used available
+ * line is returned — suggestions and your own sends (including an explicit `from`
+ * on chat creation) both count as use, so successive calls cycle through your
+ * available lines and traffic spreads evenly. Pass the returned `phone_number` as
+ * `from` when you create the chat to guarantee the same line.
*
* Also returns `vcf_url`: a time-limited link to a vCard (`.vcf`) for the chosen
* line, carrying its contact card (name/photo) with the chosen number as the
- * primary `TEL` and the partner's other healthy lines as backups. Share it with
+ * primary `TEL` and the partner's other available lines as backups. Share it with
* recipients so they can save the line as a contact.
*/
retrieve(
@@ -49,7 +52,7 @@ export interface AvailableNumberRetrieveResponse {
/**
* Time-limited link to a vCard (`.vcf`) for the selected line. The card carries
* the line's contact details with the selected number as the primary `TEL` and the
- * partner's other healthy lines as backups. The link expires; re-call this
+ * partner's other available lines as backups. The link expires; re-call this
* endpoint to mint a fresh one.
*/
vcf_url: string;
diff --git a/src/resources/chats/location.ts b/src/resources/chats/location.ts
index 9c2f0e2..296baef 100644
--- a/src/resources/chats/location.ts
+++ b/src/resources/chats/location.ts
@@ -7,23 +7,59 @@ import { RequestOptions } from '../../internal/request-options';
import { path } from '../../internal/utils/path';
/**
- * Request and retrieve real-time location data via iMessage.
- *
- * Use these endpoints to request a contact's location, retrieve location data
- * for contacts who are sharing with you, and subscribe to webhooks when someone
- * starts or stops sharing their location.
+ * Request a contact's location, retrieve location for contacts sharing with you,
+ * and subscribe to webhooks when someone starts or stops sharing.
*
* **Coordinates** are returned in [GeoJSON](https://datatracker.ietf.org/doc/html/rfc7946) format:
* `[longitude, latitude]` or `[longitude, latitude, altitude]` if altitude is available.
+ *
+ * ### Reading location is poll-based
+ *
+ * Poll `GET /v3/chats/{chatId}/location` whenever you need the latest position.
+ * **There is no webhook that pushes updated coordinates** — the
+ * `location.sharing.started` / `location.sharing.stopped` webhooks fire only when a
+ * contact begins or ends sharing, not on each position update. To track a moving
+ * contact, poll the `GET` endpoint.
+ *
+ * ### Freshness
+ *
+ * Each feature's `properties.updated_at` tells you when that participant's
+ * location was last updated — use it to judge freshness.
+ *
+ * ### Polling guidance
+ *
+ * Locations refresh on Apple's cadence, not per request — polling faster than a
+ * participant's location actually updates just returns the same position. Poll at a
+ * modest interval (for example, once every few minutes per chat) rather than
+ * continuously.
+ *
+ * ### Why is location empty after `location.sharing.started` fired?
+ *
+ * If the contact started sharing from the **standalone Find My app** instead of the
+ * Messages conversation, the share may be tied to their **Apple ID email** rather
+ * than their phone number — the webhook's `shared_by` field shows the email in that
+ * case. Location is readable only through a chat with the handle that shared, so
+ * `GET /v3/chats/{chatId}/location` on the phone-number chat stays empty.
+ *
+ * The fix: have the contact stop sharing and re-share from **Find My inside the
+ * Messages conversation** with your number.
*/
export class Location extends APIResource {
/**
- * Send a location sharing request to a contact. They will receive an iMessage
- * prompt asking them to share their location.
+ * Request a contact in a chat to share their location. They receive an iMessage
+ * prompt and must accept before any location is available; once they do, read
+ * their location coordinates with `GET /v3/chats/{chatId}/location`.
*
- * Location requests only work in **1:1 iMessage chats** (Apple limitation).
- * Attempting to request location in a group chat, or in an SMS or RCS chat,
- * returns `409` (Operation not supported on this chat's service type).
+ * The request is delivered asynchronously. The endpoint returns immediately with
+ * `{ "success": true, "message": "Location request sent" }` and does not return
+ * coordinates.
+ *
+ * Location requests only work in **1:1 iMessage chats** (Apple limitation):
+ *
+ * - Group chats (any service) return `409` with code `2016`
+ * (`GroupChatNotSupported`).
+ * - 1:1 SMS and RCS chats return `409` with code `2017`
+ * (`ChatServiceNotSupported`).
*
* @example
* ```ts
@@ -50,7 +86,12 @@ export class Location extends APIResource {
* `properties.handle` identifies the user.
*
* Returns an empty `data.features` array if no one is sharing or no location data
- * is available yet.
+ * is available yet. If sharing started but this stays empty, see the **Location
+ * Sharing** overview.
+ *
+ * Poll this endpoint to track a moving contact. `properties.updated_at` reflects
+ * when each participant's location was last updated. There is no coordinate-update
+ * webhook. See the **Location Sharing** overview for polling guidance.
*
* @example
* ```ts
diff --git a/src/resources/chats/typing.ts b/src/resources/chats/typing.ts
index dd6b1ea..d67b7d9 100644
--- a/src/resources/chats/typing.ts
+++ b/src/resources/chats/typing.ts
@@ -28,14 +28,20 @@ export class Typing extends APIResource {
/**
* Send a typing indicator to show that someone is typing in the chat.
*
- * ## Behavior & Limitations
+ * ## Behavior
*
- * Typing indicators are best-effort signals with the following limitations:
+ * Typing indicators are best-effort signals that behave as follows:
*
- * - **Active conversations only:** The recipient must have sent or received a
- * message in this chat within the **last 5 minutes**. If the chat is inactive,
- * the request is still accepted (`204`) but the indicator will not reach the
- * recipient's device.
+ * - **iMessage chats only:** Typing indicators are only supported for iMessage
+ * chats. Requests for RCS or SMS chats are accepted (`204`) but no indicator is
+ * delivered.
+ *
+ * - **Send a message first for reliable delivery:** Typing indicators are
+ * best-effort. If you have not sent a message in this chat recently (roughly the
+ * **last 5 minutes**), a typing indicator may not reach the recipient — the
+ * request is still accepted (`204`), but delivery is not deterministic. Once you
+ * have sent a message in the chat, typing indicators reliably reach the
+ * recipient.
*
* - **No delivery guarantee:** Even for active chats, a `204` response only
* indicates the request was accepted for processing.
@@ -43,6 +49,34 @@ export class Typing extends APIResource {
* - **Group chats not supported:** Attempting to start a typing indicator in a
* group chat will return a `403` error.
*
+ * ## Duration & keeping it visible
+ *
+ * - A single call shows the indicator for about **85–90 seconds**, then it clears
+ * automatically.
+ *
+ * - To keep it visible longer, call this endpoint again every **60 seconds**. Each
+ * call refreshes the indicator so it stays visible continuously.
+ *
+ * - Sending a message clears the indicator.
+ *
+ * - To resume typing after sending a message, call this endpoint again.
+ *
+ * - Incoming messages do not affect the indicator.
+ *
+ * ## Recipient re-opening the chat
+ *
+ * If the recipient brings their messaging app to the foreground while the chat has
+ * an unread message, their device clears any showing typing indicator. Calling
+ * this endpoint again on its own may not bring it back. To make it reappear,
+ * either send a message, or call `DELETE /v3/chats/{chatId}/typing` (stop) and
+ * then call start typing again.
+ *
+ * ## Recommended usage
+ *
+ * Call this endpoint when composing begins, call it again every 60 seconds while
+ * composing, and send the message to clear the indicator. To clear the indicator
+ * without sending a message, call `DELETE /v3/chats/{chatId}/typing`.
+ *
* @example
* ```ts
* await client.chats.typing.start(
@@ -58,12 +92,14 @@ export class Typing extends APIResource {
}
/**
- * Stop the typing indicator for the chat.
+ * Immediately clears the typing indicator for the chat, without sending a message.
*
- * Typing indicators are automatically stopped when a message is sent, so calling
- * this endpoint after sending a message is unnecessary.
+ * The typing indicator also clears automatically when you send a message, or about
+ * 85–90 seconds after the last `POST /v3/chats/{chatId}/typing` (start typing)
+ * request.
*
- * See the `POST` endpoint above for behavior details and limitations.
+ * See the start typing endpoint (`POST /v3/chats/{chatId}/typing`) above for
+ * behavior details.
*
* **Note:** Group chats are not supported and will return a `403` error.
*
diff --git a/src/resources/index.ts b/src/resources/index.ts
index 768ea04..6ecc9d9 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -60,6 +60,13 @@ export {
type MessageUpdateAppCardParams,
type MessagesListMessagesPagination,
} from './messages';
+export {
+ PaymentRequests,
+ type PaymentRequest,
+ type PaymentRequestListResponse,
+ type PaymentRequestCreateParams,
+ type PaymentRequestListParams,
+} from './payment-requests';
export {
PhoneNumbers,
type PhoneNumberUpdateResponse,
diff --git a/src/resources/messages.ts b/src/resources/messages.ts
index 7606a6c..3416385 100644
--- a/src/resources/messages.ts
+++ b/src/resources/messages.ts
@@ -83,12 +83,14 @@ export class Messages extends APIResource {
*
* ## How the from-number and chat are chosen
*
- * - **Reuse** — if a chat with exactly these recipients already exists and the
- * line it lives on is healthy, the message is sent into that chat on its
- * existing line (`from_selection.reason = reused_active_chat`).
+ * - **Reuse** — if a chat with exactly these recipients already exists on a line
+ * that can still send, the message is sent into that chat on its existing line
+ * (`from_selection.reason = reused_active_chat`). The most-recently-active such
+ * chat wins; chats stranded on flagged lines (e.g. by an earlier failover) are
+ * skipped.
* - **New** — if no such chat exists, a new chat is created on the best available
* line (`from_selection.reason = new_best_number`).
- * - **Failover** — if a matching chat exists but its line has been flagged, a
+ * - **Failover** — if matching chats exist but none is on a line that can send, a
* **new** chat is created on a fresh best line and the flagged chat is abandoned
* (`from_selection.reason = failover_flagged`, `previous_chat_id` set). If you
* supply `continuation_message`, that text is sent as the single message INSTEAD
@@ -633,8 +635,8 @@ export namespace MessageCreateResponse {
/**
* - `reused_active_chat` — reused an existing chat on its healthy line
* - `new_best_number` — created a new chat on the best available line
- * - `failover_flagged` — prior chat's line was flagged; created a new chat on a
- * fresh line
+ * - `failover_flagged` — no existing chat for these recipients was on a line that
+ * could send; created a new chat on a fresh line
*/
reason: 'reused_active_chat' | 'new_best_number' | 'failover_flagged';
diff --git a/src/resources/payment-requests.ts b/src/resources/payment-requests.ts
new file mode 100644
index 0000000..8cce15b
--- /dev/null
+++ b/src/resources/payment-requests.ts
@@ -0,0 +1,487 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../core/resource';
+import { APIPromise } from '../core/api-promise';
+import { buildHeaders } from '../internal/headers';
+import { RequestOptions } from '../internal/request-options';
+import { path } from '../internal/utils/path';
+
+/**
+ * Request a payment from a recipient over iMessage. You create a payment
+ * request, send its `checkout_url` to the recipient, and they pay with Apple
+ * Pay or card. Funds settle **directly to your own Stripe account** — Linq
+ * never holds the money.
+ *
+ * ## How it works
+ *
+ * 1. **Create** a payment request with an amount and currency. You get back a
+ * `checkout_url` and a `status` of `requested`.
+ * 2. **Send** the `checkout_url` to the recipient as a `link` message part so
+ * it arrives as a tappable card (see *Sending the link* below).
+ * 3. The recipient **pays** on the hosted checkout (Apple Pay App Clip on a
+ * supported iPhone, web checkout everywhere else).
+ * 4. You receive a **`payment.succeeded`** webhook and the request's `status`
+ * becomes `succeeded`. Requests you don't collect eventually `expire`.
+ *
+ * ## Connected accounts (Stripe Standard, direct charges)
+ *
+ * Agent Pay runs on **Stripe Connect Standard accounts** using **direct
+ * charges**: the charge is created on *your* connected account and **you are
+ * the merchant of record**. That means the money, the payout schedule, the
+ * customer relationship, and the compliance surface are all yours — Linq
+ * orchestrates the request and the checkout but is never in the funds flow.
+ *
+ * **Refunds, disputes, and chargebacks are handled by you, in your own Stripe
+ * Dashboard.** Because charges settle directly to your account, Linq has no
+ * custody of the funds and cannot issue refunds or contest disputes on your
+ * behalf — and there is no refund/dispute endpoint in this API by design. Use
+ * the Stripe Dashboard (or the Stripe API on your own account) for the money
+ * lifecycle after a payment succeeds.
+ *
+ * ## Getting set up
+ *
+ * Open **Agent Pay** in your Linq dashboard
+ * (`https://zero.linqapp.com/organization/payments`), click **Connect Stripe**,
+ * and complete Stripe's onboarding (business details + a bank account). When
+ * your account reaches `charges_enabled`, request creation unlocks; until you
+ * connect Stripe, `POST /v3/payment_requests` returns `403`. You can keep
+ * collecting even while Stripe finishes background verification.
+ *
+ * ## Subscriptions
+ *
+ * Set `mode: subscription` on `POST /v3/payment_requests` to start an
+ * **auto-renewing subscription** instead of a one-time charge. Instead of an
+ * amount, you pass a `price_id` — an active **recurring Price** on your
+ * connected Stripe account (create one in your Stripe Dashboard under
+ * Product catalog; if you sell through Stripe Payment Links today, reuse the
+ * price your link is built from). The recipient pays the first invoice at
+ * the same checkout, and their payment method is saved to the subscription
+ * for automatic renewals.
+ *
+ * The division of labor is deliberate: **Linq handles the first payment,
+ * your Stripe account handles the rest.** The request reaches `succeeded`
+ * when the first invoice is paid; from then on the subscription lives
+ * entirely on your connected account. The response's `stripe` object gives
+ * you the join keys — `customer_id` and `subscription_id` — so renewals,
+ * plan changes, dunning, and cancellation are managed with your own Stripe
+ * Dashboard/API and your own Stripe webhooks. Your `metadata` is stamped on
+ * the Customer and Subscription, so correlating in either direction is
+ * trivial. There are no renewal webhooks from Linq by design.
+ *
+ * ### Free trials
+ *
+ * Add `trial_period_days` (or a fixed `trial_end` timestamp) to start the
+ * subscription with a free trial. The checkout still collects the
+ * recipient's payment method — the pay sheet shows "$0 due today" with the
+ * first charge date — and saves it to the subscription; Stripe bills it
+ * automatically when the trial ends. The request reaches `succeeded` when
+ * the card is collected, and the response carries `trial_end`. If the trial
+ * would end without a payment method on file, the subscription cancels
+ * rather than generating unpayable invoices. Trial lifecycle after checkout
+ * (extending, ending early) is managed in your own Stripe account via
+ * `stripe.subscription_id`.
+ *
+ * A subscription request you cancel (or that expires unpaid) cancels the
+ * incomplete Stripe subscription — nothing lingers on your account.
+ *
+ * ## Pre-created customers
+ *
+ * By default each request stands alone: payment mode attaches no Customer,
+ * and subscription mode creates a fresh one. If you already manage
+ * Customers on your connected account, pass their id as `customer_id`
+ * (`cus_...`) on create — in payment mode the charge lands on that
+ * customer's payment history, and in subscription mode the subscription is
+ * created on them instead of on a new Customer. The id must reference an
+ * existing, non-deleted customer on your connected account or the request
+ * fails with `400`. We never modify a customer you pass — no metadata is
+ * stamped on it.
+ *
+ * ## Sending the link
+ *
+ * Deliver the `checkout_url` as a **`link` message part** via
+ * `POST /v3/chats/{chatId}/messages` — it renders as a rich card with your
+ * branding (title, amount, image) instead of a bare URL, which converts far
+ * better. A `link` part must be the only part in the message. See
+ * [Rich Link Previews](/guides/messaging/sending-messages).
+ *
+ * On a supported iPhone the link opens an **Apple Pay App Clip** — a native,
+ * no-install checkout sheet. Everywhere else (Android, desktop, iPhones
+ * without the App Clip yet) the same URL opens the web checkout, so the link
+ * always works. The App Clip experience for your payment links is registered
+ * automatically by Linq and refreshed whenever you update your Agent Pay
+ * branding; a newly registered experience can take up to ~24 hours to
+ * activate on Apple's side, during which links open the web checkout.
+ *
+ * ## Webhooks
+ *
+ * Subscribe to payment lifecycle events to reconcile server-side rather than
+ * polling: `payment.succeeded`, `payment.canceled`, and `payment.expired`.
+ * Each event carries the payment request id, amount, currency, and your
+ * `metadata`. See [Webhooks](/guides/webhooks).
+ */
+export class PaymentRequests extends APIResource {
+ /**
+ * Creates a payment request and returns a `checkout_url` the recipient opens to
+ * pay with Apple Pay or card. Funds settle directly to your connected Stripe
+ * account. A payment request is independent of any chat; to associate one with a
+ * chat for your records, store the chat id in `metadata`. Requires your connected
+ * account to be `charges_enabled` (returns `403` otherwise).
+ *
+ * Set `mode: subscription` with a recurring `price_id` from your connected Stripe
+ * account to start an **auto-renewing subscription** instead of a one-time charge
+ * — the recipient pays the first invoice at checkout and the response's `stripe`
+ * object carries the customer and subscription ids for the ongoing lifecycle in
+ * your own Stripe account. See the _Subscriptions_ section of the tag overview.
+ *
+ * In either mode, pass `customer_id` to attach the request to an **existing
+ * Customer** on your connected account instead of creating a new one — see
+ * _Pre-created customers_ in the tag overview.
+ *
+ * @example
+ * ```ts
+ * const paymentRequest = await client.paymentRequests.create({
+ * amount: 497,
+ * currency: 'usd',
+ * description: 'Coffee with Ava',
+ * metadata: { order_id: 'order_8675309' },
+ * });
+ * ```
+ */
+ create(params: PaymentRequestCreateParams, options?: RequestOptions): APIPromise {
+ const { 'Idempotency-Key': idempotencyKey, ...body } = params;
+ return this._client.post('/v3/payment_requests', {
+ body,
+ ...options,
+ headers: buildHeaders([
+ { ...(idempotencyKey != null ? { 'Idempotency-Key': idempotencyKey } : undefined) },
+ options?.headers,
+ ]),
+ });
+ }
+
+ /**
+ * Returns a payment request's status and details.
+ *
+ * @example
+ * ```ts
+ * const paymentRequest =
+ * await client.paymentRequests.retrieve(
+ * '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
+ * );
+ * ```
+ */
+ retrieve(paymentRequestID: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/payment_requests/${paymentRequestID}`, options);
+ }
+
+ /**
+ * Lists your payment requests, newest first, for reconciliation. Paginate with
+ * `limit` + `offset`; `has_more` indicates whether another page exists.
+ *
+ * @example
+ * ```ts
+ * const paymentRequests = await client.paymentRequests.list();
+ * ```
+ */
+ list(
+ query: PaymentRequestListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/payment_requests', { query, ...options });
+ }
+
+ /**
+ * Cancels an unpaid payment request: the underlying payment intent is canceled and
+ * the request moves to `canceled`. A request that is already paid, canceled, or
+ * expired returns 409.
+ *
+ * @example
+ * ```ts
+ * const paymentRequest = await client.paymentRequests.cancel(
+ * '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
+ * );
+ * ```
+ */
+ cancel(paymentRequestID: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/v3/payment_requests/${paymentRequestID}/cancel`, options);
+ }
+}
+
+export interface PaymentRequest {
+ /**
+ * Unique identifier of the payment request.
+ */
+ id: string;
+
+ /**
+ * Amount in the currency's minor units. In `subscription` mode this is the
+ * recurring amount (price × quantity) the recipient pays per interval, starting at
+ * checkout.
+ */
+ amount: number;
+
+ /**
+ * URL the recipient opens to pay:
+ * `https://zero.linqapp.com/pay/{slug}?session=...`, where `{slug}` is your
+ * partner checkout slug.
+ */
+ checkout_url: string;
+
+ created_at: string;
+
+ currency: string;
+
+ /**
+ * Whether this request collects a one-time charge or starts a subscription.
+ */
+ mode: 'payment' | 'subscription';
+
+ object: string;
+
+ /**
+ * Lifecycle status of the payment request.
+ */
+ status: 'requested' | 'succeeded' | 'canceled' | 'expired';
+
+ description?: string;
+
+ /**
+ * When an unpaid request auto-expires.
+ */
+ expires_at?: string;
+
+ /**
+ * Subscription mode — how often the subscription renews.
+ */
+ interval?: 'day' | 'week' | 'month' | 'year';
+
+ /**
+ * Subscription mode — intervals per renewal (e.g. `3` + `month` = quarterly).
+ */
+ interval_count?: number;
+
+ metadata?: { [key: string]: string };
+
+ /**
+ * Natural-rail join keys, present when `rail: natural`.
+ */
+ natural?: PaymentRequest.Natural;
+
+ /**
+ * When the request was paid. Absent until it succeeds.
+ */
+ paid_at?: string;
+
+ /**
+ * Subscription mode — the recurring price this request subscribes to.
+ */
+ price_id?: string;
+
+ /**
+ * Subscription mode — units of the price subscribed to.
+ */
+ quantity?: number;
+
+ /**
+ * The rail this request settled on.
+ */
+ rail?: 'stripe' | 'natural';
+
+ /**
+ * Ids of the Stripe objects created **on your connected account** — your join keys
+ * into your own Stripe Dashboard, webhooks, and API. After a subscription's first
+ * payment succeeds, its ongoing lifecycle (renewals, plan changes, cancellation)
+ * is managed in your Stripe account using `subscription_id`.
+ */
+ stripe?: PaymentRequest.Stripe;
+
+ /**
+ * Subscription mode — when the free trial ends and the first charge happens.
+ * Present only on trial requests; `paid_at`/`succeeded` mean the payment method
+ * was collected (no funds move until this time).
+ */
+ trial_end?: string;
+
+ updated_at?: string;
+}
+
+export namespace PaymentRequest {
+ /**
+ * Natural-rail join keys, present when `rail: natural`.
+ */
+ export interface Natural {
+ /**
+ * The Natural payment request (`prq_...`).
+ */
+ payment_request_id?: string;
+
+ /**
+ * The settled transaction (`txn_...`).
+ */
+ transaction_id?: string;
+ }
+
+ /**
+ * Ids of the Stripe objects created **on your connected account** — your join keys
+ * into your own Stripe Dashboard, webhooks, and API. After a subscription's first
+ * payment succeeds, its ongoing lifecycle (renewals, plan changes, cancellation)
+ * is managed in your Stripe account using `subscription_id`.
+ */
+ export interface Stripe {
+ /**
+ * The Customer this request is attached to (`cus_...`). Always set in subscription
+ * mode (created for you unless you passed `customer_id`); set in payment mode only
+ * when you passed one.
+ */
+ customer_id?: string;
+
+ /**
+ * The PaymentIntent collected at checkout (`pi_...`).
+ */
+ payment_intent_id?: string;
+
+ /**
+ * Subscription mode — the Subscription (`sub_...`).
+ */
+ subscription_id?: string;
+ }
+}
+
+export interface PaymentRequestListResponse {
+ data: Array;
+
+ /**
+ * Whether more results exist beyond this page.
+ */
+ has_more: boolean;
+
+ object: 'list';
+}
+
+export interface PaymentRequestCreateParams {
+ /**
+ * Body param: Amount to charge, in the currency's minor units (e.g. cents). Must
+ * be at least the payment provider's minimum (50 for `usd`). Required in `payment`
+ * mode; must be omitted in `subscription` mode (the amount comes from the price).
+ */
+ amount?: number;
+
+ /**
+ * Body param: Three-letter ISO 4217 currency code. Only `usd` is currently
+ * supported. Required in `payment` mode; must be omitted in `subscription` mode
+ * (the currency comes from the price).
+ */
+ currency?: string;
+
+ /**
+ * Body param: Optional id of an **existing Customer** on your connected Stripe
+ * account (`cus_...`) to attach this request to, instead of a new Customer being
+ * created. In `payment` mode the charge lands on that customer's payment history;
+ * in `subscription` mode the subscription is created on them. The customer must
+ * exist (and not be deleted) on your connected account.
+ */
+ customer_id?: string;
+
+ /**
+ * Body param: Optional description shown to the recipient at checkout.
+ */
+ description?: string;
+
+ /**
+ * Body param: Required for `rail: natural`. The line the request is sent from, in
+ * E.164 format. Must be a phone number your organization owns.
+ */
+ from?: string;
+
+ /**
+ * Body param: Optional key/value metadata (up to 49 keys) echoed back on retrieval
+ * and on `payment.*` webhooks, and stamped on the Stripe objects we create on your
+ * connected account (the PaymentIntent, and in subscription mode the Subscription
+ * and any Customer created for you — a customer you pass via `customer_id` is
+ * never modified) — use it to correlate a request with your own records (e.g. a
+ * chat id). Keys starting with `linq_` are reserved.
+ */
+ metadata?: { [key: string]: string };
+
+ /**
+ * Body param: `payment` (default) collects a one-time charge for `amount` +
+ * `currency`. `subscription` starts an auto-renewing subscription from a recurring
+ * `price_id` on your connected Stripe account: the recipient pays the first
+ * invoice at checkout and Stripe renews it automatically from then on.
+ */
+ mode?: 'payment' | 'subscription';
+
+ /**
+ * Body param: Required for `rail: natural`. The payer to bill, in E.164 format.
+ */
+ payer_handle?: string;
+
+ /**
+ * Body param: Subscription mode only (required there): id of an **active recurring
+ * Price** on your connected Stripe account (`price_...`). If you sell through
+ * Stripe Payment Links today, pass the same price the link was built from to get
+ * the native iMessage checkout for it.
+ */
+ price_id?: string;
+
+ /**
+ * Body param: Subscription mode only — units of the price to subscribe to.
+ */
+ quantity?: number;
+
+ /**
+ * Body param: Payment rail. `stripe` (default) is the direct-charge flow that
+ * settles to your connected Stripe account. `natural` collects through the Natural
+ * custodial wallet; it requires `from` + `payer_handle` and that your organization
+ * has completed Natural merchant onboarding.
+ */
+ rail?: 'stripe' | 'natural';
+
+ /**
+ * Body param: Subscription mode only — end the free trial at a fixed timestamp
+ * (must be in the future) instead of a day count. Mutually exclusive with
+ * `trial_period_days`.
+ */
+ trial_end?: string;
+
+ /**
+ * Body param: Subscription mode only — start with a free trial of this many days.
+ * The recipient's card is still collected at checkout (Apple Pay or card), saved
+ * to the subscription, and first charged when the trial ends. Mutually exclusive
+ * with `trial_end`.
+ */
+ trial_period_days?: number;
+
+ /**
+ * Header param: Optional idempotency key (max 200 characters). Reuse the same key
+ * to safely retry without creating a second payment request. Reusing a key with
+ * different request parameters returns 409.
+ */
+ 'Idempotency-Key'?: string;
+}
+
+export interface PaymentRequestListParams {
+ /**
+ * Max results to return (default 20, max 100).
+ */
+ limit?: number;
+
+ /**
+ * Number of results to skip.
+ */
+ offset?: number;
+
+ /**
+ * Filter by lifecycle status.
+ */
+ status?: 'requested' | 'succeeded' | 'canceled' | 'expired';
+}
+
+export declare namespace PaymentRequests {
+ export {
+ type PaymentRequest as PaymentRequest,
+ type PaymentRequestListResponse as PaymentRequestListResponse,
+ type PaymentRequestCreateParams as PaymentRequestCreateParams,
+ type PaymentRequestListParams as PaymentRequestListParams,
+ };
+}
diff --git a/src/resources/phone-numbers.ts b/src/resources/phone-numbers.ts
index 1c2128e..2105493 100644
--- a/src/resources/phone-numbers.ts
+++ b/src/resources/phone-numbers.ts
@@ -83,19 +83,6 @@ export namespace PhoneNumberListResponse {
*/
id: string;
- /**
- * @deprecated **[BETA]** Current reputation for a phone line. Always present —
- * lines start at `HEALTHY` and may shift based on aggregate engagement and
- * delivery signals across all conversations on the line.
- *
- * Unlike chat health, line reputation does not include `opted_out` — opt-out
- * applies to individual recipients, not the whole line.
- *
- * See the [Phone Reputation guide](/guides/phone-numbers/phone-reputation) for
- * what each status means and how to react.
- */
- health_status: PhoneNumber.HealthStatus;
-
/**
* Phone number in E.164 format
*/
@@ -122,37 +109,6 @@ export namespace PhoneNumberListResponse {
}
export namespace PhoneNumber {
- /**
- * @deprecated **[BETA]** Current reputation for a phone line. Always present —
- * lines start at `HEALTHY` and may shift based on aggregate engagement and
- * delivery signals across all conversations on the line.
- *
- * Unlike chat health, line reputation does not include `opted_out` — opt-out
- * applies to individual recipients, not the whole line.
- *
- * See the [Phone Reputation guide](/guides/phone-numbers/phone-reputation) for
- * what each status means and how to react.
- */
- export interface HealthStatus {
- /**
- * Deep-link to the relevant section of the Phone Reputation guide for this status.
- */
- doc_url: string;
-
- /**
- * Current reputation of this phone line.
- *
- * - `HEALTHY` — The line is in good standing. Send normally.
- * - `AT_RISK` — The line's overall engagement is trending down. Slow the line's
- * send pace and review your messaging patterns.
- * - `CRITICAL` — Strong signals that messages from this line aren't landing well.
- * Pause outbound on the line until it recovers.
- *
- * Defaults to `HEALTHY` for lines that have not yet been scored.
- */
- status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL';
- }
-
/**
* **[BETA]** Current reputation for a phone line. Always present — lines start at
* `HEALTHY` and may shift based on aggregate engagement and delivery signals
@@ -174,8 +130,11 @@ export namespace PhoneNumberListResponse {
* Current reputation of this phone line.
*
* - `HEALTHY` — The line is in good standing. Send normally.
- * - `AT_RISK` — The line's overall engagement is trending down. Slow the line's
- * send pace and review your messaging patterns.
+ * - `AT_RISK` — Warning signs on the line: engagement is low across many of its
+ * conversations, or it's starting too many brand-new conversations in a single
+ * day — and a spike in send volume can add to either. Slow the line's send pace,
+ * avoid opening many new conversations at once, and review your messaging
+ * patterns.
* - `CRITICAL` — Strong signals that messages from this line aren't landing well.
* Pause outbound on the line until it recovers.
*
diff --git a/src/resources/webhook-events.ts b/src/resources/webhook-events.ts
index 6eb3465..df449bb 100644
--- a/src/resources/webhook-events.ts
+++ b/src/resources/webhook-events.ts
@@ -166,6 +166,7 @@ export type WebhookEventType =
| 'chat.group_icon_updated'
| 'chat.group_name_update_failed'
| 'chat.group_icon_update_failed'
+ | 'chat.background_updated'
| 'chat.typing_indicator.started'
| 'chat.typing_indicator.stopped'
| 'phone_number.status_updated'
@@ -177,7 +178,10 @@ export type WebhookEventType =
| 'call.declined'
| 'call.no_answer'
| 'location.sharing.started'
- | 'location.sharing.stopped';
+ | 'location.sharing.stopped'
+ | 'payment.succeeded'
+ | 'payment.canceled'
+ | 'payment.expired';
export interface WebhookEventListResponse {
/**
diff --git a/src/resources/webhooks.ts b/src/resources/webhooks.ts
index c3dd2bb..511d9c3 100644
--- a/src/resources/webhooks.ts
+++ b/src/resources/webhooks.ts
@@ -2079,6 +2079,7 @@ export interface PhoneNumberStatusUpdatedWebhookEvent {
| 'chat.group_icon_updated'
| 'chat.group_name_update_failed'
| 'chat.group_icon_update_failed'
+ | 'chat.background_updated'
| 'chat.typing_indicator.started'
| 'chat.typing_indicator.stopped'
| 'phone_number.status_updated'
@@ -2090,7 +2091,10 @@ export interface PhoneNumberStatusUpdatedWebhookEvent {
| 'call.declined'
| 'call.no_answer'
| 'location.sharing.started'
- | 'location.sharing.stopped';
+ | 'location.sharing.stopped'
+ | 'payment.succeeded'
+ | 'payment.canceled'
+ | 'payment.expired';
/**
* Partner identifier. Present on all webhooks for cross-referencing.
@@ -2120,19 +2124,6 @@ export namespace PhoneNumberStatusUpdatedWebhookEvent {
*/
changed_at: string;
- /**
- * @deprecated Current reputation of this phone line.
- *
- * - `HEALTHY` — The line is in good standing. Send normally.
- * - `AT_RISK` — The line's overall engagement is trending down. Slow the line's
- * send pace and review your messaging patterns.
- * - `CRITICAL` — Strong signals that messages from this line aren't landing well.
- * Pause outbound on the line until it recovers.
- *
- * Defaults to `HEALTHY` for lines that have not yet been scored.
- */
- new_health_status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL';
-
/**
* The new line reputation
*/
@@ -2148,19 +2139,6 @@ export namespace PhoneNumberStatusUpdatedWebhookEvent {
*/
phone_number: string;
- /**
- * @deprecated Current reputation of this phone line.
- *
- * - `HEALTHY` — The line is in good standing. Send normally.
- * - `AT_RISK` — The line's overall engagement is trending down. Slow the line's
- * send pace and review your messaging patterns.
- * - `CRITICAL` — Strong signals that messages from this line aren't landing well.
- * Pause outbound on the line until it recovers.
- *
- * Defaults to `HEALTHY` for lines that have not yet been scored.
- */
- previous_health_status: 'HEALTHY' | 'AT_RISK' | 'CRITICAL';
-
/**
* The previous line reputation
*/
diff --git a/tests/api-resources/payment-requests.test.ts b/tests/api-resources/payment-requests.test.ts
new file mode 100644
index 0000000..ac54540
--- /dev/null
+++ b/tests/api-resources/payment-requests.test.ts
@@ -0,0 +1,73 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import LinqAPIV3 from '@linqapp/sdk';
+
+const client = new LinqAPIV3({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource paymentRequests', () => {
+ // Mock server tests are disabled
+ test.skip('create', async () => {
+ const responsePromise = client.paymentRequests.create({});
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('retrieve', async () => {
+ const responsePromise = client.paymentRequests.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.paymentRequests.list();
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.paymentRequests.list(
+ {
+ limit: 1,
+ offset: 0,
+ status: 'requested',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(LinqAPIV3.NotFoundError);
+ });
+
+ // Mock server tests are disabled
+ test.skip('cancel', async () => {
+ const responsePromise = client.paymentRequests.cancel('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+});