Eventonomy

REST API Reference

Eventonomy is 100% REST - there is no admin-ajax.php usage anywhere. Every UI surface (blocks, admin console, CLI) hits the same endpoints. Third-party code uses the same contract.

Canonical contract: docs/REST-API.md in the plugin root is the authoritative specification. This page is a navigable summary with key examples. When anything here conflicts with the source file, the source file wins.

What You Will Learn

  • Base URL, namespace, and authentication strategies
  • The canonical list-response envelope
  • All resources: Events, Occurrences, RSVPs, Tickets, Orders, ICS, App Config, Bulk
  • Pagination strategies (cursor vs. offset)
  • The error contract

Conventions

Concern Value
REST namespace eventonomy/v1
Base URL /wp-json/eventonomy/v1/
HTTP methods GET (read), POST (create), PATCH (partial update), DELETE (delete). No PUT.
Timestamps ISO 8601 UTC. Never a field named date.

Authentication

First-Party (Cookie + Nonce)

Used by blocks, the frontend SPA, and in-browser clients.

fetch('/wp-json/eventonomy/v1/events', {
  headers: { 'X-WP-Nonce': eventonomyData.nonce },
  credentials: 'same-origin'
});

Headless (Application Passwords)

Used by external integrations, mobile apps, and server-to-server calls. Requires HTTPS.

curl -u "jane:abcd EFGH ijkl MNOP qrst UVWX" \
  https://example.com/wp-json/eventonomy/v1/events

Public Endpoints

No auth required: GET /events (published only), GET /events/{id} (published), GET /occurrences, GET /events/{id}.ics, GET /calendar.ics, GET /settings/app-config, the magic-link RSVP flow.

The List Envelope

Every list endpoint returns the same uniform envelope:

{
  "items": [ /* resource objects */ ],
  "total": 124,
  "pages": 11,
  "has_more": true,
  "next_cursor": "470"
}

Cursor lists set total and pages to null unless ?with_total=1 is passed.

Resources

Events - /events

Method Path Auth Description
GET /events Public (published) List events. Cursor pagination.
GET /events/{id} Public (published) Single event detail.
POST /events evnm_create_events Create an event.
PATCH /events/{id} Owner or evnm_manage_events Partial update.
DELETE /events/{id} Owner or evnm_manage_events Soft-delete (trash) or force-delete.

Key list parameters: from, to, category, tag, organizer, city, featured, search, status, author, cursor, page, per_page, fields (card|detail).

Occurrences - /occurrences

Calendar query endpoint. Returns occurrence rows joined to a compact event summary.

Method Path Auth Description
GET /occurrences Public Calendar list. Cursor pagination on (id).
GET /events/{id}/occurrences Public Occurrences for one event.
PATCH /occurrences/{id} Event owner or evnm_manage_events Update a single occurrence.
DELETE /occurrences/{id} Event owner or evnm_manage_events Soft-cancel an occurrence.

Key parameters: from, to, category, venue, cursor, per_page.

RSVPs - /rsvps

Method Path Auth Description
POST /events/{id}/rsvp Logged-in or guest (name+email) Create/update RSVP. Idempotent per identity.
POST /occurrences/{id}/rsvp Logged-in or guest Occurrence-scoped RSVP.
DELETE /events/{id}/rsvp RSVP owner or magic-link token Cancel RSVP. Triggers waitlist promotion.
GET /events/{id}/attendees evnm_manage_rsvps Attendee list. Cursor pagination.
POST /rsvp/magic-link Public (rate-limited) Request a management link by email.
GET /rsvp/verify Public (token is credential) Verify token; returns RSVP + session token.
PATCH /rsvp/manage Token in body or header Update RSVP via token.

RSVP statuses: going, maybe, no, waitlist.

Tickets - /events/{id}/tickets

Method Path Auth
GET /events/{id}/tickets Public
POST /events/{id}/tickets evnm_manage_tickets
PATCH /events/{id}/tickets/{ticket_id} evnm_manage_tickets
DELETE /events/{id}/tickets/{ticket_id} evnm_manage_tickets

Ticket types: free, donation, paid. Defining paid tickets is allowed in Free; selling them returns 402 evnm_pro_required.

Orders - /orders

Method Path Auth
POST /orders Logged-in or guest
GET /orders/{id} Order owner or evnm_manage_orders
GET /orders evnm_manage_orders (event-scoped for organizers)

Free completes only $0 orders. Orders with total > 0 return 402 evnm_pro_required.

ICS Feeds

GET /events/{id}.ics          # single event download
GET /calendar.ics             # subscribable feed (supports from, to, category, organizer, venue, token)

App Config

GET /settings/app-config      # public bootstrap - features, currency, timezone, is_pro_active

Bulk Operations

POST /events/bulk             # ids (max 50), action (publish|draft|trash|delete|feature|unfeature)

Pagination

Endpoint Strategy
GET /events Cursor (default); offset via ?page=
GET /occurrences Cursor
GET /events/{id}/attendees Cursor
GET /events/{id}/tickets Offset
GET /orders Offset

Cursor parameters: ?cursor=<opaque_id>, ?per_page=. Offset parameters: ?page=, ?per_page=. Default per_page = 12, max = 100.

Error Contract

All errors use WP_Error with an evnm_ code prefix:

{
  "code": "evnm_not_found",
  "message": "Event not found.",
  "data": { "status": 404 }
}

Validation errors (422) include per-field detail under data.errors.

Common codes: evnm_unauthorized (401), evnm_forbidden (403), evnm_not_found (404), evnm_validation_failed (422), evnm_rsvp_closed (409), evnm_capacity_full (409), evnm_pro_required (402), evnm_rate_limited (429), evnm_bulk_limit (422).

Adding Your Own Endpoints

Register in any namespace and reuse Eventonomy services via evnm():

add_action( 'rest_api_init', function () {
    register_rest_route( 'my-addon/v1', '/events/(?P<id>\d+)/my-data', [
        'methods'             => 'GET',
        'permission_callback' => '__return_true',
        'callback' => function ( $req ) {
            $event = evnm( \Eventonomy\Contracts\EventRepositoryInterface::class )
                ->get( (int) $req['id'] );
            return rest_ensure_response( [ 'event_id' => $event['id'] ] );
        },
    ] );
} );

What's Next?

Browse the full hook and filter catalog.

Hooks & Filters →