Events API

Complete documentation for the VOTR Events API endpoint

📅 Events Retrieval

The Events API allows you to retrieve voting events filtered by record date or using cursor-based pagination. This endpoint provides access to event information including event IDs, record dates, CUSIP numbers, and issuer details.

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 Requirements

Parameter Type Required Description
date string Record date to filter events (YYYY-MM-DD format, ET timezone)
cursor string Cursor for pagination (ObjectId of last event)
limit integer Maximum events per page (default: 50, max: 100)

Important: The date parameter is required for all requests. If the date parameter is not provided, the API will return a 400 Bad Request error. Use cursor along with date for pagination.

Parameter Details

Date Parameter

  • Format: YYYY-MM-DD (ISO 8601 date format, ET timezone)
  • Timezone: ET (Eastern Time)
  • Purpose: Fetch events for a specific record date
  • Required: Yes, must be provided in all requests
  • Example: 2024-01-15 (ET timezone)

Cursor Parameter

  • Format: 24-character hexadecimal ObjectId
  • Purpose: Fetch the next page of events using pagination
  • Required: No, use only for pagination with the date parameter
  • Example: 64f8a1b2c3d4e5f6a7b8c9d0

Limit Parameter

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

Pagination

Important: The date parameter is required for all requests.

  • First request: Pass the date parameter (e.g., ?date=2024-01-15)
  • To fetch next page: Pass both date AND cursor parameters together (e.g., ?date=2024-01-15&cursor=64f8a1b2c3d4e5f6a7b8c9d0)
  • Use the nextCursor value from the pagination response to fetch the next page
  • Continue until hasMore is false to retrieve all events for the specified date

Response Format

Success Response

{
  "message": "Events retrieved successfully",
  "status": true,
  "data": {
    "events": [
      {
        "eventId": "64f8a1b2c3d4e5f6a7b8c9d0",
        "recordDate": "2024-01-15",
        "cusip": ["123456789", "987654321"],
        "isin": ["US1234567890", "US0987654321"],
        "ticker": ["AAPL", "MSFT"],
        "issuerName": "Apple Inc.",
        "eventType": "Proxy"
      }
    ],
    "pagination": {
      "hasMore": true,
      "nextCursor": "64f8a1b2c3d4e5f6a7b8c9d1",
      "limit": 50
    }
  }
}

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
pagination object Pagination metadata

Event Object

Field Type Description
eventId string Unique event identifier (ObjectId)
recordDate string Event record date (YYYY-MM-DD, ET timezone)
cusip array Array of CUSIP numbers
isin array Array of ISIN (International Securities Identification Number) for matching child issuers
ticker array Array of ticker symbols for matching child issuers
issuerName string Name of the issuing company
eventType string Type of voting event (see Event Types below)

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

Event Types

The eventType field can contain one of the following values:

  • Proxy
  • Regulatory
  • Voluntary Corporate Actions

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": 50
    }
  }
}

Usage Examples

Get Events by Date (First Request)

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

Get Next Page Using Cursor and Date (Subsequent Requests)

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

Note: When paginating through events for a specific date, always include both the date and cursor parameters in subsequent requests to ensure you’re getting the next page of events for that same date.

JavaScript/Node.js Example

