Skip to main content

Changelog

All notable changes to the WPPR API will be documented here.

[1.3.0] - 2026-04-13​

Documentation​

Match Set Validation Rules Clarified​

The verified match documentation now explains the score progression rules more explicitly so partners can validate set logic locally before submitting matches.

What is now documented more clearly:

  • one-set matches are allowed when set_1 has a winner
  • two-set matches are allowed only when the same team wins both submitted sets, so the result is 2:0
  • three-set matches are allowed only when the first two sets are split 1:1, so set_3 is the deciding set
  • set_3 must be omitted if one team already won the first two sets
  • tied set scores such as 6:6 are rejected
  • placeholder 0:0 scores for unplayed sets are rejected; unplayed sets must be omitted

Docs updated:

  • Create Match With AI now includes a dedicated set-rules section and a valid three-set example
  • new guide: Match Set Validation

Breaking Changes​

🚨 Verified Match Submission Uses Source-Based Player Identity​

Endpoint: POST /v1/matches/verified

The verified match submission endpoint now accepts players without a WPPR ID and identifies them by source + source_player_id when wppr_id is not provided. This replaces the earlier WPPR-only match submission contract.

Before:

  • Every submitted player had to include wppr_id
  • A player without wppr_id was rejected
  • Business-level duplicate and rejection outcomes could return 200 with status: "duplicate" or status: "rejected"

After:

  • Every submitted player must include first_name and source_player_id; last_name is optional
  • wppr_id and phone_number are optional
  • If wppr_id is present, it is authoritative
  • Otherwise the player is resolved by source + source_player_id
  • If no existing mapping exists, the API may create a new external/unclaimed player profile
  • The API never auto-links players by name alone
  • If a player with the same name already exists but no mapping exists yet, the API may still create a new external/unclaimed player profile and let duplicate/merge handle it later
  • If a submitted source_player_id is already linked to another player, the request is rejected with 400
  • Business-level duplicate and validation failures now return 400
  • Successful submissions return 200 with status: "created"
  • The developer portal now preserves actionable verified-match 400 conflict messages even when an upstream error body is missing a top-level message

Before Request Example:

curl -X POST https://developers.wecourts.com/api/v1/matches/verified \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_id": "13844",
"team1": {
"player1": { "wppr_id": "P12B41" },
"player2": { "wppr_id": "PCD275" },
"set_1": 4
},
"team2": {
"player1": { "wppr_id": "PB5821" },
"player2": { "wppr_id": "PF0501" },
"set_1": 6
},
"match_details": {
"date": "2026-03-23",
"club_id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7"
}
}'

After Request Example:

curl -X POST https://developers.wecourts.com/api/v1/matches/verified \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_id": "source-match-123",
"team1": {
"player1": {
"first_name": "Alex",
"last_name": "Smith",
"source_player_id": "src-player-1",
"wppr_id": "P12B41"
},
"player2": {
"first_name": "Jamie",
"last_name": "Smith",
"source_player_id": "src-player-2"
},
"set_1": 6
},
"team2": {
"player1": {
"first_name": "Taylor",
"last_name": "Jones",
"source_player_id": "src-player-3"
},
"player2": {
"first_name": "Casey",
"last_name": "Jones",
"source_player_id": "src-player-4"
},
"set_1": 4
},
"match_details": {
"date": "2026-04-08",
"club_id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7"
}
}'

Before Success and Business Outcomes:

{
"source_match_id": "13845",
"status": "duplicate",
"match_id": "MC123ABC"
}
{
"source_match_id": "14129",
"status": "rejected",
"reason": "missing_wppr_id"
}

After Success Response (200 OK):

{
"source_match_id": "source-match-123",
"status": "created",
"match_id": "MC123ABC"
}

After Business Rejection Response (400 Bad Request):

{
"error": true,
"message": "The submitted source_player_id (partner-player-2) already belongs to P77777 (Mapped Player) for team1.player2 (Player Two), but this request sent wppr_id PCD275. Send wppr_id P77777 with source_player_id partner-player-2, or send a different source_player_id if PCD275 is a different player. If PCD275 should replace P77777, ask support to merge or correct the existing player mapping before retrying.",
"statusCode": 400
}

Migration Steps:

  • Update all verified match player objects to send first_name and source_player_id, and include last_name when available
  • Continue sending wppr_id when you already know it
  • Stop relying on 200 duplicate or 200 rejected outcomes; handle business-rule failures as 400
  • Do not send any set as 0:0; omit unplayed optional sets instead
  • Do not send tied set scores; each submitted set must have a winner
  • For two-set matches, the same team must win both sets for a 2:0 result
  • Only send set_3 when the first two sets are split 1:1 and the third set decides the match
  • If you receive a source_player_id conflict, use the returned player slot and message to correct the submitted identity instead of retrying unchanged

[1.2.0] - 2026-03-26​

Added​

Create WPPR Profile​

Endpoint: POST /v1/players/profile

Create new WPPR player profiles via the API. Submit a phone number, name, and optional rating to register a new player in the WPPR system.

Request Body:

FieldTypeRequiredDescription
phone_numberstringYesPlayer phone number
namestringYesPlayer full name
ratingnumberNoInitial player rating

Example Request:

curl -X POST https://developers.wecourts.com/api/v1/players/profile \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone_number": "971501234567", "name": "John Doe", "rating": 3.5}'

Example Response (201 Created):

{
"wppr_id": "P30C1B",
"phone_number": "971501234567",
"name": "John Doe",
"rating": 3.5,
"rating_status": "IR",
"rating_category_name": "C+",
"wppr_profile_url": "https://wecourts.com/wppr/P30C1B"
}

Behavior:

  • If a profile with the same phone number already exists, returns the existing profile with HTTP 200
  • Phone numbers are normalized automatically (leading + or 00 stripped, non-digit characters removed)
  • Rating values are automatically scaled to WPPR ratings based on your API consumer profile. If no scaling is configured for your account, the value is used directly as a WPPR rating (0–8)

Per-Consumer Rating Scaling​

When creating WPPR profiles, ratings are automatically converted from your system's scale to WPPR ratings based on your API consumer profile. If no custom scale is configured, ratings are passed through as-is (valid range: 0–8).

Benefits:

  • Send ratings in your own system's scale
  • Automatic conversion to WPPR ratings

Club Lookup Endpoints​

Endpoints: GET /v1/clubs/search, GET /v1/clubs/{club_id}

New club lookup endpoints help partners find the correct club before submitting a WPPR verified match, then fetch the canonical club record again by UUID when needed.

Query Parameters (GET /v1/clubs/search):

FieldTypeRequiredDescription
namestringYesClub name to search for similar matches
limitnumberNoMaximum number of clubs to return. Defaults to 20 and caps at 100

Search Response Fields:

  • id
  • name
  • address
  • city_name
  • country_name
  • country_code

Use Case: Partners can enter a club name and receive similar club matches before submitting a WPPR verified match.

Then, if they already know the canonical club UUID, they can fetch the single club record directly with GET /v1/clubs/{club_id}.

Example Request:

curl -X GET "https://developers.wecourts.com/api/v1/clubs/search?name=Padel%20Art" \
-H "Authorization: Bearer YOUR_API_KEY"

Example Response (200 OK):

[
{
"id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7",
"name": "Padel Art",
"address": "Padel Art, Dubai",
"city_name": "Dubai",
"country_name": "United Arab Emirates",
"country_code": "AE"
}
]

Get By ID Example:

curl -X GET "https://developers.wecourts.com/api/v1/clubs/d62bd044-7dfd-4dc6-991d-9e5d9dc058ca" \
-H "Authorization: Bearer YOUR_API_KEY"

Get By ID Response (200 OK):

{
"id": "d62bd044-7dfd-4dc6-991d-9e5d9dc058ca",
"name": "Padel Art",
"address": "Padel Art",
"city_name": "Dubai",
"country_name": "United Arab Emirates",
"country_code": "AE"
}

Error Responses:

  • 400 if name is missing on GET /v1/clubs/search
  • 401 if the bearer token is missing or invalid
  • 404 if GET /v1/clubs/{club_id} references a club that does not exist
  • 503 if the upstream WPPR service is unavailable

Benefits:

  • Faster club lookup by name before match submission
  • Smaller, cleaner search responses
  • Direct retrieval of a canonical club record by UUID

WPPR Verified Match Submission​

Endpoint: POST /v1/matches/verified

Partners can now submit one completed WPPR verified match per request through a simplified single-match payload.

Request Body:

FieldTypeRequiredDescription
match_idstringYesYour own match ID
team1objectYesFirst team players and set scores
team2objectYesSecond team players and set scores
match_detailsobjectYesMatch metadata

Rules:

  • Every player must include first_name and source_player_id.
  • wppr_id, last_name, and phone_number are optional.
  • If wppr_id is provided, it is authoritative.
  • Every match must include match_details.club_id.
  • match_id is your own match ID.
  • If set_2 is provided for one team, it must also be provided for the other team.
  • If set_3 is provided for one team, it must also be provided for the other team, and set_2 must also be present for both teams.
  • Every submitted set must have a winner; tied set scores are rejected.
  • A two-set match must finish 2:0, meaning the same team wins both submitted sets.
  • A three-set match must split the first two sets 1:1, with set_3 as the deciding set.

Request Behavior:

  • Each player object includes first_name and source_player_id; last_name, wppr_id, and phone_number are optional
  • The submitted payload is a single match object, not a batch array
  • match_details includes date and club_id
  • set_1 is required for each team; set_2 and set_3 are optional
  • Optional sets are paired across teams. Do not send set_2 or set_3 for one team and omit it for the other team.
  • Do not send tied set scores or 0:0 placeholder scores.
  • If only two sets are submitted, one team must win both sets.
  • If three sets are submitted, the first two sets must be split and set_3 must decide the match.
  • Requests with optional sets on only one team are rejected with a 400 error

Example Requests: Single set:

curl -X POST https://developers.wecourts.com/api/v1/matches/verified \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_id": "13844",
"team1": {
"player1": { "wppr_id": "P12B41", "first_name": "Player", "source_player_id": "partner-player-1" },
"player2": { "wppr_id": "PCD275", "first_name": "Player", "source_player_id": "partner-player-2" },
"set_1": 4
},
"team2": {
"player1": { "wppr_id": "PB5821", "first_name": "Player", "source_player_id": "partner-player-3" },
"player2": { "wppr_id": "PF0501", "first_name": "Player", "source_player_id": "partner-player-4" },
"set_1": 6
},
"match_details": {
"date": "2026-03-23",
"club_id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7"
}
}'

Two sets:

curl -X POST https://developers.wecourts.com/api/v1/matches/verified \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_id": "13845",
"team1": {
"player1": { "wppr_id": "P12B41", "first_name": "Player", "source_player_id": "partner-player-10" },
"player2": { "wppr_id": "PCD275", "first_name": "Player", "source_player_id": "partner-player-11" },
"set_1": 6,
"set_2": 6
},
"team2": {
"player1": { "wppr_id": "PB5821", "first_name": "Player", "source_player_id": "partner-player-12" },
"player2": { "wppr_id": "PF0501", "first_name": "Player", "source_player_id": "partner-player-13" },
"set_1": 4,
"set_2": 2
},
"match_details": {
"date": "2026-03-24",
"club_id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7"
}
}'

Three sets:

curl -X POST https://developers.wecourts.com/api/v1/matches/verified \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_id": "13846",
"team1": {
"player1": { "wppr_id": "P12B41", "first_name": "Player", "source_player_id": "partner-player-21" },
"player2": { "wppr_id": "PCD275", "first_name": "Player", "source_player_id": "partner-player-22" },
"set_1": 4,
"set_2": 6,
"set_3": 6
},
"team2": {
"player1": { "wppr_id": "PB5821", "first_name": "Player", "source_player_id": "partner-player-23" },
"player2": { "wppr_id": "PF0501", "first_name": "Player", "source_player_id": "partner-player-24" },
"set_1": 6,
"set_2": 1,
"set_3": 4
},
"match_details": {
"date": "2026-03-25",
"club_id": "87b2ee5d-1fc6-42be-90bc-ab69d95566a7"
}
}'

