> For the complete documentation index, see [llms.txt](https://docs.common.xyz/commonwealth/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.common.xyz/commonwealth/protocol/poll-integration-example.md).

# 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

| Purpose                       | Sample API Path             | Core Fields Returned                                                 |
| ----------------------------- | --------------------------- | -------------------------------------------------------------------- |
| 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

1. **Bootstrap**
   * On startup, call GetPolls for target threads
   * Cache by poll.id
2. **Periodic Refresh**
   * Every **60s**: re-fetch GetPolls
   * Compare updated\_at to detect changes
3. **Vote Fetch**
   * On change or first load, call GetPollVotes
   * Aggregate client-side
4. **Rate-Limit Handling**
   * On 429, back off exponentially: 60 → 120 → 240 → 300s
5. **Merge & Emit**
   * Update cache and fire polls.updated event
6. **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

| Event         | UI Behavior                          |
| ------------- | ------------------------------------ |
| 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

1. **Unit:** Mock tRPC, test aggregation & back-off
2. **Integration:** Staging API keys, multiple poll states
3. **Load:** Simulate 10+ clients @60s intervals
4. **Auth:** Invalid/missing headers → 401
5. **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

1. **Backend:** Obtain API keys; identify thread IDs
2. **Frontend:** Build tRPC wrapper & aggregation utils
3. **DevOps:** Monitor errors, rate limits, latency
4. **Docs:** Publish API key guide & thread discovery