// Get events by date (first request)
async function getEventsByDate(accessToken, date, limit = 50) {
  try {
    const response = await fetch(
      `https://api-dev.govotr.com/api/v1/events?date=${date}&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 date (subsequent requests)
async function getEventsByDateAndCursor(accessToken, date, cursor, limit = 50) {
  try {
    const response = await fetch(
      `https://api-dev.govotr.com/api/v1/events?date=${date}&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 date = "2024-01-15"

// First request
getEventsByDate(accessToken, date, 50)

// Subsequent requests with cursor
// getEventsByDateAndCursor(accessToken, date, "64f8a1b2c3d4e5f6a7b8c9d0", 50)

Python Example

import requests
from datetime import datetime

def get_events_by_date(access_token, date, limit=50):
    """
    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 = {
        "date": 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_date_and_cursor(access_token, date, cursor, limit=50):
    """
    Retrieve events using cursor pagination for a specific date
    """
    url = "https://api-dev.govotr.com/api/v1/events"

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

    params = {
        "date": 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"
date = "2024-01-15"

# First request
events_data = get_events_by_date(access_token, date, 50)

# Subsequent requests with cursor
# next_data = get_events_by_date_and_cursor(access_token, date, "64f8a1b2c3d4e5f6a7b8c9d0", 50)

Error Handling

Common Error Responses

400 - Bad Request

Invalid date format:

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

Invalid parameter combination (when not paginating correctly):

{
  "status": false,
  "error": "Invalid parameter combination"
}

Note: You can use date and cursor together for pagination. This error occurs when parameters are used incorrectly.

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

Missing required date parameter:

{
  "status": false,
  "error": "Date parameter is required"
}

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

Next Steps:

  • Check event voting status and availability: Event Voting Status API
  • Use the retrieved event information with the Voting URL API to generate voting URLs for specific events and shareholders

Get the current voting status and availability information for a specific event. This endpoint allows brokers to check whether voting is currently active and available for an event.

Note: This endpoint is optional and not required for basic voting functionality. Use it to provide enhanced UI experience by checking voting availability before presenting options to shareholders.

API Endpoints

Development:

GET https://api-dev.govotr.com/api/v1/event/{eventId}

Production:

GET https://api.govotr.com/api/v1/event/{eventId}

Authentication

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

Headers

Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

Path Parameters

Parameter Type Required Description
eventId string Unique identifier for the event (ObjectId)

Parameter Details

Event ID Parameter

  • Format: 24-character hexadecimal MongoDB ObjectId
  • Pattern: ^[0-9a-fA-F]{24}$
  • Required: Yes
  • Example: 64f8a1b2c3d4e5f6a7b8c9d0

Query Parameters

Parameter Type Required Description
cusip string Optional CUSIP number to filter by specific security

Parameter Details

CUSIP Parameter

  • Format: String
  • Required: No
  • Purpose: Filter the event by specific security CUSIP
  • Example: 037833100

Use Cases

  • Check Voting Availability: Determine if voting links are currently active
  • Event Status Verification: Get current event status (Active, Upcoming, Expired, Cancelled)
  • Timeline Information: Retrieve voting open date/time and deadline
  • UI Enhancement: Verify event details before presenting to shareholders
  • Status Polling: Monitor when voting becomes available

Event Status Values

Status Description
Active Event is currently accepting votes
Upcoming Event has not started yet (status = 1)
Expired Voting period has ended (status = 3)
Cancelled Event has been cancelled (status = 5)

The votingLinksActive field indicates whether shareholders can currently vote:

  • true: Voting is open and links are functional
  • false: Voting is not available (event not started, ended, or cancelled)

Conditions for Active Voting Links:

  • Final documents are confirmed (confirmFinalDocuments = true)
  • Event status is Active (status = 2)
  • Current time is before the voting deadline

Response Caching

Responses are cached with dynamic TTL for optimal performance:

Event State Cache Duration
Active Events Cached until voting ends (minimum 60 seconds)
Expired/Cancelled Cached for 24 hours
Default 1 hour

Cache Auto-Clear Triggers:

  • Event details are updated
  • Event status changes
  • Ballots are modified
  • Mailing status is updated

Response Format

Success Response

{
  "message": "Event voting status retrieved successfully",
  "status": true,
  "data": {
    "eventId": "64f8a1b2c3d4e5f6a7b8c9d0",
    "cusip": "037833100",
    "recordDate": "2024-01-15",
    "meetingDate": "2024-02-15",
    "meetingTime": "10:00 AM",
    "votingOpenDateTime": "2024-01-16T09:00:00.000Z",
    "votingDeadline": "2024-02-14T23:59:59.000Z",
    "eventStatus": "Active",
    "votingLinksActive": true
  }
}

Response Schema

Main Response Object

Field Type Description
message string Success message
status boolean Request status (true for success)
data object Event voting status data

Data Object

Field Type Description
eventId string Unique identifier for the event
cusip string CUSIP number (if provided in request), nullable
recordDate string Record date (YYYY-MM-DD, ET timezone), nullable
meetingDate string Meeting date (YYYY-MM-DD, ET timezone), nullable
meetingTime string Meeting time (ET timezone), nullable
votingOpenDateTime string ISO 8601 timestamp when voting became available (when first email was delivered). Null if no emails delivered.
votingDeadline string ISO 8601 timestamp for voting end date and time
eventStatus string Current event status (Active, Upcoming, Expired, Cancelled)
votingLinksActive boolean Whether voting links are currently active and functional

Usage Examples

Get Event Voting Status by Event ID

curl -X GET "https://api-dev.govotr.com/api/v1/event/64f8a1b2c3d4e5f6a7b8c9d0" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"

Get Event Voting Status with CUSIP Filter

curl -X GET "https://api-dev.govotr.com/api/v1/event/64f8a1b2c3d4e5f6a7b8c9d0?cusip=037833100" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"

JavaScript/Node.js Example

async function getEventVotingStatus(accessToken, eventId, cusip = null) {
  try {
    const url = new URL(`https://api-dev.govotr.com/api/v1/event/${eventId}`)

    if (cusip) {
      url.searchParams.append("cusip", cusip)
    }

    const response = await fetch(url.toString(), {
      method: "GET",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
    })

    const data = await response.json()

    if (data.status) {
      console.log("Event voting status:", data.data)

      // Check if voting is available
      if (data.data.votingLinksActive) {
        console.log("✅ Voting is currently active!")
        console.log(`Voting deadline: ${data.data.votingDeadline}`)
      } else {
        console.log(
          `❌ Voting not available. Event status: ${data.data.eventStatus}`
        )
      }

      return data.data
    } else {
      console.error("Error retrieving event status:", data.error)
      return null
    }
  } catch (error) {
    console.error("Network error:", error)
    return null
  }
}

// Usage examples
const accessToken = "your_access_token_here"
const eventId = "64f8a1b2c3d4e5f6a7b8c9d0"

// Get event status
getEventVotingStatus(accessToken, eventId)

// Get event status with CUSIP filter
getEventVotingStatus(accessToken, eventId, "037833100")

Python Example

import requests
from datetime import datetime

def get_event_voting_status(access_token, event_id, cusip=None):
    """
    Retrieve voting status for a specific event
    """
    url = f"https://api-dev.govotr.com/api/v1/event/{event_id}"

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

    params = {}
    if cusip:
        params["cusip"] = cusip

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

        if response.status_code == 200:
            data = response.json()
            if data.get("status"):
                event_data = data["data"]
                print(f"Event Status: {event_data['eventStatus']}")

                if event_data["votingLinksActive"]:
                    print("✅ Voting is currently active!")
                    print(f"Voting deadline: {event_data['votingDeadline']}")
                else:
                    print(f"❌ Voting not available. Status: {event_data['eventStatus']}")

                return event_data
            else:
                print(f"Error: {data.get('error', 'Unknown error')}")
                return None
        elif response.status_code == 404:
            print(f"Event not found: {event_id}")
            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 examples
access_token = "your_access_token_here"
event_id = "64f8a1b2c3d4e5f6a7b8c9d0"

# Get event status
event_status = get_event_voting_status(access_token, event_id)

# Get event status with CUSIP filter
event_status_with_cusip = get_event_voting_status(access_token, event_id, "037833100")

Error Handling

Common Error Responses

400 - Bad Request

Invalid Event ID format:

{
  "status": false,
  "error": "Event ID must be a valid ObjectId"
}

Missing Event ID:

{
  "status": false,
  "error": "Event ID is required"
}

Invalid CUSIP type:

{
  "status": false,
  "error": "CUSIP must be a string"
}

401 - Unauthorized

Invalid or missing OAuth token:

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

404 - Not Found

Event not found:

{
  "status": false,
  "error": "Event not found for the provided Event ID"
}

Event not found with CUSIP:

{
  "status": false,
  "error": "Event not found for the provided Event ID and CUSIP"
}

500 - Internal Server Error

Server error:

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

Best Practices

Polling Strategy

  • Check before presenting UI: Verify voting is active before showing “Vote Now” button
  • Implement smart polling: Poll more frequently as voting deadline approaches
  • Cache responses: Leverage the built-in caching mechanism
  • Handle status transitions: Update UI when event status changes

Error Handling

  • Validate Event ID format: Ensure Event ID matches ObjectId pattern before API call
  • Handle 404 gracefully: Event may not exist or may be filtered out by CUSIP
  • Implement retry logic: Handle transient failures with exponential backoff
  • Log errors appropriately: Monitor API usage and error patterns

Performance

  • Use caching: Respect cache headers to reduce unnecessary API calls
  • Batch checks: If checking multiple events, space out requests appropriately
  • Monitor response times: Track API performance for your use case

UI/UX

  • Display event status: Show clear status indicators (Active, Upcoming, Expired)
  • Show voting timeline: Display voting open date/time and deadline to users
  • Disable when inactive: Disable “Vote Now” button when votingLinksActive is false
  • Provide context: Explain why voting is not available (upcoming, expired, cancelled)

Next Steps: Use the retrieved event information with the Voting URL API to generate voting URLs for specific events and shareholders.