Public API Overview
No Authentication Required CORS EnabledAll endpoints listed below are publicly accessible and support cross-origin requests. No API key or authentication is needed. Responses are returned as JSON (unless otherwise noted).
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/events/public | Upcoming active events with lineup |
| GET | /api/events/public/:id | Event detail with related content |
| GET | /api/events/past | Past events archive |
| GET | /api/news/public | Published news articles |
| GET | /api/news/categories | Available news categories |
| GET | /api/albums/public | Approved photo albums |
| GET | /api/videos/public | Approved videos |
| GET | /api/artists/public | All artists with stats |
| GET | /api/artists/public/:id | Artist profile with related content |
| GET | /api/search | Global content search |
| GET | /api/public/headliner-announcements | Active headliner announcements |
| POST | /api/newsletter/subscribe | Subscribe to newsletter |
| POST | /api/public/staff-application | Submit staff application |
| GET | /api/calendar/events.ics | iCal calendar feed |
| POST | /api/contact | Submit contact form |
| GET | /api/sitemap.xml | XML sitemap |
| GET | /api/llms.txt | LLM-friendly site summary |
| GET | /api/llms-full.txt | Full LLM context with all content |
CORS Headers
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
Standard Error Response
{
"message": "Error description"
}
Events API
Returns all active future events sorted by start date, including full lineup artists with photos and genre information.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Maximum number of events. Use 0 for unlimited. |
recent | boolean | false | Sort by most recently added instead of soonest |
includePast | boolean | false | Include past events in the response |
Response
{
"events": [
{
"id": 87,
"name": "Suikerrock 2026 - Day 3",
"eventType": "Festival",
"artist": "Headliner Name",
"lineupArtists": [
{
"id": 5,
"name": "Coldplay",
"photoUrl": "https://mainstage.vision/.../coldplay.jpg",
"genre": "Pop/Rock"
}
],
"logo": "event-logo-123.jpg",
"logoUrl": "https://mainstage.vision/.../event-logo-123.jpg",
"startDate": "2026-07-25T14:00:00.000Z",
"endDate": "2026-07-25T23:00:00.000Z",
"venueName": "Festivalpark",
"city": "Tienen",
"province": "Vlaams-Brabant",
"country": "Belgium",
"parentEventId": 85,
"organizationName": "Festival Organization"
}
],
"total": 23,
"timestamp": "2026-02-19T12:00:00.000Z"
}
Returns detailed event information including full lineup (with artist photos), related news articles, photo albums, videos, and sub-events (for multi-day festivals).
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Event ID |
Response
{
"id": 87,
"name": "Suikerrock 2026 - Day 3",
"eventType": "Festival",
"artist": "Headliner",
"description": "Full event description...",
"startDate": "2026-07-25T14:00:00.000Z",
"endDate": "2026-07-25T23:00:00.000Z",
"venueName": "Festivalpark",
"address": "Grote Markt",
"city": "Tienen",
"postalCode": "3300",
"province": "Vlaams-Brabant",
"country": "Belgium",
"status": "open",
"logoUrl": "https://mainstage.vision/.../event-logo.jpg",
"parentEvent": { "id": 85, "name": "Suikerrock 2026" },
"childEvents": [
{ "id": 86, "name": "Suikerrock 2026 - Day 2", "startDate": "..." }
],
"lineup": [
{
"id": 5, "name": "Coldplay", "genre": "Pop/Rock",
"description": "...", "photoUrl": "..."
}
],
"relatedNews": [
{
"id": 12, "title": "...", "summary": "...",
"category": "Festival", "featuredImage": "...", "publishDate": "..."
}
],
"relatedAlbums": [
{
"id": 3, "title": "...", "artistName": "Coldplay",
"photoCount": 25, "featuredPhotoUrl": "..."
}
],
"relatedVideos": [
{
"id": 1, "title": "...", "artistName": "Coldplay",
"youtubeVideoId": "abc123",
"youtubeUrl": "https://www.youtube.com/watch?v=abc123",
"thumbnailUrl": "https://img.youtube.com/vi/abc123/hqdefault.jpg"
}
]
}
Returns all past events sorted by date (most recent first), including lineup artists and logo URLs.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Maximum number of events. Use 0 for unlimited. |
Response
{
"events": [
{
"id": 54,
"name": "Rock Werchter 2025",
"eventType": "Festival",
"startDate": "2025-07-04T14:00:00.000Z",
"venueName": "Festivalpark Werchter",
"city": "Werchter",
"lineupArtists": [
{ "id": 3, "name": "Dua Lipa", "photoUrl": "...", "genre": "Pop" }
],
"logoUrl": "https://mainstage.vision/.../rw-2025.jpg"
}
],
"total": 45
}
News API
Returns all published news articles sorted by publication date (newest first). Includes rich text content, tags, and related event information.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | Maximum articles (omit for all) |
eventId | integer | Filter by event ID |
category | string | Filter by category name |
breaking | boolean | Only breaking news (true) |
Response
{
"articles": [
{
"id": 12,
"title": "Festival announces headliners",
"slug": "festival-announces-headliners",
"excerpt": "Short summary...",
"summary": "Full summary...",
"content": "<p>Full HTML content...</p>",
"photoCredit": "Sarah Lens",
"author": "Gunther Vangenechten",
"publishedAt": "2026-06-01T10:00:00.000Z",
"createdAt": "2026-06-01T09:30:00.000Z",
"category": "Festival",
"tags": ["festival", "lineup"],
"featuredImage": "/uploads/news/headliners.jpg",
"isBreaking": false,
"isFeatured": true,
"readTime": 3,
"eventId": 85,
"relatedEventIds": [85, 86, 87],
"isEventSpecific": true
}
],
"total": 25,
"timestamp": "2026-02-19T12:00:00.000Z"
}
featuredImage field may be a relative path (/uploads/news/file.jpg), a filename (file.jpg), or an absolute URL. Prepend the base URL for relative paths.
Returns all available news categories. Categories are dynamically managed via the admin settings.
Response
{
"categories": [
{ "id": 0, "name": "Algemeen", "slug": "algemeen" },
{ "id": 1, "name": "Concert", "slug": "concert" },
{ "id": 2, "name": "Festival", "slug": "festival" },
{ "id": 3, "name": "Nieuws", "slug": "nieuws" }
]
}
Albums API
Returns approved photo albums including all photos with per-photo photographer credits. Albums go through an approval workflow before becoming public.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
id | integer | - | Fetch a single album by ID |
limit | integer | 20 | Maximum albums (max: 50) |
eventId | integer | - | Filter by event |
featured | boolean | - | Only featured albums |
recent | boolean | - | Sort by newest first |
Response
{
"albums": [
{
"id": 3,
"title": "Suikerrock 2026 - Coldplay",
"slug": "suikerrock-2026-coldplay",
"eventId": 87,
"eventName": "Suikerrock 2026 - Day 3",
"artistName": "Coldplay",
"photographerName": "Sarah Lens",
"photoCount": 25,
"featuredPhotoId": 42,
"isFeatured": true,
"featuredPhoto": {
"url": "https://mainstagevision.be/photos/.../photo-001.jpg",
"thumbnailUrl": "https://mainstagevision.be/photos/.../thumb.jpg",
"isFeatured": true
},
"photos": [
{
"id": 42,
"url": "https://mainstagevision.be/photos/.../photo-001.jpg",
"thumbnailUrl": "https://mainstagevision.be/photos/.../thumb.jpg",
"filename": "photo-001.jpg",
"isFeatured": true,
"photographerName": "Sarah Lens"
}
],
"event": {
"name": "Suikerrock 2026 - Day 3",
"startDate": "2026-07-25T14:00:00.000Z",
"venueName": "Festivalpark",
"city": "Tienen"
},
"tags": ["concert", "festival"],
"createdAt": "2026-07-26T10:00:00.000Z"
}
],
"total": 5,
"timestamp": "2026-02-19T12:00:00.000Z"
}
photos array has its own photographerName field, which may differ per photo when multiple photographers contributed to an album.
Videos API
Returns approved and published videos. Videos go through an approval workflow before becoming public. Most videos are hosted on YouTube.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
id | integer | - | Fetch a single video |
limit | integer | 20 | Maximum videos (max: 50) |
eventId | integer | - | Filter by event |
recent | boolean | - | Sort by newest first |
Response
{
"videos": [
{
"id": 1,
"title": "Suikerrock 2026 - Coldplay Highlights",
"slug": "suikerrock-2026-coldplay-highlights",
"description": "Concert highlights",
"eventId": 87,
"eventName": "Suikerrock 2026 - Day 3",
"artistName": "Coldplay",
"videographerName": "Mark Capture",
"youtubeVideoId": "dQw4w9WgXcQ",
"youtubeUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"thumbnailUrl": "https://img.youtube.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"websiteUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"duration": 180,
"tags": ["concert", "live"],
"createdAt": "2026-07-26T12:00:00.000Z",
"approvedAt": "2026-07-26T14:00:00.000Z"
}
],
"total": 3,
"timestamp": "2026-02-19T12:00:00.000Z"
}
youtubeVideoId to construct embed URLs: https://www.youtube.com/embed/{youtubeVideoId}. The thumbnailUrl provides a high-quality YouTube thumbnail.
Artists API
Returns all artists with upcoming event count and total photo count from approved albums.
Response
[
{
"id": 5,
"name": "Coldplay",
"genre": "Pop/Rock",
"bio": "British rock band",
"photoUrl": "https://mainstage.vision/.../coldplay.jpg",
"eventCount": 2,
"photoCount": 45
}
]
Returns a full artist profile including all related events (upcoming and past), photo albums, news articles, and videos.
URL Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Artist ID |
Response
{
"id": 5,
"name": "Coldplay",
"genre": "Pop/Rock",
"description": "British rock band from London",
"bio": "Coldplay is a British rock band...",
"photoUrl": "https://mainstage.vision/.../coldplay.jpg",
"events": [
{
"id": 87, "name": "Suikerrock 2026",
"eventType": "Festival",
"startDate": "2026-07-25T14:00:00.000Z",
"venueName": "Festivalpark",
"city": "Tienen", "logoUrl": "...", "isPast": false
}
],
"albums": [
{ "id": 3, "title": "Suikerrock 2026 - Coldplay", "photoCount": 25, "featuredPhotoUrl": "..." }
],
"news": [
{ "id": 12, "title": "Festival announces headliners", "summary": "...", "category": "Festival" }
],
"videos": [
{
"id": 1, "title": "Coldplay Highlights",
"youtubeVideoId": "abc123",
"youtubeUrl": "https://www.youtube.com/watch?v=abc123",
"thumbnailUrl": "https://img.youtube.com/vi/abc123/hqdefault.jpg"
}
]
}
Search API
Searches across events, news articles, albums, and artists. Also matches lineup artists linked to events. Results are sorted by relevance and date (newest first). Requires a minimum of 2 characters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
q | string | Search query (minimum 2 characters) |
Response
{
"results": [
{
"type": "event",
"id": 87,
"title": "Suikerrock 2026",
"subtitle": "Festivalpark - Tienen",
"image": "https://mainstage.vision/.../event-logo.jpg",
"url": "events-detail.html?id=87",
"date": "2026-07-25T14:00:00.000Z"
},
{
"type": "nieuws",
"id": 12,
"title": "Festival announces headliners",
"subtitle": "Summary text...",
"image": "/uploads/news/headliners.jpg",
"url": "nieuws-detail.html?id=12",
"date": "2026-06-01T10:00:00.000Z"
},
{
"type": "album",
"id": 3,
"title": "Suikerrock 2026 - Coldplay",
"subtitle": "Coldplay",
"image": "https://mainstagevision.be/photos/.../photo.jpg",
"url": "album-detail.html?id=3",
"date": "2026-07-26T10:00:00.000Z"
},
{
"type": "artiest",
"id": 5,
"title": "Coldplay",
"subtitle": "Pop/Rock",
"image": "https://mainstage.vision/.../coldplay.jpg",
"url": "artist-detail.html?id=5",
"date": null
}
],
"total": 4,
"query": "coldplay"
}
Content Types
| Type | Searched Fields |
|---|---|
event | Name, artist, venue, city, lineup artists |
nieuws | Title, summary, excerpt, author, category |
album | Title, artist name, event name |
artiest | Name, genre, bio |
Headliner Announcements
NewReturns all currently active headliner announcements, enriched with event and artist details. Announcements are time-bound and only returned when within their active window.
Response
[
{
"id": 1,
"eventId": 87,
"artistId": 5,
"title": "Headliner Revealed!",
"description": "Coldplay will headline Suikerrock 2026",
"announcementDate": "2026-03-15T10:00:00.000Z",
"isActive": true,
"eventName": "Suikerrock 2026 - Day 3",
"eventLogo": "https://mainstage.vision/.../event-logo.jpg",
"eventStartDate": "2026-07-25T14:00:00.000Z",
"artistName": "Coldplay",
"artistPhoto": "https://mainstage.vision/.../coldplay.jpg"
}
]
Newsletter API
NewSubscribe an email address to the MainStage Vision newsletter. Duplicate subscriptions are handled gracefully.
Request Body
{
"email": "john@example.com"
}
Validation
| Field | Type | Required | Constraints |
|---|---|---|---|
email | string | Yes | Valid email format |
Success Response
{
"message": "Succesvol ingeschreven!",
"subscriber": {
"id": 42,
"email": "john@example.com"
}
}
Error Response (400)
{ "message": "Ongeldig e-mailadres" }
Staff Applications
NewSubmit a staff application to join the MainStage Vision team. Applications are reviewed by administrators. A confirmation email with terms & conditions PDF is sent automatically.
Request Body
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+32 471 12 34 56",
"address": "Hoofdstraat 1",
"city": "Antwerpen",
"postalCode": "2000",
"motivation": "I'm passionate about concert photography...",
"cameraEquipment": "Canon EOS R5, 70-200mm f/2.8",
"portfolioUrl": "https://portfolio.example.com",
"desiredRole": "photographer"
}
Validation
| Field | Type | Required | Constraints |
|---|---|---|---|
firstName | string | Yes | - |
lastName | string | Yes | - |
email | string | Yes | Valid email format |
phone | string | No | - |
address | string | No | - |
city | string | No | - |
postalCode | string | No | - |
motivation | string | Yes | - |
cameraEquipment | string | No | - |
portfolioUrl | string | No | Valid URL |
desiredRole | string | Yes | photographer, videographer, editor, or reporter |
Success Response
{ "success": true, "message": "Aanmelding succesvol ontvangen!" }
Calendar API
Returns all active events in iCal format. Subscribe directly from any calendar application to stay updated with upcoming events.
Response Headers
Content-Type: text/calendar; charset=utf-8
Content-Disposition: attachment; filename="mainstage-events.ics"
Subscribe via Calendar App
| Application | Instructions |
|---|---|
| Google Calendar | Other calendars → From URL → paste the endpoint URL |
| Apple Calendar | File → New Calendar Subscription → paste the endpoint URL |
| Outlook | Add Calendar → From Internet → paste the endpoint URL |
Contact API
Sends a contact form message to the MainStage Vision team. Messages are delivered via email.
Request Body
{
"name": "John Doe",
"email": "john@example.com",
"subject": "Press accreditation inquiry",
"message": "Hello, I would like to inquire about..."
}
Validation
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | Yes | - |
email | string | Yes | Valid email format |
subject | string | Yes | - |
message | string | Yes | Max 5000 characters |
Success Response
{ "message": "Thank you! We will get back to you shortly." }
Error Response (400)
{ "error": "All fields are required." }
Sitemap & SEO
Returns an XML sitemap containing all public pages, published news articles, approved albums, and artist pages for search engine indexing.
Response
Content-Type: application/xml
Included pages:
- Static pages (homepage, news, albums, videos, events, artists)
- All published news article detail pages
- All approved album detail pages
- All artist detail pages
Returns a plain-text summary of the MainStage Vision website optimized for consumption by large language models (LLMs). Follows the llms.txt specification.
Response
Content-Type: text/plain; charset=utf-8
Returns a comprehensive plain-text export of all public content (events, news, albums, videos, artists) for deep LLM context. This is the extended version of /api/llms.txt.
Response
Content-Type: text/plain; charset=utf-8
Code Examples
Fetch Upcoming Events (JavaScript)
const API = 'https://mainstagevision.replit.app';
async function getEvents(limit = 10) {
const res = await fetch(`${API}/api/events/public?limit=${limit}`);
const data = await res.json();
return data.events;
}
getEvents().then(events => {
events.forEach(e => {
console.log(`${e.name} @ ${e.venueName}, ${e.city}`);
console.log(`Date: ${new Date(e.startDate).toLocaleDateString('en-GB')}`);
if (e.lineupArtists?.length > 0) {
console.log(`Lineup: ${e.lineupArtists.map(a => a.name).join(', ')}`);
}
});
});
Fetch News with Filters (JavaScript)
const API = 'https://mainstagevision.replit.app';
async function getNews(options = {}) {
const params = new URLSearchParams();
if (options.limit) params.append('limit', options.limit);
if (options.category) params.append('category', options.category);
if (options.breaking) params.append('breaking', 'true');
const res = await fetch(`${API}/api/news/public?${params}`);
const data = await res.json();
return data.articles;
}
function getImageUrl(img) {
if (!img) return null;
if (img.startsWith('http')) return img;
if (img.startsWith('/')) return `${API}${img}`;
return `${API}/uploads/news/${img}`;
}
getNews({ category: 'Festival', limit: 5 }).then(articles => {
articles.forEach(a => {
console.log(`${a.title} - ${getImageUrl(a.featuredImage)}`);
});
});
Search (JavaScript)
const API = 'https://mainstagevision.replit.app';
async function search(query) {
const res = await fetch(`${API}/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
return data.results;
}
search('coldplay').then(results => {
results.forEach(r => console.log(`[${r.type}] ${r.title}`));
});
Subscribe to Newsletter (JavaScript)
const API = 'https://mainstagevision.replit.app';
async function subscribe(email) {
const res = await fetch(`${API}/api/newsletter/subscribe`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
return await res.json();
}
subscribe('fan@example.com').then(result => {
console.log(result.message);
});
HTML Events Widget (Embeddable)
<div id="events"></div>
<script>
fetch('https://mainstagevision.replit.app/api/events/public?limit=10')
.then(res => res.json())
.then(data => {
const el = document.getElementById('events');
data.events.forEach(e => {
const date = new Date(e.startDate).toLocaleDateString('en-GB');
const lineup = (e.lineupArtists || []).map(a => a.name).join(', ');
el.innerHTML += `
<div style="padding:12px;border:1px solid #eee;margin:8px 0;border-radius:8px">
<h3>${e.name}</h3>
<p>${e.venueName}, ${e.city} • ${date}</p>
${lineup ? `<p style="color:#666">Lineup: ${lineup}</p>` : ''}
</div>`;
});
});
</script>
Python Example
import requests
API = 'https://mainstagevision.replit.app'
# Get upcoming events
events = requests.get(f'{API}/api/events/public?limit=10').json()
for event in events['events']:
print(f"{event['name']} - {event['city']}")
artists = [a['name'] for a in event.get('lineupArtists', [])]
if artists:
print(f" Lineup: {', '.join(artists)}")
# Search
results = requests.get(f'{API}/api/search', params={'q': 'rock werchter'}).json()
for r in results['results']:
print(f"[{r['type']}] {r['title']}")
cURL Examples
# Get upcoming events
curl -s "https://mainstagevision.replit.app/api/events/public?limit=5" | jq
# Get event detail
curl -s "https://mainstagevision.replit.app/api/events/public/87" | jq
# Search
curl -s "https://mainstagevision.replit.app/api/search?q=coldplay" | jq
# Subscribe to newsletter
curl -X POST "https://mainstagevision.replit.app/api/newsletter/subscribe" \
-H "Content-Type: application/json" \
-d '{"email":"fan@example.com"}'
# Get iCal feed
curl -s "https://mainstagevision.replit.app/api/calendar/events.ics" -o events.ics
No rate limiting is currently active. For high-volume usage, cache responses and avoid querying the same endpoint more than once per minute.
Support: planning@mainstage.vision