Response Outcomes (200 OK): Created:

{
"source_match_id": "13844",
"status": "created",
"match_id": "MC123ABC"
}

Successful submissions return 200 OK with status: "created". Business-rule failures, duplicate source matches, identity conflicts, and invalid score progressions return 400 Bad Request.

Error Responses:

  • 400 if submitted scores are invalid, including 0:0, tied sets, a two-set 1:1 split without set_3, or an unnecessary set_3
  • 401 if the Authorization header is missing
  • 401 if the bearer token is invalid
  • 500 for unexpected internal proxy errors
  • 503 if the upstream WPPR service is unavailable
  • 504 if the upstream WPPR service times out
  • Other upstream client/server errors are passed through with the same status code using the standard error envelope. Documented examples include 400, 404, 422, 429, and 502.

Benefits:

  • Simplified submission flow for partners
  • Clear mapping between partner match IDs and WPPR processing
  • Cleaner payload structure focused on the required match data

[1.1.1] - 2026-03-25​

Added​

Contextual Player Search (Beta)​

Endpoint: GET /v1/players/search/contextual

A new endpoint that helps you find players by name with contextual information about whether they have played at a specific club or in tournaments organized by a specific company.

Use Case: Instead of searching for a player by only their name, if you provide an organizer company that organized a tournament for this player before, or a club where they played, this endpoint will help you find the right player you are looking forβ€”even if you pass only the player's first name or last name.

Query Parameters:

ParameterTypeRequiredDescription
namestringYesPlayer name to search (min 2 chars, supports fuzzy matching)
organizer_idUUIDConditionalOrganizer company ID
club_idUUIDConditionalClub ID

Note: At least one of organizer_id or club_id must be provided. When both are provided, only players who have played matches in BOTH contexts are returned.

Example Request:

GET /v1/players/search/contextual?name=john&organizer_id=550e8400-e29b-41d4-a716-446655440000

Example Response:

[
{
"id": "P30C1B",
"wppr_id": "P30C1B",
"wppr_profile_url": "https://wecourts.com/wppr/P30C1B",
"display_name": "John Doe",
"rating": 3.791,
"rating_category_name": "C+",
"rating_status": "AR",
"nationality": "AE",
"gender": "M",
"display_gender": "Male",
"display_nationality": "Emirati",
"display_nationality_flag": "πŸ‡¦πŸ‡ͺ",
"display_location": "Dubai, UAE",
"display_location_flag": "πŸ‡¦πŸ‡ͺ",
"display_gender_nationality": "Emirati β€’ M β€’ πŸ‡¦πŸ‡ͺ",
"image_url": "https://example.com/image.jpg",
"context": {
"matches_with_organizer": 15,
"matches_at_club": 8,
"total_context_matches": 23,
"confidence_score": 0.85
}
}
]

Context Fields:

FieldTypeDescription
matches_with_organizernumberCount of matches in tournaments by the specified organizer
matches_at_clubnumberCount of matches at the specified club
total_context_matchesnumberSum of organizer + club matches
confidence_scorenumberRelevance score from 0.0 to 1.0

Limits:

  • Results are limited to a maximum of 10 players
  • Results are sorted by confidence_score in descending order

[1.1.0] - 2025-11-27​

Breaking Changes​

Endpoint: GET /v1/players/search/by-name

The page and limit query parameters have been removed. The endpoint now returns all matching results without pagination.

Before:

GET /v1/players/search/by-name?name=john&page=1&limit=20

After:

GET /v1/players/search/by-name?name=john

Migration Steps:

  • Remove page and limit parameters from your search requests
  • Handle the full result set in your application
  • Implement client-side pagination if needed

🚨 Categories Response Schema Changed​

Endpoint: GET /v1/categories/list

The color field has been removed and replaced with a description field.

Old Response:

{
"name": "C+, B-",
"range": "3.750 - 4.749",
"category": "Expert",
"color": "bg-amber-500",
"min": 3.75,
"max": 4.749
}

New Response:

