Open API · Europe
Search Agena's own events as JSON, Markdown, a live calendar, or through MCP. Reading is keyless and open to browser clients. Writing needs a bearer key. Every event keeps the original source link.
Sample placeholders are left out. Prices are only what the source stated. q is ranked with keyword and topic scores, not a paid language model.
GET /api/events
q ranks matches and fills matchReasons. city, country, topic (comma-separated), format, from, and to hard-filter. limit is 1–100 and defaults to 50. Without from, events that ended more than six hours ago are omitted.
| Param | Notes |
|---|---|
| q | Free text. Title, topic, organiser, place, then description. |
| city | Slug or name. Zurich and zurich both work. |
| country | CH, DE, AT, GB, FR, NL, or the country name. UK maps to GB. |
| topic | Comma list. An event matches if it has any of them. |
| format | meetup, conference, workshop, hackathon, online, hybrid, other. in_person means not online. |
| from, to | ISO date or datetime. A date is a UTC day. |
| limit | 1–100. Default 50. total is the match count before the page. |
The body is query, count, total, calendar, and events. Each event has id, title, start, end, city, country, venue, geo, format, price, topics, organizer, sourceUrl, url, and matchReasons. geo.precision is venue only when the listing has its own point; otherwise it is the city centroid. Responses send Access-Control-Allow-Origin: * and Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=86400.
Search
curl "https://agentevents.xyz/api/events?q=agents&city=zurich&limit=10"
GET /api/md · /events.md · /cities/{slug}.md · /topics/{slug}.md
The same filters, as a table. A live-source line points at the API URL that always has the current list. Links go to the Agena event page, which carries the original ticket link.
City feed
curl "https://agentevents.xyz/cities/berlin.md"
Same filters as JSON
curl "https://agentevents.xyz/api/md?topic=robotics&country=ch"
GET /api/calendar
text/calendar with a one-hour VALARM on each event. The URL is the subscription: clients re-fetch it, so new matches show up in Google, Apple, and Outlook. City and topic pages link the webcal form.
Subscribe
webcal://agentevents.xyz/api/calendar?q=agents
POST /api/mcp · streamable HTTP · protocol 2025-06-18
Read-only tools: search_events, get_event, best_next_event, subscribe_calendar. No key. The server is stateless. Send Accept: application/json, text/event-stream and, after initialize, MCP-Protocol-Version: 2025-06-18.
Claude Code
claude mcp add agena --transport http https://agentevents.xyz/api/mcp
Any MCP client
{
"mcpServers": {
"agena": { "type": "http", "url": "https://agentevents.xyz/api/mcp" }
}
}POST and DELETE /api/events
Send Authorization: Bearer <key>. The raw key is never stored. Agena keeps the SHA-256 hex in agena.api_keys. A trusted key publishes immediately. Any other key files the event as pending, so it stays off the public catalogue until an editor trusts the key. Re-POST the same externalId to update that listing instead of creating a second one. DELETE removes it from the public catalogue. POSTing the same externalId again brings it back.
GET /api/events?mine=1 with the same key returns that organiser's rows, including pending ones. It is not cached.
Create or update
curl -X POST https://agentevents.xyz/api/events \
-H "Authorization: Bearer agena_live_…" \
-H "Content-Type: application/json" \
-d '{"title":"Zurich AI Builders Night","startAt":"2026-11-12T18:30:00+01:00","city":"Zurich","venue":"Impact Hub","topics":["ai-agents"],"url":"https://example.org/night","externalId":"night-123"}'Remove
curl -X DELETE "https://agentevents.xyz/api/events?externalId=night-123" \ -H "Authorization: Bearer agena_live_…"
Keys are issued by the operator. Hash the token, then insert the digest. Apply supabase/migrations/20261016120000_api_keys.sql first if that table is not there yet.
Hash a key
node -e "console.log(require('crypto').createHash('sha256').update(process.argv[1]).digest('hex'))" 'agena_live_…'