Skip to main content
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

limit
number
default:"10"
Number of proposals to return (max: 50)
offset
number
default:"0"
Number of proposals to skip for pagination
filter
string
default:"relevant"
Filter proposals by status
  • relevant - Active and upcoming proposals (excludes cancelled)
  • everything - All proposals including cancelled
type
string
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

meta
object
Pagination metadata
data
array
Array of proposal objects

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

proposalId
string
required
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

proposalId
string
required
The unique identifier of the proposal

Query Parameters

limit
number
default:"20"
Number of votes to return (max: 1000)
offset
number
default:"0"
Number of votes to skip for pagination
sort
string
default:"weight"
Sort order:
  • weight - Sort by voting power (highest first)
  • block_number - Sort by vote timestamp (newest first)

Response

meta
object
Pagination metadata
data
array
Array of vote objects

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:
  1. DAO Node API - Primary source with caching (30 second revalidation)
  2. PostgreSQL Database - Fallback for when DAO Node is unavailable
  3. Archive Service - Historical proposal data
  4. 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

Pagination Example

# 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
}

Build docs developers (and LLMs) love