Build guide

Build an election results bot for X
live counts, race calls, polls

A small script watches your results source and posts each new count and call the minute it changes. Schedule the night's poll closings ahead of time. No X developer account, no per-post billing, ready for November 3.

Card required, cancel any time.

The short answer

An election results bot polls a results source (a licensed feed such as AP, a state election office, or your own poll tracking) every few minutes, compares each race with what it last posted, and sends only the changes to POST https://opentweet.io/api/v1/posts. Post race calls with the name of whoever made the call, never your own. The 2026 US midterms are on Tuesday, November 3.

Six post types for an election account

Election night rewards speed and punishes mistakes. Post less often than you can, and only when a number really moved.

Count updates

Event-driven

A close race moves 10 points of expected vote. One line: who leads, by how much, how much is left.

Race calls

Event-driven

Your source calls a race. Name the source in the post, every time.

Poll closings

Scheduled

The schedule of the night, hour by hour. Written days ahead and scheduled.

Flips

Event-driven

A seat changes party. The post people share, so keep it to the facts and the margin.

Poll averages

Event-driven

Between elections: a new poll lands, your average moves, you post the change with a chart.

Morning recap

Scheduled

The overnight results as one thread: what was called, what is still counting, and when the next batch is due.

The results watcher

The loop below posts a call once, and a count update only when another 10% of the expected vote is in, so a close race does not flood your followers. Swap the field names for whatever your source returns.

Python, about 35 lines

import json, pathlib, time, requests

OT_KEY = "ot_your_key"
RESULTS_URL = "https://your-results-source.example.com/races.json"
STATE = pathlib.Path("last_posted.json")   # what we already said
last = json.loads(STATE.read_text()) if STATE.exists() else {}

def post(text):
    requests.post(
        "https://opentweet.io/api/v1/posts",
        headers={"Authorization": f"Bearer {OT_KEY}"},
        json={"text": text, "publish_now": True},
    )

while True:
    for race in requests.get(RESULTS_URL).json()["races"]:
        rid, prev = race["id"], last.get(race["id"], {})
        lead = max(race["candidates"], key=lambda c: c["votes"])
        total = sum(c["votes"] for c in race["candidates"])

        if race.get("called_by") and not prev.get("called"):
            post(f"{race['called_by']} calls {race['name']} for "
                 f"{race['winner']} ({race['winner_party']}).")
            prev["called"] = True
        elif race["pct_reporting"] - prev.get("pct", 0) >= 10:
            share = lead["votes"] / total * 100 if total else 0
            post(f"{race['name']}, {race['pct_reporting']}% expected vote in: "
                 f"{lead['name']} leads with {share:.1f}%.")
            prev["pct"] = race["pct_reporting"]

        last[rid] = prev
    STATE.write_text(json.dumps(last))
    time.sleep(180)   # every 3 minutes

Run it on any server or laptop that stays awake. Every field is in the API reference. The same pattern, for scores instead of votes, is in the sports stats bot.

Write the night's schedule today

Poll closing times are known weeks ahead. Write those posts now and send them in one request with scheduled_date, up to 50 per request, so your script only has to handle the live numbers.

POST https://opentweet.io/api/v1/posts
{
  "posts": [
    { "text": "Polls close in Indiana and Kentucky at 6pm local. First counts within the hour.", "scheduled_date": "2026-11-03T22:30:00Z" },
    { "text": "7pm ET: polls close in Georgia, Virginia, South Carolina and Vermont.", "scheduled_date": "2026-11-03T23:55:00Z" },
    { "text": "8pm ET: the biggest wave of closings. Here are the 6 House races to watch first.", "scheduled_date": "2026-11-04T00:55:00Z" }
  ]
}

Between elections: the poll tracker

The accounts that keep their followers after election night post polls the rest of the year: each new poll, your running average, and a chart. Render the chart to an image, pass its URL in media_urls, and it is attached to the post. An image is not a link post.

{
  "text": "Generic ballot, 14-day average (8 polls): D 47.2, R 45.9. Last week: D 46.8, R 46.1.",
  "media_urls": ["https://your-cdn.example.com/generic-ballot-oct-23.png"],
  "publish_now": true
}

Which plan fits your account

Flat monthly price. On election night the deciding number is posts per day.

Account typeElection night volumePlan
One state, or a poll trackerUp to 20 posts a dayPro, $19.99/mo
National, the closest racesUp to 100 posts a dayAdvanced, $29/mo, 3 X accounts
One account per state or chamberUp to 300 posts a dayAgency, $49/mo, 10 X accounts

Posts with a URL also count toward link posts: Pro 1 a day, Advanced 10, Agency 20, plus link credits. Counts and calls need no link. See pricing.

