Skip to content
LinqCopy agent prompt

Create and send a poll in a chat

POST/v3/chats/{chatId}/polls

Create an iMessage poll in an existing chat and send it. Polls are iMessage-only.

The chat must already exist — a poll cannot be the first message of a new chat (use POST /v3/chats for that). Options are add-only and immutable: you can add options later via POST /v3/messages/{messageId}/poll/options, but never edit or remove them.

Path ParametersExpand Collapse
chatId: string
formatuuid
Body ParametersJSONExpand Collapse
poll: object { options, idempotency_key }

Poll content to create. A poll needs at least two options. Options are add-only and immutable — there is no title/question (send that as a normal text message).

options: array of object { text }
text: string
idempotency_key: optional string

Optional key to deduplicate the poll creation.

ReturnsExpand Collapse
PollEnvelope object { chat_id, created_at, message_id, 3 more }

Message-level envelope returned by every poll endpoint.

chat_id: string
formatuuid
created_at: string
formatdate-time
message_id: string

The poll-definition message’s ID — reference this poll by it.

formatuuid
poll: Poll { options, total_voters }

Poll content — options and the aggregate voter count.

options: array of object { can_be_edited, creator_handle, option_id, 2 more }
can_be_edited: boolean
creator_handle: ChatHandle { id, handle, joined_at, 4 more }

The participant who added this option (poll creator for the initial options; whoever added later ones).

id: string

Unique identifier for this handle

formatuuid
handle: string

Phone number (E.164) or email address of the participant

joined_at: string

When this participant joined the chat

formatdate-time
service: ServiceType

Messaging service type

One of the following:
"iMessage"
"SMS"
"RCS"
is_me: optional boolean

Whether this handle belongs to the sender (your phone number)

left_at: optional string

When they left (if applicable)

formatdate-time
status: optional "active" or "left" or "removed"

Participant status

One of the following:
"active"
"left"
"removed"
option_id: string
formatuuid
text: string
voters: array of object { handle, voted_at }

Participants who voted for this option (vote_count = voters.length).

handle: string
voted_at: string
formatdate-time
total_voters: number

Distinct participants across the whole poll (a voter picking two options counts once).

reactions: array of Reaction { handle, is_me, type, 2 more }

Tapbacks/stickers on the whole poll (message part 0).

handle: ChatHandle { id, handle, joined_at, 4 more }
id: string

Unique identifier for this handle

formatuuid
handle: string

Phone number (E.164) or email address of the participant

joined_at: string

When this participant joined the chat

formatdate-time
service: ServiceType

Messaging service type

One of the following:
"iMessage"
"SMS"
"RCS"
is_me: optional boolean

Whether this handle belongs to the sender (your phone number)

left_at: optional string

When they left (if applicable)

formatdate-time
status: optional "active" or "left" or "removed"

Participant status

One of the following:
"active"
"left"
"removed"
is_me: boolean

Whether this reaction is from the current user

Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question. Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field. Sticker reactions have type “sticker” with sticker attachment details in the sticker field.

One of the following:
"love"
"like"
"dislike"
"laugh"
"emphasize"
"question"
"custom"
"sticker"
custom_emoji: optional string

Custom emoji if type is “custom”, null otherwise

sticker: optional object { file_name, height, mime_type, 2 more }

Sticker attachment details when reaction_type is “sticker”. Null for non-sticker reactions.

file_name: optional string

Filename of the sticker

height: optional number

Sticker image height in pixels

mime_type: optional string

MIME type of the sticker image

url: optional string

Presigned URL for downloading the sticker image (expires in 1 hour).

formaturi
width: optional number

Sticker image width in pixels

updated_at: string
formatdate-time

Create and send a poll in a chat

