Skip to content

REST API

This document describes all REST API endpoints available in Rondo Club, including both WordPress standard endpoints and custom endpoints.

All API requests require authentication via WordPress session with REST nonce.

Headers:

X-WP-Nonce: {nonce_value}

The nonce is automatically injected by the frontend via window.wpApiSettings.nonce.

Rondo Club uses two API namespaces:

NamespacePurpose
/wp/v2/Standard WordPress REST API for CRUD operations on post types
/rondo/v1/Custom endpoints for dashboard, search, and specialized operations

These endpoints are provided by WordPress with access control applied:

MethodEndpointDescription
GET/wp/v2/peopleList all accessible people
GET/wp/v2/people/{id}Get single person
POST/wp/v2/peopleCreate new person
PUT/wp/v2/people/{id}Update person
DELETE/wp/v2/people/{id}Delete person
MethodEndpointDescription
GET/wp/v2/teamsList all accessible teams
GET/wp/v2/teams/{id}Get single team
POST/wp/v2/teamsCreate new team
PUT/wp/v2/teams/{id}Update team
DELETE/wp/v2/teams/{id}Delete team
MethodEndpointDescription
GET/wp/v2/relationship_typeList relationship types
GET/wp/v2/seizoenList seasons (for discipline cases)

These endpoints provide specialized functionality beyond basic CRUD operations.

GET /rondo/v1/dashboard

Returns summary statistics and recent activity for the dashboard.

Permission: Logged in users only

Response:

{
"stats": {
"total_people": 150,
"total_teams": 45
},
"recent_people": [
{
"id": 123,
"name": "John Doe",
"first_name": "John",
"infix": "",
"last_name": "Doe",
"thumbnail": "https://...",
"is_favorite": true
}
],
"upcoming_reminders": [
{
"id": 456,
"title": "John Doe's Birthday",
"date_value": "2025-01-15",
"days_until": 5,
"is_recurring": true
}
],
"favorites": [...]
}

GET /rondo/v1/version

Returns the current theme version. Used for PWA/mobile app cache invalidation.

Permission: Public (no authentication required)

Response:

{
"version": "1.42.0"
}

This endpoint is called periodically by the frontend to detect when a new version has been deployed, allowing users to reload and get the latest code.


GET /rondo/v1/search

Search across people and teams.

Permission: Logged in users only

Parameters:

NameTypeRequiredDescription
qstringYesSearch query (minimum 2 characters)

Response:

{
"people": [
{ "id": 1, "name": "John Doe", "thumbnail": "...", "is_favorite": true }
],
"teams": [
{ "id": 2, "name": "Acme Corp", "thumbnail": "...", "website": "https://..." }
]
}

GET /rondo/v1/reminders

Get upcoming birthdays for reminders.

Permission: Logged in users only

Parameters:

NameTypeDefaultDescription
days_aheadint30Number of days to look ahead (1-365)

Response:

[
{
"id": 123,
"title": "John's Birthday",
"next_occurrence": "2025-01-20",
"days_until": 10,
"related_people": [
{ "id": 456, "name": "John Doe", "thumbnail": "..." }
]
}
]

Birthdays are generated from the birthdate field on person records.


GET /rondo/v1/teams/{team_id}/people

Get all people who work or worked at a team.

Permission: Must have access to the team

Response:

{
"current": [
{
"id": 1,
"name": "John Doe",
"thumbnail": "...",
"job_title": "CEO",
"start_date": "2020-01-15",
"end_date": ""
}
],
"former": [
{
"id": 2,
"name": "Jane Smith",
"thumbnail": "...",
"job_title": "CTO",
"start_date": "2018-03-01",
"end_date": "2023-06-30"
}
]
}

GET /rondo/v1/people/filter-options

Returns available filter options for the People list with counts. Options are derived dynamically from database values.

Authentication: Required (authenticated user)

Response:

{
"total": 523,
"age_groups": [
{ "value": "Onder 6", "count": 12 },
{ "value": "Onder 7", "count": 18 },
{ "value": "Onder 8", "count": 24 },
{ "value": "Onder 9", "count": 31 },
{ "value": "Onder 9 Meiden", "count": 15 },
{ "value": "Onder 10", "count": 28 },
{ "value": "Onder 11", "count": 35 },
{ "value": "Onder 11 Meiden", "count": 18 },
{ "value": "Onder 12", "count": 42 },
{ "value": "Onder 13", "count": 38 },
{ "value": "Onder 13 Meiden", "count": 19 },
{ "value": "Onder 14", "count": 45 },
{ "value": "Onder 15", "count": 41 },
{ "value": "Onder 15 Meiden", "count": 22 },
{ "value": "Onder 16", "count": 39 },
{ "value": "Onder 17", "count": 36 },
{ "value": "Onder 17 Meiden", "count": 20 },
{ "value": "Onder 18", "count": 33 },
{ "value": "Onder 19", "count": 29 },
{ "value": "Senioren", "count": 87 },
{ "value": "Senioren Vrouwen", "count": 34 }
],
"member_types": [
{ "value": "Junior", "count": 142 },
{ "value": "Senior", "count": 287 },
{ "value": "Donateur", "count": 51 },
{ "value": "Lid van Verdienste", "count": 8 }
]
}

Notes:

  • Only values with at least 1 matching person are included
  • Age groups sorted youngest to oldest (numeric extraction from “Onder X”), gender variants after base groups
  • Member types sorted in priority order (new types from sync appear at end)
  • Frontend caches with 5-minute staleTime

GET /rondo/v1/user/me

Get information about the currently logged in user.

Permission: Logged in users only

Response:

{
"id": 1,
"name": "Admin User",
"email": "[email protected]",
"avatar_url": "https://...",
"is_admin": true,
"profile_url": "https://.../wp-admin/profile.php",
"admin_url": "https://.../wp-admin/"
}

POST /rondo/v1/people/{person_id}/photo

Upload and set a person’s profile photo. The filename is automatically generated from the person’s name.

Permission: Must be able to edit the person

Content-Type: multipart/form-data

Body:

  • file - Image file (JPEG, PNG, GIF, WebP)

Response:

{
"success": true,
"attachment_id": 789,
"filename": "john-doe.jpg",
"thumbnail_url": "https://...",
"full_url": "https://..."
}

POST /rondo/v1/teams/{team_id}/logo/upload

Upload and set a team’s logo. The filename is automatically generated from the team name.

Permission: Must be able to edit the team

Content-Type: multipart/form-data

Body:

  • file - Image file (JPEG, PNG, GIF, WebP, SVG)

Response:

{
"success": true,
"attachment_id": 789,
"filename": "acme-corp-logo.png",
"thumbnail_url": "https://...",
"full_url": "https://..."
}

POST /rondo/v1/teams/{team_id}/logo

Set a team’s logo from an existing media library item.

Permission: Must be able to edit the team

Body:

{
"media_id": 789
}

Response:

{
"success": true,
"media_id": 789,
"thumbnail_url": "https://...",
"full_url": "https://..."
}

POST /rondo/v1/relationship-types/restore-defaults

Restore default inverse relationship mappings and gender-dependent configurations.

Permission: Logged in users only

Response:

{
"success": true,
"message": "Default relationship type configurations have been restored."
}

GET /rondo/v1/workspaces

List all workspaces the current user is a member of.

Permission: Logged in users only

Response:

[
{
"id": 1,
"name": "My Workspace",
"description": "Shared team workspace",
"member_count": 3,
"role": "owner"
}
]

GET /rondo/v1/workspaces/{id}

Get single workspace with members.

Permission: Must be workspace member

Response:

{
"id": 1,
"name": "My Workspace",
"description": "Shared team workspace",
"members": [
{
"user_id": 1,
"display_name": "John Doe",
"email": "[email protected]",
"role": "owner"
}
]
}

POST /rondo/v1/workspaces

Create a new workspace.

Permission: Logged in users only

Body:

{
"name": "New Workspace",
"description": "Optional description"
}

