Messages

Send a message (auto-selected from-number)

Send a message to one or more recipients without supplying a from number. Linq resolves both the sending line and the target chat for you, then returns exactly which line was used, which chat the message landed in, whether a new chat was created, and every resulting message id.

This fuses "create chat" and "send message" behind a single message-centric resource. Provide only the recipients (to) and the message; the platform decides the rest.

How the from-number and chat are chosen

  • 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 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 of message (useful as a fresh-number-appropriate opener). Exactly one message is sent either way.

Recipients (to) are an order-independent set: a single handle is a direct chat, multiple handles a group chat.

Excluding lines

exclude_from keeps specific lines out of this send's line pick. It only affects picking a line for a new chat — an existing chat is always reused on its own line, preferring a chat on a non-excluded line when the recipients have more than one. An exclusion never abandons a live chat or moves it to a new number, so if the only chat these recipients have is on an excluded line, that chat is still used. from tells you the line that was actually used.

Differences from POST /v3/chats

  • The first message may contain a link (including for a newly created chat). Note: sending a link as the very first message on a freshly selected line can elevate that line's flagging risk — it is allowed, not recommended.
  • Voice memos are not supported here. To send an iMessage voice-memo bubble, use POST /v3/chats/{chatId}/voicememo with a known chat id.

Service preference, effects, decorations, inline stickers

Set message.preferred_service (iMessage | RCS | SMS), message.effect, and per-part text_decorations and inline_stickers exactly as on the other send endpoints.

Always responds 202 Accepted — chat creation is incidental to the send.

post/v3/messages

Request

  • Base URL: https://api.linqapp.com/api/partner
  • URL: https://api.linqapp.com/api/partner/v3/messages
  • Auth: HTTP bearer

Headers

Idempotency-Keystring
Example:send-abc123xyz

Optional idempotency key for the send. Reuse the same key to safely retry without sending twice. May also be supplied as message.idempotency_key.

Request body

tostring[] required

Recipient handles (E.164 phone numbers or email addresses). One handle is a direct chat; multiple handles a group chat. Order-independent — the set identifies the chat.

exclude_fromstring[]

Lines (E.164) not to pick for this send. Applies for this request only — nothing is remembered between calls.

Exclusion only affects picking a line for a new chat. If to already has a chat, that chat is reused on its own line, and a chat on a non-excluded line is preferred when there is more than one. If the only chat these recipients have is on an excluded line, it is still reused — an exclusion never abandons a live chat or moves it to a new number. Check from in the response to see the line that was actually used.

Numbers that are not your lines are ignored. Every entry must be E.164 — a value like 4155551234 is rejected rather than silently skipped. Excluding every one of your available lines returns 400 when a line has to be picked.

override_optoutboolean

Send even though the recipient asked you to stop (403, error code 2024). Applies to this request only: the opt-out stays in place, so the next send without this flag is rejected again. Every override is recorded against your API key.

Example request

{
  "to": [
    "+14155559876"
  ],
  "exclude_from": [
    "+12052535597"
  ],
  "message": {
    "experience": {
      "name": "agentcard",
      "action": "attach_card"
    },
    "parts": [
      {
        "type": "text",
        "value": "Check this out!"
      },
      {
        "type": "media",
        "url": "https://cdn.linqapp.com/attachments/example/photo.jpg"
      }
    ],
    "effect": {
      "type": "screen",
      "name": "confetti"
    },
    "reply_to": {
      "message_id": "550e8400-e29b-41d4-a716-446655440000"
    },
    "idempotency_key": "msg-abc123xyz",
    "preferred_service": "iMessage"
  },
  "continuation_message": {
    "text": "Hi, it's Acme Support reaching you from a new number."
  }
}

Response

Message accepted for delivery

chat_idstring uuid required

The resolved chat (reused or newly created) the message landed in.

created_new_chatboolean required

True when a new chat was created (new or failover), false on reuse.

fromstring required

The line (E.164) the message was actually sent from.

is_groupboolean required

Whether the resolved chat is a group chat.

service'iMessage' | 'SMS' | 'RCS' required

Messaging service type. Where this names the transport a message used, it is per-message: a chat's own service can differ from a message in it, and Apple can downgrade an individual message.

previous_chat_idstring uuid nullable

Set ONLY on failover_flagged: the abandoned flagged chat that was NOT sent into. Null otherwise.

Example response

{
  "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
  "from": "+12052535597",
  "from_selection": {
    "reason": "reused_active_chat",
    "reused_existing_chat": true
  },
  "service": "iMessage",
  "handles": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "handle": "+15551234567",
      "service": "iMessage",
      "joined_at": "2025-05-21T15:30:00.000-05:00",
      "line_type": "iMessage"
    }
  ],
  "message": {
    "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    "service": "iMessage",
    "preferred_service": "iMessage",
    "parts": [
      {
        "type": "text",
        "value": "Hello!"
      }
    ],
    "created_at": "2025-10-23T13:07:55.019-05:00",
    "delivery_status": "pending",
    "effect": {
      "type": "screen",
      "name": "confetti"
    },
    "from_handle": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "handle": "+15551234567",
      "service": "iMessage",
      "joined_at": "2025-05-21T15:30:00.000-05:00",
      "line_type": "iMessage"
    },
    "reply_to": {
      "message_id": "550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.