# Polls

## Create and send a poll in a chat

`client.Chats.Polls.New(ctx, chatID, body) (*PollEnvelope, error)`

**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.

### Parameters

- `chatID string`

- `body ChatPollNewParams`

  - `Poll param.Field[ChatPollNewParamsPoll]`

    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 []ChatPollNewParamsPollOption`

      - `Text string`

    - `IdempotencyKey string`

      Optional key to deduplicate the poll creation.

### Returns

- `type PollEnvelope struct{…}`

  Message-level envelope returned by every poll endpoint.

  - `ChatID string`

  - `CreatedAt Time`

  - `MessageID string`

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

  - `Poll Poll`

    Poll content — options and the aggregate voter count.

    - `Options []PollOption`

      - `CanBeEdited bool`

      - `CreatorHandle ChatHandle`

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

        - `ID string`

          Unique identifier for this handle

        - `Handle string`

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

        - `JoinedAt Time`

          When this participant joined the chat

        - `Service ServiceType`

          Messaging service type

          - `const ServiceTypeIMessage ServiceType = "iMessage"`

          - `const ServiceTypeSMS ServiceType = "SMS"`

          - `const ServiceTypeRCS ServiceType = "RCS"`

        - `IsMe bool`

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

        - `LeftAt Time`

          When they left (if applicable)

        - `Status ChatHandleStatus`

          Participant status

          - `const ChatHandleStatusActive ChatHandleStatus = "active"`

          - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

          - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

      - `OptionID string`

      - `Text string`

      - `Voters []PollOptionVoter`

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

        - `Handle string`

        - `VotedAt Time`

    - `TotalVoters int64`

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

  - `Reactions []Reaction`

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

    - `Handle ChatHandle`

    - `IsMe bool`

      Whether this reaction is from the current user

    - `Type ReactionType`

      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.

      - `const ReactionTypeLove ReactionType = "love"`

      - `const ReactionTypeLike ReactionType = "like"`

      - `const ReactionTypeDislike ReactionType = "dislike"`

      - `const ReactionTypeLaugh ReactionType = "laugh"`

      - `const ReactionTypeEmphasize ReactionType = "emphasize"`

      - `const ReactionTypeQuestion ReactionType = "question"`

      - `const ReactionTypeCustom ReactionType = "custom"`

      - `const ReactionTypeSticker ReactionType = "sticker"`

    - `CustomEmoji string`

      Custom emoji if type is "custom", null otherwise

    - `Sticker ReactionSticker`

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

      - `FileName string`

        Filename of the sticker

      - `Height int64`

        Sticker image height in pixels

      - `MimeType string`

        MIME type of the sticker image

      - `URL string`

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

      - `Width int64`

        Sticker image width in pixels

  - `UpdatedAt Time`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  pollEnvelope, err := client.Chats.Polls.New(
    context.TODO(),
    "550e8400-e29b-41d4-a716-446655440000",
    linqgo.ChatPollNewParams{
      Poll: linqgo.ChatPollNewParamsPoll{
        Options: []linqgo.ChatPollNewParamsPollOption{linqgo.ChatPollNewParamsPollOption{
          Text: "Tacos",
        }, linqgo.ChatPollNewParamsPollOption{
          Text: "Sushi",
        }},
        IdempotencyKey: linqgo.String("poll-abc123"),
      },
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", pollEnvelope.ChatID)
}
```

#### Response

```json
{
  "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"
}
```

## Domain Types

### Poll

- `type Poll struct{…}`

  Poll content — options and the aggregate voter count.

  - `Options []PollOption`

    - `CanBeEdited bool`

    - `CreatorHandle ChatHandle`

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

      - `ID string`

        Unique identifier for this handle

      - `Handle string`

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

      - `JoinedAt Time`

        When this participant joined the chat

      - `Service ServiceType`

        Messaging service type

        - `const ServiceTypeIMessage ServiceType = "iMessage"`

        - `const ServiceTypeSMS ServiceType = "SMS"`

        - `const ServiceTypeRCS ServiceType = "RCS"`

      - `IsMe bool`

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

      - `LeftAt Time`

        When they left (if applicable)

      - `Status ChatHandleStatus`

        Participant status

        - `const ChatHandleStatusActive ChatHandleStatus = "active"`

        - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

        - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

    - `OptionID string`

    - `Text string`

    - `Voters []PollOptionVoter`

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

      - `Handle string`

      - `VotedAt Time`

  - `TotalVoters int64`

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

### Poll Envelope

- `type PollEnvelope struct{…}`

  Message-level envelope returned by every poll endpoint.

  - `ChatID string`

  - `CreatedAt Time`

  - `MessageID string`

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

  - `Poll Poll`

    Poll content — options and the aggregate voter count.

    - `Options []PollOption`

      - `CanBeEdited bool`

      - `CreatorHandle ChatHandle`

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

        - `ID string`

          Unique identifier for this handle

        - `Handle string`

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

        - `JoinedAt Time`

          When this participant joined the chat

        - `Service ServiceType`

          Messaging service type

          - `const ServiceTypeIMessage ServiceType = "iMessage"`

          - `const ServiceTypeSMS ServiceType = "SMS"`

          - `const ServiceTypeRCS ServiceType = "RCS"`

        - `IsMe bool`

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

        - `LeftAt Time`

          When they left (if applicable)

        - `Status ChatHandleStatus`

          Participant status

          - `const ChatHandleStatusActive ChatHandleStatus = "active"`

          - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

          - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

      - `OptionID string`

      - `Text string`

      - `Voters []PollOptionVoter`

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

        - `Handle string`

        - `VotedAt Time`

    - `TotalVoters int64`

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

  - `Reactions []Reaction`

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

    - `Handle ChatHandle`

    - `IsMe bool`

      Whether this reaction is from the current user

    - `Type ReactionType`

      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.

      - `const ReactionTypeLove ReactionType = "love"`

      - `const ReactionTypeLike ReactionType = "like"`

      - `const ReactionTypeDislike ReactionType = "dislike"`

      - `const ReactionTypeLaugh ReactionType = "laugh"`

      - `const ReactionTypeEmphasize ReactionType = "emphasize"`

      - `const ReactionTypeQuestion ReactionType = "question"`

      - `const ReactionTypeCustom ReactionType = "custom"`

      - `const ReactionTypeSticker ReactionType = "sticker"`

    - `CustomEmoji string`

      Custom emoji if type is "custom", null otherwise

    - `Sticker ReactionSticker`

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

      - `FileName string`

        Filename of the sticker

      - `Height int64`

        Sticker image height in pixels

      - `MimeType string`

        MIME type of the sticker image

      - `URL string`

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

      - `Width int64`

        Sticker image width in pixels

  - `UpdatedAt Time`
