Skip to Content
For DevelopersSide Events API

Side Events API

Retrieve side events for major web3 conferences. This read-only API provides event details including location, timing, organizers, and attendee information.

Quick Start

Get your API key

Contact platform@serotonin.co to request an API key scoped to your desired parent events.

Make your first request

curl https://api.se.ro/v1/events/ethcc/side-events?limit=10 \ -H "Authorization: Bearer YOUR_API_KEY"

Parse the response

The API returns a JSON object with event data sorted by start date:

{ "success": true, "data": { "parentEventSlug": "ethcc", "totalCount": 125, "events": [...] } }

Authentication

Include your API key in the Authorization header for all requests:

Authorization: Bearer YOUR_API_KEY
⚠️

API keys are scoped to specific parent events. A key for ETHDenver cannot access Consensus data. Contact platform@serotonin.co to request access to additional events.

Base URL

https://api.se.ro/v1

All requests must use the api.se.ro subdomain. Requests to other subdomains will be rejected.

Retrieve Side Events

GET /events/{slug}/side-events

Fetch side events for a parent conference, sorted by start date.

Parameters

ParameterTypeRequiredDescription
slugstringYesParent event identifier (e.g., ethcc, consensus-2025)
limitintegerNoEvents to return. Default: 50. Max: 500.
offsetintegerNoEvents to skip for pagination. Default: 0.

Example Request

curl https://api.se.ro/v1/events/ethcc/side-events?limit=10&offset=0 \ -H "Authorization: Bearer YOUR_API_KEY"

Response

Returns a JSON object with an array of event objects sorted by start date:

{ "success": true, "data": { "parentEventSlug": "ethcc", "totalCount": 125, "limit": 10, "offset": 0, "events": [ { "id": "cm4abc123xyz", "name": "DeFi Builders Happy Hour", "slug": "defi-builders-happy-hour", "description": "Connect with fellow DeFi builders and discuss the latest innovations in decentralized finance.", "url": "https://se.ro/events/defi-builders-happy-hour", "startDate": "2025-07-08T18:00:00.000Z", "endDate": "2025-07-08T21:00:00.000Z", "timeZone": "Europe/Brussels", "eventType": ["meetup", "networking"], "topics": ["defi", "blockchain", "ethereum"], "organizers": [ { "type": "COMPANY", "label": "Acme DeFi Protocol", "isVisible": true } ], "venueName": null, "location": { "address": "123 Avenue Louise", "city": "Brussels", "state": null, "country": "Belgium", "latitude": 50.8371, "longitude": 4.3676 }, "images": { "avatar": "https://cdn.se.ro/events/avatar-abc123.jpg", "banner": "https://cdn.se.ro/events/banner-abc123.jpg" } } ] } }

Response Fields

Event Object

FieldTypeDescription
idstringUnique identifier for the event
namestringEvent name
slugstringURL-friendly identifier
descriptionstring | nullEvent description
urlstringFull URL to event page on Sero
startDatestringISO 8601 timestamp (UTC)
endDatestringISO 8601 timestamp (UTC)
timeZonestringIANA timezone identifier
eventTypestring[]Event categories (e.g., ["meetup", "networking"])
topicsstring[]Event topics/tags (e.g., ["web3", "blockchain"])
organizersobject[]List of event organizers (see below)
venueNamenullReserved for future use
locationobjectGeographic details (see below)
imagesobjectEvent imagery (see below)

Organizer Object

FieldTypeDescription
typestringEither USER or COMPANY
labelstringDisplay name
isVisiblebooleanWhether to display publicly

Location Object

FieldTypeDescription
addressstring | nullStreet address
citystring | nullCity name
statestring | nullState or region
countrystring | nullCountry name
latitudenumber | nullGeographic latitude
longitudenumber | nullGeographic longitude

Images Object

FieldTypeDescription
avatarstring | nullEvent avatar/logo URL
bannerstring | nullEvent banner URL

Rate Limits

⚠️

1000 requests per hour per API key. Exceeding this limit returns a 429 Too Many Requests response.

Check rate limit status in response headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per hour (1000)
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when limit resets

Pagination

For events with hundreds of side events, paginate through results using limit and offset:

# Fetch page 2 (events 51-100) curl https://api.se.ro/v1/events/ethcc/side-events?limit=50&offset=50 \ -H "Authorization: Bearer YOUR_API_KEY"

Calculate total pages using the totalCount field in the response:

const totalPages = Math.ceil(data.totalCount / limit);

Error Handling

The API uses standard HTTP status codes:

CodeStatusDescription
200OKRequest succeeded
400Bad RequestInvalid parameters (e.g., invalid limit/offset)
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key lacks access to this event
404Not FoundParent event not found or has no side events
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error (contact support if persistent)

Error Response Format

{ "success": false, "error": { "code": "FORBIDDEN", "message": "API key does not have access to this parent event" } }

Best Practices

Cache responses

Side event data changes infrequently. Cache responses for 5-10 minutes to reduce API calls and improve performance.

Handle rate limits

Implement retry logic with exponential backoff when you hit rate limits:

async function fetchWithRetry(slug, retries = 3) { const response = await fetch( `https://api.se.ro/v1/events/${slug}/side-events`, { headers: { 'Authorization': `Bearer ${API_KEY}` } } ); if (response.status === 429 && retries > 0) { const resetTime = response.headers.get('X-RateLimit-Reset'); const waitTime = (resetTime * 1000) - Date.now(); await new Promise(resolve => setTimeout(resolve, waitTime)); return fetchWithRetry(slug, retries - 1); } return response.json(); }

Paginate large result sets

Request events in batches rather than fetching everything at once:

async function fetchAllEvents(slug) { const allEvents = []; let offset = 0; const limit = 100; while (true) { const response = await fetch( `https://api.se.ro/v1/events/${slug}/side-events?limit=${limit}&offset=${offset}`, { headers: { 'Authorization': `Bearer ${API_KEY}` } } ); const data = await response.json(); allEvents.push(...data.data.events); if (offset + limit >= data.data.totalCount) break; offset += limit; } return allEvents; }

Additional Information

CORS Support

The API supports Cross-Origin Resource Sharing (CORS) for all origins, allowing safe browser-based requests.

Getting Help


Return to the Developer Documentation for more APIs and resources.

Last updated on