Skip to main content

Changelog

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

[1.3.2] - 2026-07-13

Fixed

Clear rejection when a phone_number already belongs to another player

Endpoint: POST /v1/matches/verified

Submitting a player with a phone_number that already belongs to a different WPPR player could return an unclear 409 with a generic message ("An error occurred while processing your request"). It now returns an actionable 400 that names the blocking player so you can resolve it directly.

Before:

{
"error": true,
"message": "An error occurred while processing your request",
"statusCode": 409
}

After:

{
"error": true,
"message": "The submitted phone_number (447700900123) is already linked to PTEST01 (Alex Example). Send wppr_id PTEST01 for this player if it is the same person, or omit phone_number to create a separate player.",
"statusCode": 400
}

How to resolve: if it's the same player, send that player's wppr_id; if it's a different player, omit or change phone_number.

Documentation

How players are matched, documented in full

The verified match docs now spell out the exact player-resolution order and the conditions behind it, so partners can predict which profile a submission resolves to and avoid duplicate-profile conflicts.

What is now documented:

  • Resolution order per player: wppr_id (authoritative) → previously-recorded source_player_idphone_number (fallback) → create new
  • A source_player_id only auto-links after its first successful submission records the mapping; a brand-new source_player_id does not resolve anyone on its own
  • The first time you submit a player who already exists in WPPR, include their wppr_id to establish the link; afterwards the source_player_id alone is enough
  • phone_number is unique per player; a new actionable 400 for phone-number conflicts is documented with its message format and resolution steps

Docs updated: Matches reference (new "How players are matched" section + phone-number conflict error), and the OpenAPI spec (endpoint description, phone_number field, and a new error example).

No request or response schema changes. No migration required.


[1.3.1] - 2026-06-25

Improved

Platform Reliability & Performance

We made infrastructure improvements to strengthen the stability and performance of the API.

  • Improved overall service stability and uptime
  • Hardened the platform infrastructure for more consistent response times
  • General reliability and performance enhancements

No changes to API endpoints, request formats, or response schemas. No action is required from partners.


[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/player/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/player/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.12026-06-25✅ CurrentPlatform reliability and performance improvements
1.3.02026-04-13StableVerified 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: