Guide8 min read

WhatsApp polls API: send polls and get live votes

Yes, you can send a WhatsApp poll through an API: with Mossmoon it is one POST /send call with a poll object, on any WhatsApp number your customer links by QR. Every vote, changed vote or cleared vote then reaches your webhook as message.poll_vote, carrying the whole current tally.

Published By the Mossmoon team


On this page
  1. 01Can you send polls by API?
  2. 02Send a poll
  3. 03Poll field rules
  4. 04Get the votes
  5. 05Changed and cleared votes
  6. 06Read results later
  7. 07Step by step
  8. 08Events and RSVPs
  9. 09Limits
  10. 10Mossmoon vs goghl.ai
  11. 11FAQ

Polls are how WhatsApp groups decide things: which slot, which menu, which date. When the poll comes from your app, the answers can land in your app too, already counted, instead of someone screenshotting the results into a spreadsheet.

This guide shows the exact request, the rules WhatsApp puts on questions and options, the vote payload, how to handle changed votes, and the sibling feature people often want next: events with RSVPs. Polls are part of everything you can send on the $15 per line plan.

Can you send WhatsApp polls with an API?

Not with Meta’s official WhatsApp Business API. It has no poll message type, so a business on the Cloud API can’t send a poll or receive one. Its nearest tools are interactive buttons and lists, which are a different thing: one tap that becomes a reply message, with no shared tally anyone can see.

Mossmoon takes the other route. Your customer links their own WhatsApp number as a linked device, so your code can do what they can do on their phone, including real polls. It works on personal WhatsApp and the WhatsApp Business app, in one-to-one chats and in groups, with no templates or business verification.

A poll is one send. Every vote after that comes to you, already counted.

How do I send a WhatsApp poll with the API?

Call the same send endpoint you use for text, with a poll object instead of text. To post into a group, put the group id (it ends in @g.us) in to_wa_id. Authenticate with your API key as a Bearer token.

curl https://mossmoon.app/api/v1/wa/lines/wa_8f3c2e1a/send \
  -H "Authorization: Bearer mm_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to_wa_id": "[email protected]",
    "poll": {
      "question": "Long run this week?",
      "options": ["Sat 7am", "Sat 9am", "Sun 8am"],
      "multiple_answers": true
    }
  }'
202 means queued, not delivered. message.delivered follows like for any send, and the message_id is WhatsApp’s own id for the poll.

A poll to one person

For a one-to-one chat, use to with a phone number in international format. Leave out multiple_answers and each person can pick one answer.

Poll in a direct chat
{
  "to": "+15553182290",
  "poll": {
    "question": "Which slot suits you for the viewing?",
    "options": ["Thu 5pm", "Fri 12pm", "Sat 10am"]
  }
}

What are the rules for questions and options?

Mossmoon checks the same limits WhatsApp’s own “Create poll” screen enforces, before the message is stored or counted. A request that breaks one gets a 400 with the reason, so it is safe to fix and retry.

WhatsApp's Create poll screen, and the field and rule behind each part.

In words: a question of up to 255 characters, a list of 2 to 12 options of up to 100 characters each with no two the same, and an optional multiple_answers flag. A poll also travels alone, so it can’t share a send with text, media or mentions; if it needs an explanation, send that as its own message first. The full contract, including the other message kinds that share this endpoint, is in the docs under polls, events, locations, contact cards and forwards.

How do I get WhatsApp poll results?

Through your webhook. Each time someone votes, message.poll_vote arrives with the voter, the options they picked, and the whole current tally in results. You never add votes up yourself: the numbers come from WhatsApp’s own vote data for that poll.

Daniel ticks two answers. Your app gets one webhook with his choice and the new totals.
Webhook: message.poll_vote
POST https://your-app.com/webhooks/whatsapp
X-Mossmoon-Event: message.poll_vote
X-Mossmoon-Signature: sha256=...

