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
eventStatusandvotingLinksActiveto 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;
recordDatemust be explicitly specified if you want to filter by record date
- If no query parameters are passed: Defaults to current 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
recordDatebehavior
- No parameters: If you call the endpoint with no query parameters (e.g.,
GET /v1/events), the API automatically appliesrecordDate = current dateand returns events for today.- Any parameter provided: If you provide any query parameter (e.g.,
?eventStatus=Active,?cusip=037833100,?limit=10, etc.), the defaultrecordDateis not applied. You must explicitly includerecordDatein your query if you want to filter by record date.
Pagination
- Use the
cursorparameter for cursor-based pagination. - For the first request, omit
cursorand pass any filters you need (for example,recordDate,eventStatus,cusip, etc.). - For subsequent requests, pass the same filters plus the
cursorvalue from the previous response’spagination.nextCursor. - Continue until
pagination.hasMoreisfalseto 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, andvotingLinksActivemay benullor an empty string depending on the event. When available,meetingDateis 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 thecursorparameter 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
statusfield 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