Events API

Complete documentation for the VOTR Events API endpoint

📅 Events Retrieval

The Events API allows you to search for voting events based on parameters such as recordDate, eventStatus, and more. The query response then provides access to event information including event IDs, record dates, event status, voting status, and issuer details.

Why Use This Endpoint?

  • Fetch events by record date: Brokers can call this endpoint with a recordDate to retrieve all events associated with that record date. When using this endpoint to report shareholders back for issuer communications, the request should be made on the evening of the record date to ensure all shareholders with a reportable interest are captured prior to record-date cutoff.
  • Check if events are live: Use filters like eventStatus and votingLinksActive to determine if events are currently live and available for voting.

API Endpoints

Development:

GET https://api-dev.govotr.com/api/v1/events

Production:

GET https://api.govotr.com/api/v1/events

Authentication

This endpoint uses the same OAuth authentication flow as other VOTR APIs.

Headers

Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

📋 For OAuth token generation, refer to: OAuth Token Documentation


Query Parameters

Parameter Type Description
recordDate string Record date to filter events (YYYY-MM-DD format, ET timezone). Important: The default recordDate = current date is only applied when no query parameters are passed. If any query parameter is provided (e.g., cusip, eventStatus, votingLinksActive, etc.), the default recordDate is not applied and recordDate must be explicitly specified if you want to filter by record date.
cusip string[] Comma-separated list of CUSIPs to filter by. Example: 037833100, 037833101 (max 15 CUSIPs allowed).
isin string[] Comma-separated list of ISINs to filter by. Example: AU0000254476, BMG6891L1054 (max 15 ISINs allowed).
ticker string[] Comma-separated list of tickers to filter by. Example: AAPL,TSLA (max 15 tickers allowed).
eventType string One of the supported event types: Proxy, Regulatory, Voluntary Corporate Actions.
eventStatus string Event lifecycle status. One of: Active, Upcoming, Cancelled, Completed.
votingLinksActive boolean Filter events where the voting link is active (true) or inactive (false).
cursor string Cursor for pagination (ObjectId of last event).
limit integer Maximum events per page (default: 25, max: 25).

Parameter Details

Record Date Parameter

  • Format: YYYY-MM-DD (ISO 8601 date format, ET timezone)
  • Timezone: ET (Eastern Time)
  • Example: 2024-01-15 (ET timezone)
  • Default Behavior:
    • If no query parameters are passed: Defaults to current date (Date.now)
    • If any query parameter is passed: Default is not applied; recordDate must be explicitly specified if you want to filter by record date

Cursor Parameter

  • Format: 24-character hexadecimal ObjectId
  • Purpose: Fetch the next page of events using pagination
  • Example: 64f8a1b2c3d4e5f6a7b8c9d0

Limit Parameter

  • Type: Integer
  • Default: 25
  • Maximum: 25
  • Purpose: Control number of events returned per page

Important: Default recordDate behavior

  • No parameters: If you call the endpoint with no query parameters (e.g., GET /v1/events), the API automatically applies recordDate = current date and returns events for today.
  • Any parameter provided: If you provide any query parameter (e.g., ?eventStatus=Active, ?cusip=037833100, ?limit=10, etc.), the default recordDate is not applied. You must explicitly include recordDate in your query if you want to filter by record date.

Pagination

  • Use the cursor parameter for cursor-based pagination.
  • For the first request, omit cursor and pass any filters you need (for example, recordDate, eventStatus, cusip, etc.).
  • For subsequent requests, pass the same filters plus the cursor value from the previous response’s pagination.nextCursor.
  • Continue until pagination.hasMore is false to retrieve all matching events.

Response Format

Success Response

{
  "message": "Events retrieved successfully",
  "status": true,
  "data": {
    "events": [
      {
        "eventId": "6970d4833721621f6eeab416",
        "cusip": ["86603R100"],
        "isin": ["SUM2"],
        "ticker": ["SBKO"],
        "recordDate": "2026-01-28",
        "meetingDate": "2026-02-26T00:30:00.000Z",
        "issuerName": "Summit Bank",
        "eventType": "Proxy",
        "eventStatus": "Upcoming",
        "votingOpenDateTime": null,
        "votingDeadline": null,
        "shareholderReportingDeadline": "2026-01-31T01:00:00.000Z",
        "votingLinksActive": null
      },
      {
        "eventId": "6970d7323721621f6eeab5d3",
        "cusip": ["33767E202"],
        "isin": ["CA33767E2024"],
        "ticker": ["FSV"],
        "recordDate": "2026-01-28",
        "meetingDate": "2026-03-15T14:00:00.000Z",
        "issuerName": "FirstService Corporation",
        "eventType": "Proxy",
        "eventStatus": "Cancelled",
        "votingOpenDateTime": null,
        "votingDeadline": null,
        "shareholderReportingDeadline": "2026-01-30T02:00:00.000Z",
        "votingLinksActive": null
      }
    ],
    "pagination": {
      "hasMore": true,
      "nextCursor": "6970d7323721621f6eeab5d3",
      "limit": 2
    }
  }
}

Note: Fields such as meetingDate, votingOpenDateTime, votingDeadline, shareholderReportingDeadline, and votingLinksActive may be null or an empty string depending on the event. When available, meetingDate is provided as an ISO 8601 timestamp.

Success Response (Empty Result)

{
  "message": "Events retrieved successfully",
  "status": true,
  "data": {
    "events": [],
    "pagination": {
      "hasMore": false,
      "nextCursor": null,
      "limit": 25
    }
  }
}

Response Schema

Main Response Object

Field Type Description
message string Success message
status boolean Request status (true for success)
data object Response data containing events

Data Object

Field Type Description
events array Array of event objects with voting data
pagination object Pagination metadata
meta object Response metadata (optional)

Event Object

Field Type Description
eventId string Unique event identifier (ObjectId).
eventType string Event type. One of: Proxy, Regulatory, Voluntary Corporate Actions.
issuerName string Name of the issuer. May be null.
cusip string[] Array of CUSIP numbers.
isin string[] Array of ISINs (International Securities Identification Numbers).
ticker string[] Array of ticker symbols.
recordDate string Record date in YYYY-MM-DD format (ET-based event date).
meetingDate string ISO 8601 timestamp for meeting date. May be an empty string or null when not available.
votingOpenDateTime string ISO 8601 timestamp when voting became available (when first communication was sent). May be null.
votingDeadline string ISO 8601 timestamp for voting end date and time (ET timezone). May be null.
shareholderReportingDeadline string ISO 8601 timestamp (ET) by which shareholder information must be submitted to capture and process issuer communications. May be null.
eventStatus string Current event status. One of: Active, Upcoming, Completed, Cancelled.
votingLinksActive boolean Whether voting links are currently active and functional. May be null.

Pagination Object

Field Type Description
hasMore boolean Whether more events are available
nextCursor string Cursor for next page (if hasMore=true)
limit integer Current page limit

Empty Data Response

When there are no events for the requested date or cursor, the API returns:

{
  "message": "Events retrieved successfully",
  "status": true,
  "data": {
    "events": [],
    "pagination": {
      "hasMore": false,
      "nextCursor": null,
      "limit": 25
    }
  }
}

Usage Examples

Example Requests

Get all active events

GET /v1/events?eventStatus=Active

Filter by record date

GET /v1/events?recordDate=2026-01-15

Filter by voting links status

GET /v1/events?votingLinksActive=true

Combine multiple filters

GET /v1/events?recordDate=2026-01-15&votingLinksActive=true

Filter by CUSIP

GET /v1/events?cusip=037833100

Filter by status and Voting Link

GET /v1/events?eventStatus=Active&votingLinksActive=true

Pagination - Get next page

GET /v1/events?recordDate=2026-01-15&cursor=64f8a1b2c3d4e5f6a7b8c9d2

Set custom page size

GET /v1/events?limit=25

Pagination with filters

GET /v1/events?eventStatus=Active&limit=10&cursor=64f8a1b2c3d4e5f6a7b8c9d2

Get Events by Record Date (First Request)

curl -X GET "https://api-dev.govotr.com/api/v1/events?recordDate=2024-01-15&limit=25" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"

Get Next Page Using Cursor and Record Date (Subsequent Requests)

curl -X GET "https://api-dev.govotr.com/api/v1/events?recordDate=2024-01-15&cursor=64f8a1b2c3d4e5f6a7b8c9d0&limit=25" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"

Note: When paginating through events, always include the same filter parameters (e.g., recordDate, eventStatus, etc.) along with the cursor parameter in subsequent requests to ensure you’re getting the next page of events with the same filters.

JavaScript/Node.js Example

// Get events by record date (first request)
async function getEventsByRecordDate(accessToken, recordDate, limit = 25) {
  try {
    const response = await fetch(
      `https://api-dev.govotr.com/api/v1/events?recordDate=${recordDate}&limit=${limit}`,
      {
        method: "GET",
        headers: {
          Authorization: `Bearer ${accessToken}`,
          "Content-Type": "application/json",
        },
      },
    )

    const data = await response.json()

    if (data.status) {
      console.log("Events retrieved successfully:", data.data.events)
      return data.data
    } else {
      console.error("Error retrieving events:", data.message)
      return null
    }
  } catch (error) {
    console.error("Network error:", error)
    return null
  }
}

