The Proposals API provides access to on-chain and off-chain governance proposals.
List Proposals
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://vote.ens.domains/api/v1/proposals?limit=10&filter=relevant"
Location in code: src/app/api/v1/proposals/route.ts:46
Query Parameters
Number of proposals to return (max: 50)
Number of proposals to skip for pagination
Filter proposals by status
relevant - Active and upcoming proposals (excludes cancelled)
everything - All proposals including cancelled
Filter by proposal type:
STANDARD - Standard on-chain proposals
APPROVAL - Approval voting proposals
OPTIMISTIC - Optimistic proposals
SNAPSHOT - Snapshot off-chain proposals
OFFCHAIN_OPTIMISTIC - Off-chain optimistic proposals
OFFCHAIN_OPTIMISTIC_TIERED - Tiered off-chain optimistic
OFFCHAIN_STANDARD - Off-chain standard proposals
OFFCHAIN_APPROVAL - Off-chain approval voting
OFFCHAIN - All off-chain proposals
EXCLUDE_ONCHAIN - Only off-chain proposals
Response
Pagination metadata
Whether more results are available
Number of proposals in current response
Total number of proposals matching filter
Array of proposal objects
Unique proposal identifier
Full proposal description (markdown)
Current status: PENDING, ACTIVE, SUCCEEDED, DEFEATED, EXECUTED, CANCELLED
Type of proposal (see type parameter above)
Block number when voting starts
Block number when voting ends
ISO timestamp when voting starts
ISO timestamp when voting ends
Required quorum for proposal
Transaction hash of proposal creation
Example Response
{
"meta": {
"has_next": true,
"next_offset": 10,
"total_returned": 10,
"total_count": 245
},
"data": [
{
"id": "0x1a2b3c4d5e6f...",
"proposalId": "123",
"title": "Upgrade Treasury Timelock",
"description": "# Proposal Summary\n\nThis proposal upgrades...",
"status": "ACTIVE",
"proposalType": "STANDARD",
"startBlock": "18500000",
"endBlock": "18550000",
"startTime": "2024-01-15T10:00:00Z",
"endTime": "2024-01-18T10:00:00Z",
"forVotes": "5000000000000000000000",
"againstVotes": "1000000000000000000000",
"abstainVotes": "500000000000000000000",
"quorum": "4000000000000000000000",
"proposer": "0x1234567890abcdef1234567890abcdef12345678",
"transactionHash": "0xabcd...1234"
}
]
}
Get Proposal by ID
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://vote.ens.domains/api/v1/proposals/123"
Location in code: src/app/api/v1/proposals/[proposalId]/route.ts:4
Path Parameters
The unique identifier of the proposal
Response
Returns a single proposal object with the same structure as the list endpoint.
Example Response
{
"id": "0x1a2b3c4d5e6f...",
"proposalId": "123",
"title": "Upgrade Treasury Timelock",
"description": "# Proposal Summary\n\nThis proposal upgrades the treasury timelock contract to add multi-sig support...",
"status": "ACTIVE",
"proposalType": "STANDARD",
"startBlock": "18500000",
"endBlock": "18550000",
"forVotes": "5000000000000000000000",
"againstVotes": "1000000000000000000000",
"abstainVotes": "500000000000000000000",
"proposer": "0x1234567890abcdef1234567890abcdef12345678",
"proposalData": {
"targets": ["0xTreasuryAddress"],
"values": ["0"],
"calldatas": ["0x..."],
"description": "Upgrade Treasury Timelock"
}
}
Get Proposal Votes
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://vote.ens.domains/api/v1/proposals/123/votes?limit=20&sort=weight"
Location in code: src/app/api/v1/proposals/[proposalId]/votes/route.ts:28
Path Parameters
The unique identifier of the proposal
Query Parameters
Number of votes to return (max: 1000)
Number of votes to skip for pagination
Sort order:
weight - Sort by voting power (highest first)
block_number - Sort by vote timestamp (newest first)
Response
Array of vote objects
Vote choice: 0 = Against, 1 = For, 2 = Abstain
Optional vote reason/comment
Transaction hash of the vote
Block number when vote was cast
Example Response
{
"meta": {
"has_next": true,
"next_offset": 20,
"total_returned": 20,
"total_count": 156
},
"data": [
{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"support": 1,
"weight": "50000000000000000000000",
"reason": "This proposal improves security and decentralization.",
"transactionHash": "0xabc...123",
"blockNumber": "18525000"
}
]
}
Proposal Types
The API supports multiple proposal types:
Standard Proposals
Traditional on-chain proposals with for/against/abstain voting.
{
proposalType: "STANDARD",
proposalData: {
targets: string[], // Contract addresses to call
values: string[], // ETH values to send
calldatas: string[], // Encoded function calls
description: string // Proposal description
}
}
Approval Voting Proposals
Voters can approve multiple options from a list.
{
proposalType: "APPROVAL",
proposalData: {
options: Array<[string[], string[], string[], string]>,
params: [maxApprovals, criteria, budgetToken, criteriaValue, budget]
}
}
Optimistic Proposals
Proposals that pass unless explicitly vetoed.
{
proposalType: "OPTIMISTIC",
proposalData: {
targets: string[],
values: string[],
calldatas: string[],
description: string
}
}
Snapshot Proposals
Off-chain voting via Snapshot.
{
proposalType: "SNAPSHOT",
proposalData: {
snapshotId: string,
choices: string[],
type: "single-choice" | "approval" | "ranked-choice"
}
}
Data Sources
Proposals are fetched from multiple sources:
- DAO Node API - Primary source with caching (30 second revalidation)
- PostgreSQL Database - Fallback for when DAO Node is unavailable
- Archive Service - Historical proposal data
- Snapshot - Off-chain voting proposals
Filtering and Sorting
Filter by Status
# Only active proposals
GET /api/v1/proposals?filter=relevant
# All proposals including cancelled
GET /api/v1/proposals?filter=everything
Filter by Type
# Only on-chain proposals
GET /api/v1/proposals?type=STANDARD
# Only off-chain proposals
GET /api/v1/proposals?type=EXCLUDE_ONCHAIN
# Snapshot proposals only
GET /api/v1/proposals?type=SNAPSHOT
# Page 1: First 20 proposals
GET /api/v1/proposals?limit=20&offset=0
# Page 2: Next 20 proposals
GET /api/v1/proposals?limit=20&offset=20
# Page 3: Next 20 proposals
GET /api/v1/proposals?limit=20&offset=40
Error Responses
Invalid Query Parameters
{
"error": "Invalid query parameters: limit must be between 1 and 50",
"status": 400
}
Proposal Not Found
{
"error": "Proposal not found",
"status": 404
}
Authentication Required
{
"error": "Missing or invalid bearer token",
"status": 401
}