PUT /rondo/v1/workspaces/{id}

Update workspace details.

Permission: Must be workspace owner or admin

Body:

{
"name": "Updated Name",
"description": "Updated description"
}

DELETE /rondo/v1/workspaces/{id}

Delete a workspace.

Permission: Must be workspace owner


POST /rondo/v1/workspaces/{id}/members

Add a member to the workspace.

Permission: Must be workspace owner or admin

Body:

{
"user_id": 123,
"role": "member"
}

PUT /rondo/v1/workspaces/{id}/members/{user_id}

Update member role.

Permission: Must be workspace owner or admin

Body:

{
"role": "admin"
}

DELETE /rondo/v1/workspaces/{id}/members/{user_id}

Remove a member from the workspace.

Permission: Must be workspace owner or admin


GET /rondo/v1/workspaces/{id}/invites

List pending invites for a workspace.

Permission: Must be workspace owner or admin


POST /rondo/v1/workspaces/{id}/invites

Create and send an email invitation.

Permission: Must be workspace owner or admin

Body:

{
"email": "[email protected]",
"role": "member"
}

DELETE /rondo/v1/workspaces/{id}/invites/{invite_id}

Revoke a pending invite.

Permission: Must be workspace owner or admin


GET /rondo/v1/invites/{token}

Validate an invite token (public endpoint).

Permission: Public (no authentication required)

Response:

{
"valid": true,
"workspace_name": "Team Workspace",
"invited_by": "John Doe",
"role": "member"
}

POST /rondo/v1/invites/{token}/accept

Accept an invite and join the workspace.

Permission: Must be logged in


GET /rondo/v1/people/{id}/shares

Get list of users a person is shared with.

Permission: Must be post owner

Response:

[
{
"user_id": 123,
"display_name": "Jane Smith",
"email": "[email protected]",
"avatar_url": "https://...",
"permission": "view"
}
]

POST /rondo/v1/people/{id}/shares

Share a person with another user.

Permission: Must be post owner

Body:

{
"user_id": 123,
"permission": "view"
}

Response:

{
"success": true,
"message": "Shared successfully."
}

DELETE /rondo/v1/people/{id}/shares/{user_id}

Remove sharing from a user.

Permission: Must be post owner

Response:

{
"success": true,
"message": "Share removed."
}

GET /rondo/v1/teams/{id}/shares

Get list of users a team is shared with.

Permission: Must be post owner

Response: Same format as People shares.


POST /rondo/v1/teams/{id}/shares

Share a team with another user.

Permission: Must be post owner

Body: Same format as People shares.


DELETE /rondo/v1/teams/{id}/shares/{user_id}

Remove sharing from a user.

Permission: Must be post owner


GET /rondo/v1/users/search

Search for users to share with.

Permission: Logged in users only

Parameters:

NameTypeRequiredDescription
qstringYesSearch query (minimum 2 characters)

Response:

[
{
"id": 123,
"display_name": "Jane Smith",
"email": "[email protected]",
"avatar_url": "https://..."
}
]

Note: The current user is automatically excluded from search results.


POST /rondo/v1/user/mention-notifications

Update the user’s preference for @mention notifications.

Permission: Logged in users only

Body:

{
"preference": "digest"
}

Valid values:

  • digest - Include mentions in daily digest (default)
  • immediate - Send email notification immediately when mentioned
  • never - Do not notify me of mentions

Response:

{
"success": true,
"mention_notifications": "digest"
}

The preference is also returned by GET /rondo/v1/user/notification-channels as part of the response:

{
"channels": ["email"],
"notification_time": "09:00",
"mention_notifications": "digest"
}

GET /rondo/v1/workspaces/members/search

Search for workspace members for @mention autocomplete.

Permission: Logged in users only

Parameters:

NameTypeRequiredDescription
workspace_idsstringYesComma-separated workspace IDs
querystringYesSearch query for member names

Response:

[
{
"id": 123,
"name": "Jane Smith",
"email": "[email protected]"
}
]

The rest_prepare_person filter automatically expands relationship data in person responses:

