Interactive Polls & Quizzes (sendPoll & poll_answer)

Raw MD
Create regular voting polls, educational trivia quizzes with explanations, timer deadlines, and process live voting updates.

Interactive Polls & Trivia Quizzes Overview

Telegram polls allow bots to engage communities, run democratic elections, or administer educational quizzes with instant correct/wrong animations and confetti. Poll updates arrive via the poll_answer webhook object.

1. Creating Regular Polls vs. Quiz Mode

Poll Type Key Parameters Behavior in Telegram
Regular Poll type => 'regular', allows_multiple_answers, is_anonymous Standard public or anonymous voting. Users can retract or change their vote unless poll is closed.
Quiz Mode type => 'quiz', correct_option_id, explanation Users choose once. Correct answer triggers celebratory confetti; wrong answer displays the explanation tooltip.
PHP — Creating Regular and Quiz Polls
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

// 1. Send Public Multiple-Choice Poll
function send_community_poll(string|int $chatId): void {
    bot('sendPoll', [
        'chat_id'                 => $chatId,
        'question'                => 'Which feature should Botlify Cloud build next?',
        'options'                 => json_encode([
            ['text' => '⚡ Edge CDN Webhooks'],
            ['text' => '📱 Native iOS/Android SDK'],
            ['text' => '🧠 Autonomous Agent Swarms'],
            ['text' => '📊 Advanced Analytics Dashboard']
        ]),
        'is_anonymous'            => false, // Vote identities visible to admins
        'allows_multiple_answers' => true,
        'open_period'             => 86400  // Automatically closes after 24 hours
    ]);
}

// 2. Send Educational Trivia Quiz with Explanation
function send_developer_quiz(string|int $chatId): void {
    bot('sendPoll', [
        'chat_id'                => $chatId,
        'question'               => 'What is the default SQLite journal mode used by Botlify Cloud?',
        'options'                => json_encode([
            ['text' => 'DELETE (Default Rollback)'],
            ['text' => 'WAL (Write-Ahead Logging)'],
            ['text' => 'MEMORY Mode'],
            ['text' => 'OFF (No Journaling)']
        ]),
        'type'                   => 'quiz',
        'correct_option_id'      => 1, // 0-indexed: Option 1 (WAL) is correct
        'explanation'            => 'Botlify Cloud runs SQLite in WAL (Write-Ahead Logging) mode with a 32MB cache to achieve 20ms concurrent reads and writes.',
        'explanation_parse_mode' => 'HTML',
        'is_anonymous'           => true
    ]);
}

2. Stopping / Closing a Poll Programmatically

When a contest ends or voting deadline arrives, freeze the poll using stopPoll:

PHP — Freezing Polls with stopPoll
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

$result = bot('stopPoll', [
    'chat_id'    => $chatId,
    'message_id' => $pollMessageId
]);

if ($result['ok'] ?? false) {
    $finalPoll = $result['result'];
    $totalVoters = $finalPoll['total_voter_count'];
    error_log("Poll closed. Total voters: {$totalVoters}");
}

3. Handling Live poll_answer Webhook Updates

When a user casts or changes a vote in a non-anonymous poll, Telegram dispatches a poll_answer update to your webhook:

PHP — Capturing and Storing poll_answer Updates
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

if (isset($update['poll_answer'])) {
    $answer   = $update['poll_answer'];
    $pollId   = $answer['poll_id'];
    $userId   = $answer['user']['id'];
    $userName = $answer['user']['first_name'] ?? 'User';
    $selected = $answer['option_ids']; // Array of selected option indices e.g. [1]

    if (empty($selected)) {
        // User retracted their vote
        $pdo->prepare("DELETE FROM poll_votes WHERE poll_id = ? AND user_id = ?")
            ->execute([$pollId, $userId]);
    } else {
        // Record or update vote in SQLite database.db
        $stmt = $pdo->prepare("
            INSERT INTO poll_votes (poll_id, user_id, chosen_option, voted_at)
            VALUES (?, ?, ?, ?)
            ON CONFLICT(poll_id, user_id) DO UPDATE SET chosen_option = excluded.chosen_option, voted_at = excluded.voted_at
        ");
        $stmt->execute([$pollId, $userId, $selected[0], time()]);
        
        // Optionally send a private reward message to the voter
        bot('sendMessage', [
            'chat_id'    => $userId,
            'text'       => "🎉 Thanks for voting in our poll, {$userName}! +50 XP awarded.",
            'parse_mode' => 'HTML'
        ]);
    }

    http_response_code(200);
    exit;
}
Botlify Cloud Runtime
Credentials are auto-injected in .env — always load them with getenv(): BOT_TOKEN, ADMIN_CHAT_ID, BOT_USERNAME. Main database: database.db (SQLite, WAL mode). Runtime errors: error.log. Quick test: send to $ADMIN_CHAT_ID. Full details: Runtime Reference.