Never call a race yourself. Post calls with their source. If your source retracts a call, post the correction at once.

Stay off how-to-vote claims. X's Civic Integrity policy targets misleading information about how to take part in an election. Link to the official election office instead of restating rules.

One account, labelled. Turn on the Automated label, and do not mirror the same post across accounts or tag candidates. More in X automation rules.

Frequently asked questions

When are the 2026 US midterm elections?

Tuesday, November 3, 2026. Every House seat is on the ballot, plus about a third of the Senate and most governorships. Counting runs well past election night in many states, so plan for an account that keeps posting for days, not hours.

Where does an election bot get its results?

Three options. Licensed feeds: the Associated Press sells vote counts and race calls to newsrooms and companies (Kalshi licensed AP data for the 2026 midterms, per Axios), and pricing is negotiated, not published. Official sources: state and county election offices publish results pages, and many offer downloadable files on election night. Your own analysis: polls, turnout and past results you compile yourself. The bot only posts; it never decides who won.

How do I make an election results bot for X?

Poll your results source every few minutes, compare each race with what you posted last, and send a post to https://opentweet.io/api/v1/posts only when something changed: a new count, a call, a flipped seat. OpenTweet posts it to your X account through a normal login, so you never create an X developer app or pay per post.

Can my bot call races?

Post calls, but say whose call it is ("AP calls the race for ...") and post nothing as a call that your source has not called. A bot that calls races from partial counts is the fastest way to spread a wrong result, and X's Civic Integrity policy lets it label or restrict posts that mislead people about an election.

What does X allow for automated election accounts?

Original posts on your own timeline are fine. X's Civic Integrity policy targets misleading information about how to vote, voter suppression and intimidation, and X reported suspending about 13,000 accounts tied to coordinated influence operations ahead of the midterms. Turn on the Automated label, post from one account, never auto-reply to or mention candidates, and do not post the same update from several accounts.

How many posts does election night take?

A national account easily posts 50 to 150 times on election night: counts for each close race, calls, and recaps. Pro allows 20 posts a day, Advanced 100, and Agency 300. A one-state account fits on Pro; a national one needs Advanced or Agency.

Can an AI agent run the account?

It can draft, not decide. Connect Claude, ChatGPT or Cursor to the OpenTweet MCP server and have it write the recap thread from the numbers your script collected, then approve it before it posts. Keep the numbers in the post from your data, never from the model.

Covering the news beyond election night? See the AI news account and the news aggregator account. Firing alerts from any data source? See the alert bot.

Everything you can build on X with OpenTweet

Post to X from your code, a watcher, or an AI agent. Start anywhere in the cluster.

OpenTweet vs the X API

Post, schedule, and automate X without a developer account or the $200/mo minimum.

X DM outreach, human-approved

Find and qualify leads, AI-draft DMs, approve each one, and drip-send from your own account via API or MCP.

Post to X without an API

The clean, account-safe way to post to X from your code or an AI agent.

Twitter MCP Server

Give Claude, Cursor, and OpenClaw the ability to post to X. 44 tools included.

Developer docs

Quickstart, API keys, MCP setup, and the REST reference for posting to X from code or an agent.

Cross-posting reference

One call posts to X, Bluesky and LinkedIn. The platforms field, per-network results, and why a network gets skipped.

Social media API for AI agents

Three ways an agent can post to X, Bluesky and LinkedIn, and the trade-offs of each.

LinkedIn MCP server

Post and schedule to a LinkedIn profile from Claude or Cursor through the official LinkedIn API.

XMCP vs OpenTweet

X's official MCP server bills per API call and cannot schedule. Compare it with the flat-fee hosted MCP.

MCP for AI agents

Connect your AI client to X in under two minutes, no X developer account.

Developer API and keys

REST endpoints, one bearer key, and usage tracking. Build on OpenTweet.

OpenTweet for AI agents

The posting layer for autonomous agents and automations that live on X.

Build an AI Twitter persona

Give your AI agent its own X account. Setup, cadence, and the rules that keep it safe.

Best MCP servers for social media

The 2026 ranked list. How the hosted OpenTweet MCP compares with the official X MCP and others.

Cheapest way to post to X via code

Flat fee vs pay-per-use. Why the $0.20 per-link fee flips the math past ~145 link posts a month.

X API pricing 2026

Every pay-per-use X API endpoint price from docs.x.com in one searchable table.

Bluesky posting API

Post and schedule to Bluesky with one REST call and OAuth, and cross-post to X and LinkedIn in the same request.

Automate LinkedIn posts

Post to LinkedIn from an AI agent, n8n or a script through the official Posts API, with one REST or MCP call.

Be ready before the polls close

Connect X, create a key, schedule the night, and let the watcher post the counts.