Polls API Integration Example
1 Scope & Goal
Enable a client application to surface live Polls data that originates in Common.
Read-only access to Poll objects
Periodic refresh of results for live tallies
2 Commonwealth API โ Polls Contract
Get polls for a thread
POST /api/v1/GetPolls
id, prompt, options[], ends_at, created_at, updated_at, votes[]
Get votes for a specific poll
POST /api/v1/GetPollVotes
id, poll_id, option, address, user_id, weight, created_at
Create a new poll
POST /api/v1/CreatePoll
id, prompt, options[], ends_at, thread_id, community_id
Vote on a poll
POST /api/v1/CreatePollVote
Vote object: poll_id, option, address, community_id
Details:
Protocol: tRPC over HTTP
Authentication: API Key (x-api-key) + Address (address)
Rate Limits:
Tier 1: 10 req/min
Tier 2: 60 req/min
Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Base URL: /api/v1/
Version: 2.0.0
3 Data Models
interface Poll {
id: number;
community_id: string;
thread_id: number;
prompt: string;
options: string[];
ends_at: Date | null;
created_at: Date;
updated_at: Date;
votes?: Vote[];
}
interface Vote {
id: number;
poll_id: number;
option: string;
address: string;
user_id: number;
author_community_id?: string;
community_id: string;
calculated_voting_weight?: string;
created_at: Date;
updated_at: Date;
}
Notes:
Polls are thread-scoped
Vote weights calculated server-side
ends_at null = infinite
4 Polling Strategy
Bootstrap
On startup, call GetPolls for target threads
Cache by poll.id
Periodic Refresh
Every 60s: re-fetch GetPolls
Compare updated_at to detect changes
Vote Fetch
On change or first load, call GetPollVotes
Aggregate client-side
Rate-Limit Handling
On 429, back off exponentially: 60 โ 120 โ 240 โ 300s
Merge & Emit
Update cache and fire polls.updated event
Housekeeping
Stop polling when polls closed and view hidden
No incremental endpoint available; rely on updated_at diffing.
5 Authentication & Headers
const headers = {
'x-api-key': 'YOUR_API_KEY',
'address': 'USER_WALLET_ADDRESS',
'Content-Type': 'application/json'
};
Include both headers on every call.
6 Example Client Data Model
interface PollOption {
id: string;
text: string;
count: number;
weight: string;
}
interface ExamplePoll {
pollId: number;
threadId: number;
communityId: string;
prompt: string;
options: PollOption[];
startTime: string;
endTime: string | null;
state: 'active' | 'closed';
totalVotes: number;
totalWeight: string;
updatedAt: string;
}
Aggregation Logic:
function aggregateVotes(votes: Vote[]): PollOption[] {
const map = new Map<string, {count: number; weight: bigint}>();
votes.forEach(v => {
const cur = map.get(v.option) || {count: 0, weight: 0n};
const w = v.calculated_voting_weight ? BigInt(v.calculated_voting_weight) : 1n;
map.set(v.option, {count: cur.count + 1, weight: cur.weight + w});
});
return Array.from(map.entries()).map(([text, data], i) => ({
id: `${i}`, text, count: data.count, weight: data.weight.toString()
}));
}
Cache in IndexedDB/localStorage for fast cold starts.
7 UX Hooks
polls.loading
Show skeleton/shimmer
polls.updated
Animate count change; toast optional
Poll expired
Mark closed, disable voting
Rate limited
Show back-off indicator
8 Testing Checklist
Unit: Mock tRPC, test aggregation & back-off
Integration: Staging API keys, multiple poll states
Load: Simulate 10+ clients @60s intervals
Auth: Invalid/missing headers โ 401
Offline/Online: Cache persists; first refresh uses cache
9 Sample Implementation
Extract core patterns into service and manager classes.
CommonwealthPollService
// Handles tRPC calls with rate-limit error handling
PollManager
// Coordinates periodic refresh, back-off, caching, and events
10 Action Items
Backend: Obtain API keys; identify thread IDs
Frontend: Build tRPC wrapper & aggregation utils
DevOps: Monitor errors, rate limits, latency
Docs: Publish API key guide & thread discovery
Last updated
Was this helpful?