{
  "event": "message.poll_vote",
  "line_id": "wa_8f3c2e1a",
  "data": {
    "message_id": "[email protected]_3EB0C431D4B0FF2A_36554986758374@lid",
    "chat_wa_id": "[email protected]",
    "is_group": true,
    "voter_wa_id": "103414994325753@lid",
    "voter_e164": "+15553182290",
    "from_me": false,
    "selected_options": ["Sat 7am", "Sun 8am"],
    "ts": "2026-10-16T18:06:40.000Z",
    "results": [
      { "option": "Sat 7am", "votes": 10 },
      { "option": "Sat 9am", "votes": 5 },
      { "option": "Sun 8am", "votes": 4 }
    ],
    "voters": [
      {
        "wa_id": "103414994325753@lid",
        "e164": "+15553182290",
        "options": ["Sat 7am", "Sun 8am"],
        "voted_at": "2026-10-16T18:06:40.000Z"
      }
      // ...one entry per person who has voted
    ]
  }
}
  • Match on message_id. It is the poll’s id, the same one the send returned. chat_wa_id and is_group tell you which chat it is in.
  • voters is everyone, not just this voter. One entry per person who has voted, with their options and voted_at. It is the “View votes” screen as data.
  • voter_e164 can be null. Some people reach a line only by WhatsApp’s internal id (ending in @lid), so key voters on voter_wa_id.
  • from_me: true means the vote came from the line’s own phone, for example your customer voting on their own poll.

Every webhook is signed, so check X-Mossmoon-Signature before trusting it (signature docs). If you have no endpoint yet, the webhook setup guide walks through one.

What happens when someone changes or removes a vote?

You get another message.poll_vote. A changed vote carries the new choice; a vote taken back carries selected_options: []. Either way results and voters are recalculated, so the rule for your code is simple: keep the newest one.

One person, three webhooks. Each carries the tally as it stands at that moment.

Can I read poll results without the webhook?

Yes. The latest tally is stored on the poll message itself. GET /lines/:id/messages returns the poll with its question, options, current results and voters, which makes it the reconciliation path if your endpoint was down while people voted (message history docs).

Polls other people send arrive too. A poll posted into a chat the line is in comes in as message.received with readable text such as “Poll: Which day works?” plus a poll object with question, options and selectable_count (0 means any number of answers). Details are under locations, contact cards and polls.

Step by step: from a poll to its results

The whole flow, from a freshly linked number to a tally your app keeps up to date on its own.

  1. 1

    Link the WhatsApp number

    Create a line with POST /api/v1/wa/lines and show your customer the connect_url. They scan the QR from WhatsApp’s Linked devices screen, and you get line.ready.
  2. 2

    Send the poll

    POST /lines/:id/send with to (a phone number) or to_wa_id (a group) and a poll object: question, 2 to 12 options, and multiple_answers if people may pick more than one.
  3. 3

    Store the message_id

    The 202 response returns WhatsApp’s id for the poll message. Every vote webhook carries the same message_id, so save it next to whatever the poll is about (a booking, a class, a deal).
  4. 4

    Handle message.poll_vote

    Verify the signature, find the poll by message_id, and replace your stored tally with results and voters when the webhook’s ts is newer than the one you have.
    Keep the newest tally
    // Express-style handler. Verify the signature first (see the docs).
    app.post("/webhooks/whatsapp", async (req, res) => {
      res.sendStatus(200); // ack fast, work after
      const { event, data } = req.body;
      if (event !== "message.poll_vote") return;
    
      const poll = await db.polls.findByMessageId(data.message_id);
      if (!poll) return; // a poll you didn't send through the API
    
      // Webhooks can arrive out of order: keep only the newest tally.
      if (poll.tally_at && poll.tally_at >= data.ts) return;
      if (data.results) {
        await db.polls.update(poll.id, {
          results: data.results,
          voters: data.voters,
          tally_at: data.ts,
        });
      }
    });
  5. 5

    Read the results any time

    GET /lines/:id/messages returns the poll message with its latest results and voters, so a missed webhook never loses the count.

How do I send a WhatsApp event and collect RSVPs?

When the question is “who’s coming?”, an event often beats a poll. It renders as a WhatsApp event card with a date, and people answer Going, Maybe or Not going. Send it with an event object on the same endpoint.

Send an event
POST /api/v1/wa/lines/wa_8f3c2e1a/send
Authorization: Bearer mm_live_...

{
  "to_wa_id": "[email protected]",
  "event": {
    "name": "Long run + coffee",
    "start_time": "2026-10-24T14:00:00Z",
    "end_time": "2026-10-24T16:00:00Z",
    "location": "Riverside Park, north gate",
    "allow_extra_guests": true
  }
}

name (up to 100 characters) and start_time (ISO 8601) are required. end_time must come after the start, and the start can be at most 5 years ahead. description, location, allow_extra_guests and call are optional; call: "voice" or "video" adds a WhatsApp call link to the event.

