Skip to content

GET /polls/{pollMessageId}/results always returns 404 "No votes found" even after votes arrive via webhook (v0.7.1) #60

@asoftdb

Description

@asoftdb

Welcome!

  • Yes, I have searched for similar issues on GitHub and found none.

What did you do?

Tried to retrieve poll results via GET /polls/{pollMessageId}/results for polls that I sent via POST /send/poll, after a real recipient voted on the poll in their WhatsApp app.

Reproduction

  1. Pair an instance with a sender WhatsApp number.
  2. Send a poll: POST /send/poll with { "number": "<recipient>", "question": "...", "options": ["A","B","C"], "maxAnswer": 1 }. Capture the response's data.Info.ID (e.g. 3EB0DBF1C91EA77B149327) and data.Message.messageContextInfo.messageSecret.
  3. On the recipient phone, open the chat and tap one of the poll options.
  4. Confirm the vote arrived at evolution-go by checking the webhook payload — it shows a pollUpdateMessage with the original poll's pollCreationMessageKey.ID, an encIV, and an encPayload (the encrypted vote).
  5. Call GET /polls/{pollMessageId}/results with the poll's WhatsApp message ID from step 2, using the same instance's apikey.

Tested via every available auth surface:

  • fetch() from a tab on the Manager origin with the instance's apikey
  • fetch() with the global API key (returns 401 — endpoint requires instance scope, as expected)
  • The Manager UI's own API Tester at /manager/api-tester against the same endpoint, with the correct instance selected and the same pollMessageId

Across all five attempts, response is identical.

What did you expect?

I expected GET /polls/{pollMessageId}/results to return the votes for the poll — either as decrypted option counts (preferred) or at minimum the encrypted vote records that evolution-go has clearly already received (we can see them in our webhook payload sitting in our DB).

The endpoint's description in the API tester says "Retorna todos os votos de uma enquete específica" / "Returns all votes of a specific poll," which sets the expectation that it should return ALL received votes.

What did you observe instead of what you expected?

Endpoint always returns HTTP 404 with body:

{
  "error": "No votes found for this poll",
  "message": "This poll has no votes yet, or the pollMessageId is incorrect"
}

This is consistent across:

  • Polls created seconds ago
  • Polls created hours ago
  • Polls voted on before AND after the webhook was registered
  • Polls voted on by a recipient with readMessages=true set on the sender instance
  • Multiple distinct pollMessageId values

Meanwhile the corresponding pollUpdateMessage webhook event arrives normally in the configured webhook URL within ~1 second of the vote, including the pollCreationMessageKey.ID matching the pollMessageId we're querying. So the server clearly knows the vote exists — /polls/{id}/results just doesn't return it.

Reading pkg/routes/routes.go confirms the route is registered:

routes.GET("/:pollMessageId/results", r.pollHandler.GetPollResults)

Without source access to the handler implementation it's not clear whether (a) the handler is stubbed and never populates results from webhook ingestion, (b) it queries a vote table that's only populated by some other code path, or (c) it tries to decrypt the votes server-side using messageSecret and fails silently. Any of these explanations would result in the same observed 404.

Screenshots/Videos

No response

Which version are you using?

evolution-go v0.7.1 (Docker)

What is your environment?

Docker

If applicable, paste the log output

No response

Additional Notes

Sender / recipient setup

  • Sender: personal WhatsApp number connected via QR (not Business)
  • Recipient: personal WhatsApp number on Android, current app version, not on Business / WABA / Cloud API
  • Webhook URL is correctly registered (other inbound events flow normally; pollUpdateMessage arrives within ~1s of voting)
  • readMessages advanced setting was ON during the final retests (made no difference)

Sample webhook payload (the vote IS arriving)

{
  "event": "Message",
  "data": {
    "Info": { "ID": "<vote msg id>", "Type": "poll", "Sender": "<voter>@s.whatsapp.net", "PushName": "..." },
    "Message": {
      "pollUpdateMessage": {
        "vote": { "encIV": "<base64>", "encPayload": "<base64>" },
        "pollCreationMessageKey": { "ID": "<original poll msg id>", "fromMe": false, "remoteJID": "<creator-lid>@lid" }
      }
    }
  }
}

The pollCreationMessageKey.ID is the same pollMessageId we pass to GET /polls/{pollMessageId}/results.

Questions for maintainers

  1. Is GetPollResults intended to return only votes decrypted server-side, or also the raw encrypted records?
  2. Is there a separate ingestion path that populates the underlying vote storage that the handler reads from, and is that ingestion working in v0.7.1? (i.e. does the webhook handler write votes anywhere durable, or is it fire-and-forward only?)
  3. If self-decryption is required client-side instead, would maintainers consider documenting the algorithm? I attempted ~11 HKDF/AES-GCM variants based on Baileys forks and none decrypted the encPayload against messageSecret + stanzaId + creatorJid + voterJid + "Poll Vote" — would help to know whether the algorithm uses the LID-form JIDs vs phone-form, includes the senderTimestampMS, or follows a different scheme.

Happy to provide raw payload bytes (encIV + encPayload + messageSecret + JIDs) for a test case if it helps maintainers reproduce.

Thanks for the project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions