Teams API Documentation
This document describes how to use the Rondo Club REST API to manage teams (organizations, companies, etc.).
Base URL
Section titled “Base URL”All endpoints are relative to your WordPress installation:
https://your-site.com/wp-json/Authentication
Section titled “Authentication”The API supports two authentication methods:
Method 1: Application Password (Recommended for External Integrations)
Section titled “Method 1: Application Password (Recommended for External Integrations)”Use HTTP Basic Authentication with a WordPress Application Password. This is the recommended method for scripts, external services, and API integrations.
- Generate an Application Password in WordPress: Users → Profile → Application Passwords
- Use your WordPress username and the generated password (with spaces)
curl -X GET "https://your-site.com/wp-json/wp/v2/teams" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx"Or with the Authorization header:
curl -X GET "https://your-site.com/wp-json/wp/v2/teams" \ -H "Authorization: Basic $(echo -n 'username:xxxx xxxx xxxx xxxx xxxx xxxx' | base64)"Method 2: Session + Nonce (Browser Use)
Section titled “Method 2: Session + Nonce (Browser Use)”For requests from the Rondo Club frontend (same browser session), use the REST nonce:
X-WP-Nonce: {nonce_value}The nonce is available in window.rondoConfig.nonce when logged in to Rondo Club.
Access Control: Users can only see and modify teams they created themselves. Sharing and workspace visibility can extend access to other users.
Endpoints Overview
Section titled “Endpoints Overview”| Method | Endpoint | Description |
|---|---|---|
GET | /wp/v2/teams | List all accessible teams |
GET | /wp/v2/teams/{id} | Get single team |
POST | /wp/v2/teams | Create new team |
PUT | /wp/v2/teams/{id} | Update team |
DELETE | /wp/v2/teams/{id} | Delete team |
POST | /rondo/v1/teams/{id}/logo/upload | Upload team logo |
POST | /rondo/v1/teams/{id}/logo | Set logo from media library |
GET | /rondo/v1/teams/{id}/people | Get people associated with team |
GET | /rondo/v1/teams/{id}/shares | Get users team is shared with |
POST | /rondo/v1/teams/{id}/shares | Share team with user |
DELETE | /rondo/v1/teams/{id}/shares/{user_id} | Remove share |
Field Reference
Section titled “Field Reference”Basic Information
Section titled “Basic Information”| Field | Type | Description |
|---|---|---|
title | object | Team name (rendered as title.rendered) |
content | object | Team description (rendered as content.rendered) |
featured_media | integer | Logo attachment ID |
ACF Fields
Section titled “ACF Fields”| Field | Type | Description | Format |
|---|---|---|---|
acf.website | string | Team website URL | Full URL |
acf.contact_info | array | Contact methods (repeater) | See below |
Contact Info (Repeater)
Section titled “Contact Info (Repeater)”"acf": { "contact_info": [ { "contact_type": "email", "contact_label": "Algemeen", }, { "contact_type": "phone", "contact_label": "Receptie", "contact_value": "+31 20 123 4567" } ]}Contact Types:
phone- Telefoonemail- E-mailadresaddress- Adresother- Anders
Visibility
Section titled “Visibility”| Field | Type | Description | Values |
|---|---|---|---|
acf._visibility | string | Who can see this team | private, workspace, shared |
acf._assigned_workspaces | array | Workspace term IDs | [1, 2, 3] |
Create a Team
Section titled “Create a Team”Request:
POST /wp/v2/teamsContent-Type: application/jsonX-WP-Nonce: {nonce}Body:
{ "status": "publish", "title": "Ajax Amsterdam", "content": "Professionele voetbalclub uit Amsterdam", "acf": { "website": "https://www.ajax.nl", "contact_info": [ { "contact_type": "email", "contact_label": "Algemeen", }, { "contact_type": "phone", "contact_label": "Arena", "contact_value": "+31 20 311 1444" }, { "contact_type": "address", "contact_label": "Johan Cruijff ArenA", "contact_value": "ArenA Boulevard 1, 1101 AX Amsterdam" } ], "_visibility": "private" }}Response (201 Created):
{ "id": 789, "date": "2026-01-26T10:00:00", "slug": "ajax-amsterdam", "status": "publish", "type": "team", "title": { "rendered": "Ajax Amsterdam" }, "content": { "rendered": "<p>Professionele voetbalclub uit Amsterdam</p>" }, "author": 1, "featured_media": 0, "acf": { "website": "https://www.ajax.nl", "contact_info": [...], "_visibility": "private", "_assigned_workspaces": [] }}Update a Team
Section titled “Update a Team”Request:
PUT /wp/v2/teams/789Content-Type: application/jsonX-WP-Nonce: {nonce}Body (partial update):
{ "acf": { "website": "https://www.ajax.nl/nl/", "contact_info": [ { "contact_type": "email", "contact_label": "Klantenservice", } ] }}Important: When updating repeater fields (contact_info), you must send the complete array. Partial updates will replace the entire field.
Response (200 OK): Returns the full updated team object.
Get a Team
Section titled “Get a Team”Request:
GET /wp/v2/teams/789X-WP-Nonce: {nonce}Response:
{ "id": 789, "title": { "rendered": "Ajax Amsterdam" }, "content": { "rendered": "<p>Professionele voetbalclub uit Amsterdam</p>" }, "featured_media": 123, "acf": { "website": "https://www.ajax.nl", "contact_info": [...], "_visibility": "private", "_assigned_workspaces": [] }}List Teams
Section titled “List Teams”Request:
GET /wp/v2/teams?per_page=20&page=1X-WP-Nonce: {nonce}Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
per_page | int | 10 | Items per page (max: 100) |
page | int | 1 | Page number |
search | string | - | Search in name |
orderby | string | date | Sort by: date, title, modified |
order | string | desc | Sort order: asc or desc |
_fields | string | - | Limit fields returned (comma-separated) |
Example - Search for teams:
GET /wp/v2/teams?search=Ajax&per_page=50Example - Get only IDs and names (faster):
GET /wp/v2/teams?_fields=id,title,acf.websiteDelete a Team
Section titled “Delete a Team”Request:
DELETE /wp/v2/teams/789X-WP-Nonce: {nonce}Response (200 OK):
{ "deleted": true, "previous": { ... }}Upload Team Logo
Section titled “Upload Team Logo”Upload and set a team’s logo. The filename is automatically generated from the team name.
Request:
POST /rondo/v1/teams/789/logo/uploadContent-Type: multipart/form-dataX-WP-Nonce: {nonce}Form Data:
file: Image file (JPEG, PNG, GIF, WebP, SVG)
Response:
{ "success": true, "attachment_id": 456, "filename": "ajax-amsterdam-logo.png", "thumbnail_url": "https://your-site.com/wp-content/uploads/2026/01/ajax-amsterdam-logo-150x150.png", "full_url": "https://your-site.com/wp-content/uploads/2026/01/ajax-amsterdam-logo.png"}Set Team Logo (by Media ID)
Section titled “Set Team Logo (by Media ID)”Set a team’s logo from an existing media library item.
Request:
POST /rondo/v1/teams/789/logoContent-Type: application/jsonX-WP-Nonce: {nonce}Body:
{ "media_id": 456}Response:
{ "success": true, "media_id": 456, "thumbnail_url": "https://your-site.com/wp-content/uploads/2026/01/logo-150x150.png", "full_url": "https://your-site.com/wp-content/uploads/2026/01/logo.png"}Get People by Team
Section titled “Get People by Team”Get all people who work or worked at a team.
Request:
GET /rondo/v1/teams/789/peopleX-WP-Nonce: {nonce}Response:
{ "current": [ { "id": 123, "name": "Johan Cruijff", "thumbnail": "https://...", "job_title": "Technisch Directeur", "start_date": "2020-01-15", "end_date": "" } ], "former": [ { "id": 456, "name": "Marco van Basten", "thumbnail": "https://...", "job_title": "Speler", "start_date": "1982-04-01", "end_date": "1987-06-30" } ]}Direct Sharing
Section titled “Direct Sharing”Get Team Shares
Section titled “Get Team Shares”Request:
GET /rondo/v1/teams/789/sharesX-WP-Nonce: {nonce}Permission: Must be team owner
Response:
[ { "user_id": 5, "display_name": "Jan Jansen", "avatar_url": "https://...", "permission": "view" }]Share Team with User
Section titled “Share Team with User”Request:
POST /rondo/v1/teams/789/sharesContent-Type: application/jsonX-WP-Nonce: {nonce}Permission: Must be team owner
Body:
{ "user_id": 5, "permission": "view"}Permission values:
view- Can view the teamedit- Can view and edit the team
Response:
{ "success": true, "message": "Shared successfully."}Remove Share
Section titled “Remove Share”Request:
DELETE /rondo/v1/teams/789/shares/5X-WP-Nonce: {nonce}Permission: Must be team owner
Response:
{ "success": true, "message": "Share removed."}Error Handling
Section titled “Error Handling”Common Error Responses:
401 Unauthorized:
{ "code": "rest_not_logged_in", "message": "You are not currently logged in.", "data": { "status": 401 }}403 Forbidden:
{ "code": "rest_forbidden", "message": "Sorry, you are not allowed to edit this team.", "data": { "status": 403 }}404 Not Found:
{ "code": "rest_post_invalid_id", "message": "Invalid team ID.", "data": { "status": 404 }}Code Examples
Section titled “Code Examples”JavaScript/TypeScript (fetch)
Section titled “JavaScript/TypeScript (fetch)”const API_BASE = 'https://your-site.com/wp-json';const nonce = window.rondoConfig?.nonce || 'your-nonce';
// Create a teamasync function createTeam(data) { const response = await fetch(`${API_BASE}/wp/v2/teams`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce, }, credentials: 'include', body: JSON.stringify({ status: 'publish', title: data.name, content: data.description || '', acf: { website: data.website, contact_info: data.contacts || [], }, }), });
if (!response.ok) { throw new Error(`HTTP ${response.status}`); }
return response.json();}
// Update a teamasync function updateTeam(id, data) { const response = await fetch(`${API_BASE}/wp/v2/teams/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce, }, credentials: 'include', body: JSON.stringify(data), });
if (!response.ok) { throw new Error(`HTTP ${response.status}`); }
return response.json();}
// Upload team logoasync function uploadTeamLogo(teamId, file) { const formData = new FormData(); formData.append('file', file);
const response = await fetch(`${API_BASE}/rondo/v1/teams/${teamId}/logo/upload`, { method: 'POST', headers: { 'X-WP-Nonce': nonce, }, credentials: 'include', body: formData, });
if (!response.ok) { throw new Error(`HTTP ${response.status}`); }
return response.json();}
// Get people by teamasync function getPeopleByTeam(teamId) { const response = await fetch(`${API_BASE}/rondo/v1/teams/${teamId}/people`, { headers: { 'X-WP-Nonce': nonce, }, credentials: 'include', });
if (!response.ok) { throw new Error(`HTTP ${response.status}`); }
return response.json();}
// Usageconst newTeam = await createTeam({ name: 'Ajax Amsterdam', description: 'Professionele voetbalclub', website: 'https://www.ajax.nl', contacts: [ ],});
console.log('Created team:', newTeam.id);PHP (WordPress context)
Section titled “PHP (WordPress context)”<?php// Create a team programmatically$team_id = wp_insert_post([ 'post_type' => 'team', 'post_status' => 'publish', 'post_title' => 'Ajax Amsterdam', 'post_content' => 'Professionele voetbalclub uit Amsterdam', 'post_author' => get_current_user_id(),]);
if ($team_id && !is_wp_error($team_id)) { // Set ACF fields update_field('website', 'https://www.ajax.nl', $team_id);
// Set contact info (repeater) update_field('contact_info', [ [ 'contact_type' => 'email', 'contact_label' => 'Algemeen', ], [ 'contact_type' => 'phone', 'contact_label' => 'Receptie', 'contact_value' => '+31 20 123 4567', ], ], $team_id);
// Set visibility update_field('_visibility', 'private', $team_id);}
// Get all teams for current user$teams = get_posts([ 'post_type' => 'team', 'posts_per_page' => -1, 'author' => get_current_user_id(),]);
foreach ($teams as $team) { $website = get_field('website', $team->ID); echo $team->post_title . ': ' . $website . "\n";}cURL (with Application Password)
Section titled “cURL (with Application Password)”# Create a teamcurl -X POST "https://your-site.com/wp-json/wp/v2/teams" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx" \ -H "Content-Type: application/json" \ -d '{ "status": "publish", "title": "Ajax Amsterdam", "content": "Professionele voetbalclub uit Amsterdam", "acf": { "website": "https://www.ajax.nl", "contact_info": [ { "contact_type": "email", "contact_label": "Algemeen", "contact_value": "[email protected]" } ] } }'
# Update a teamcurl -X PUT "https://your-site.com/wp-json/wp/v2/teams/789" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx" \ -H "Content-Type: application/json" \ -d '{ "acf": { "website": "https://www.ajax.nl/nl/" } }'
# Get people by teamcurl -X GET "https://your-site.com/wp-json/rondo/v1/teams/789/people" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx"
# Upload team logocurl -X POST "https://your-site.com/wp-json/rondo/v1/teams/789/logo/upload" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx" \
# List teamscurl -X GET "https://your-site.com/wp-json/wp/v2/teams?per_page=10" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx"
# Delete a teamcurl -X DELETE "https://your-site.com/wp-json/wp/v2/teams/789" \ -u "username:xxxx xxxx xxxx xxxx xxxx xxxx"-
Title Field: Unlike People (which use ACF for first/last name), Teams use the standard WordPress post title.
-
Description: Team descriptions use the WordPress
contentfield (editor), not an ACF field. -
Logo: Team logos use the WordPress featured image system (
featured_media). Use the logo upload endpoints for easy management. -
Repeater Fields: When updating
contact_info, always send the complete array. WordPress will replace the entire field. -
Access Control: Each user only sees teams they created. Use visibility settings and sharing to extend access.
-
People Association: People are linked to teams via the person’s
work_historyrepeater field, not stored on the team itself.
Documentation generated: 2026-01-26