REST API
REST API#
Access event data through the WordPress REST API. Build custom integrations, mobile apps, or external displays.
Overview#
The API provides endpoints for:
- Events (create, read, update, delete)
- Venues (create, read, update, delete)
- Organizers (create, read, update, delete)
- Attendees (read, update, lookup by ticket code)
- Check-in (check in, check out, validate, stats, recent)
- Calendar data (month, range, upcoming, categories)
- Webhooks (see the Webhooks page)
There is no speakers endpoint.
Base URL#
All endpoints use the base:
https://yoursite.com/wp-json/emwc/v1/
The API can be switched off under Events > Settings > Advanced > REST API (option emwc_enable_rest_api). When it is off, every emwc/v1 request returns emwc_api_disabled with status 403.
Authentication#
Public endpoints#
These endpoints work without authentication:
- GET events, venues, organizers (published items only)
- GET calendar/*
- GET webhooks/topics
Protected endpoints#
| Operation | Capability |
|---|---|
| POST events, venues, organizers | edit_posts |
| PUT events, venues, organizers | edit_post on that item |
| DELETE events, venues, organizers | delete_post on that item |
| All attendees and checkin routes | manage_woocommerce |
| All webhooks routes except topics | manage_options |
Authentication methods#
Application Passwords (recommended)
- Go to Users > Profile
- Scroll to Application Passwords
- Create a new password
- Use it with HTTP Basic Auth
curl -u username:application_password https://yoursite.com/wp-json/emwc/v1/events
Cookie authentication
For logged-in requests from JavaScript on your site. Send the X-WP-Nonce header.
Pagination#
List endpoints return X-WP-Total and X-WP-TotalPages headers and a Link header with prev and next URLs.
Events endpoints#
List events#
GET /wp-json/emwc/v1/events
Only published events are returned.
Parameters
| Parameter | Type | Description |
|---|---|---|
page | int | Page number (default: 1) |
per_page | int | Results per page (default: 10, max: 100) |
search | string | Search term |
orderby | string | date (default), title, modified, id, meta_value |
order | string | ASC or DESC (default) |
status | string | Event status: scheduled, cancelled, postponed, sold-out |
category | string | Category ID or slug |
venue | int | Venue ID |
organizer | int | Organizer ID |
start_after | string | Events starting on or after this date |
start_before | string | Events starting on or before this date |
upcoming | bool | Only events starting today or later |
featured | bool | Only featured events |
include | string | Comma-separated IDs to include |
exclude | string | Comma-separated IDs to exclude |
_embed | bool | Add venue and organizer objects to each event |
Example
curl "https://yoursite.com/wp-json/emwc/v1/events?per_page=5&status=scheduled&upcoming=1"
Response
[
{
"id": 123,
"title": "Tech Conference 2025",
"slug": "tech-conference-2025",
"status": "publish",
"content": "Annual technology conference...",
"excerpt": "",
"permalink": "https://yoursite.com/events/tech-conference-2025/",
"date_created": "2025-01-10T08:00:00",
"date_modified": "2025-01-12T09:30:00",
"featured_image": { "id": 55, "url": "...", "thumbnail": "...", "alt": "" },
"start_date": "2025-03-15",
"start_time": "09:00",
"end_date": "2025-03-15",
"end_time": "17:00",
"start_datetime": "2025-03-15T09:00:00",
"end_datetime": "2025-03-15T17:00:00",
"timezone": "America/New_York",
"all_day": false,
"venue_id": 45,
"organizer_id": 12,
"capacity": 500,
"event_status": "scheduled",
"event_type": "in-person",
"virtual_url": "",
"featured": false,
"categories": [3],
"_links": { "self": [...], "collection": [...] }
}
]
status is the WordPress post status. event_status is the event status shown in the admin.
Get single event#
GET /wp-json/emwc/v1/events/{id}
Unpublished events need read_post permission.
Create event#
POST /wp-json/emwc/v1/events
Body fields
| Field | Type | Description |
|---|---|---|
title | string | Required |
content | string | Description (HTML allowed) |
excerpt | string | Short description |
status | string | Post status: publish (default), draft, pending, private |
start_date, end_date | string | YYYY-MM-DD |
start_time, end_time | string | HH:MM |
timezone | string | Timezone name |
all_day | bool | All-day event |
venue_id | int | Venue ID |
organizer_id | int | Organizer ID |
capacity | int | Maximum attendees |
event_status | string | scheduled, cancelled, postponed, sold-out |
event_type | string | in-person, virtual, hybrid |
virtual_url | string | Virtual event URL |
featured | bool | Featured event |
categories | int[] | Category term IDs |
{
"title": "New Workshop",
"content": "Workshop description here",
"start_date": "2025-04-01",
"start_time": "14:00",
"end_date": "2025-04-01",
"end_time": "16:00",
"event_status": "scheduled",
"event_type": "in-person",
"venue_id": 45,
"organizer_id": 12,
"capacity": 30
}
Returns status 201 with a Location header.
Update event#
PUT /wp-json/emwc/v1/events/{id}
Accepts the same fields as create. Only fields you send are changed.
Delete event#
DELETE /wp-json/emwc/v1/events/{id}
Moves the event to trash. Add force=true to delete permanently. Returns { "deleted": true, "previous": { ... } }.
Venues endpoints#
GET /wp-json/emwc/v1/venues
GET /wp-json/emwc/v1/venues/{id}
POST /wp-json/emwc/v1/venues
PUT /wp-json/emwc/v1/venues/{id}
DELETE /wp-json/emwc/v1/venues/{id}
List parameters: page, per_page, search, orderby (title default, date, modified, id), order (ASC default), city, country.
Body fields: name (required on create), address, city, state, country, postal, capacity, phone, email, website.
Response fields: the body fields plus id, date_created, date_modified, event_count, _links.
{
"name": "Downtown Hall",
"address": "123 Main St",
"city": "New York",
"state": "NY",
"postal": "10001",
"country": "US",
"capacity": 200
}
Organizers endpoints#
GET /wp-json/emwc/v1/organizers
GET /wp-json/emwc/v1/organizers/{id}
POST /wp-json/emwc/v1/organizers
PUT /wp-json/emwc/v1/organizers/{id}
DELETE /wp-json/emwc/v1/organizers/{id}
List parameters: page, per_page, search, orderby (title default, date, modified, id), order (ASC default).
Body fields: name (required on create), phone, email, website, facebook, twitter, linkedin.
Response fields: the body fields plus id, date_created, date_modified, event_count, _links.
Attendees endpoints#
All attendee routes require manage_woocommerce.
List attendees#
GET /wp-json/emwc/v1/attendees
| Parameter | Type | Description |
|---|---|---|
page | int | Page number (default: 1) |
per_page | int | Results per page (default: 10, max: 100) |
search | string | Matches first name, last name, email, or ticket code |
orderby | string | created_at (default), first_name, last_name, email, status |
order | string | ASC or DESC (default) |
event | int | Filter by event ID |
order_id | int | Filter by WooCommerce order ID |
status | string | active, cancelled, checked_in, checked_out |
Response
[
{
"id": 456,
"event_id": 123,
"event_name": "Tech Conference 2025",
"order_id": 789,
"order_number": "789",
"user_id": 7,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "",
"ticket_code": "EMWC-ABC123DEF",
"status": "active",
"checked_in_at": null,
"checked_out_at": null,
"custom_fields": {},
"date_created": "2025-01-15T10:30:00",
"date_modified": "2025-01-15T10:30:00",
"qr_code_url": "https://...",
"_links": { "self": [...], "collection": [...] }
}
]
Get single attendee#
GET /wp-json/emwc/v1/attendees/{id}
GET /wp-json/emwc/v1/attendees/code/{ticket_code}
Update attendee#
PUT /wp-json/emwc/v1/attendees/{id}
Fields: first_name, last_name, email, phone, status (active, cancelled, checked_in, checked_out). Fires emwc_rest_attendee_updated.
Check-in endpoints#
All check-in routes require manage_woocommerce.
Check in#
POST /wp-json/emwc/v1/checkin
| Field | Type | Description |
|---|---|---|
ticket_code | string | Required |
event_id | int | Optional. Rejects the ticket if it belongs to another event |
Response
{
"success": true,
"message": "Successfully checked in!",
"attendee": {
"id": 456,
"name": "John Doe",
"email": "john@example.com",
"ticket_code": "EMWC-ABC123DEF",
"status": "checked_in",
"event_id": 123,
"event_name": "Tech Conference 2025"
},
"checked_in_at": "2025-03-15 09:15:00"
}
A ticket that is already checked in returns success: true with already_in: true.
Errors: emwc_rest_invalid_ticket (404), emwc_rest_wrong_event (400), emwc_rest_cancelled_ticket (400), emwc_rest_checkin_failed (500).
Check out#
POST /wp-json/emwc/v1/checkin/checkout
Body: ticket_code. The attendee must be checked in, otherwise emwc_rest_not_checked_in (400) is returned.
Validate a ticket#
POST /wp-json/emwc/v1/checkin/validate
Body: ticket_code, optional event_id. Does not change the ticket. Always returns status 200 with valid (bool), message, and attendee and status when the ticket exists.
Check-in stats#
GET /wp-json/emwc/v1/checkin/stats/{event_id}
Returns event_id, event_name, total, pending, checked_in, checked_out, cancelled, percentage.
Recent check-ins#
GET /wp-json/emwc/v1/checkin/recent/{event_id}?limit=10
limit is capped at 50. Returns event_id, event_name, and checkins (id, name, ticket_code, status, checked_in_at, checked_out_at).
Calendar endpoints#
All calendar routes are public and return published events only.
Month#
GET /wp-json/emwc/v1/calendar/month
| Parameter | Type | Description |
|---|---|---|
year | int | Default: current year |
month | int | 1 to 12 (default: current month) |
category | string | Category ID or slug |
Returns year, month, month_name, start_date, end_date, total_events, events, and events_by_date (events keyed by start date).
Range#
GET /wp-json/emwc/v1/calendar/range?start=2025-03-01&end=2025-03-31
start and end are required (YYYY-MM-DD). The range cannot exceed 365 days. Optional category.
Upcoming#
GET /wp-json/emwc/v1/calendar/upcoming?limit=5
limit is 1 to 50 (default: 5). Optional category.
Categories#
GET /wp-json/emwc/v1/calendar/categories?hide_empty=true
Returns total and categories (id, name, slug, description, count, color).
Calendar event fields#
Each event in a calendar response has: id, title, slug, url, start_date, start_time, end_date, end_time, all_day, start, end (ISO date-time strings), venue (name), venue_id, categories (id, name, slug, color), color, thumbnail, event_status, event_type, featured.
Error handling#
Error response format#
{
"code": "emwc_rest_forbidden",
"message": "Sorry, you are not allowed to manage attendees.",
"data": {
"status": 403
}
}
Common error codes#
| Code | Status | Description |
|---|---|---|
emwc_api_disabled | 403 | REST API switched off in settings |
emwc_rest_forbidden | 401 or 403 | Missing or insufficient permission |
emwc_rest_event_invalid_id | 404 | Event not found |
emwc_rest_venue_invalid_id | 404 | Venue not found |
emwc_rest_organizer_invalid_id | 404 | Organizer not found |
emwc_rest_attendee_invalid_id | 404 | Attendee not found |
emwc_rest_attendee_invalid_code | 404 | Ticket code not found |
emwc_rest_cannot_delete | 500 | Delete failed |
rest_invalid_param | 400 | Parameter failed validation |
Rate limiting#
The API does not impose rate limits. Use a caching plugin or CDN for high-traffic APIs.
Examples#
JavaScript fetch#
fetch("https://yoursite.com/wp-json/emwc/v1/events?upcoming=1")
.then((response) => response.json())
.then((events) => console.log(events));
PHP with wp_remote_get#
$response = wp_remote_get( 'https://yoursite.com/wp-json/emwc/v1/events' );
$events = json_decode( wp_remote_retrieve_body( $response ) );
cURL#
curl -X POST \
-H "Content-Type: application/json" \
-u admin:application_password \
-d '{"ticket_code":"EMWC-ABC123DEF"}' \
https://yoursite.com/wp-json/emwc/v1/checkin
Extending the API#
Custom endpoints#
add_action( 'rest_api_init', function() {
register_rest_route( 'emwc/v1', '/custom', array(
'methods' => 'GET',
'callback' => 'my_custom_endpoint',
'permission_callback' => '__return_true',
) );
} );
Modifying responses#
Each resource has a prepare filter:
add_filter( 'emwc_rest_prepare_event', function( $data, $post, $request ) {
$data['custom_field'] = get_post_meta( $post->ID, 'custom_field', true );
return $data;
}, 10, 3 );
| Filter | Arguments |
|---|---|
emwc_rest_prepare_event | $data, $post, $request |
emwc_rest_prepare_venue | $data, $post, $request |
emwc_rest_prepare_organizer | $data, $post, $request |
emwc_rest_prepare_attendee | $data, $attendee (array), $request |
Actions#
| Action | Arguments |
|---|---|
emwc_rest_event_created, emwc_rest_event_updated | $post_id, $request |
emwc_rest_event_deleted | $post_id, $force |
emwc_rest_venue_created, emwc_rest_venue_updated | $post_id, $request |
emwc_rest_venue_deleted | $post_id, $force |
emwc_rest_organizer_created, emwc_rest_organizer_updated | $post_id, $request |
emwc_rest_organizer_deleted | $post_id, $force |
emwc_rest_attendee_updated | $attendee_id, $request |
emwc_attendee_checked_in, emwc_attendee_checked_out | $attendee_id, $attendee |