// Get next page using cursor and record date (subsequent requests)
async function getEventsByRecordDateAndCursor(
  accessToken,
  recordDate,
  cursor,
  limit = 25,
) {
  try {
    const response = await fetch(
      `https://api-dev.govotr.com/api/v1/events?recordDate=${recordDate}&cursor=${cursor}&limit=${limit}`,
      {
        method: "GET",
        headers: {
          Authorization: `Bearer ${accessToken}`,
          "Content-Type": "application/json",
        },
      },
    )

    const data = await response.json()

    if (data.status) {
      console.log("Events retrieved successfully:", data.data.events)
      return data.data
    } else {
      console.error("Error retrieving events:", data.message)
      return null
    }
  } catch (error) {
    console.error("Network error:", error)
    return null
  }
}

// Usage example
const accessToken = "your_access_token_here"
const recordDate = "2024-01-15"

// First request
getEventsByRecordDate(accessToken, recordDate, 25)

// Subsequent requests with cursor
// getEventsByRecordDateAndCursor(accessToken, recordDate, "64f8a1b2c3d4e5f6a7b8c9d0", 25)

Python Example

import requests
from datetime import datetime

def get_events_by_record_date(access_token, record_date, limit=25):
    """
    Retrieve events for a specific record date
    """
    url = "https://api-dev.govotr.com/api/v1/events"

    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }

    params = {
        "recordDate": record_date,
        "limit": limit
    }

    try:
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            data = response.json()
            if data.get("status"):
                print(f"Events retrieved successfully: {len(data['data']['events'])} events")
                return data["data"]
            else:
                print(f"Error: {data.get('message', 'Unknown error')}")
                return None
        else:
            print(f"HTTP Error: {response.status_code}")
            print(response.text)
            return None

    except requests.exceptions.RequestException as e:
        print(f"Network error: {e}")
        return None

def get_events_by_record_date_and_cursor(access_token, record_date, cursor, limit=25):
    """
    Retrieve events using cursor pagination for a specific record date
    """
    url = "https://api-dev.govotr.com/api/v1/events"

    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }

    params = {
        "recordDate": record_date,
        "cursor": cursor,
        "limit": limit
    }

    try:
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            data = response.json()
            if data.get("status"):
                print(f"Events retrieved successfully: {len(data['data']['events'])} events")
                return data["data"]
            else:
                print(f"Error: {data.get('message', 'Unknown error')}")
                return None
        else:
            print(f"HTTP Error: {response.status_code}")
            print(response.text)
            return None

    except requests.exceptions.RequestException as e:
        print(f"Network error: {e}")
        return None

# Usage example
access_token = "your_access_token_here"
record_date = "2024-01-15"

# First request
events_data = get_events_by_record_date(access_token, record_date, 25)

# Subsequent requests with cursor
# next_data = get_events_by_record_date_and_cursor(access_token, record_date, "64f8a1b2c3d4e5f6a7b8c9d0", 25)

Error Handling

Common Error Responses

400 - Bad Request

Invalid record date format:

{
  "status": false,
  "error": "Invalid record date format. Use YYYY-MM-DD format"
}

401 - Unauthorized

Invalid or missing OAuth token:

{
  "status": false,
  "error": "Authorization header is required"
}

429 - Rate Limited

Too many requests:

{
  "status": false,
  "error": "Rate limit exceeded. Please try again later"
}

500 - Internal Server Error

Server error:

{
  "status": false,
  "error": "Internal server error"
}

Features

Rate Limiting

  • Protection: Prevents API abuse
  • Scope: Applied per access token
  • Response: HTTP 429 when limit exceeded

Best Practices

Performance

  • Use appropriate limits - Don’t request more events than needed
  • Handle pagination efficiently - Process events in batches rather than loading all at once

Error Handling

  • Check response status - Always verify the status field before processing data
  • Implement retry logic - Handle rate limiting with exponential backoff
  • Log errors appropriately - Monitor API usage and error patterns

Security

  • Secure token storage - Store OAuth tokens securely
  • Token refresh - Implement token refresh logic for long-running applications
  • Environment separation - Use development endpoints for testing

Data Processing

  • Validate event data - Check required fields before processing
  • Handle empty results - Account for dates with no events
  • Process CUSIP arrays - Remember that CUSIP is an array field