{
"acf": {
"relationships": [
{
"related_person": 123,
"person_name": "Jane Doe",
"person_thumbnail": "https://...",
"relationship_type": 5,
"relationship_name": "Spouse",
"relationship_slug": "spouse",
"relationship_label": ""
}
]
}
}

Relationship type taxonomy terms include ACF fields in their REST response:

{
"id": 5,
"name": "Parent",
"slug": "parent",
"acf": {
"inverse_relationship_type": 6,
"is_gender_dependent": false,
"gender_dependent_group": ""
}
}

All endpoints return standard WordPress REST error format:

{
"code": "rest_forbidden",
"message": "You do not have permission to access this item.",
"data": {
"status": 403
}
}

Common error codes:

CodeStatusDescription
rest_forbidden403Access denied
rest_not_found404Resource not found
rest_invalid_param400Invalid parameter
not_logged_in401Authentication required

Manage the mapping between Sportlink “functies” (club-level roles) and Rondo permission roles.

GET /rondo/v1/functie-capability-map

Returns the current functie-to-role mapping.

Permission: Admin only

Response:

{
"map": {
"Voorzitter": ["admin"],
"Penningmeester": ["financieel"],
"Secretaris": ["admin"],
"Wedstrijdsecretaris": ["wedstrijdzaken"]
}
}

POST /rondo/v1/functie-capability-map

Update the functie-to-role mapping.

Permission: Admin only

Body:

{
"map": {
"Voorzitter": ["admin"],
"Penningmeester": ["financieel"]
}
}

Response:

{
"success": true,
"map": { ... }
}

Create WordPress user accounts from person records and manage provisioning settings.

POST /rondo/v1/people/{person_id}/provision

Provision a WordPress user account for a person. Creates a user with the Rondo User role, links it bidirectionally to the person record, and optionally sends a welcome email.

Permission: Admin only

Response:

{
"success": true,
"user_id": 42,
"person_id": 789,
"welcome_email_sent": true
}

GET /rondo/v1/provisioning/settings

Returns current provisioning settings including the welcome email template.

Permission: Admin only

Response:

{
"welcome_email_subject": "Welkom bij Rondo",
"welcome_email_body": "Beste {{naam}},\n\nJe account is aangemaakt...",
"auto_send_welcome_email": true
}

POST /rondo/v1/provisioning/settings

Update provisioning settings.

Permission: Admin only

Body:

{
"welcome_email_subject": "Welkom bij Rondo",
"welcome_email_body": "Beste {{naam}},\n\nJe account is aangemaakt...",
"auto_send_welcome_email": true
}

Volunteer Role Classification (Admin Only)

Section titled “Volunteer Role Classification (Admin Only)”

Manage how Sportlink job titles are classified for volunteer status calculation.

GET /rondo/v1/volunteer-roles/available

Returns all distinct job_title values from work_history across all person posts.

Permission: Admin only

Response: Array of strings (role names), sorted alphabetically.


GET /rondo/v1/volunteer-roles/settings

Returns current and default role classification arrays.

Permission: All authenticated users (read access for team detail page player/staff split)

Response:

{
"player_roles": ["Aanvaller", "Keeper", ...],
"excluded_roles": ["Donateur", "Erelid", ...],
"default_player_roles": ["Aanvaller", "Keeper", ...],
"default_excluded_roles": ["Donateur", "Erelid", ...]
}

POST /rondo/v1/volunteer-roles/settings

Update role classifications. Triggers volunteer status recalculation for all people.

Permission: Admin only

Parameters:

NameTypeDescription
player_rolesarrayRole names classified as player (not volunteer)
excluded_rolesarrayRole names excluded from volunteer count entirely

Response:

{
"player_roles": ["Aanvaller", ...],
"excluded_roles": ["Donateur", ...],
"people_recalculated": 245
}

WordPress Options:

  • rondo_player_roles - Array of player role names
  • rondo_excluded_roles - Array of excluded role names

When no option is set, hardcoded defaults from VolunteerStatus class are used.