Skip to content

Teams API Documentation

This document describes how to use the Rondo Club REST API to manage teams (organizations, companies, etc.).

All endpoints are relative to your WordPress installation:

https://your-site.com/wp-json/

The API supports two authentication methods:

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.

  1. Generate an Application Password in WordPress: Users → Profile → Application Passwords
  2. Use your WordPress username and the generated password (with spaces)
Terminal window
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:

Terminal window
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)"

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.


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
POST/rondo/v1/teams/{id}/logo/uploadUpload team logo
POST/rondo/v1/teams/{id}/logoSet logo from media library
GET/rondo/v1/teams/{id}/peopleGet people associated with team
GET/rondo/v1/teams/{id}/sharesGet users team is shared with
POST/rondo/v1/teams/{id}/sharesShare team with user
DELETE/rondo/v1/teams/{id}/shares/{user_id}Remove share

FieldTypeDescription
titleobjectTeam name (rendered as title.rendered)
contentobjectTeam description (rendered as content.rendered)
featured_mediaintegerLogo attachment ID
FieldTypeDescriptionFormat
acf.websitestringTeam website URLFull URL
acf.contact_infoarrayContact methods (repeater)See below
"acf": {
"contact_info": [
{
"contact_type": "email",
"contact_label": "Algemeen",
"contact_value": "[email protected]"
},
{
"contact_type": "phone",
"contact_label": "Receptie",
"contact_value": "+31 20 123 4567"
}
]
}

Contact Types:

  • phone - Telefoon
  • email - E-mailadres
  • address - Adres
  • other - Anders
FieldTypeDescriptionValues
acf._visibilitystringWho can see this teamprivate, workspace, shared
acf._assigned_workspacesarrayWorkspace term IDs[1, 2, 3]

Request:

POST /wp/v2/teams
Content-Type: application/json
X-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_value": "[email protected]"
},
{
"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": []
}
}

Request:

PUT /wp/v2/teams/789
Content-Type: application/json
X-WP-Nonce: {nonce}

Body (partial update):

{
"acf": {
"website": "https://www.ajax.nl/nl/",
"contact_info": [
{
"contact_type": "email",
"contact_label": "Klantenservice",
"contact_value": "[email protected]"
}
]
}
}

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.


Request:

GET /wp/v2/teams/789
X-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": []
}
}

Request:

GET /wp/v2/teams?per_page=20&page=1
X-WP-Nonce: {nonce}

Query Parameters:

ParameterTypeDefaultDescription
per_pageint10Items per page (max: 100)
pageint1Page number
searchstring-Search in name
orderbystringdateSort by: date, title, modified
orderstringdescSort order: asc or desc
_fieldsstring-Limit fields returned (comma-separated)

Example - Search for teams:

GET /wp/v2/teams?search=Ajax&per_page=50

Example - Get only IDs and names (faster):

GET /wp/v2/teams?_fields=id,title,acf.website

Request:

DELETE /wp/v2/teams/789
X-WP-Nonce: {nonce}

Response (200 OK):

{
"deleted": true,
"previous": { ... }
}

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

Request:

POST /rondo/v1/teams/789/logo/upload
Content-Type: multipart/form-data
X-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 a team’s logo from an existing media library item.

Request:

POST /rondo/v1/teams/789/logo
Content-Type: application/json
X-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 all people who work or worked at a team.

Request:

GET /rondo/v1/teams/789/people
X-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"
}
]
}

Request:

GET /rondo/v1/teams/789/shares
X-WP-Nonce: {nonce}

Permission: Must be team owner

Response:

[
{
"user_id": 5,
"display_name": "Jan Jansen",
"email": "[email protected]",
"avatar_url": "https://...",
"permission": "view"
}
]

Request:

POST /rondo/v1/teams/789/shares
Content-Type: application/json
X-WP-Nonce: {nonce}

Permission: Must be team owner

Body:

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

Permission values:

  • view - Can view the team
  • edit - Can view and edit the team

Response:

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

Request:

DELETE /rondo/v1/teams/789/shares/5
X-WP-Nonce: {nonce}

Permission: Must be team owner

Response:

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

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 }
}

const API_BASE = 'https://your-site.com/wp-json';
const nonce = window.rondoConfig?.nonce || 'your-nonce';
// Create a team
async 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 team
async 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 logo
async 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 team
async 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();
}
// Usage
const newTeam = await createTeam({
name: 'Ajax Amsterdam',
description: 'Professionele voetbalclub',
website: 'https://www.ajax.nl',
contacts: [
{ contact_type: 'email', contact_label: 'Algemeen', contact_value: '[email protected]' }
],
});
console.log('Created team:', newTeam.id);
<?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_value' => '[email protected]',
],
[
'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";
}
Terminal window
# Create a team
curl -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 team
curl -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 team
curl -X GET "https://your-site.com/wp-json/rondo/v1/teams/789/people" \
-u "username:xxxx xxxx xxxx xxxx xxxx xxxx"
# Upload team logo
curl -X POST "https://your-site.com/wp-json/rondo/v1/teams/789/logo/upload" \
-u "username:xxxx xxxx xxxx xxxx xxxx xxxx" \
# List teams
curl -X GET "https://your-site.com/wp-json/wp/v2/teams?per_page=10" \
-u "username:xxxx xxxx xxxx xxxx xxxx xxxx"
# Delete a team
curl -X DELETE "https://your-site.com/wp-json/wp/v2/teams/789" \
-u "username:xxxx xxxx xxxx xxxx xxxx xxxx"

  1. Title Field: Unlike People (which use ACF for first/last name), Teams use the standard WordPress post title.

  2. Description: Team descriptions use the WordPress content field (editor), not an ACF field.

  3. Logo: Team logos use the WordPress featured image system (featured_media). Use the logo upload endpoints for easy management.

  4. Repeater Fields: When updating contact_info, always send the complete array. WordPress will replace the entire field.

  5. Access Control: Each user only sees teams they created. Use visibility settings and sharing to extend access.

  6. People Association: People are linked to teams via the person’s work_history repeater field, not stored on the team itself.


Documentation generated: 2026-01-26