{
"name": "C+",
"range": "3.750 - 4.249",
"category": "Expert",
"description": "Controlled on court, basic tactics",
"min": 3.75,
"max": 4.249
}

Migration Steps:

  • Remove any code that depends on the color field
  • Implement your own color mapping if needed for UI
  • Use the new description field for enhanced user experience

Added​

Enhanced Error Response Documentation​

All endpoints now return standardized, well-documented error responses:

{
"error": true,
"message": "Descriptive error message",
"statusCode": 401
}

Documented HTTP Status Codes:

  • 400 - Bad Request (invalid query parameters)
  • 401 - Unauthorized (missing or invalid API key)
  • 404 - Not Found (player or resource not found)
  • 500 - Internal Server Error
  • 503 - Service Unavailable (upstream service issues)

Benefits:

  • More predictable error handling
  • Better debugging with consistent error messages
  • Improved client-side error handling logic

Phone Number Format Documentation​

Endpoint: GET /v1/players/search/by-phone/{phonenumber}

Enhanced documentation for supported phone number formats:

Supported Formats:

  • 971501234567 (standard)
  • +971501234567 (with plus prefix)
  • 00971501234567 (with 00 prefix)
  • 971-50-123-4567 (with dashes)
  • 971 50 123 4567 (with spaces)

Benefits:

  • Clearer documentation of accepted formats
  • Reduces integration errors
  • Better developer experience

Comprehensive Property Descriptions​

All response properties now include detailed descriptions in the OpenAPI specification:

Player Response Properties:

  • id - "Player WPPR profile ID"
  • wppr_id - "WPPR profile identifier"
  • wppr_profile_url - "URL to the player profile on WeCourts"
  • display_name - "Player display name"
  • rating - "Current WPPR rating"
  • rating_category_name - "Rating category name"
  • rating_status - "Rating status (e.g., AR for Active Rating)"
  • nationality - "Nationality ISO2 country code"
  • gender - "Gender code" (enum: ["M", "F"])
  • And many more...

Benefits:

  • Self-documenting API responses
  • Clearer field purposes and formats
  • Better TypeScript/type generation support

Schema Requirements​

All response schemas now explicitly define required fields using the required array.

Example:

{
"required": ["id", "wppr_id", "wppr_profile_url", "display_name", "rating_status"]
}

Benefits:

  • Know which fields are always present
  • Better TypeScript/type generation
  • More reliable client-side code

Changed​

Player Rating Endpoint Description​

Endpoint: GET /v1/players/{wppr_id}/rating

  • Old description: "Retrieves the current rating and ranking information for a player from their WPPR profile."
  • New description: "Retrieves the current rating and rating status and rating category for a player from their WPPR profile."

This clarifies that the endpoint returns rating, status, and category information (not ranking).


Match Response Documentation​

Endpoint: GET /v1/players/{wppr_id}/matches

All nested match properties now have detailed descriptions:

Match Properties:

  • match_id - "Match ID"
  • date - "Match date in ISO format"
  • display_date - "Human-readable match date"

Team Properties:

  • team_1 / team_2 - "First team" / "Second team"
  • won - "Whether this team won the match"
  • set_1 / set_2 / set_3 - Score information with nullable indicators

Benefits:

  • Better understanding of complex match data structure
  • Easier to build match display UI
  • Clear indication of nullable fields

[1.0.0] - 2025-11-11​

Added​

Players API​

  • GET /v1/players/:wppr_id - Get player information
  • GET /v1/players/:wppr_id/rating - Get player rating from WPPR profile
  • GET /v1/players/:wppr_id/matches - Get player match history
  • GET /v1/players/:wppr_id/stats - Get player statistics

Technical Details​

  • Base URL: https://developers.wecourts.com/api
  • OpenAPI: 3.0

Version History​

VersionRelease DateStatusNotes
1.3.02026-04-13βœ… CurrentVerified match source-based identity and contract update
1.2.02026-03-26StableCreate WPPR profile endpoint, rating scaling
1.1.12026-03-25StableContextual player search endpoint
1.1.02025-11-27StableEnhanced docs, breaking changes
1.0.02025-11-11DeprecatedInitial release

Support​

If you have questions or encounter issues: