Server-Sent Events (SSE)
Real-time updates via Server-Sent Events for appointment and availability changes. This endpoint powers the live update functionality in the admin calendar, providing instant synchronization across multiple browser sessions.
Endpoint
GET /wc-appointments/v2/sse
Purpose: Receive real-time updates when appointments or availabilities are created, updated, or deleted.
Permissions: Private to logged-in admins/staff. Requires a valid wp_rest nonce and session cookies.
Authentication
Nonce Methods (any of):
- Query parameter:
nonceor_wpnonce - Header:
X-WP-Nonce
Requirements:
- Request must include logged-in admin cookies
- EventSource automatically includes cookies when used from the same origin
- Nonce must be valid
wp_restnonce tied to the logged-in admin session
Behavior
- One-shot stream - Emits up to 50 events, flushes, and exits
- Client reconnection - Client should reconnect after stream ends
- Resume support - Use
since_idparameter orLast-Event-IDheader to resume from last event
Query Parameters
| Parameter | Type | Description |
|---|---|---|
nonce | string | wp_rest nonce tied to the logged-in admin session |
_wpnonce | string | Alternate WordPress nonce parameter |
since_id | int | Last event ID received; server only emits events with id > since_id |
Event Topics
Appointment Events
appointment.created- New appointment createdappointment.updated- Appointment updatedappointment.deleted- Appointment deletedappointment.trashed- Appointment moved to trashappointment.rescheduled- Appointment rescheduledappointment.cancelled- Appointment cancelled
Availability Events
availability.created- New availability rule createdavailability.updated- Availability rule updatedavailability.deleted- Availability rule deleted
Event Payload
Format: JSON in data: field
Structure:
{
"topic": "appointment.created",
"resource": "appointment",
"resource_id": 123,
"payload": {
"id": 123,
"start": 1733044800,
"end": 1733048400,
"product_id": 456,
"staff_ids": [5],
"staff_id": 5,
"status": "confirmed",
"customer_id": 789,
"order_id": 101112,
"order_item_id": 131415,
"cost": "50.00",
"all_day": false,
"customer_status": "expected"
},
"ts": 1733044800
}
Payload Fields (for appointments):
id,start,end,product_idstaff_ids,staff_idstatus,customer_idorder_id,order_item_idcost,all_day,customer_status
Example: Browser EventSource
// On an admin page with a localized wp_rest nonce
const restBase = wpApiSettings?.root || wcAppointmentsReactCalendar?.restUrl;
const nonce = wcAppointmentsReactCalendar?.nonce;
const lastId = parseInt(localStorage.getItem('wca:lastEventId') || '0', 10);
const u = new URL(restBase.replace(/\/$/, '/') + 'wc-appointments/v2/sse');
if (nonce) u.searchParams.set('nonce', nonce);
if (lastId > 0) u.searchParams.set('since_id', String(lastId));
const src = new EventSource(u.toString(), { withCredentials: true });
src.addEventListener('appointment.created', (e) => {
const d = JSON.parse(e.data);
// Handle new appointment in calendar view...
localStorage.setItem('wca:lastEventId', d.id);
});
src.addEventListener('appointment.updated', (e) => {
const d = JSON.parse(e.data);
// Update appointment in calendar view...
localStorage.setItem('wca:lastEventId', d.id);
});
src.addEventListener('error', () => {
// Let EventSource auto-reconnect; optionally trigger a refetch if needed.
setTimeout(() => {
// Reconnect logic
}, 5000);
});
Example: cURL (requires cookies)
# Note: You must include your admin session cookies for nonce verification.
# Replace COOKIE_FILE with a cookie jar exported from your browser or created via curl login.
curl -i \
-H "X-WP-Nonce: <wp_rest_nonce>" \
-b COOKIE_FILE \
"https://example.com/wp-json/wc-appointments/v2/sse?since_id=0"
Error Handling
401 Unauthorized:
Returned when:
- Called without valid cookies (anonymous)
- Stale/invalid nonce provided
Response:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"code": "rest_forbidden",
"message": "Sorry, you are not allowed to do that.",
"data": {
"status": 401
}
}
Headers
Response Headers:
Content-Type: text/event-streamX-Accel-Buffering: no(minimizes proxy buffering)Cache-Control: no-cache
Best Practices
- Reconnect on error - EventSource will auto-reconnect, but handle errors gracefully
- Store last event ID - Use
since_idto avoid missing events on reconnection - Handle one-shot nature - Reconnect after stream ends (50 events or timeout)
- Use withCredentials - Ensure cookies are sent with EventSource requests
- Debounce updates - Batch UI updates if receiving many events quickly
Limitations
- One-shot stream - Intentionally limited to avoid long-lived PHP processes
- 50 event limit - Stream ends after 50 events; client must reconnect
- Admin only - Not available for public/frontend use
- Requires cookies - Cannot be used with API key authentication
Related Documentation
- Appointments Endpoints - Managing appointments
- Availabilities Endpoints - Managing availability rules
- MDN: Server-Sent Events - SSE specification