The event in the group, and the webhook one RSVP produces.

Every answer arrives as message.event_response, shaped like a poll vote: who answered (responder_wa_id, responder_e164), their response (going, not_going or maybe), everyone’s latest answer in responses, and the totals in counts. A changed answer sends a new webhook with the new totals, and the event message in GET /messages keeps the latest responses and counts too.

Reactions follow the same pattern for lighter feedback: message.reaction fires for every emoji left on a message, and you can react from the API too (reactions docs, which also hold the vote and RSVP payloads).

What are the limits of the WhatsApp polls API?

  • Your code can’t vote. There is no endpoint to vote on a poll or answer an event as the line. People vote on their phones; you receive the result.
  • A poll can’t be edited. The edit endpoint covers text and captions only. To change a poll, delete it for everyone (the line’s own messages, within about 2 days) and send a new one. There is no endpoint to close a poll either.
  • One kind per message. No text, media or mentions in the same send as a poll or an event.
  • Polls count as sends. Each poll counts against the line’s daily cap (soft 750, hard 1,500 for warmed lines, reset at midnight UTC; see rate limits). Votes coming back don’t.
  • Treat results as optional. If the tally can’t be read at that moment it comes back null while selected_options still tells you what this person picked. Keep the last tally you had.
  • No buttons or lists. Mossmoon sends what a person can send from the WhatsApp app, so there are no interactive buttons or list menus. A poll is the closest thing.
  • Groups follow group rules. In a group where only admins can send, the line needs to be an admin to post a poll; otherwise the send fails with cannot_send.

Mossmoon vs goghl.ai for WhatsApp polls

goghl.ai links WhatsApp by QR inside GoHighLevel. Its public site and help center don’t mention polls or events anywhere, so every row below is marked “Not listed” rather than “No”. These are the poll and event features we offer that their docs don’t list.

Mossmoon

$15 a line. First line free for 7 days.

Start free →
Mossmoon vs goghl.ai
FeatureRecommendedMossmoon$15 a line. First line free for 7 days.Start free →goghl.ai
Send WhatsApp polls from your own codeYespoll on POST /send, single or multiple answer, to a person or a groupNot listed
A webhook for every vote, with the full tallyYesmessage.poll_vote with results and every voterNot listedTheir webhooks cover inbound, outbound and failed messages
Send WhatsApp events and collect RSVPsYesevent on /send, plus message.event_response with countsNot listed
Latest poll results in the message historyYesGET /messages returns results and voters on the pollNot listed

Checked against goghl.ai’s public site and help center on October 16, 2026. “Not listed” means we couldn’t find it in their docs, not that it can’t exist. Only features goghl.ai doesn’t list are shown. Sources: goghl.ai webhooks, goghl.ai help center, goghl.ai.

Meta’s WhatsApp Business API can’t send or receive polls at all. Our Business API vs personal API explainer covers the other differences, and the full three-way table is on the features page.

Frequently asked questions


Yes. With Mossmoon you call POST /api/v1/wa/lines/:id/send with a poll object (a question and 2 to 12 options) on any WhatsApp number linked by QR, personal or Business app. Each vote then reaches your webhook as message.poll_vote with the full tally.


No. Meta's WhatsApp Business API has no poll message type, so it can't send polls or receive them. Its closest tools are interactive buttons and lists, which work differently and which Mossmoon doesn't offer.


Every message.poll_vote webhook carries voters: one entry per person with their wa_id, phone number when WhatsApp shares it, the options they picked and when. The same list sits on the poll in GET /messages.


Between 2 and 12. Each option can be up to 100 characters and no two can be the same, and the question can be up to 255 characters. Anything outside those rules gets a 400 with the reason, before anything is sent or counted.


Yes. Use to with their phone number in international format instead of to_wa_id. Polls work the same in one-to-one chats and in groups.


No. The API sends polls and reports votes, but has no endpoint to vote or to close a poll. To stop answers, you can delete the poll for everyone (the line's own messages, within about 2 days) and post the result.


Yes, a poll is one send, wherever it goes. Votes coming back don't count. Warmed lines get a soft cap of 750 sends a day and a hard cap of 1,500, reset at midnight UTC.



Ask on WhatsApp. Count in your app.

Link a number with one QR scan, send polls and events over REST and get every vote on your webhook. $15 per line a month, first line free for 7 days.

WhatsApp polls API: send polls and get live votes · Mossmoon