curl https://api.linqapp.com/api/partner/v3/chats/$CHAT_ID/polls \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \
    -d '{
          "poll": {
            "options": [
              {
                "text": "Tacos"
              },
              {
                "text": "Sushi"
              }
            ],
            "idempotency_key": "poll-abc123"
          }
        }'
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2019-12-27T18:11:19.117Z",
  "message_id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "poll": {
    "options": [
      {
        "can_be_edited": true,
        "creator_handle": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "handle": "+15551234567",
          "joined_at": "2025-05-21T15:30:00.000-05:00",
          "service": "iMessage",
          "is_me": false,
          "left_at": "2019-12-27T18:11:19.117Z",
          "status": "active"
        },
        "option_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
        "text": "Tacos",
        "voters": [
          {
            "handle": "+14155559876",
            "voted_at": "2019-12-27T18:11:19.117Z"
          }
        ]
      }
    ],
    "total_voters": 0
  },
  "reactions": [
    {
      "handle": {
        "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "is_me": false,
      "type": "love",
      "custom_emoji": null,
      "sticker": {
        "file_name": "sticker.png",
        "height": 420,
        "mime_type": "image/png",
        "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
        "width": 420
      }
    }
  ],
  "updated_at": "2019-12-27T18:11:19.117Z"
}
{
  "error": {
    "status": 400,
    "code": 1002,
    "message": "Phone number must be in E.164 format",
    "doc_url": "https://docs.linqapp.com/error/codes/1xxx/1002/"
  },
  "success": false
}
{
  "error": {
    "status": 401,
    "code": 2004,
    "message": "Unauthorized - missing or invalid authentication token",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2004/"
  },
  "success": false
}
{
  "error": {
    "status": 403,
    "code": 2005,
    "message": "Access denied - insufficient permissions for this resource",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2005/"
  },
  "success": false
}
{
  "error": {
    "status": 404,
    "code": 2001,
    "message": "Resource not found",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2001/"
  },
  "success": false
}
{
  "error": {
    "status": 429,
    "code": 1007,
    "message": "Rate limited. Try again in 45 seconds.",
    "doc_url": "https://docs.linqapp.com/error/codes/1xxx/1007/",
    "retry_after": 45
  },
  "success": false
}
{
  "error": {
    "status": 500,
    "code": 3006,
    "message": "Internal server error",
    "doc_url": "https://docs.linqapp.com/error/codes/3xxx/3006/"
  },
  "success": false
}
Returns Examples
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2019-12-27T18:11:19.117Z",
  "message_id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "poll": {
    "options": [
      {
        "can_be_edited": true,
        "creator_handle": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "handle": "+15551234567",
          "joined_at": "2025-05-21T15:30:00.000-05:00",
          "service": "iMessage",
          "is_me": false,
          "left_at": "2019-12-27T18:11:19.117Z",
          "status": "active"
        },
        "option_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
        "text": "Tacos",
        "voters": [
          {
            "handle": "+14155559876",
            "voted_at": "2019-12-27T18:11:19.117Z"
          }
        ]
      }
    ],
    "total_voters": 0
  },
  "reactions": [
    {
      "handle": {
        "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "is_me": false,
      "type": "love",
      "custom_emoji": null,
      "sticker": {
        "file_name": "sticker.png",
        "height": 420,
        "mime_type": "image/png",
        "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
        "width": 420
      }
    }
  ],
  "updated_at": "2019-12-27T18:11:19.117Z"
}
{
  "error": {
    "status": 400,
    "code": 1002,
    "message": "Phone number must be in E.164 format",
    "doc_url": "https://docs.linqapp.com/error/codes/1xxx/1002/"
  },
  "success": false
}
{
  "error": {
    "status": 401,
    "code": 2004,
    "message": "Unauthorized - missing or invalid authentication token",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2004/"
  },
  "success": false
}
{
  "error": {
    "status": 403,
    "code": 2005,
    "message": "Access denied - insufficient permissions for this resource",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2005/"
  },
  "success": false
}
{
  "error": {
    "status": 404,
    "code": 2001,
    "message": "Resource not found",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2001/"
  },
  "success": false
}
{
  "error": {
    "status": 429,
    "code": 1007,
    "message": "Rate limited. Try again in 45 seconds.",
    "doc_url": "https://docs.linqapp.com/error/codes/1xxx/1007/",
    "retry_after": 45
  },
  "success": false
}
{
  "error": {
    "status": 500,
    "code": 3006,
    "message": "Internal server error",
    "doc_url": "https://docs.linqapp.com/error/codes/3xxx/3006/"
  },
  "success": false
}