# 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.common.xyz/commonwealth/protocol/poll-integration-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
