API Docs · v1

Build on Eventium.

Everything you need to plug your stack into the Eventium platform. REST endpoints, real-time webhooks, secure auth and battle-tested code samples in cURL, JavaScript and Python.

Quick start

From zero to your first request in 90 seconds.

Generate an API key from the dashboard, drop it in the x-api-key header, hit /v1/events. That's it — same auth scheme on every endpoint.

  1. 1

    Generate an API key

    Head to Dashboard → API & Webhooks, click Generar API Key, give it a name (e.g. “CRM Producción”) and copy the resulting sk_live_… — it's shown ONCE.

  2. 2

    Authenticate every request

    Send the key as the x-api-key header (or the equivalent Authorization: Bearer form). Requests scope automatically to your organizer account — no team-id parameter needed.

  3. 3

    Call /v1/events

    List your events with pagination (?limit ≤ 100, default 25). Response follows Stripe's { object, data, has_more, next_cursor } shape.

GET /v1/events
1curl https://api.myeventium.com/v1/events \
2 -H "x-api-key: sk_live_•••••••••"
Authentication

One header. Rotating keys. No OAuth required.

API keys are generated per organizer from the dashboard. Each key is hashed with a peppered SHA-256 — only a 4-character public prefix and the digest survive in the database. Plaintext is shown once at creation and never again.

Format

sk_live_ prefix followed by 43 base64url-safe characters of entropy. Total length 51 chars.

Transport

Send via x-api-key header. Authorization: Bearer <key> also accepted.

Rotation

Click Revocar on any key from the dashboard — it stops working immediately. Generate a new one and rotate at your leisure.

REST endpoints

v1 reference.

All endpoints under https://api.myeventium.com/v1/*. Every response carries Cache-Control: private, no-store — we never let scoped data sit on a shared edge.

GET/v1/events

List events for the authenticated organizer.

Cursor-based pagination. Pass ?cursor=<ISO timestamp> back as next_cursor from the previous response to walk further. Optional ?status filter (draft | published | archived).

Returns only events where organizer_id = your account. There is no way to query another organizer's events via this endpoint — the scope is enforced server-side regardless of key permissions.

{
  "object": "list",
  "data": [
    {
      "id": "evt_4kQz...",
      "name": "Reggaeton Saturday",
      "slug": "reggaeton-saturday-bcn",
      "date": "2026-03-21T22:00:00Z",
      "location": "Apolo, Barcelona",
      "status": "published",
      "capacity": 1200,
      "organizer_id": "org_8nFw...",
      "created_at": "2026-01-12T14:02:31Z",
      "updated_at": "2026-02-04T09:11:08Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

More endpoints are rolling out — POST /v1/tickets, GET /v1/attendees, GET /v1/passes. If you need one urgently for an integration, get in touch.

Webhooks

Real-time events, HMAC-signed, at-least-once.

Subscribe a URL from the dashboard. Eventium POSTs JSON with an X-Eventium-Signature header in the same t=,v1= format Stripe uses — so your existing verification code likely already handles it.

order.completed

Fires when a ticket payment clears Stripe and the buyer receives their QR. Use this to push the buyer into your CRM, Slack channel or marketing list.

{
  "id": "evt_8nFwL2hQ",
  "type": "order.completed",
  "created": 1716490281,
  "data": {
    "ticket_id": "tkt_8nFwL2hQ",
    "event_id": "evt_4kQz...",
    "organizer_id": "org_8nFw...",
    "buyer_email": "maria@example.com",
    "quantity": 2,
    "total": 48.00,
    "currency": "EUR",
    "paid_at": "2026-05-13T22:31:21Z"
  }
}
ticket.refunded

Fires when a charge is refunded through Stripe (full or partial). Includes both the gross refund and the organizer-net delta so payout dashboards stay in sync.

{
  "id": "evt_R2xK...",
  "type": "ticket.refunded",
  "created": 1716492000,
  "data": {
    "ticket_id": "tkt_8nFwL2hQ",
    "event_id": "evt_4kQz...",
    "organizer_id": "org_8nFw...",
    "refunded_amount": 24.00,
    "organizer_refunded_amount": 22.80,
    "fully_refunded": false,
    "currency": "EUR",
    "refunded_at": "2026-05-13T23:00:00Z"
  }
}
checkin.scanned

Fires every time the door staff scans a ticket QR in or out. Use it to power real-time attendee dashboards, automated VIP greetings or BI tooling.

{
  "id": "evt_S1cI...",
  "type": "checkin.scanned",
  "created": 1716598800,
  "data": {
    "ticket_id": "tkt_8nFwL2hQ",
    "event_id": "evt_4kQz...",
    "organizer_id": "org_8nFw...",
    "direction": "in",
    "scanned_at": "2026-05-15T00:30:00Z",
    "scanned_by_name": "Door Staff #2",
    "tier_name": "VIP Table",
    "is_vip_table": true
  }
}
promoter.registered

Fires when a promoter (RRPP) registers a guest through their personal link. Lets you reward promoters in real time without polling the dashboard.

{
  "id": "evt_P1mR...",
  "type": "promoter.registered",
  "created": 1716480000,
  "data": {
    "promoter_id": "pro_4Qa...",
    "event_id": "evt_4kQz...",
    "organizer_id": "org_8nFw...",
    "guest_email": "guest@example.com",
    "registered_at": "2026-05-12T18:00:00Z"
  }
}

Verify the signature

Recompute HMAC-SHA256 over `${t}.${rawBody}` with the per-webhook secret (shown ONCE at creation, format whsec_…) and constant-time-compare against the v1 portion of the header.

Signature verification
1# Eventium sends each webhook with a header
2# X-Eventium-Signature: t=<unix>,v1=<hex>
3# Verify in your handler — see JS / Python tabs.

Delivery semantics

  • • At-least-once delivery — your handler must be idempotent (key off event.id).
  • • 8s delivery timeout. Return 2xx within that window or we'll retry with exponential backoff.
  • • Replay window: signatures older than 5 minutes are rejected by the reference verifier — keep your clock in sync.
Errors

Predictable shapes, never empty bodies.

Every 4xx/5xx response carries a JSON envelope with a stable code your client can switch on.

401 invalid_api_key

Missing, malformed or revoked x-api-key. The prefix-lookup couldn't match a live row — rotate from the dashboard.

403 forbidden

Key is valid but the requested resource doesn't belong to your organizer scope. We never leak whether the resource exists — same response as 404.

429 rate_limited

Too many requests in the rolling window. Back off with exponential jitter; the Retry-After header tells you when the next slot opens.

500 internal_error

Something exploded on our side. We log every 5xx — usually transient, retry with backoff. If it persists, the status page will say so.

{
  "error": {
    "code": "invalid_api_key",
    "message": "Missing or invalid x-api-key."
  }
}
Ready when you are

Generate your first key and ship.

60 seconds from the dashboard to a working integration. No credit card, no rate limits at the free tier.