Quick Start
From zero to your first API call in 5 minutes. You need a client_id and a private key (created in the Admin UI).
1. Get Credentials
Register an API client in Admin. Download the private key PEM file.
2. Sign Assertion
Create a JWT signed with your private key (ES256).
3. Get Token
POST to /auth/token to exchange for an access token.
4. Call API
Use Authorization: Bearer <token> on all requests.
Python
# pip install authlib requests
from authlib.jose import jwt as jose_jwt
from datetime import datetime, timedelta, UTC
import uuid, requests
# Load your private key (received when client was created in Admin)
with open("client-private-key.pem", "rb") as f:
private_key = f.read()
client_id = "acme-integration"
token_endpoint = "http://api.petanque.life/auth/token"
# Sign a client assertion
now = datetime.now(UTC)
assertion = jose_jwt.encode(
header={"alg": "ES256", "kid": "2026-04-primary"},
payload={
"iss": client_id,
"sub": client_id,
"aud": token_endpoint,
"jti": str(uuid.uuid4()),
"iat": int(now.timestamp()),
"exp": int((now + timedelta(minutes=2)).timestamp()),
},
key=private_key,
).decode()
# Request an access token (scope = capability names)
resp = requests.post(token_endpoint, data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": "bookings:read",
})
resp.raise_for_status()
access_token = resp.json()["access_token"]
# Call the API
bookings = requests.get(
"http://api.petanque.life/bookings",
headers={"Authorization": f"Bearer {access_token}"},
).json()
print(f"Found {bookings['total']} bookings")C#
// NuGet: Microsoft.IdentityModel.Tokens, System.IdentityModel.Tokens.Jwt
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
var clientId = "acme-integration";
var tokenEndpoint = "http://api.petanque.life/auth/token";
// Load private key
var ecdsa = ECDsa.Create();
ecdsa.ImportFromPem(File.ReadAllText("client-private-key.pem"));
// Sign client assertion
var handler = new JwtSecurityTokenHandler();
var assertion = handler.CreateEncodedJwt(new SecurityTokenDescriptor {
Issuer = clientId,
Subject = new ClaimsIdentity(new[] {
new Claim("sub", clientId),
new Claim("jti", Guid.NewGuid().ToString()),
}),
Audience = tokenEndpoint,
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(2),
SigningCredentials = new SigningCredentials(
new ECDsaSecurityKey(ecdsa) { KeyId = "2026-04-primary" },
SecurityAlgorithms.EcdsaSha256
),
});
// Request access token
using var http = new HttpClient();
var tokenResp = await http.PostAsync(tokenEndpoint, new FormUrlEncodedContent(new[] {
KeyValuePair.Create("grant_type", "client_credentials"),
KeyValuePair.Create("client_id", clientId),
KeyValuePair.Create("client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
KeyValuePair.Create("client_assertion", assertion),
KeyValuePair.Create("scope", "bookings:read"),
}));
tokenResp.EnsureSuccessStatusCode();
var tokenData = await tokenResp.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = tokenData.GetProperty("access_token").GetString()!;
// Call the API
http.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var bookings = await http.GetFromJsonAsync<JsonElement>($"http://api.petanque.life/bookings");
Console.WriteLine($"Found {bookings.GetProperty("total")} bookings");Node.js
// npm install jose
import { importPKCS8, SignJWT } from 'jose'
import { readFile } from 'fs/promises'
const clientId = 'acme-integration'
const tokenEndpoint = 'http://api.petanque.life/auth/token'
// Load private key
const privateKey = await importPKCS8(
await readFile('client-private-key.pem', 'utf8'),
'ES256'
)
// Sign client assertion
const assertion = await new SignJWT({
sub: clientId,
jti: crypto.randomUUID(),
})
.setProtectedHeader({ alg: 'ES256', kid: '2026-04-primary' })
.setIssuer(clientId)
.setAudience(tokenEndpoint)
.setIssuedAt()
.setExpirationTime('2m')
.sign(privateKey)
// Request access token
const tokenResp = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: clientId,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: assertion,
scope: 'bookings:read',
}),
})
const { access_token } = await tokenResp.json()
// Call the API
const bookings = await fetch('http://api.petanque.life/bookings', {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json())
console.log(`Found ${bookings.total} bookings`)cURL
#!/bin/bash
# Complete cURL workflow — useful for debugging, not recommended for production.
# Requires: openssl, jq, curl
CLIENT_ID="acme-integration"
KID="2026-04-primary"
TOKEN_ENDPOINT="http://api.petanque.life/auth/token"
PRIVATE_KEY="client-private-key.pem"
# --- Build JWT header and payload ---
HEADER=$(echo -n '{"alg":"ES256","kid":"'$KID'","typ":"JWT"}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
NOW=$(date +%s)
EXP=$((NOW + 120))
JTI=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen)
PAYLOAD=$(echo -n '{"iss":"'$CLIENT_ID'","sub":"'$CLIENT_ID'","aud":"'$TOKEN_ENDPOINT'","jti":"'$JTI'","iat":'$NOW',"exp":'$EXP'}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
# --- Sign ---
SIGNATURE=$(echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -sign "$PRIVATE_KEY" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
ASSERTION="$HEADER.$PAYLOAD.$SIGNATURE"
# --- Request access token ---
TOKEN_RESPONSE=$(curl -s -X POST "$TOKEN_ENDPOINT" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=$ASSERTION" \
-d "scope=bookings:read")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
echo "Token type: $(echo "$TOKEN_RESPONSE" | jq -r '.token_type')"
echo "Expires in: $(echo "$TOKEN_RESPONSE" | jq -r '.expires_in')s"
# --- Call the API ---
curl -s "http://api.petanque.life/bookings" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq .Concepts
OAuth 2.0 Client Credentials
The API uses the OAuth 2.0 Client Credentials grant (RFC 6749 section 4.4) for machine-to-machine (M2M) authentication. There is no user interaction — your service authenticates directly.
private_key_jwt — Why Asymmetric?
Client authentication uses private_key_jwt (RFC 7523).
Instead of a shared secret (client_secret), the client signs
a short-lived JWT with its private key. The server verifies the signature
using the registered public key. Advantages:
- The private key never leaves the client.
- No shared secret to leak or rotate on both ends.
- Each key has a
kid— multiple keys can coexist during rotation. - The JWT includes
jti(unique ID) to prevent replay attacks.
Access Tokens & Bearer
POST /auth/token returns a JWT access token. Default lifetime
is 15 minutes (900 seconds). Include it in all requests:
Authorization: Bearer eyJhbGciOiJFUzUxMiIs...Scopes = Capabilities
scope=bookings:read in the token request, you are asking for
the bookings:read capability. The granted token will contain
only the intersection of requested scopes and the client's assigned capabilities.
Rotation & Security
Keys can be rotated without downtime. When you create a new key, the old
key gets an active_until date (default 30 days). Both keys
work during the overlap period. See the Key Rotation
section for step-by-step instructions.
Authentication
3.1 Register Client
Create an API client in the Admin UI under Settings → API Clients.
You will receive a client_id and can register a public key.
Alternatively, use POST /api-clients to create clients programmatically.
3.2 Generate Keypair
Generate an ES256 (P-256) keypair:
# Python (cryptography library)
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
private_key = ec.generate_private_key(ec.SECP256R1())
# Save private key (keep this secret!)
with open("client-private-key.pem", "wb") as f:
f.write(private_key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
))
# Save public key (register this in Admin)
with open("client-public-key.pem", "wb") as f:
f.write(private_key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.SubjectPublicKeyInfo,
))// C# — generate and save keypair
using System.Security.Cryptography;
var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
// Export private key (keep secret!)
File.WriteAllText("client-private-key.pem", ecdsa.ExportECPrivateKeyPem());
// Export public key (register in Admin)
File.WriteAllText("client-public-key.pem", ecdsa.ExportSubjectPublicKeyInfoPem());// Node.js — generate keypair
import { generateKeyPair, exportPKCS8, exportSPKI } from 'jose'
import { writeFile } from 'fs/promises'
const { privateKey, publicKey } = await generateKeyPair('ES256')
await writeFile('client-private-key.pem', await exportPKCS8(privateKey))
await writeFile('client-public-key.pem', await exportSPKI(publicKey))# OpenSSL
openssl ecparam -genkey -name prime256v1 -noout -out client-private-key.pem
openssl ec -in client-private-key.pem -pubout -out client-public-key.pem3.3 Sign Client Assertion
Create a JWT with these required claims:
| Claim | Value | Description |
|---|---|---|
iss | Your client_id | Issuer |
sub | Your client_id | Subject |
aud | Token endpoint URL | Audience — must match exactly |
jti | Unique UUID | Prevents replay — each assertion must be unique |
iat | Current Unix timestamp | Issued at |
exp | iat + max 5 min | Expiry — server rejects assertions older than 5 minutes |
Sign with ES256 (preferred), ES384, or ES512.
Set the kid header to match your registered key ID.
3.4 Request Access Token
resp = requests.post(token_endpoint, data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": "bookings:read bookings:create", # space-separated capabilities
})
resp.raise_for_status()
token_data = resp.json()
print(f"Token: {token_data['access_token'][:20]}...")
print(f"Type: {token_data['token_type']}") # "Bearer"
print(f"Expires in: {token_data['expires_in']}s") # 900
print(f"Scope: {token_data['scope']}") # "bookings:read bookings:create"
# Error handling
if resp.status_code != 200:
error = resp.json()
print(f"Error: {error['error']} — {error['error_description']}")var tokenResp = await http.PostAsync(tokenEndpoint, new FormUrlEncodedContent(new[] {
KeyValuePair.Create("grant_type", "client_credentials"),
KeyValuePair.Create("client_id", clientId),
KeyValuePair.Create("client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
KeyValuePair.Create("client_assertion", assertion),
KeyValuePair.Create("scope", "bookings:read bookings:create"),
}));
if (!tokenResp.IsSuccessStatusCode)
{
var error = await tokenResp.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"Error: {error.GetProperty("error")} — {error.GetProperty("error_description")}");
return;
}
var tokenData = await tokenResp.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = tokenData.GetProperty("access_token").GetString()!;
Console.WriteLine($"Expires in: {tokenData.GetProperty("expires_in")}s");const tokenResp = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: clientId,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: assertion,
scope: 'bookings:read bookings:create',
}),
})
if (!tokenResp.ok) {
const error = await tokenResp.json()
console.error(`Error: ${error.error} — ${error.error_description}`)
process.exit(1)
}
const { access_token, expires_in, scope } = await tokenResp.json()
console.log(`Expires in: ${expires_in}s, scope: ${scope}`)curl -X POST 'http://api.petanque.life/auth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d 'client_id=acme-integration' \
-d 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
-d 'client_assertion=eyJ...' \
-d 'scope=bookings:read bookings:create'
# Response:
# {
# "access_token": "eyJ...",
# "token_type": "Bearer",
# "expires_in": 900,
# "scope": "bookings:read bookings:create"
# }3.5 Call API with Bearer Token
Include the access token in all API requests:
headers = {"Authorization": f"Bearer {access_token}"}
# List bookings
bookings = requests.get(f"{base_url}/bookings", headers=headers).json()
# Create a booking
new_booking = requests.post(f"{base_url}/bookings/", headers=headers, json={
"product_id": "64a1b2c3d4e5f6789012abcd",
"start_time": "2026-04-01T08:00:00Z",
"end_time": "2026-04-01T17:00:00Z",
}).json()http.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
// List bookings
var bookings = await http.GetFromJsonAsync<JsonElement>($"{baseUrl}/bookings");
// Create a booking
var newBooking = await http.PostAsJsonAsync($"{baseUrl}/bookings/", new {
product_id = "64a1b2c3d4e5f6789012abcd",
start_time = "2026-04-01T08:00:00Z",
end_time = "2026-04-01T17:00:00Z",
});const headers = { Authorization: `Bearer ${access_token}` }
// List bookings
const bookings = await fetch(`${baseUrl}/bookings`, { headers }).then(r => r.json())
// Create a booking
const newBooking = await fetch(`${baseUrl}/bookings/`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({
product_id: '64a1b2c3d4e5f6789012abcd',
start_time: '2026-04-01T08:00:00Z',
end_time: '2026-04-01T17:00:00Z',
}),
}).then(r => r.json())curl 'http://api.petanque.life/bookings' \
-H 'Authorization: Bearer eyJ...'
curl -X POST 'http://api.petanque.life/bookings/' \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"product_id": "64a1...", "start_time": "2026-04-01T08:00:00Z", "end_time": "2026-04-01T17:00:00Z"}'3.6 Handle Token Expiry
Access tokens expire after expires_in seconds (default 900 = 15 minutes).
There is no refresh endpoint for M2M tokens — request a new one before
the current token expires. Recommended pattern:
import time
class TokenManager:
def __init__(self, client_id, private_key, token_endpoint):
self.client_id = client_id
self.private_key = private_key
self.token_endpoint = token_endpoint
self._token = None
self._expires_at = 0
def get_token(self, scope=""):
# Refresh 60 seconds before expiry
if self._token and time.time() < self._expires_at - 60:
return self._token
assertion = self._sign_assertion()
resp = requests.post(self.token_endpoint, data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_assertion_type":
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": scope,
})
resp.raise_for_status()
data = resp.json()
self._token = data["access_token"]
self._expires_at = time.time() + data["expires_in"]
return self._token
def _sign_assertion(self):
now = datetime.now(UTC)
return jose_jwt.encode(
header={"alg": "ES256", "kid": "2026-04-primary"},
payload={
"iss": self.client_id, "sub": self.client_id,
"aud": self.token_endpoint,
"jti": str(uuid.uuid4()),
"iat": int(now.timestamp()),
"exp": int((now + timedelta(minutes=2)).timestamp()),
},
key=self.private_key,
).decode()public class TokenManager
{
private readonly string _clientId;
private readonly ECDsa _key;
private readonly string _tokenEndpoint;
private string? _token;
private DateTimeOffset _expiresAt;
public TokenManager(string clientId, ECDsa key, string tokenEndpoint)
{
_clientId = clientId;
_key = key;
_tokenEndpoint = tokenEndpoint;
}
public async Task<string> GetTokenAsync(string scope = "")
{
if (_token != null && DateTimeOffset.UtcNow < _expiresAt.AddSeconds(-60))
return _token;
var assertion = SignAssertion();
using var http = new HttpClient();
var resp = await http.PostAsync(_tokenEndpoint, new FormUrlEncodedContent(new[] {
KeyValuePair.Create("grant_type", "client_credentials"),
KeyValuePair.Create("client_id", _clientId),
KeyValuePair.Create("client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
KeyValuePair.Create("client_assertion", assertion),
KeyValuePair.Create("scope", scope),
}));
resp.EnsureSuccessStatusCode();
var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
_token = data.GetProperty("access_token").GetString()!;
_expiresAt = DateTimeOffset.UtcNow.AddSeconds(data.GetProperty("expires_in").GetInt32());
return _token;
}
private string SignAssertion()
{
var handler = new JwtSecurityTokenHandler();
return handler.CreateEncodedJwt(new SecurityTokenDescriptor {
Issuer = _clientId,
Subject = new ClaimsIdentity(new[] {
new Claim("sub", _clientId),
new Claim("jti", Guid.NewGuid().ToString()),
}),
Audience = _tokenEndpoint,
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(2),
SigningCredentials = new SigningCredentials(
new ECDsaSecurityKey(_key) { KeyId = "2026-04-primary" },
SecurityAlgorithms.EcdsaSha256),
});
}
}class TokenManager {
#token = null
#expiresAt = 0
constructor(clientId, privateKey, tokenEndpoint) {
this.clientId = clientId
this.privateKey = privateKey
this.tokenEndpoint = tokenEndpoint
}
async getToken(scope = '') {
if (this.#token && Date.now() / 1000 < this.#expiresAt - 60)
return this.#token
const assertion = await new SignJWT({
sub: this.clientId,
jti: crypto.randomUUID(),
})
.setProtectedHeader({ alg: 'ES256', kid: '2026-04-primary' })
.setIssuer(this.clientId)
.setAudience(this.tokenEndpoint)
.setIssuedAt()
.setExpirationTime('2m')
.sign(this.privateKey)
const resp = await fetch(this.tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: this.clientId,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: assertion,
scope,
}),
})
const data = await resp.json()
this.#token = data.access_token
this.#expiresAt = Date.now() / 1000 + data.expires_in
return this.#token
}
}# cURL does not support automatic token refresh.
# Re-run the token request script before expiry.
# Check token expiry:
echo "$TOKEN_RESPONSE" | jq '.expires_in'3.7 OAuth Scope = Capability
scope parameter in /auth/token uses
capability names as scope values. They are identical strings.
For example, scope=bookings:read users:list requests the
bookings:read and users:list capabilities.
See the Capabilities Reference for the full list.
DPoP (Optional, Advanced)
Demonstrating Proof-of-Possession (RFC 9449) binds access tokens to a client-held keypair, preventing stolen tokens from being used by an attacker.
When to Use
Use DPoP when tokens traverse untrusted networks, when compliance requirements demand proof-of-possession, or when defense-in-depth is important for your integration. Default (Bearer) is sufficient for most use cases.
Flow Overview
Separate from the client auth key. Used only for DPoP proofs.
Include a
DPoP header with a proof JWT on POST /auth/token.
Response has token_type: "DPoP".
Authorization: DPoP <token> + DPoP: <proof> header.
Each proof is bound to the HTTP method, URL, and the access token hash.
Python Example
from authlib.jose import jwt as jose_jwt, JsonWebKey
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
import hashlib, base64, uuid, time
# 1. Generate DPoP keypair (separate from client auth key)
dpop_private = ec.generate_private_key(ec.SECP256R1())
dpop_jwk = JsonWebKey.import_key(dpop_private)
dpop_public_jwk = {
"kty": dpop_jwk.as_dict()["kty"],
"crv": dpop_jwk.as_dict()["crv"],
"x": dpop_jwk.as_dict()["x"],
"y": dpop_jwk.as_dict()["y"],
}
def create_dpop_proof(method, url, access_token=None):
payload = {
"jti": str(uuid.uuid4()),
"htm": method,
"htu": url,
"iat": int(time.time()),
}
if access_token:
# ath = base64url(SHA-256(access_token))
ath = base64.urlsafe_b64encode(
hashlib.sha256(access_token.encode()).digest()
).rstrip(b"=").decode()
payload["ath"] = ath
return jose_jwt.encode(
header={"alg": "ES256", "typ": "dpop+jwt", "jwk": dpop_public_jwk},
payload=payload,
key=dpop_private,
).decode()
# 2. Token request with DPoP
dpop_proof = create_dpop_proof("POST", token_endpoint)
resp = requests.post(token_endpoint, data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_assertion_type":
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": "bookings:read",
}, headers={"DPoP": dpop_proof})
access_token = resp.json()["access_token"]
# token_type will be "DPoP" instead of "Bearer"
# 3. API call with DPoP
api_url = f"{base_url}/bookings"
api_proof = create_dpop_proof("GET", api_url, access_token)
bookings = requests.get(api_url, headers={
"Authorization": f"DPoP {access_token}",
"DPoP": api_proof,
}).json()Making Requests
Complete examples for setting up an authenticated API client.
Python — Full Client Setup
import requests
from authlib.jose import jwt as jose_jwt
from datetime import datetime, timedelta, UTC
import uuid, time
class ApiClient:
"""M2M API client with automatic token management."""
def __init__(self, base_url: str, client_id: str, private_key: bytes,
kid: str, scope: str = ""):
self.base_url = base_url
self.client_id = client_id
self.private_key = private_key
self.kid = kid
self.scope = scope
self.token_endpoint = f"{base_url}/auth/token"
self._token = None
self._expires_at = 0
def _ensure_token(self):
if self._token and time.time() < self._expires_at - 60:
return
now = datetime.now(UTC)
assertion = jose_jwt.encode(
header={"alg": "ES256", "kid": self.kid},
payload={
"iss": self.client_id, "sub": self.client_id,
"aud": self.token_endpoint,
"jti": str(uuid.uuid4()),
"iat": int(now.timestamp()),
"exp": int((now + timedelta(minutes=2)).timestamp()),
},
key=self.private_key,
).decode()
resp = requests.post(self.token_endpoint, data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_assertion_type":
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": self.scope,
})
resp.raise_for_status()
data = resp.json()
self._token = data["access_token"]
self._expires_at = time.time() + data["expires_in"]
def _headers(self):
self._ensure_token()
return {
"Authorization": f"Bearer {self._token}",
"Content-Type": "application/json",
}
def list(self, resource, where=None, page=1, per_page=25, sort="-created_at"):
params = {"page": page, "per_page": per_page, "sort": sort}
if where:
import json
params["where"] = json.dumps(where)
resp = requests.get(f"{self.base_url}/{resource}/",
params=params, headers=self._headers())
resp.raise_for_status()
return resp.json()
def get(self, resource, item_id):
resp = requests.get(f"{self.base_url}/{resource}/{item_id}",
headers=self._headers())
resp.raise_for_status()
return resp.json(), resp.headers.get("ETag", "")
def create(self, resource, data):
resp = requests.post(f"{self.base_url}/{resource}/",
json=data, headers=self._headers())
resp.raise_for_status()
return resp.json(), resp.headers.get("ETag", "")
def update(self, resource, item_id, data, etag):
headers = {**self._headers(), "If-Match": etag}
resp = requests.patch(f"{self.base_url}/{resource}/{item_id}",
json=data, headers=headers)
resp.raise_for_status()
return resp.json(), resp.headers.get("ETag", "")
def delete(self, resource, item_id, etag):
headers = {**self._headers(), "If-Match": etag}
resp = requests.delete(f"{self.base_url}/{resource}/{item_id}",
headers=headers)
resp.raise_for_status()
# Usage
with open("client-private-key.pem", "rb") as f:
key = f.read()
api = ApiClient("http://api.petanque.life", "acme-integration", key, "2026-04-primary",
scope="bookings:read bookings:create")
# List active bookings
bookings = api.list("bookings", where={"status": "active"})
for b in bookings["items"]:
print(f"{b['_id']} — {b['start_time']}")
# Create a booking
booking, etag = api.create("bookings", {
"product_id": "64a1b2c3d4e5f6789012abcd",
"start_time": "2026-04-01T08:00:00Z",
"end_time": "2026-04-01T17:00:00Z",
})
print(f"Created: {booking['_id']}")C# — Full Client Setup
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
public class ApiClient : IDisposable
{
private readonly HttpClient _http = new();
private readonly string _baseUrl;
private readonly string _clientId;
private readonly ECDsa _key;
private readonly string _kid;
private readonly string _scope;
private readonly string _tokenEndpoint;
private string? _token;
private DateTimeOffset _expiresAt;
public ApiClient(string baseUrl, string clientId, string keyPath,
string kid, string scope = "")
{
_baseUrl = baseUrl;
_clientId = clientId;
_key = ECDsa.Create();
_key.ImportFromPem(File.ReadAllText(keyPath));
_kid = kid;
_scope = scope;
_tokenEndpoint = $"{baseUrl}/auth/token";
_http.Timeout = TimeSpan.FromSeconds(30);
}
private async Task EnsureTokenAsync()
{
if (_token != null && DateTimeOffset.UtcNow < _expiresAt.AddSeconds(-60))
return;
var handler = new JwtSecurityTokenHandler();
var assertion = handler.CreateEncodedJwt(new SecurityTokenDescriptor {
Issuer = _clientId,
Subject = new ClaimsIdentity(new[] {
new Claim("sub", _clientId),
new Claim("jti", Guid.NewGuid().ToString()),
}),
Audience = _tokenEndpoint,
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(2),
SigningCredentials = new SigningCredentials(
new ECDsaSecurityKey(_key) { KeyId = _kid },
SecurityAlgorithms.EcdsaSha256),
});
var resp = await _http.PostAsync(_tokenEndpoint, new FormUrlEncodedContent(new[] {
KeyValuePair.Create("grant_type", "client_credentials"),
KeyValuePair.Create("client_id", _clientId),
KeyValuePair.Create("client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
KeyValuePair.Create("client_assertion", assertion),
KeyValuePair.Create("scope", _scope),
}));
resp.EnsureSuccessStatusCode();
var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
_token = data.GetProperty("access_token").GetString()!;
_expiresAt = DateTimeOffset.UtcNow.AddSeconds(data.GetProperty("expires_in").GetInt32());
_http.DefaultRequestHeaders.Remove("Authorization");
_http.DefaultRequestHeaders.Add("Authorization", $"Bearer {_token}");
}
public async Task<JsonElement> ListAsync(string resource, string? where = null,
int page = 1, int perPage = 25, string sort = "-created_at")
{
await EnsureTokenAsync();
var query = $"?page={page}&per_page={perPage}&sort={sort}";
if (where != null)
query += $"&where={Uri.EscapeDataString(where)}";
var resp = await _http.GetAsync($"{_baseUrl}/{resource}/{query}");
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadFromJsonAsync<JsonElement>();
}
public async Task<(JsonElement Item, string ETag)> GetAsync(string resource, string id)
{
await EnsureTokenAsync();
var resp = await _http.GetAsync($"{_baseUrl}/{resource}/{id}");
resp.EnsureSuccessStatusCode();
var item = await resp.Content.ReadFromJsonAsync<JsonElement>();
return (item, resp.Headers.ETag?.Tag ?? "");
}
public async Task<(JsonElement Item, string ETag)> CreateAsync(string resource, object data)
{
await EnsureTokenAsync();
var resp = await _http.PostAsJsonAsync($"{_baseUrl}/{resource}/", data);
resp.EnsureSuccessStatusCode();
var item = await resp.Content.ReadFromJsonAsync<JsonElement>();
return (item, resp.Headers.ETag?.Tag ?? "");
}
public async Task<(JsonElement Item, string ETag)> UpdateAsync(
string resource, string id, object data, string etag)
{
await EnsureTokenAsync();
var request = new HttpRequestMessage(HttpMethod.Patch,
$"{_baseUrl}/{resource}/{id}")
{ Content = JsonContent.Create(data) };
request.Headers.Add("If-Match", etag);
var resp = await _http.SendAsync(request);
resp.EnsureSuccessStatusCode();
var item = await resp.Content.ReadFromJsonAsync<JsonElement>();
return (item, resp.Headers.ETag?.Tag ?? "");
}
public async Task DeleteAsync(string resource, string id, string etag)
{
await EnsureTokenAsync();
var request = new HttpRequestMessage(HttpMethod.Delete,
$"{_baseUrl}/{resource}/{id}");
request.Headers.Add("If-Match", etag);
var resp = await _http.SendAsync(request);
resp.EnsureSuccessStatusCode();
}
public void Dispose() => _http.Dispose();
}Filtering & Querying
All list endpoints support two filtering styles that can be combined.
1. JSON Where Clause
Pass a where query parameter with a JSON object.
# Simple equality
products = api.list("products", where={"status": "active"})
# Multiple conditions (AND)
products = api.list("products", where={
"status": "active",
"city": "New York"
})
# Comparison operators
charges = api.list("service-charges", where={"amount": {"$gt": 500}})
# Date ranges
orders = api.list("orders", where={
"start_time": {"$gte": "2026-04-01T00:00:00Z"},
"end_time": {"$lte": "2026-04-30T23:59:59Z"}
})
# OR queries
orders = api.list("orders", where={
"$or": [{"status": "active"}, {"status": "confirmed"}]
})
# Regex (case-insensitive)
products = api.list("products", where={
"name": {"$regex": "^Prem", "$options": "i"}
})// Simple equality
var products = await api.ListAsync("products",
where: "{\"status\":\"active\"}");
// Comparison operators
var charges = await api.ListAsync("service-charges",
where: "{\"amount\":{\"$gt\":500}}");
// OR queries
var active = await api.ListAsync("orders",
where: "{\"$or\":[{\"status\":\"active\"},{\"status\":\"confirmed\"}]}");// JSON where
const products = await fetch(
`${baseUrl}/products/?where=${encodeURIComponent(JSON.stringify({ status: 'active' }))}`,
{ headers }
).then(r => r.json())
// Comparison operators
const charges = await fetch(
`${baseUrl}/service-charges/?where=${encodeURIComponent(JSON.stringify({ amount: { $gt: 500 } }))}`,
{ headers }
).then(r => r.json())# Simple equality
curl -G 'http://api.petanque.life/products/' --data-urlencode 'where={"status":"active"}'
# Comparison operators
curl -G 'http://api.petanque.life/service-charges/' --data-urlencode 'where={"amount":{"$gt":500}}'
# OR queries
curl -G 'http://api.petanque.life/orders/' \
--data-urlencode 'where={"$or":[{"status":"active"},{"status":"confirmed"}]}'Allowed Operators
$gt, $gte | Greater than / greater than or equal |
$lt, $lte | Less than / less than or equal |
$ne | Not equal |
$in, $nin | In / not in array |
$exists | Field exists (true/false) |
$regex | Regular expression match |
$and, $or, $not | Logical operators |
$where, $expr, and $function
are blocked to prevent injection attacks.
2. Query Parameter Filters
# Equality
GET /products/?status=active&city=New York
# Operators via __suffix
GET /service-charges/?amount__gt=500
GET /orders/?status__in=active,confirmed
GET /products/?name__regex=^Prem
GET /subscriptions/?valid_until__exists=falseSorting
# Newest first (default)
orders = api.list("orders", sort="-created_at")
# Sort by name ascending
products = api.list("products", sort="name")
# Multiple sort fields
orders = api.list("orders", sort="-start_time,status")// Newest first
var orders = await api.ListAsync("orders", sort: "-created_at");
// Sort by name ascending
var products = await api.ListAsync("products", sort: "name");// Newest first
const orders = await fetch(`${baseUrl}/orders/?sort=-created_at`, { headers }).then(r => r.json())curl 'http://api.petanque.life/orders/?sort=-start_time,status' -H 'Authorization: Bearer eyJ...'Field Selection
# Only return specific fields (reduces payload size)
GET /products/?fields=name,status,city,total_itemsPagination
All list endpoints return paginated results. Default: 25 items, max 100.
# Page through all results
page = 1
all_items = []
while True:
result = api.list("orders", where={"status": "active"},
page=page, per_page=100)
all_items.extend(result["items"])
if page * 100 >= result["total"]:
break
page += 1
print(f"Fetched all {len(all_items)} orders")// Page through all results
var allItems = new List<JsonElement>();
var page = 1;
while (true)
{
var result = await api.ListAsync("orders",
where: "{\"status\":\"active\"}", page: page, perPage: 100);
// ... add to list
if (page * 100 >= result.GetProperty("total").GetInt32()) break;
page++;
}let page = 1
const allItems = []
while (true) {
const result = await fetch(
`${baseUrl}/orders/?where=${encodeURIComponent('{"status":"active"}')}` +
`&page=${page}&per_page=100`,
{ headers }
).then(r => r.json())
allItems.push(...result.items)
if (page * 100 >= result.total) break
page++
}curl 'http://api.petanque.life/orders/?page=2&per_page=50' -H 'Authorization: Bearer eyJ...'Response Format
{
"items": [...],
"total": 142,
"page": 2,
"per_page": 50
}Response Headers
X-Total-Count | Total matching items |
X-Page | Current page |
X-Per-Page | Items per page |
X-Total-Pages | Total pages |
Concurrency Control (ETag)
All update and delete operations require optimistic concurrency control. This prevents lost updates when multiple clients modify the same document.
ETag headerIf-Match: "the-etag"# Get-then-update pattern
product, etag = api.get("products", "64a1...")
# Update with ETag
updated, new_etag = api.update("products", "64a1...", {
"status": "maintenance"
}, etag)
# Handle conflicts
try:
api.update("products", "64a1...", {"status": "active"}, etag)
except requests.HTTPError as e:
if e.response.status_code == 412:
print("Conflict! Re-fetch and retry.")
product, etag = api.get("products", "64a1...")
elif e.response.status_code == 428:
print("Missing If-Match header!")// Get-then-update pattern
var (product, etag) = await api.GetAsync("products", "64a1...");
// Update with ETag
var (updated, newEtag) = await api.UpdateAsync("products", "64a1...",
new { status = "maintenance" }, etag);
// Handle conflicts
try
{
await api.UpdateAsync("products", "64a1...",
new { status = "active" }, etag);
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.PreconditionFailed)
{
Console.WriteLine("Conflict! Re-fetch and retry.");
(product, etag) = await api.GetAsync("products", "64a1...");
}// Get-then-update
const getResp = await fetch(`${baseUrl}/products/64a1...`, { headers })
const product = await getResp.json()
const etag = getResp.headers.get('etag')
// Update with ETag
const updateResp = await fetch(`${baseUrl}/products/64a1...`, {
method: 'PATCH',
headers: { ...headers, 'Content-Type': 'application/json', 'If-Match': etag },
body: JSON.stringify({ status: 'maintenance' }),
})
if (updateResp.status === 412) {
console.log('Conflict! Re-fetch and retry.')
}# 1. Get the resource and its ETag
curl -i 'http://api.petanque.life/products/64a1...' -H 'Authorization: Bearer eyJ...'
# Response header: ETag: "abc123"
# 2. Update with If-Match
curl -X PATCH 'http://api.petanque.life/products/64a1...' \
-H 'Authorization: Bearer eyJ...' \
-H 'If-Match: "abc123"' \
-H 'Content-Type: application/json' \
-d '{"status": "maintenance"}'CRUD Lifecycle
Complete example: managing resources from creation to deletion.
# === CREATE ===
product, etag = api.create("products", {
"name": "Premium Suite",
"address": "5th Avenue 12",
"city": "New York",
"zip_code": "10001",
"total_items": 45,
})
product_id = product["_id"]
print(f"Created: {product['name']} ({product_id})")
# === READ ===
product, etag = api.get("products", product_id)
print(f"Status: {product['status']}")
# === UPDATE (partial) ===
product, etag = api.update("products", product_id, {
"is_published": True,
}, etag)
# === LIST with filters ===
published = api.list("products", where={
"is_published": True,
"city": "New York",
})
print(f"{published['total']} published products in New York")
# === DELETE (will fail if children exist — cascade deny) ===
try:
api.delete("products", product_id, etag)
except requests.HTTPError as e:
if e.response.status_code == 409:
print("Cannot delete — has related items (cascade deny)")// === CREATE ===
var (product, etag) = await api.CreateAsync("products", new {
name = "Premium Suite",
address = "5th Avenue 12",
city = "New York",
zip_code = "10001",
total_items = 45,
});
var productId = product.GetProperty("_id").GetString()!;
// === READ ===
(product, etag) = await api.GetAsync("products", productId);
// === UPDATE ===
(product, etag) = await api.UpdateAsync("products", productId, new {
is_published = true,
}, etag);
// === DELETE ===
await api.DeleteAsync("products", productId, etag);// CREATE
const { _id: productId } = await fetch(`${baseUrl}/products/`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Premium Suite', city: 'New York' }),
}).then(r => r.json())
// DELETE
await fetch(`${baseUrl}/products/${productId}`, {
method: 'DELETE',
headers: { ...headers, 'If-Match': etag },
})# Create
curl -X POST 'http://api.petanque.life/products/' \
-H 'Authorization: Bearer eyJ...' \
-H 'Content-Type: application/json' \
-d '{"name": "Premium Suite", "city": "New York"}'
# Delete (requires ETag from GET)
curl -X DELETE 'http://api.petanque.life/products/64a1...' \
-H 'Authorization: Bearer eyJ...' \
-H 'If-Match: "abc123"'Cascade Operations
The API maintains data consistency automatically.
Cascade Update
When a referenced resource changes, related fields are updated automatically.
For example, renaming a product updates product_name
on all orders, inventory items, subscriptions, and service charges.
Cascade Delete Rules
| Rule | Behavior | Example |
|---|---|---|
deny |
Block deletion if children exist (409 Conflict) | Cannot delete product that has inventory items |
null |
Set reference to null on children | Deleting a manager nullifies manager_id |
delete |
Delete all children | Not currently used |
Capabilities Reference
requires()) and an OAuth 2.0 scope
value (for the scope parameter in /auth/token requests).
They are always identical strings.
| Capability / Scope | Action | Resource | Description |
|---|---|---|---|
federation:manage | custom | Manage federation settings and configuration | |
federation:view | custom | View federation information | |
federation:configure | custom | Configure federation rules, fees, and policies | |
federation:admin | custom | Full federation administration access | |
continuity:read | custom | Read continuity export status, manifest and run history | |
continuity:configure | custom | Update continuity export public encryption key + trigger test-destination dry-runs | |
district:manage | custom | Manage district settings and operations | |
district:view | custom | View district information | |
district:create | custom | Create new districts | |
district:delete | custom | Delete districts | |
club:manage | custom | Manage club settings and operations | |
club:view | custom | View club information | |
club:members | custom | Manage club member roster | |
club:create | custom | Create new clubs | |
club:delete | custom | Delete clubs | |
license:issue | custom | Issue new licenses to players | |
license:verify | custom | Verify license status | |
license:suspend | custom | Suspend active licenses | |
license:revoke | custom | Revoke licenses permanently | |
license:view | custom | View license details | |
license:renew | custom | Renew existing licenses | |
league:manage | custom | Manage league operations (status transitions, eligibility checks) | |
competition:create | custom | Create new competitions | |
competition:sanction | custom | Sanction and approve competitions | |
competition:manage | custom | Manage competition operations (draw, schedule) | |
competition:view | custom | View competition information and results | |
competition:delete | custom | Delete competitions | |
competition:register | custom | Register for competitions (entry, payment, validation) | |
competition:award | custom | Manage competition awards (POTM, tournament awards) | |
competition:publish_results | custom | Publish finalized competition results publicly | |
competition:manage_series | custom | Create, edit, and manage championship series | |
calendar:create | custom | Create calendar events | |
calendar:manage | custom | Manage calendar events (edit, cancel) | |
calendar:approve | custom | Approve or reject calendar events | |
calendar:view | custom | View calendar events | |
match:officiate | custom | Officiate matches as umpire | |
match:score | custom | Enter and edit match scores | |
match:view | custom | View match details and results | |
match:manage | custom | Full match management (assign courts, override) | |
match:scorekeeper | custom | Assign and manage official scorekeepers for matches | |
match:sign | custom | Sign completed match results as official or delegate | |
match:live_score | custom | Start and manage live scoring sessions | |
ranking:manage | custom | Manage ranking configurations and point rules | |
ranking:view | custom | View rankings and standings | |
ranking:calculate | custom | Trigger ranking recalculations | |
ranking:dispute | custom | Submit and manage ranking point disputes | |
ranking:resolve_dispute | custom | Resolve ranking disputes (accept/reject) | |
ranking:qualification_snapshot | custom | Create and manage qualification deadline snapshots | |
ranking:cross_tenant_elo | custom | Manage cross-tenant ELO configuration | |
elo:view | custom | View ELO ratings and leaderboards | |
elo:manage | custom | Manage ELO settings and K-factor configuration | |
elo:calculate | custom | Trigger ELO rating recalculations after matches | |
finance:manage | custom | Manage financial operations and budgets | |
finance:view | custom | View financial reports and transactions | |
finance:approve | custom | Approve financial transactions and budgets | |
finance:reconcile | custom | Import bank statements and perform bank reconciliation | |
discipline:manage | custom | Manage disciplinary cases and sanctions | |
discipline:view | custom | View disciplinary records | |
discipline:create | custom | Create new disciplinary cases | |
discipline:case:read | custom | Read discipline case-spine cases (within actor's org scope) | |
discipline:case:write | custom | Create/edit discipline cases (intake, transitions, escalation) | |
discipline:case:decide | custom | Confirm panel decisions and apply sanctions | |
discipline:case:appeal | custom | File appeals on behalf of accused parties | |
discipline:case:publish | custom | Publish or correct anonymised public protocols | |
discipline:case:lift_sanction | custom | Lift or modify active sanctions outside the appeal process | |
discipline:evidence:write | custom | Upload, supersede, withdraw, and redact evidence | |
discipline:evidence:verify | custom | Run evidence-chain integrity verification | |
discipline:catalog:write | custom | Manage tenant sanction catalog and offence vocabulary | |
discipline:precedent:read | custom | Search precedent records and recommended ranges | |
discipline:cross_tenant:publish | custom | Publish suspensions to the FIPJP cross-tenant registry | |
discipline:cross_tenant:read | custom | Read the FIPJP cross-tenant suspension registry | |
transfer:approve | custom | Approve player transfers | |
transfer:request | custom | Request player transfers | |
transfer:view | custom | View transfer status and history | |
player:manage | custom | Manage player profiles and registrations | |
player:view | custom | View player profiles | |
player:register | custom | Register new players | |
official:manage | custom | Manage official registrations and assignments | |
official:certify | custom | Certify and grade officials (umpire levels) | |
official:view | custom | View official profiles and certifications | |
coach:manage | custom | Manage coach registrations and assignments | |
coach:certify | custom | Certify and grade coaches | |
coach:view | custom | View coach profiles and certifications | |
officials.training.read | custom | View umpire training modules and exam content | |
officials.training.manage | custom | Create/edit umpire training modules and exams | |
officials.exams.take | custom | Participate in practice exams and certification attempts | |
officials.exams.review | custom | Manually review/grade scenario exam questions | |
officials.commission.manage | custom | Manage evaluation templates and read all evaluations | |
mentor.serve | custom | Accept mentor assignments and serve as mentor | |
mentor.thread.access | custom | Access mentor threads (computed dynamically per assignment) | |
finance.fx.manage | custom | Manage FX rates and convert currencies | |
finance.fx.read | custom | Read FX rates and conversions | |
coaching.content.drill.read | custom | View drill templates | |
coaching.content.drill.write | custom | Create or edit drill templates | |
coaching.content.drill.publish | custom | Mark a drill template as shareable cross-tenant | |
coaching.content.session.read | custom | View session plans | |
coaching.content.session.write | custom | Create or edit session plans + export PDF | |
coaching.content.tactical.read | custom | View tactical scenarios | |
coaching.content.tactical.write | custom | Create or edit tactical scenarios | |
coaching.content.mental.read | custom | View mental skills tracks | |
coaching.content.mental.write | custom | Create or edit mental skills tracks | |
coaching.content.track.read | custom | View learning tracks | |
coaching.content.track.write | custom | Create or edit learning tracks | |
coaching.school.read | custom | View PE curriculum packs and school activations | |
coaching.school.write | custom | Create PE curriculum packs and activate them on partnerships | |
coaching.umpire.read | custom | View umpire exam tracks, item bank and practice exams | |
coaching.umpire.write | custom | Create or edit umpire exam tracks, item bank and practice exams | |
coaching.mentor.read | custom | View mentor pairings and session logs | |
coaching.mentor.write | custom | Create or edit mentor pairings and session logs | |
coaching.mentor.match | custom | Run mentor-matching suggestions | |
cms:edit | custom | Edit CMS content and pages | |
cms:publish | custom | Publish CMS content | |
cms:view | custom | View unpublished CMS drafts | |
cms:edit:federation | custom | Edit federation-level CMS site content | |
cms:edit:club | custom | Edit club-level CMS site content only | |
cms:edit:region | custom | Edit region/district-level CMS site content | |
cms:approve | custom | Approve CMS content for publication (review → published) | |
cms:publish:immediate | custom | Publish CMS content immediately | |
cms:publish:schedule | custom | Schedule CMS content for future publication | |
cms:widget:manage | custom | Manage CMS dynamic data widget configurations | |
delegate:manage | custom | Manage delegate appointments, reports, and templates | |
delegate:view | custom | View delegate assignments, observations, and reports | |
safeguarding:manage | custom | Manage safeguarding policies and officers | |
safeguarding:report | custom | Submit safeguarding incident reports | |
safeguarding:view | custom | View safeguarding records and reports | |
safeguarding:training | custom | Manage safeguarding training requirements and records | |
medical_emergency:view | custom | View emergency contacts and medical info at events | |
medical_emergency:manage | custom | Manage medical emergency incidents and compliance checks | |
medical_emergency:report | custom | Report medical emergency incidents at events | |
integrity:view | custom | View integrity alerts, reports and investigations | |
integrity:manage | custom | Manage integrity investigations and equipment checks | |
integrity:report | custom | Submit suspicious activity reports | |
dispute:view | custom | View disputes and resolution history | |
dispute:manage | custom | Manage disputes, escalation and mediation | |
audit:view | custom | View audit logs and system activity | |
election:manage | custom | Manage elections (create, configure, cancel) | |
election:view | custom | View elections and results | |
election:nominate | custom | Register as candidate or nominate others | |
election:vote | custom | Cast votes in elections | |
election:count | custom | Count votes and publish results | |
election:proxy | custom | Manage proxy voting authorizations | |
selection:manage | custom | Manage national team selection and squads | |
selection:view | custom | View national team selections | |
membership:manage | custom | Manage club memberships and registrations | |
membership:view | custom | View membership records | |
equipment:manage | custom | Manage personal equipment inventory | |
equipment:view | custom | View equipment information | |
equipment:create | custom | Register new equipment items | |
equipment:delete | custom | Delete equipment items | |
casual_game:create | custom | Create casual games | |
casual_game:play | custom | Play and score casual games | |
casual_game:view | custom | View casual game history and results | |
casual_game:invite | custom | Invite players to casual games | |
casual_game:availability | custom | Set looking-for-match availability | |
casual_game:club_night | custom | Create and manage club night events | |
record:view | custom | View records and record history | |
record:manage | custom | Manage and verify records | |
milestone:view | custom | View milestones and milestone definitions | |
milestone:manage | custom | Manage milestone definitions and detect milestones | |
partnership:view | custom | View partnerships and partnership statistics | |
partnership:manage | custom | Create, update, dissolve, and record results for partnerships | |
gamification:manage | custom | Manage gamification settings, badges, and challenges | |
gamification:view | custom | View badges, achievements, XP, and leaderboards | |
gamification:award | custom | Award badges and XP to players | |
gamification:predict | custom | Make predictions on matches and tournaments | |
gamification:fantasy | custom | Create and manage fantasy teams | |
gamification:challenge | custom | Join and participate in challenges | |
community:react | custom | Add reactions/kudos to activity feed entries | |
community:share | custom | Share achievements to social media | |
community:year_in_review | custom | Generate and view year-in-review summaries | |
gdpr:export | custom | Export personal data (GDPR Art. 20) | |
gdpr:delete | custom | Request data deletion (GDPR Art. 17) | |
gdpr:view | custom | View GDPR requests and deletion status | |
gdpr:manage | custom | Manage GDPR requests and data retention policies | |
consent:manage | custom | Manage consent records and parental consent | |
consent:view | custom | View consent records | |
gdpr:dpo:read | custom | Read DPO console — consent scopes, access requests, cross-tenant overview | |
gdpr:dpo:write | custom | Publish consent-scope versions and file/transition DPO access requests | |
marketplace:manage | custom | Manage marketplace listings, retailers, and boule bars | |
marketplace:view | custom | View marketplace listings and retailer catalog | |
marketplace:create | custom | Create marketplace listings | |
marketplace:moderate | custom | Moderate listings, verify retailers and boule bars | |
sponsor:manage | custom | Manage sponsors, contracts, and ad placements | |
sponsor:view | custom | View sponsor information and exposure reports | |
sponsor:analytics:read | custom | Read pre-aggregated sponsor visibility analytics rollups | |
rule:manage | custom | Manage rule documents, versions, and interpretations | |
rule:view | custom | View rule documents and interpretations | |
rule:propose | custom | Propose rule changes for review | |
rule:approve | custom | Approve or reject rule change proposals | |
rule:translate | custom | Manage rule translations | |
webhook:manage | custom | Manage webhook subscriptions and view delivery logs | |
webhook:view | custom | View webhook subscriptions and delivery status | |
api_token:manage | custom | Create, revoke, and manage M2M API tokens | |
api_token:view | custom | View M2M API token metadata | |
statistics:view | custom | View statistics and analytics dashboards | |
statistics:manage | custom | Manage dashboards, scheduled reports, and export configs | |
statistics:export | custom | Export reports (PDF, CSV, Excel) | |
statistics:federation_reports | custom | View and generate federation-level reports | |
statistics:global_reports | custom | View and generate FIPJP global analytics | |
profile:read_dob | custom | Read exact date of birth on user profiles | |
profile:read_license_number | custom | Read player license numbers | |
profile:read_contact | custom | Read contact details on administrator profiles | |
profile:read_sensitive | custom | Read all sensitive profile fields | |
data_visibility:manage | custom | Manage public field configuration and data visibility rules | |
data_visibility:view | custom | View public field configuration | |
access:debug | custom | Inspect effective capabilities and role resolution traces | |
role_request:create | custom | Request a role assignment | |
role_request:view | custom | View role requests | |
role_request:approve | custom | Approve or deny role requests | |
scoreboard:manage | custom | Manage scoreboard devices (create, update, retire) | |
scoreboard:view | custom | View scoreboard details and telemetry | |
scoreboard:custody | custom | Transfer scoreboard custody between org nodes | |
chain.analytics.read | custom | View chain-venue analytics dashboards and drill-downs | |
chain.analytics.export | custom | Export chain-venue analytics reports (CSV/PDF/XLSX) | |
analytics.scout.read | custom | View scout reports (team or federation visibility) | |
analytics.scout.write | custom | Create, edit and publish scout reports | |
analytics.federation.read | custom | Read federation→club engagement metrics and conversion attribution | |
analytics.grants.read | custom | Read grant workflows and impact reports | |
analytics.grants.write | custom | Create grants, run state transitions and build impact reports | |
analytics.cohort.read | custom | Run and view cohort-comparison statistical queries | |
para.classification.read | custom | Read para-pétanque classifications and panel rosters | |
para.classification.write | custom | Create provisional classifications and update consent flags | |
para.classification.decide | custom | Record panel decisions and revoke para-pétanque classifications | |
events.marshal.read | custom | View court marshal live ops board and acknowledge threshold alerts (event-scoped) | |
federation.engagement.read | custom | Read federation→club engagement metrics, silent-club flagging and per-club drill-downs | |
government.grants.read | custom | Read ministry/government grant applications and impact reports | |
government.grants.write | custom | Create, edit and progress ministry/government grant applications and reports | |
self_registration.read_config | custom | Read self-registration configuration (admin) | |
partners:list | list | partners | List partners |
partners:read | read | partners | Read a single partners item |
partners:create | create | partners | Create a new partners item |
partners:update | update | partners | Update a partners item |
partners:delete | delete | partners | Delete a partners item |
tenants:list | list | tenants | List tenants |
tenants:read | read | tenants | Read a single tenants item |
tenants:create | create | tenants | Create a new tenants item |
tenants:update | update | tenants | Update a tenants item |
tenants:delete | delete | tenants | Delete a tenants item |
users:list | list | users | List users |
users:read | read | users | Read a single users item |
users:create | create | users | Create a new users item |
users:update | update | users | Update a users item |
users:delete | delete | users | Delete a users item |
roles:list | list | roles | List roles |
roles:read | read | roles | Read a single roles item |
roles:create | create | roles | Create a new roles item |
roles:update | update | roles | Update a roles item |
roles:delete | delete | roles | Delete a roles item |
role-assignments:list | list | role-assignments | List role-assignments |
role-assignments:read | read | role-assignments | Read a single role-assignments item |
role-assignments:create | create | role-assignments | Create a new role-assignments item |
role-assignments:update | update | role-assignments | Update a role-assignments item |
role-assignments:delete | delete | role-assignments | Delete a role-assignments item |
imports/templates:list | list | imports/templates | List imports/templates |
imports/templates:read | read | imports/templates | Read a single imports/templates item |
imports/templates:create | create | imports/templates | Create a new imports/templates item |
imports/templates:update | update | imports/templates | Update a imports/templates item |
imports/templates:delete | delete | imports/templates | Delete a imports/templates item |
imports/sources:list | list | imports/sources | List imports/sources |
imports/sources:read | read | imports/sources | Read a single imports/sources item |
imports/sources:create | create | imports/sources | Create a new imports/sources item |
imports/sources:update | update | imports/sources | Update a imports/sources item |
imports/sources:delete | delete | imports/sources | Delete a imports/sources item |
rejected-records:list | list | rejected-records | List rejected-records |
rejected-records:read | read | rejected-records | Read a single rejected-records item |
rejected-records:create | create | rejected-records | Create a new rejected-records item |
rejected-records:update | update | rejected-records | Update a rejected-records item |
rejected-records:delete | delete | rejected-records | Delete a rejected-records item |
alert-channels:list | list | alert-channels | List alert-channels |
alert-channels:read | read | alert-channels | Read a single alert-channels item |
alert-channels:create | create | alert-channels | Create a new alert-channels item |
alert-channels:update | update | alert-channels | Update a alert-channels item |
alert-channels:delete | delete | alert-channels | Delete a alert-channels item |
alert-routing-rules:list | list | alert-routing-rules | List alert-routing-rules |
alert-routing-rules:read | read | alert-routing-rules | Read a single alert-routing-rules item |
alert-routing-rules:create | create | alert-routing-rules | Create a new alert-routing-rules item |
alert-routing-rules:update | update | alert-routing-rules | Update a alert-routing-rules item |
alert-routing-rules:delete | delete | alert-routing-rules | Delete a alert-routing-rules item |
tenant-configs:list | list | tenant-configs | List tenant-configs |
tenant-configs:read | read | tenant-configs | Read a single tenant-configs item |
tenant-configs:create | create | tenant-configs | Create a new tenant-configs item |
tenant-configs:update | update | tenant-configs | Update a tenant-configs item |
tenant-configs:delete | delete | tenant-configs | Delete a tenant-configs item |
seasons:list | list | seasons | List seasons |
seasons:read | read | seasons | Read a single seasons item |
seasons:create | create | seasons | Create a new seasons item |
seasons:update | update | seasons | Update a seasons item |
seasons:delete | delete | seasons | Delete a seasons item |
i18n/bundles:list | list | i18n/bundles | List i18n/bundles |
i18n/bundles:read | read | i18n/bundles | Read a single i18n/bundles item |
i18n/bundles:create | create | i18n/bundles | Create a new i18n/bundles item |
i18n/bundles:update | update | i18n/bundles | Update a i18n/bundles item |
i18n/bundles:delete | delete | i18n/bundles | Delete a i18n/bundles item |
self.profile.access | custom | Self-service: read and manage the caller's own profile | |
self.auth.manage | custom | Self-service: manage the caller's own auth, 2FA, WebAuthn, sessions | |
self.feedback.submit | custom | Self-service: submit feedback from the signed-in user | |
sys.console.access | custom | Access the cross-tenant system console | |
admin.tenant.access | custom | Access the tenant administration surface | |
admin.agreements.manage | custom | Manage tenant agreements and feature contracts | |
admin.partners.manage | custom | Manage platform partners and integrations | |
admin.tenants.manage | custom | Manage tenants (create, archive, configure sub-tenants) | |
admin.roles.manage | custom | Manage roles, capabilities, and role assignments | |
admin.developer_api.manage | custom | Manage developer API tokens, M2M clients and quotas | |
admin.notifications.manage | custom | Manage tenant notification templates and scheduling | |
admin.templates.manage | custom | Manage tenant template libraries (clone, preview, version, rollback) | |
admin.audit.view | custom | Read and export tenant audit logs | |
admin.imports.manage | custom | Manage file imports, migrations, and rejected-record review | |
admin.jobs.manage | custom | Manage background jobs and schedules | |
admin.claims.manage | custom | Manage insurance claims, escalations and payment plans | |
admin.collections.manage | custom | Manage debt collection workflows and assignments | |
admin.cost_types.manage | custom | Manage chart-of-accounts cost types | |
admin.holiday_calendars.manage | custom | Manage tenant holiday calendars | |
admin.webhooks.manage | custom | Manage webhook subscriptions, replays and dead-letter queue | |
privacy.gdpr.manage | custom | Act on behalf of data subjects (exports, deletions, consents) | |
tenant-config.manage | custom | Edit tenant configuration (branding, currencies, VAT, policies) | |
finance.reconciliation.view | custom | Read cross-tenant client-fund reconciliation reports | |
finance.settlements.manage | custom | Manage cross-tenant settlement batches and payouts | |
finance.revenue.manage | custom | Manage revenue-split rules and calculations | |
finance.accounts.manage | custom | Manage payment/account configuration across tenants | |
domain.users.access | custom | Catch-all access to 'users' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.photo_galleries.access | custom | Catch-all access to 'photo-galleries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.photographer_accreditations.access | custom | Catch-all access to 'photographer-accreditations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.photo_consents.access | custom | Catch-all access to 'photo-consents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.video_highlights.access | custom | Catch-all access to 'video-highlights' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.media_items.access | custom | Catch-all access to 'media-items' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.press_kits.access | custom | Catch-all access to 'press-kits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_events.access | custom | Catch-all access to 'calendar-events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_subscriptions.access | custom | Catch-all access to 'calendar-subscriptions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_notification_preferences.access | custom | Catch-all access to 'calendar-notification-preferences' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_reminders.access | custom | Catch-all access to 'calendar-reminders' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club.access | custom | Catch-all access to 'club' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.affiliate.access | custom | Catch-all access to 'affiliate' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seasons.access | custom | Catch-all access to 'seasons' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_types.access | custom | Catch-all access to 'license-types' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_applications.access | custom | Catch-all access to 'license-applications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_fee_configs.access | custom | Catch-all access to 'license-fee-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_fee_overrides.access | custom | Catch-all access to 'license-fee-overrides' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_fees.access | custom | Catch-all access to 'license-fees' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.licenses.access | custom | Catch-all access to 'licenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_audit.access | custom | Catch-all access to 'license-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.medical_certificates.access | custom | Catch-all access to 'medical-certificates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.insurance.access | custom | Catch-all access to 'insurance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.international_licenses.access | custom | Catch-all access to 'international-licenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.foreign_licenses.access | custom | Catch-all access to 'foreign-licenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.unauthorized_player_violations.access | custom | Catch-all access to 'unauthorized-player-violations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.districts.access | custom | Catch-all access to 'districts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.clubs.access | custom | Catch-all access to 'clubs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.players.access | custom | Catch-all access to 'players' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.org_nodes.access | custom | Catch-all access to 'org-nodes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federations.access | custom | Catch-all access to 'federations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federation_onboarding.access | custom | Catch-all access to 'federation-onboarding' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_profiles.access | custom | Catch-all access to 'player-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.official_profiles.access | custom | Catch-all access to 'official-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_profiles.access | custom | Catch-all access to 'coach-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.administrator_profiles.access | custom | Catch-all access to 'administrator-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.hierarchy_access.access | custom | Catch-all access to 'hierarchy-access' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.equipment.access | custom | Catch-all access to 'equipment' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.equipment_wishlist.access | custom | Catch-all access to 'equipment-wishlist' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.pro_equipment_profiles.access | custom | Catch-all access to 'pro-equipment-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.equipment_catalog.access | custom | Catch-all access to 'equipment-catalog' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.homologations.access | custom | Catch-all access to 'homologations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.product_reviews.access | custom | Catch-all access to 'product-reviews' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accessory_catalog.access | custom | Catch-all access to 'accessory-catalog' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.apparel_catalog.access | custom | Catch-all access to 'apparel-catalog' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.product_announcements.access | custom | Catch-all access to 'product-announcements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cms.access | custom | Catch-all access to 'cms' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tenant.access | custom | Catch-all access to 'tenant' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.casual_games.access | custom | Catch-all access to 'casual-games' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.game_invites.access | custom | Catch-all access to 'game-invites' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_availability.access | custom | Catch-all access to 'player-availability' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_nights.access | custom | Catch-all access to 'club-nights' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.badge_definitions.access | custom | Catch-all access to 'badge-definitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_badges.access | custom | Catch-all access to 'player-badges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_xp.access | custom | Catch-all access to 'player-xp' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.challenges.access | custom | Catch-all access to 'challenges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_challenges.access | custom | Catch-all access to 'player-challenges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.predictions.access | custom | Catch-all access to 'predictions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fantasy_leagues.access | custom | Catch-all access to 'fantasy-leagues' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fantasy_teams.access | custom | Catch-all access to 'fantasy-teams' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.leaderboards.access | custom | Catch-all access to 'leaderboards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.milestones.access | custom | Catch-all access to 'milestones' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_challenges.access | custom | Catch-all access to 'match-challenges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.streaks.access | custom | Catch-all access to 'streaks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.community_challenge_templates.access | custom | Catch-all access to 'community-challenge-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_challenges.access | custom | Catch-all access to 'club-challenges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seasonal_quests.access | custom | Catch-all access to 'seasonal-quests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_quests.access | custom | Catch-all access to 'player-quests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.xp_source_configs.access | custom | Catch-all access to 'xp-source-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.activity_xp.access | custom | Catch-all access to 'activity-xp' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.personal_bests.access | custom | Catch-all access to 'personal-bests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.live_predictions.access | custom | Catch-all access to 'live-predictions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.pickem_brackets.access | custom | Catch-all access to 'pickem-brackets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.pickem_entries.access | custom | Catch-all access to 'pickem-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.potm_polls.access | custom | Catch-all access to 'potm-polls' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.head_to_head.access | custom | Catch-all access to 'head-to-head' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.form_guides.access | custom | Catch-all access to 'form-guides' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.partnerships.access | custom | Catch-all access to 'partnerships' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.partner_search.access | custom | Catch-all access to 'partner-search' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.records.access | custom | Catch-all access to 'records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_milestones.access | custom | Catch-all access to 'player-milestones' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.milestone_definitions.access | custom | Catch-all access to 'milestone-definitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.record_alerts.access | custom | Catch-all access to 'record-alerts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.first_evers.access | custom | Catch-all access to 'first-evers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_record_books.access | custom | Catch-all access to 'competition-record-books' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.record_walls.access | custom | Catch-all access to 'record-walls' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.smart_recommendations.access | custom | Catch-all access to 'smart-recommendations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disciplines.access | custom | Catch-all access to 'disciplines' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_formats.access | custom | Catch-all access to 'competition-formats' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.game_formats.access | custom | Catch-all access to 'game-formats' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_classes.access | custom | Catch-all access to 'player-classes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_classes.access | custom | Catch-all access to 'competition-classes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_levels.access | custom | Catch-all access to 'competition-levels' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_types.access | custom | Catch-all access to 'competition-types' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_config.access | custom | Catch-all access to 'competition-config' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competitions.access | custom | Catch-all access to 'competitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.national_competition_structures.access | custom | Catch-all access to 'national-competition-structures' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disability_categories.access | custom | Catch-all access to 'disability-categories' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adaptive_rules.access | custom | Catch-all access to 'adaptive-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.points_systems.access | custom | Catch-all access to 'points-systems' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.entry_fee_configs.access | custom | Catch-all access to 'entry-fee-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.participant_limits.access | custom | Catch-all access to 'participant-limits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.qualification_criteria.access | custom | Catch-all access to 'qualification-criteria' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tournament_follows.access | custom | Catch-all access to 'tournament-follows' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.temporary_licenses.access | custom | Catch-all access to 'temporary-licenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.registrations.access | custom | Catch-all access to 'registrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.saved_tournaments.access | custom | Catch-all access to 'saved-tournaments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_intents.access | custom | Catch-all access to 'travel-intents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tournaments.access | custom | Catch-all access to 'tournaments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.draws.access | custom | Catch-all access to 'draws' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.matches.access | custom | Catch-all access to 'matches' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_subscriptions.access | custom | Catch-all access to 'match-subscriptions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.melee_tournaments.access | custom | Catch-all access to 'melee-tournaments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cup_formats.access | custom | Catch-all access to 'cup-formats' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.leagues.access | custom | Catch-all access to 'leagues' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fixtures.access | custom | Catch-all access to 'fixtures' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_days.access | custom | Catch-all access to 'match-days' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.season_archives.access | custom | Catch-all access to 'season-archives' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.membership_categories.access | custom | Catch-all access to 'membership-categories' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_memberships.access | custom | Catch-all access to 'club-memberships' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.family_groups.access | custom | Catch-all access to 'family-groups' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_rules.access | custom | Catch-all access to 'license-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.affiliation_records.access | custom | Catch-all access to 'affiliation-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.affiliation_applications.access | custom | Catch-all access to 'affiliation-applications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.member_count_reports.access | custom | Catch-all access to 'member-count-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.transfers.access | custom | Catch-all access to 'transfers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.itc.access | custom | Catch-all access to 'itc' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.consent_records.access | custom | Catch-all access to 'consent-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.parental_consents.access | custom | Catch-all access to 'parental-consents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.data_deletion_requests.access | custom | Catch-all access to 'data-deletion-requests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.data_retention_policies.access | custom | Catch-all access to 'data-retention-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.data_access_audit.access | custom | Catch-all access to 'data-access-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cookie_consent.access | custom | Catch-all access to 'cookie-consent' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.commissions.access | custom | Catch-all access to 'commissions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.meetings.access | custom | Catch-all access to 'meetings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.governance.access | custom | Catch-all access to 'governance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.governance_meetings.access | custom | Catch-all access to 'governance-meetings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.juries.access | custom | Catch-all access to 'juries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.jury_decisions.access | custom | Catch-all access to 'jury-decisions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.jury_reports.access | custom | Catch-all access to 'jury-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_delegates.access | custom | Catch-all access to 'referee-delegates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.delegate_observations.access | custom | Catch-all access to 'delegate-observations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.delegate_reports.access | custom | Catch-all access to 'delegate-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.compliance_checklist_templates.access | custom | Catch-all access to 'compliance-checklist-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_certifications.access | custom | Catch-all access to 'umpire-certifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_expenses.access | custom | Catch-all access to 'umpire-expenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_statistics.access | custom | Catch-all access to 'umpire-statistics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_evaluations.access | custom | Catch-all access to 'umpire-evaluations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_training_pathways.access | custom | Catch-all access to 'umpire-training-pathways' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_availability.access | custom | Catch-all access to 'umpire-availability' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_directory.access | custom | Catch-all access to 'umpire-directory' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_id_cards.access | custom | Catch-all access to 'umpire-id-cards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_training_courses.access | custom | Catch-all access to 'umpire-training-courses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.exam_questions.access | custom | Catch-all access to 'exam-questions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.exam_sessions.access | custom | Catch-all access to 'exam-sessions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_enrollments.access | custom | Catch-all access to 'training-enrollments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.mentorship_programs.access | custom | Catch-all access to 'mentorship-programs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.continuing_education.access | custom | Catch-all access to 'continuing-education' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_materials.access | custom | Catch-all access to 'training-materials' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.recertifications.access | custom | Catch-all access to 'recertifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.candidacy_records.access | custom | Catch-all access to 'candidacy-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.exam_definitions.access | custom | Catch-all access to 'exam-definitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.umpire_assignments.access | custom | Catch-all access to 'umpire-assignments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_umpire_requirements.access | custom | Catch-all access to 'competition-umpire-requirements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_teams.access | custom | Catch-all access to 'referee-teams' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disciplinary_cases.access | custom | Catch-all access to 'disciplinary-cases' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sanctions.access | custom | Catch-all access to 'sanctions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sanction_webhooks.access | custom | Catch-all access to 'sanction-webhooks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disciplinary_audit.access | custom | Catch-all access to 'disciplinary-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sanction_catalog.access | custom | Catch-all access to 'sanction-catalog' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disciplinary_dashboard.access | custom | Catch-all access to 'disciplinary-dashboard' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.discipline.access | custom | Catch-all access to 'discipline' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fipjp.access | custom | Catch-all access to 'fipjp' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.live_productions.access | custom | Catch-all access to 'live-productions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stream_recordings.access | custom | Catch-all access to 'stream-recordings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.highlight_clips.access | custom | Catch-all access to 'highlight-clips' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stream_embeds.access | custom | Catch-all access to 'stream-embeds' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.mene_summaries.access | custom | Catch-all access to 'mene-summaries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.live_viewer.access | custom | Catch-all access to 'live-viewer' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.replay_requests.access | custom | Catch-all access to 'replay-requests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_cards.access | custom | Catch-all access to 'player-cards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_video_links.access | custom | Catch-all access to 'match-video-links' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.audio_only.access | custom | Catch-all access to 'audio-only' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.score_only_feed.access | custom | Catch-all access to 'score-only-feed' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.offline_recordings.access | custom | Catch-all access to 'offline-recordings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stream_schedules.access | custom | Catch-all access to 'stream-schedules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.live_chat.access | custom | Catch-all access to 'live-chat' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.local_recordings.access | custom | Catch-all access to 'local-recordings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cloud_recordings.access | custom | Catch-all access to 'cloud-recordings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.auto_highlight_configs.access | custom | Catch-all access to 'auto-highlight-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.post_match_edits.access | custom | Catch-all access to 'post-match-edits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_summary_videos.access | custom | Catch-all access to 'match-summary-videos' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.recording_shares.access | custom | Catch-all access to 'recording-shares' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bulk_notifications.access | custom | Catch-all access to 'bulk-notifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.notification_webhooks.access | custom | Catch-all access to 'notification-webhooks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.notification_delivery_events.access | custom | Catch-all access to 'notification-delivery-events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.notification_statistics.access | custom | Catch-all access to 'notification-statistics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.notification_digests.access | custom | Catch-all access to 'notification-digests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.conversations.access | custom | Catch-all access to 'conversations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.messages.access | custom | Catch-all access to 'messages' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.correspondences.access | custom | Catch-all access to 'correspondences' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.documents.access | custom | Catch-all access to 'documents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_sync.access | custom | Catch-all access to 'calendar-sync' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.congresses.access | custom | Catch-all access to 'congresses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.resolution_compliance.access | custom | Catch-all access to 'resolution-compliance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.form_templates.access | custom | Catch-all access to 'form-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.form_submissions.access | custom | Catch-all access to 'form-submissions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.signature_requests.access | custom | Catch-all access to 'signature-requests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.social_media.access | custom | Catch-all access to 'social-media' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_schedules.access | custom | Catch-all access to 'fee-schedules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.revenue_distribution_rules.access | custom | Catch-all access to 'revenue-distribution-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_management.access | custom | Catch-all access to 'fee-management' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_surcharge_rules.access | custom | Catch-all access to 'fee-surcharge-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_surcharges.access | custom | Catch-all access to 'fee-surcharges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_waiver_rules.access | custom | Catch-all access to 'fee-waiver-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_waivers.access | custom | Catch-all access to 'fee-waivers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_splitting.access | custom | Catch-all access to 'fee-splitting' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fee_audit.access | custom | Catch-all access to 'fee-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sanction_fee_configs.access | custom | Catch-all access to 'sanction-fee-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.suspension_fee_configs.access | custom | Catch-all access to 'suspension-fee-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.invoices.access | custom | Catch-all access to 'invoices' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payments.access | custom | Catch-all access to 'payments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.debts.access | custom | Catch-all access to 'debts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.financial_reports.access | custom | Catch-all access to 'financial-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.credit_notes.access | custom | Catch-all access to 'credit-notes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.reminder_configs.access | custom | Catch-all access to 'reminder-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.debt_collection.access | custom | Catch-all access to 'debt-collection' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_gateways.access | custom | Catch-all access to 'payment-gateways' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.checkout.access | custom | Catch-all access to 'checkout' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.receipts.access | custom | Catch-all access to 'receipts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_history.access | custom | Catch-all access to 'payment-history' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bank_transfers.access | custom | Catch-all access to 'bank-transfers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.installment_plans.access | custom | Catch-all access to 'installment-plans' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.reconciliations.access | custom | Catch-all access to 'reconciliations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.refunds.access | custom | Catch-all access to 'refunds' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bulk_payments.access | custom | Catch-all access to 'bulk-payments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.exchange_rates.access | custom | Catch-all access to 'exchange-rates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_audit.access | custom | Catch-all access to 'payment-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.expense_claims.access | custom | Catch-all access to 'expense-claims' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.expenses.access | custom | Catch-all access to 'expenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.expense_reports.access | custom | Catch-all access to 'expense-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounts.access | custom | Catch-all access to 'accounts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounting_entries.access | custom | Catch-all access to 'accounting-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.budgets.access | custom | Catch-all access to 'budgets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounting_export.access | custom | Catch-all access to 'accounting-export' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounting_integrations.access | custom | Catch-all access to 'accounting-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.financial_audit_log.access | custom | Catch-all access to 'financial-audit-log' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounting_reports.access | custom | Catch-all access to 'accounting-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.chart_of_accounts_mappings.access | custom | Catch-all access to 'chart-of-accounts-mappings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.period_locks.access | custom | Catch-all access to 'period-locks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.financial_statements.access | custom | Catch-all access to 'financial-statements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.financial_reporting.access | custom | Catch-all access to 'financial-reporting' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bank_reconciliation.access | custom | Catch-all access to 'bank-reconciliation' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.legal.access | custom | Catch-all access to 'legal' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.groups.access | custom | Catch-all access to 'groups' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.license_fee_revisions.access | custom | Catch-all access to 'license-fee-revisions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.invoice_number_series.access | custom | Catch-all access to 'invoice-number-series' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_term_rules.access | custom | Catch-all access to 'payment-term-rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sepa_mandates.access | custom | Catch-all access to 'sepa-mandates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sepa_direct_debits.access | custom | Catch-all access to 'sepa-direct-debits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_method_policies.access | custom | Catch-all access to 'payment-method-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.multi_currency_reports.access | custom | Catch-all access to 'multi-currency-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_qualifications.access | custom | Catch-all access to 'coach-qualifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_certifications.access | custom | Catch-all access to 'coach-certifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_programs.access | custom | Catch-all access to 'training-programs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_course_registrations.access | custom | Catch-all access to 'coach-course-registrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coaching_materials.access | custom | Catch-all access to 'coaching-materials' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_developments.access | custom | Catch-all access to 'player-developments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.certification_renewals.access | custom | Catch-all access to 'certification-renewals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.development_plans.access | custom | Catch-all access to 'development-plans' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_assignments.access | custom | Catch-all access to 'coach-assignments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coaching_sessions.access | custom | Catch-all access to 'coaching-sessions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.program_enrollments.access | custom | Catch-all access to 'program-enrollments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_attendance.access | custom | Catch-all access to 'training-attendance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.video_analyses.access | custom | Catch-all access to 'video-analyses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.drill_library.access | custom | Catch-all access to 'drill-library' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coaching.access | custom | Catch-all access to 'coaching' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.e_learning.access | custom | Catch-all access to 'e-learning' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.venues.access | custom | Catch-all access to 'venues' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.buvette.access | custom | Catch-all access to 'buvette' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_applications.access | custom | Catch-all access to 'tue-applications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.doping_tests.access | custom | Catch-all access to 'doping-tests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.medical_staff.access | custom | Catch-all access to 'medical-staff' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.injury_reports.access | custom | Catch-all access to 'injury-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.wada_code_articles.access | custom | Catch-all access to 'wada-code-articles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.wada_compliance_records.access | custom | Catch-all access to 'wada-compliance-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.whereabouts.access | custom | Catch-all access to 'whereabouts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.whereabouts_missed_tests.access | custom | Catch-all access to 'whereabouts-missed-tests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.testing_pools.access | custom | Catch-all access to 'testing-pools' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.testing_schedule.access | custom | Catch-all access to 'testing-schedule' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.chain_of_custody.access | custom | Catch-all access to 'chain-of-custody' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.b_sample_analyses.access | custom | Catch-all access to 'b-sample-analyses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.test_result_notifications.access | custom | Catch-all access to 'test-result-notifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_committee_reviews.access | custom | Catch-all access to 'tue-committee-reviews' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adrv_cases.access | custom | Catch-all access to 'adrv-cases' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adrv_sanctions.access | custom | Catch-all access to 'adrv-sanctions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.education_courses.access | custom | Catch-all access to 'education-courses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.education_completions.access | custom | Catch-all access to 'education-completions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.prohibited_substances.access | custom | Catch-all access to 'prohibited-substances' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.doping_audit.access | custom | Catch-all access to 'doping-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disability_classifications.access | custom | Catch-all access to 'disability-classifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.para.access | custom | Catch-all access to 'para' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.emergency_contacts.access | custom | Catch-all access to 'emergency-contacts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_medical_info.access | custom | Catch-all access to 'player-medical-info' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.international_health_certificates.access | custom | Catch-all access to 'international-health-certificates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_medical_details.access | custom | Catch-all access to 'tue-medical-details' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_review_boards.access | custom | Catch-all access to 'tue-review-boards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_board_decisions.access | custom | Catch-all access to 'tue-board-decisions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_player_status.access | custom | Catch-all access to 'tue-player-status' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.nado_referrals.access | custom | Catch-all access to 'nado-referrals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.tue_renewals.access | custom | Catch-all access to 'tue-renewals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safety_checklists.access | custom | Catch-all access to 'safety-checklists' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safety_checklist_completions.access | custom | Catch-all access to 'safety-checklist-completions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safety_incidents.access | custom | Catch-all access to 'safety-incidents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.first_aid_requirements.access | custom | Catch-all access to 'first-aid-requirements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.weather_policies.access | custom | Catch-all access to 'weather-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_incidents.access | custom | Catch-all access to 'safeguarding-incidents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_officer_directory.access | custom | Catch-all access to 'safeguarding-officer-directory' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.weather.access | custom | Catch-all access to 'weather' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.background_checks.access | custom | Catch-all access to 'background-checks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_reports.access | custom | Catch-all access to 'safeguarding-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_policies.access | custom | Catch-all access to 'safeguarding-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.medical_emergency_incidents.access | custom | Catch-all access to 'medical-emergency-incidents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.first_aid_compliance.access | custom | Catch-all access to 'first-aid-compliance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.medical_staff_registrations.access | custom | Catch-all access to 'medical-staff-registrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.weather_alerts.access | custom | Catch-all access to 'weather-alerts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.integrity_alerts.access | custom | Catch-all access to 'integrity-alerts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.suspicious_activity_reports.access | custom | Catch-all access to 'suspicious-activity-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.integrity_investigations.access | custom | Catch-all access to 'integrity-investigations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_equipment_checks.access | custom | Catch-all access to 'event-equipment-checks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.equipment_confiscations.access | custom | Catch-all access to 'equipment-confiscations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.betting_integrity_bodies.access | custom | Catch-all access to 'betting-integrity-bodies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.betting_integrity_notifications.access | custom | Catch-all access to 'betting-integrity-notifications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.integrity_audit_log.access | custom | Catch-all access to 'integrity-audit-log' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.disputes.access | custom | Catch-all access to 'disputes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.dispute_precedents.access | custom | Catch-all access to 'dispute-precedents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.dispute_appeals.access | custom | Catch-all access to 'dispute-appeals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.dispute_audit_log.access | custom | Catch-all access to 'dispute-audit-log' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_training_requirements.access | custom | Catch-all access to 'safeguarding-training-requirements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_training_records.access | custom | Catch-all access to 'safeguarding-training-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_training.access | custom | Catch-all access to 'safeguarding-training' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youth_event_risk_assessments.access | custom | Catch-all access to 'youth-event-risk-assessments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adult_child_ratio_requirements.access | custom | Catch-all access to 'adult-child-ratio-requirements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adult_child_ratio_checks.access | custom | Catch-all access to 'adult-child-ratio-checks' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_complaints.access | custom | Catch-all access to 'safeguarding-complaints' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_audit.access | custom | Catch-all access to 'safeguarding-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.gender_equity_reports.access | custom | Catch-all access to 'gender-equity-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.adaptive_equipment.access | custom | Catch-all access to 'adaptive-equipment' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.inclusion_policies.access | custom | Catch-all access to 'inclusion-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.diversity_snapshots.access | custom | Catch-all access to 'diversity-snapshots' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.venue_accessibility_audits.access | custom | Catch-all access to 'venue-accessibility-audits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.inclusion_audit.access | custom | Catch-all access to 'inclusion-audit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.encrypted_reports.access | custom | Catch-all access to 'encrypted-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.whistleblower_reports.access | custom | Catch-all access to 'whistleblower-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.retaliation_reports.access | custom | Catch-all access to 'retaliation-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.background_check_requirements.access | custom | Catch-all access to 'background-check-requirements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.background_check_compliance.access | custom | Catch-all access to 'background-check-compliance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.nation_safeguarding_policies.access | custom | Catch-all access to 'nation-safeguarding-policies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.safeguarding_officers.access | custom | Catch-all access to 'safeguarding-officers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.coach_safeguarding_training.access | custom | Catch-all access to 'coach-safeguarding-training' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.confidential_safeguarding_incidents.access | custom | Catch-all access to 'confidential-safeguarding-incidents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsors.access | custom | Catch-all access to 'sponsors' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.grants.access | custom | Catch-all access to 'grants' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsor_allocations.access | custom | Catch-all access to 'sponsor-allocations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.marketplace.access | custom | Catch-all access to 'marketplace' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.broadcast.access | custom | Catch-all access to 'broadcast' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.squad_travel.access | custom | Catch-all access to 'squad-travel' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.vip.access | custom | Catch-all access to 'vip' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.wedding.access | custom | Catch-all access to 'wedding' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.restricted_facility.access | custom | Catch-all access to 'restricted-facility' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.forums.access | custom | Catch-all access to 'forums' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ad_placements.access | custom | Catch-all access to 'ad-placements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.retailers.access | custom | Catch-all access to 'retailers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.boule_bars.access | custom | Catch-all access to 'boule-bars' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federation_shops.access | custom | Catch-all access to 'federation-shops' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.shop_products.access | custom | Catch-all access to 'shop-products' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.marketplace_watchlist.access | custom | Catch-all access to 'marketplace-watchlist' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seller_ratings.access | custom | Catch-all access to 'seller-ratings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.classified_ads.access | custom | Catch-all access to 'classified-ads' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.manufacturers.access | custom | Catch-all access to 'manufacturers' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bulk_orders.access | custom | Catch-all access to 'bulk-orders' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.marketplace_payments.access | custom | Catch-all access to 'marketplace-payments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.marketplace_payouts.access | custom | Catch-all access to 'marketplace-payouts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.shipments.access | custom | Catch-all access to 'shipments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seller_profiles.access | custom | Catch-all access to 'seller-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seller_products.access | custom | Catch-all access to 'seller-products' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seller_orders.access | custom | Catch-all access to 'seller-orders' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stripe_connect.access | custom | Catch-all access to 'stripe-connect' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.seller_reviews.access | custom | Catch-all access to 'seller-reviews' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.return_requests.access | custom | Catch-all access to 'return-requests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stock_movements.access | custom | Catch-all access to 'stock-movements' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.low_stock_alerts.access | custom | Catch-all access to 'low-stock-alerts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsorship_opportunities.access | custom | Catch-all access to 'sponsorship-opportunities' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsor_profiles.access | custom | Catch-all access to 'sponsor-profiles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ad_placement_analytics.access | custom | Catch-all access to 'ad-placement-analytics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsor_visibility.access | custom | Catch-all access to 'sponsor-visibility' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsorship_packages.access | custom | Catch-all access to 'sponsorship-packages' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sponsor_matches.access | custom | Catch-all access to 'sponsor-matches' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.homologation_applications.access | custom | Catch-all access to 'homologation-applications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.certification_tests.access | custom | Catch-all access to 'certification-tests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.approved_equipment.access | custom | Catch-all access to 'approved-equipment' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.homologation_renewals.access | custom | Catch-all access to 'homologation-renewals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.equipment_inspections.access | custom | Catch-all access to 'equipment-inspections' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.prize_pools.access | custom | Catch-all access to 'prize-pools' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.prize_payouts.access | custom | Catch-all access to 'prize-payouts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.trophy_inventories.access | custom | Catch-all access to 'trophy-inventories' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.trophy_awards.access | custom | Catch-all access to 'trophy-awards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youth_academies.access | custom | Catch-all access to 'youth-academies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youth_players.access | custom | Catch-all access to 'youth-players' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youth_competition_pathways.access | custom | Catch-all access to 'youth-competition-pathways' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.school_partnerships.access | custom | Catch-all access to 'school-partnerships' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youth_progress_reports.access | custom | Catch-all access to 'youth-progress-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.school_programs.access | custom | Catch-all access to 'school-programs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.junior_competitions.access | custom | Catch-all access to 'junior-competitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.talent_programs.access | custom | Catch-all access to 'talent-programs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.national_youth_programs.access | custom | Catch-all access to 'national-youth-programs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.junior_coach_resources.access | custom | Catch-all access to 'junior-coach-resources' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.junior_statistics.access | custom | Catch-all access to 'junior-statistics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_entries.access | custom | Catch-all access to 'training-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.development_goals.access | custom | Catch-all access to 'development-goals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.goal_templates.access | custom | Catch-all access to 'goal-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.player_pathways.access | custom | Catch-all access to 'player-pathways' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ranking_configs.access | custom | Catch-all access to 'ranking-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ranking_entries.access | custom | Catch-all access to 'ranking-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.rankings.access | custom | Catch-all access to 'rankings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_ranking_configs.access | custom | Catch-all access to 'club-ranking-configs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_ranking_entries.access | custom | Catch-all access to 'club-ranking-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_rankings.access | custom | Catch-all access to 'club-rankings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ranking_disputes.access | custom | Catch-all access to 'ranking-disputes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cross_tenant_elo.access | custom | Catch-all access to 'cross-tenant-elo' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ranking_presets.access | custom | Catch-all access to 'ranking-presets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.user_ranking_presets.access | custom | Catch-all access to 'user-ranking-presets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.elo.access | custom | Catch-all access to 'elo' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.major_events.access | custom | Catch-all access to 'major-events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_tickets.access | custom | Catch-all access to 'event-tickets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.delegation_registrations.access | custom | Catch-all access to 'delegation-registrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.media_accreditations.access | custom | Catch-all access to 'media-accreditations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.volunteer_registrations.access | custom | Catch-all access to 'volunteer-registrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.merchandise_preorders.access | custom | Catch-all access to 'merchandise-preorders' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.corporate_events.access | custom | Catch-all access to 'corporate-events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_packages.access | custom | Catch-all access to 'event-packages' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.heritage_content.access | custom | Catch-all access to 'heritage-content' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.hall_of_fame.access | custom | Catch-all access to 'hall-of-fame' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.historic_competitions.access | custom | Catch-all access to 'historic-competitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.museums.access | custom | Catch-all access to 'museums' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cultural_events.access | custom | Catch-all access to 'cultural-events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.training_camps.access | custom | Catch-all access to 'training-camps' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_packages.access | custom | Catch-all access to 'travel-packages' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.destination_guides.access | custom | Catch-all access to 'destination-guides' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_companions.access | custom | Catch-all access to 'travel-companions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.club_exchanges.access | custom | Catch-all access to 'club-exchanges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accommodation_listings.access | custom | Catch-all access to 'accommodation-listings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.world_championships.access | custom | Catch-all access to 'world-championships' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.continental_championships.access | custom | Catch-all access to 'continental-championships' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_bids.access | custom | Catch-all access to 'event-bids' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_timelines.access | custom | Catch-all access to 'event-timelines' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_venue_approvals.access | custom | Catch-all access to 'event-venue-approvals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.delegation_accommodations.access | custom | Catch-all access to 'delegation-accommodations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_transport_plans.access | custom | Catch-all access to 'event-transport-plans' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_accreditations.access | custom | Catch-all access to 'event-accreditations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_ceremonies.access | custom | Catch-all access to 'event-ceremonies' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_vip_hospitality.access | custom | Catch-all access to 'event-vip-hospitality' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_budgets.access | custom | Catch-all access to 'event-budgets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.event_tenant.access | custom | Catch-all access to 'event-tenant' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.elections.access | custom | Catch-all access to 'elections' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.statistics.access | custom | Catch-all access to 'statistics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.rules.access | custom | Catch-all access to 'rules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.rules_education.access | custom | Catch-all access to 'rules-education' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.developer.access | custom | Catch-all access to 'developer' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.v1.access | custom | Catch-all access to 'v1' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.i18n.access | custom | Catch-all access to 'i18n' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.content.access | custom | Catch-all access to 'content' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.broadcast_templates.access | custom | Catch-all access to 'broadcast-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.print.access | custom | Catch-all access to 'print' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.report_templates.access | custom | Catch-all access to 'report-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federation_reports.access | custom | Catch-all access to 'federation-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.report_deadlines.access | custom | Catch-all access to 'report-deadlines' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.compliance_checklists.access | custom | Catch-all access to 'compliance-checklists' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.data_breaches.access | custom | Catch-all access to 'data-breaches' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sensitive_fields.access | custom | Catch-all access to 'sensitive-fields' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.selection_processes.access | custom | Catch-all access to 'selection-processes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.national_team_records.access | custom | Catch-all access to 'national-team-records' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.qualification_pathways.access | custom | Catch-all access to 'qualification-pathways' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.qualification_entries.access | custom | Catch-all access to 'qualification-entries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.qualification_cross_references.access | custom | Catch-all access to 'qualification-cross-references' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.international_competitions.access | custom | Catch-all access to 'international-competitions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.nation_ceremony_info.access | custom | Catch-all access to 'nation-ceremony-info' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.hosting_bids.access | custom | Catch-all access to 'hosting-bids' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.national_ranking_feedback.access | custom | Catch-all access to 'national-ranking-feedback' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_awards.access | custom | Catch-all access to 'competition-awards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.season_awards.access | custom | Catch-all access to 'season-awards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.award_hall_of_fame.access | custom | Catch-all access to 'award-hall-of-fame' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.championship_series.access | custom | Catch-all access to 'championship-series' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.news_articles.access | custom | Catch-all access to 'news-articles' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.hotel_bookings.access | custom | Catch-all access to 'hotel-bookings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_schedules.access | custom | Catch-all access to 'travel-schedules' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.transfer_bookings.access | custom | Catch-all access to 'transfer-bookings' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_coordinators.access | custom | Catch-all access to 'travel-coordinators' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.travel_expenses.access | custom | Catch-all access to 'travel-expenses' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.feature_requests.access | custom | Catch-all access to 'feature-requests' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.startup.access | custom | Catch-all access to 'startup' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.observability.access | custom | Catch-all access to 'observability' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.incidents.access | custom | Catch-all access to 'incidents' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.communications.access | custom | Catch-all access to 'communications' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federation_integrations.access | custom | Catch-all access to 'federation-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.fipjp_submissions.access | custom | Catch-all access to 'fipjp-submissions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.continental_exchanges.access | custom | Catch-all access to 'continental-exchanges' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.payment_gateway_integrations.access | custom | Catch-all access to 'payment-gateway-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.calendar_integrations.access | custom | Catch-all access to 'calendar-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.social_media_integrations.access | custom | Catch-all access to 'social-media-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.streaming_integrations.access | custom | Catch-all access to 'streaming-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.mapping_integrations.access | custom | Catch-all access to 'mapping-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.wada_adams_integrations.access | custom | Catch-all access to 'wada-adams-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.insurance_integrations.access | custom | Catch-all access to 'insurance-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.gov_sports_registry_integrations.access | custom | Catch-all access to 'gov-sports-registry-integrations' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.export_jobs.access | custom | Catch-all access to 'export-jobs' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scheduled_exports.access | custom | Catch-all access to 'scheduled-exports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.export_templates.access | custom | Catch-all access to 'export-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.competition_exports.access | custom | Catch-all access to 'competition-exports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.widgets.access | custom | Catch-all access to 'widgets' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stripe.access | custom | Catch-all access to 'stripe' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.paypal.access | custom | Catch-all access to 'paypal' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.swish.access | custom | Catch-all access to 'swish' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ideal.access | custom | Catch-all access to 'ideal' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bancontact.access | custom | Catch-all access to 'bancontact' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.bizum.access | custom | Catch-all access to 'bizum' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sepa_direct_debit.access | custom | Catch-all access to 'sepa-direct-debit' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.klarna.access | custom | Catch-all access to 'klarna' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.accounting.access | custom | Catch-all access to 'accounting' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.geo.access | custom | Catch-all access to 'geo' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.anti_doping.access | custom | Catch-all access to 'anti-doping' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.communication.access | custom | Catch-all access to 'communication' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.youtube_embeds.access | custom | Catch-all access to 'youtube-embeds' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.twitch_embeds.access | custom | Catch-all access to 'twitch-embeds' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.rtmp_relays.access | custom | Catch-all access to 'rtmp-relays' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.stream_metadata.access | custom | Catch-all access to 'stream-metadata' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.vimeo_replays.access | custom | Catch-all access to 'vimeo-replays' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.cloudflare_streams.access | custom | Catch-all access to 'cloudflare-streams' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.dns.access | custom | Catch-all access to 'dns' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.analytics.access | custom | Catch-all access to 'analytics' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.mobile.access | custom | Catch-all access to 'mobile' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.offline.access | custom | Catch-all access to 'offline' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.live_scores.access | custom | Catch-all access to 'live-scores' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.match_timelines.access | custom | Catch-all access to 'match-timelines' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.court_views.access | custom | Catch-all access to 'court-views' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.follows.access | custom | Catch-all access to 'follows' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.commentary.access | custom | Catch-all access to 'commentary' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.score_alerts.access | custom | Catch-all access to 'score-alerts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.multi_match.access | custom | Catch-all access to 'multi-match' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.community.access | custom | Catch-all access to 'community' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.push.access | custom | Catch-all access to 'push' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.onboarding.access | custom | Catch-all access to 'onboarding' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.data_visibility.access | custom | Catch-all access to 'data-visibility' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ar.access | custom | Catch-all access to 'ar' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.sri.access | custom | Catch-all access to 'sri' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.chain.access | custom | Catch-all access to 'chain' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.inquiries.access | custom | Catch-all access to 'inquiries' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.inquiry_templates.access | custom | Catch-all access to 'inquiry-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scores.access | custom | Catch-all access to 'scores' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.operator.access | custom | Catch-all access to 'operator' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.federation.access | custom | Catch-all access to 'federation' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.ministry_reports.access | custom | Catch-all access to 'ministry-reports' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.officials.access | custom | Catch-all access to 'officials' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.mentorship.access | custom | Catch-all access to 'mentorship' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.finance.access | custom | Catch-all access to 'finance' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.staff.access | custom | Catch-all access to 'staff' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.unsubscribe.access | custom | Catch-all access to 'unsubscribe' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_loans.access | custom | Catch-all access to 'referee-loans' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_assignments.access | custom | Catch-all access to 'referee-assignments' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_payouts.access | custom | Catch-all access to 'referee-payouts' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.subscriptions.access | custom | Catch-all access to 'subscriptions' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scoreboards.access | custom | Catch-all access to 'scoreboards' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.orgnodes.access | custom | Catch-all access to 'orgnodes' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scoreboard_kits.access | custom | Catch-all access to 'scoreboard-kits' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scoreboard_kit_instances.access | custom | Catch-all access to 'scoreboard-kit-instances' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.scoreboard_rentals.access | custom | Catch-all access to 'scoreboard-rentals' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.referee_calls.access | custom | Catch-all access to 'referee-calls' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.events.access | custom | Catch-all access to 'events' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.surveys.access | custom | Catch-all access to 'surveys' domain endpoints. Narrower capabilities may be introduced over time to replace this. | |
domain.survey_templates.access | custom | Catch-all access to 'survey-templates' domain endpoints. Narrower capabilities may be introduced over time to replace this. |
Error Handling
Authentication Errors
| HTTP | error | Meaning | Action |
|---|---|---|---|
400 | invalid_request | Missing/malformed parameters | Check grant_type, client_assertion_type |
401 | invalid_client | Unknown client_id, kid mismatch, signature failure, alg mismatch | Check key, kid, client_id |
400 | invalid_grant | Expired/replay/wrong audience/wrong issuer | Check iat/exp, aud, iss, jti |
400 | invalid_scope | Requested capability unknown or not assigned to client | Check client's capabilities in Admin UI |
401 | invalid_dpop_proof | DPoP header missing or malformed | See DPoP section |
403 | missing_capabilities | Token lacks capability for this endpoint | Request token with correct scope |
429 | — | Rate limit / lockout after repeated failures | Wait per Retry-After header |
503 | server_error | Auth service unavailable | Retry with exponential backoff |
Example Error Responses
// 400 invalid_request
{
"error": "invalid_request",
"error_description": "client_assertion_type must be 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'"
}
// 401 invalid_client
{
"error": "invalid_client",
"error_description": "No active key with kid '2026-04-expired' found for client 'acme-integration'"
}
// 400 invalid_scope
{
"error": "invalid_scope",
"error_description": "Client 'acme-integration' does not have capability 'admin:delete'"
}
// 403 missing_capabilities (on API call, not token request)
{
"detail": {
"error": "missing_capabilities",
"missing": ["bookings:create"]
}
}General API Errors
| Code | Meaning | When |
|---|---|---|
400 | Bad Request | Invalid JSON in where, malformed input |
401 | Unauthorized | Missing or invalid token |
404 | Not Found | Resource doesn't exist or belongs to another tenant |
409 | Conflict | Cascade delete denied — children exist |
412 | Precondition Failed | ETag mismatch — document modified by someone else |
422 | Validation Error | Request body fails schema validation |
428 | Precondition Required | Missing If-Match header on update/delete |
429 | Too Many Requests | Rate limit exceeded |
# Recommended error handling
try:
product, etag = api.get("products", "nonexistent-id")
except requests.HTTPError as e:
status = e.response.status_code
body = e.response.json()
if status == 401:
print("Token expired or invalid — request a new one")
elif status == 403:
missing = body.get("detail", {}).get("missing", [])
print(f"Missing capabilities: {missing}")
elif status == 404:
print("Not found")
elif status == 412:
print("ETag conflict — re-fetch and retry")
elif status == 429:
retry_after = e.response.headers.get("Retry-After", "60")
print(f"Rate limited — retry after {retry_after}s")
else:
print(f"Error {status}: {body}")try
{
var (product, etag) = await api.GetAsync("products", "nonexistent");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HTTP {(int?)ex.StatusCode}: {ex.Message}");
switch (ex.StatusCode)
{
case System.Net.HttpStatusCode.Unauthorized:
Console.WriteLine("Token expired — request a new one");
break;
case System.Net.HttpStatusCode.Forbidden:
Console.WriteLine("Missing capabilities");
break;
case System.Net.HttpStatusCode.NotFound:
Console.WriteLine("Resource not found");
break;
}
}const resp = await fetch(`${baseUrl}/products/nonexistent`, { headers })
if (!resp.ok) {
const body = await resp.json()
switch (resp.status) {
case 401: console.error('Token expired'); break
case 403: console.error('Missing capabilities:', body.detail?.missing); break
case 404: console.error('Not found'); break
case 429:
console.error(`Rate limited, retry after ${resp.headers.get('Retry-After')}s`)
break
default: console.error(`Error ${resp.status}:`, body)
}
}# Check HTTP status code
curl -s -o response.json -w '%{http_code}' 'http://api.petanque.life/products/nonexistent' \
-H 'Authorization: Bearer eyJ...'
cat response.json | jq .Rate Limiting
Endpoints may have per-route rate limits. When exceeded, the API returns
429 Too Many Requests with a Retry-After header.
| Context | Limit | Lockout |
|---|---|---|
| M2M token requests | Per-client, per-IP | 5 consecutive failures triggers 15-minute lockout |
| API endpoints | Per-route (configurable) | 429 with Retry-After |
# Respect Retry-After
import time
resp = requests.get(f"{base_url}/bookings", headers=headers)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 60))
time.sleep(retry_after)
resp = requests.get(f"{base_url}/bookings", headers=headers)Key Rotation
Rotate keys without downtime using the overlap period.
Admin creates a new key in UI or via
POST /api-clients/{id}/keys/rotate.
Old key gets
active_until = now + 30 days. Both keys are valid.
Update your client to use the new
kid immediately.
During the overlap, both old and new keys work. Admin UI shows countdown.
After 30 days, the old key is removed automatically.
Automatic Rotation in Code
import json
# Check key status via API
resp = requests.get(f"{base_url}/api-clients/{client_id}",
headers=admin_headers)
client_data = resp.json()
for key in client_data.get("keys", []):
kid = key["kid"]
active_until = key.get("active_until")
if active_until:
print(f"Key {kid} expires: {active_until}")
# Plan rotation before this date
else:
print(f"Key {kid} is the primary key (no expiry)")
# Best practice: load kid from config, not hardcoded
# When you deploy a new key, update your config to use the new kidPython SDK Skeleton
Complete working example with automatic token management.
"""
Complete M2M integration example.
pip install authlib requests
"""
from authlib.jose import jwt as jose_jwt
from datetime import datetime, timedelta, UTC
import uuid, time, requests
BASE = "http://api.petanque.life"
CLIENT_ID = "acme-integration"
KID = "2026-04-primary"
TOKEN_ENDPOINT = f"{BASE}/auth/token"
with open("client-private-key.pem", "rb") as f:
PRIVATE_KEY = f.read()
def get_access_token(scope: str = "") -> tuple[str, int]:
now = datetime.now(UTC)
assertion = jose_jwt.encode(
header={"alg": "ES256", "kid": KID},
payload={
"iss": CLIENT_ID, "sub": CLIENT_ID,
"aud": TOKEN_ENDPOINT,
"jti": str(uuid.uuid4()),
"iat": int(now.timestamp()),
"exp": int((now + timedelta(minutes=2)).timestamp()),
},
key=PRIVATE_KEY,
).decode()
resp = requests.post(TOKEN_ENDPOINT, data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_assertion_type":
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": assertion,
"scope": scope,
})
if resp.status_code != 200:
error = resp.json()
raise RuntimeError(
f"Token error: {error['error']} — {error.get('error_description', '')}"
)
data = resp.json()
return data["access_token"], data["expires_in"]
def main():
token, expires_in = get_access_token("bookings:read bookings:create")
print(f"Got token (expires in {expires_in}s)")
headers = {"Authorization": f"Bearer {token}"}
# List bookings
resp = requests.get(f"{BASE}/bookings/", headers=headers)
resp.raise_for_status()
bookings = resp.json()
print(f"Found {bookings['total']} bookings")
for b in bookings["items"]:
print(f" {b['_id']} — {b.get('status', 'unknown')}")
if __name__ == "__main__":
main()C# SDK Skeleton
Complete working example using .NET 8+.
// NuGet packages:
// - Microsoft.IdentityModel.Tokens
// - System.IdentityModel.Tokens.Jwt
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
const string BaseUrl = "http://api.petanque.life";
const string ClientId = "acme-integration";
const string Kid = "2026-04-primary";
var tokenEndpoint = $"{BaseUrl}/auth/token";
// Load key
var ecdsa = ECDsa.Create();
ecdsa.ImportFromPem(File.ReadAllText("client-private-key.pem"));
// Get access token
var handler = new JwtSecurityTokenHandler();
var assertion = handler.CreateEncodedJwt(new SecurityTokenDescriptor {
Issuer = ClientId,
Subject = new ClaimsIdentity(new[] {
new Claim("sub", ClientId),
new Claim("jti", Guid.NewGuid().ToString()),
}),
Audience = tokenEndpoint,
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(2),
SigningCredentials = new SigningCredentials(
new ECDsaSecurityKey(ecdsa) { KeyId = Kid },
SecurityAlgorithms.EcdsaSha256),
});
using var http = new HttpClient();
var tokenResp = await http.PostAsync(tokenEndpoint, new FormUrlEncodedContent(new[] {
KeyValuePair.Create("grant_type", "client_credentials"),
KeyValuePair.Create("client_id", ClientId),
KeyValuePair.Create("client_assertion_type",
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
KeyValuePair.Create("client_assertion", assertion),
KeyValuePair.Create("scope", "bookings:read"),
}));
tokenResp.EnsureSuccessStatusCode();
var tokenData = await tokenResp.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = tokenData.GetProperty("access_token").GetString()!;
Console.WriteLine($"Expires in: {tokenData.GetProperty("expires_in")}s");
// Call API
http.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var bookings = await http.GetFromJsonAsync<JsonElement>($"{BaseUrl}/bookings/");
Console.WriteLine($"Found {bookings.GetProperty("total")} bookings");Node SDK Skeleton
Complete working example using ES modules.
// npm install jose
import { importPKCS8, SignJWT } from 'jose'
import { readFile } from 'fs/promises'
const BASE = 'http://api.petanque.life'
const CLIENT_ID = 'acme-integration'
const KID = '2026-04-primary'
const TOKEN_ENDPOINT = `${BASE}/auth/token`
const privateKey = await importPKCS8(
await readFile('client-private-key.pem', 'utf8'),
'ES256'
)
// Get access token
const assertion = await new SignJWT({
sub: CLIENT_ID,
jti: crypto.randomUUID(),
})
.setProtectedHeader({ alg: 'ES256', kid: KID })
.setIssuer(CLIENT_ID)
.setAudience(TOKEN_ENDPOINT)
.setIssuedAt()
.setExpirationTime('2m')
.sign(privateKey)
const tokenResp = await fetch(TOKEN_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: assertion,
scope: 'bookings:read',
}),
})
if (!tokenResp.ok) {
const err = await tokenResp.json()
console.error(`Token error: ${err.error} — ${err.error_description}`)
process.exit(1)
}
const { access_token, expires_in } = await tokenResp.json()
console.log(`Token expires in ${expires_in}s`)
// Call API
const bookings = await fetch(`${BASE}/bookings/`, {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json())
console.log(`Found ${bookings.total} bookings`)
for (const b of bookings.items) {
console.log(` ${b._id} — ${b.status ?? 'unknown'}`)
}cURL Workflow
Complete bash script for testing and debugging.
Requires: openssl, jq, curl.
#!/bin/bash
set -euo pipefail
CLIENT_ID="acme-integration"
KID="2026-04-primary"
TOKEN_ENDPOINT="http://api.petanque.life/auth/token"
PRIVATE_KEY="client-private-key.pem"
# --- Build JWT ---
HEADER=$(echo -n '{"alg":"ES256","kid":"'$KID'","typ":"JWT"}' \
| openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
NOW=$(date +%s)
EXP=$((NOW + 120))
JTI=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || uuidgen)
PAYLOAD=$(echo -n '{"iss":"'$CLIENT_ID'","sub":"'$CLIENT_ID'","aud":"'$TOKEN_ENDPOINT'","jti":"'$JTI'","iat":'$NOW',"exp":'$EXP'}' \
| openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
# --- Sign ---
SIGNATURE=$(echo -n "$HEADER.$PAYLOAD" \
| openssl dgst -sha256 -sign "$PRIVATE_KEY" \
| openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
ASSERTION="$HEADER.$PAYLOAD.$SIGNATURE"
# --- Get token ---
TOKEN_RESPONSE=$(curl -s -X POST "$TOKEN_ENDPOINT" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=$ASSERTION" \
-d "scope=bookings:read")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
if [ "$ACCESS_TOKEN" = "null" ]; then
echo "Error:" >&2
echo "$TOKEN_RESPONSE" | jq . >&2
exit 1
fi
echo "Token type: $(echo "$TOKEN_RESPONSE" | jq -r '.token_type')"
echo "Expires in: $(echo "$TOKEN_RESPONSE" | jq -r '.expires_in')s"
echo "Scope: $(echo "$TOKEN_RESPONSE" | jq -r '.scope')"
# --- Call API ---
echo ""
echo "=== Bookings ==="
curl -s "http://api.petanque.life/bookings/" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.total'UI Authentication
UI applications (admin, portal, end-user app) use interactive authentication via OTP (email/SMS), OAuth2 (Google, Microsoft), or BankID. This is not relevant for M2M integrations. For details on UI auth flows, see the framework specification.
/partners
A partner represents a management company (forvaltare) that manages multiple tenants (property owners). Partners are system-level entities — they are not scoped to any tenant. Users with scope='partner' can access data across all tenants linked to their partner.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | Display name of the partner organization |
slug | string | required | URL-safe unique identifier for the partner |
description | string = null | Brief description of the partner organization | |
contact_email | string = null | Primary contact email for the partner | |
contact_phone | string = null | Primary contact phone for the partner | |
is_enabled | boolean = True | Whether this partner is active in the system | |
logo_url | string = null | URL to the partner's logo image | |
primary_color | string = null | Primary brand color in hex format (e.g. #2563eb) |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /partners/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"slug": "..."
}/tenants
A tenant / customer / organization using the system.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | |
slug | string | required | |
is_enabled | boolean = True | ||
branding | string | ||
enabled_features | array | ||
default_currency | string | ISO 4217 currency code | |
enabled_currencies | array | List of ISO 4217 codes this tenant accepts | |
partner_id | ObjectId = null | FK | Partner (management company) managing this tenant |
partner_name | string = null | readonly | Cached name of the partner organization |
parent_tenant_id | ObjectId = null | FK | Parent tenant ID. Null = root tenant (no parent). |
tenant_path | string | Materialized path — comma-separated ancestor tenant IDs from root. Example: 'rootId,childId' for a grandchild. | |
depth | integer = 0 | Depth in the hierarchy. 0 = root tenant. | |
sublease_negative_amount_strategy | string = reject | Strategy for negative amounts in sublease calculations: 'reject' (raise error), 'clamp_zero' (set to 0 and log), 'warn' (allow but log warning). | |
ai_monthly_budget_usd | decimal = null | Monthly AI report budget in USD. Null = no limit. | |
ai_reports_enabled | boolean = True | Whether AI reports are enabled for this tenant. | |
max_users | integer = null | ||
max_storage_mb | integer = null |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
partner_id | /partners | null |
parent_tenant_id | /parent-tenants | deny |
Auto-Updated Fields
These readonly fields are kept in sync automatically when the source changes.
| Field | Source |
|---|---|
partner_name | partner_id.name |
Create Example
POST /tenants/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"slug": "..."
}/users
User in the system. Simplified — no fixed organization hierarchy. Projects define their own organizational structure using Tags and custom models with CascadeConfig.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | |
email | string = null | ||
phone | string = null | ||
description | string = null | ||
personal_id | string = null | ||
role | string = null | ||
email_oauth | string = null | ||
oauth_provider | string = null | ||
scope | string = tenant | Access scope: 'system' (all data), 'partner' (partner tenants), 'tenant' (single tenant) | |
partner_id | ObjectId = null | FK | Partner ID — required when scope='partner', ignored otherwise |
org_scope_id | ObjectId = null | FK | OrgNode ID — user sees data for this node and descendants only |
is_enabled | boolean = True | ||
system_user | boolean = False | ||
public_user | boolean = False |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
partner_id | /partners | none |
org_scope_id | /org-scopes | none |
Create Example
POST /users/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "..."
}/roles
A named collection of capabilities. Can inherit from other roles. System roles (is_system=True) are seeded in code and cannot be modified via API.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | ||
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | |
display_name | string | required | |
description | string = null | ||
capabilities | array | ||
inherits_from | array | ||
is_system | boolean = False |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /roles/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"display_name": "..."
}/role-assignments
Assigns a role to a user within a scope and a time period. A user can have multiple RoleAssignments — they accumulate into an effective capability set.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
user_id | ObjectId | required FK | |
role_name | string | required | |
scope_type | string = tenant | ||
scope_id | ObjectId = null | FK | |
valid_from | datetime | ||
valid_until | datetime = null | ||
assigned_by | ObjectId = null | ||
reason | string = null |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
user_id | /users | none |
scope_id | /scopes | none |
Create Example
POST /role-assignments/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"user_id": "64a1b2c3d4e5f6789012abcd",
"role_name": "..."
}/imports/templates
Defines how to parse and map an import file to API resources. Templates describe the source file format, field mappings, and target resource configuration. They are reusable across multiple import runs.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | Template name, e.g. 'Bank payments CSV' |
description | string = null | Human-readable description of this template | |
source_id | ObjectId = null | FK | Reference to the ImportSource this template belongs to (1 source → N templates) |
file_matcher | string | Criteria for matching incoming files to this template | |
priority | integer = 0 | Match priority — higher wins when multiple templates match the same file | |
is_active | boolean = True | Inactive templates are skipped by the matcher engine | |
file_type | string | required | Source file type: 'csv', 'excel', 'json', 'xml', 'fixed_width' |
format | string = csv | Parser format key used by ParserRegistry: 'csv', 'json', 'xml', 'flat_file'. Supersedes file_type for the streaming parser layer. | |
parser_config | object | Format-specific parser options passed to the parser constructor. CSV: {delimiter, quote_char, has_header}. JSON: {records_path, mode}. XML: {record_tag, namespaces}. Flat-file: {post_types, strict_post_types}. | |
delimiter | string = , | Column delimiter for CSV files | |
encoding | string = utf-8 | File encoding | |
has_header | boolean = True | Whether the file has a header row | |
skip_rows | integer = 0 | Number of rows to skip at the beginning | |
sheet_name | string = null | Sheet name for Excel files | |
column_widths | integer | Column widths for fixed-width files | |
field_mapping | array | List of field mappings from source to target (legacy) | |
mapping | array | Ordered list of mapper configurations. Each entry: {"type": " | |
target_resource | string | required | Target API resource, e.g. 'products', 'customers' |
import_mode | string = create | Import mode: 'create', 'upsert', 'update', 'sync', or 'append' | |
upsert_key | string = null | Field to match on for upsert/update/sync mode | |
default_values | object | Fixed values applied to every row after field_mapping. E.g. {'category_id': 'abc', 'status': 'active'} | |
scope_filter | object | Filter for sync mode: which existing records to compare against. E.g. {'category_id': 'abc'} | |
delete_column | string = null | Column name in the file that indicates deletion in upsert mode. Values 'true'/'1'/'yes'/'delete' trigger soft delete. | |
auto_execute | boolean = False | Run import automatically after validation (for SFTP flows) | |
is_portal_visible | boolean = False | Whether this template is visible in the portal for property owners | |
portal_label | string = null | Simplified name shown in the portal, e.g. 'Import products' | |
portal_description | string = null | Short description for portal users | |
required_columns | array | Columns that must be present in the source file | |
validation | string | Five-layer validation engine config: schema (JSON Schema), row_rules (regex/IBAN/BIC/orgnr/personnr/date_range/one_of/luhn), cross_row_rules (aggregates + header checks), business_rules (read-only API lookups), plugins (entry-point callables). | |
locale | string = sv | Default locale for validation messages ('sv', 'en', etc.) | |
crypto | string | Pre-flight crypto configuration: decompression, PGP/GPG decryption, and signature verification applied before parsing. | |
pre_transform | string = null | Python expression for row-level pre-transform | |
shared_from_tenant_id | ObjectId = null | FK | If set, this template is owned by a parent tenant and shared (read-only) to its sub-tenants. Sub-tenants may use the template but not modify it. |
post_process_policy | string = keep | What happens with the source file after a run: 'keep' (leave in place, system tracks via ImportRun.source_name), 'move' (move successful to completed_folder, failed to error_folder). | |
completed_folder | string = null | Relative folder under SFTP source where successful files are moved (requires post_process_policy='move'). | |
error_folder | string = null | Relative folder where files are moved on total failure (parse, schema, all rows rejected). Requires post_process_policy='move'. | |
ignored_folders | array | Relative folders that the source skips entirely when polling. Files in these folders never trigger an import. | |
temp_file_extensions | array | File extensions indicating an ongoing upload — the runner waits for the rename. | |
assert_empty | boolean = False | If True: this file is expected to be empty. If it contains rows a warning run is created and operators are notified. Used for reconciliation exception files. | |
transaction | string | Transactional execution config: mode (best_effort/all_or_nothing/batched), batch_size, max_transaction_rows, stop_on_error. | |
idempotency | string | Idempotency key config: natural_key_fields for deterministic per-row duplicate detection across re-runs. | |
retention_policy_id | ObjectId = null | FK | Reference to a RetentionPolicy. When None, the tenant default policy is used. |
retention_category | string = RetentionCategory.FINANCIAL | Retention category — determines the default retention period when no explicit policy is set | |
offload_policy | string | Controls when files are offloaded to craft-easy-jobs for async processing. Files exceeding inline_max_size_mb or inline_max_estimated_rows are queued. | |
schedule_expectation | string = null | Expected delivery schedule with cron syntax and tolerance window. When set, the SLA monitor job checks for missed deliveries. |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
source_id | /sources | none |
shared_from_tenant_id | /shared-from-tenants | none |
retention_policy_id | /retention-policys | none |
Create Example
POST /imports/templates/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"file_type": "standard",
"target_resource": "..."
}/imports/sources
A file source (SFTP server, watched directory, cloud bucket, email inbox, HTTP endpoint) that can feed files to one or more ImportTemplates. The relationship is 1:many — templates reference their source via ``ImportTemplate.source_id``.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | Human-readable source name, e.g. 'Bank A SFTP inbox' |
source_type | string | required | Source type: 'sftp', 'watched_directory', 's3', 'azure_blob', 'gcs', 'email_inbox', 'http_pull' |
connection_config | object | Type-specific connection parameters (host, path, credentials ref, etc.). Secrets must be referenced via credential_name, never stored inline. | |
is_active | boolean = True | Whether this source is polled | |
polling_interval_seconds | integer = 300 | Seconds between poll cycles (default 5 minutes) | |
event_driven | boolean = False | If True, subscribe_events() is preferred over polling. Polling runs as fallback if the event stream fails. | |
last_successful_poll_at | datetime = null | Timestamp of the last successful poll or event batch | |
last_error | string = null | Last error message from polling or health check (cleared on success) | |
move_unmatched_to_error | boolean = True | Move files without a template match to the error folder |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /imports/sources/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"source_type": "standard"
}/rejected-records
A record rejected during import — stored for review and correction.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
import_run_id | ObjectId | required FK | Parent import run |
template_id | ObjectId | required FK | Import template used |
row_number | integer | required | Row number in the source file |
original_data | object | Original row data as parsed | |
validation_errors | array | List of validation errors (field + message) | |
status | string = pending | Status: 'pending', 'corrected', 'retried', 'discarded' | |
corrected_data | object = null | Manually corrected data for retry |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
import_run_id | /import-runs | none |
template_id | /templates | none |
Create Example
POST /rejected-records/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"import_run_id": "64a1b2c3d4e5f6789012abcd",
"template_id": "64a1b2c3d4e5f6789012abcd",
"row_number": "1"
}/alert-channels
A named alert destination (log, email, Slack, Teams, PagerDuty, webhook). Resolved by name from ``ScheduleExpectation.alert_channels`` or matched via ``AlertRoutingRule``. Config is a free-form dict whose schema depends on the channel type. Rate limiting and quiet hours prevent alert storms and out-of-hours noise.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
name | string | required | Channel name, e.g. 'ops-slack', 'finance-teams' |
type | string | required | Dispatch type |
config | object | Type-specific config (webhook_url, email, credential_name, ...) | |
is_active | boolean = True | Whether this channel accepts alerts | |
max_alerts_per_5min | integer = 10 | Maximum alerts dispatched to this channel per 5-minute window | |
quiet_hours_start | string = null | Start of quiet period in HH:MM format (e.g. '22:00') | |
quiet_hours_end | string = null | End of quiet period in HH:MM format (e.g. '07:00') | |
quiet_hours_severity_override | string = critical | During quiet hours, only alerts at or above this severity are sent |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /alert-channels/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"type": "standard"
}/alert-routing-rules
Declarative routing rule that maps alert events to channels. When an alert event is dispatched, all active rules for the tenant are evaluated in priority order. A rule matches if the event's type is in ``event_types``, its severity is in ``severity``, and all ``tags`` key-value pairs match the event's tags. All matched rules' ``channel_ids`` are collected (deduplicated) and alerts are dispatched to each resolved channel.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | object | Tag key-value pairs that must all match the event's tags | |
name | string | required | Rule name for display, e.g. 'finance-critical-to-pagerduty' |
priority | integer = 0 | Higher priority rules are evaluated first | |
event_types | array | required | Event types this rule matches, e.g. ['sla_violation', 'parse_error'] |
severity | array | required | Severity levels this rule matches, e.g. ['warning', 'critical'] |
channel_ids | array | required | AlertChannel IDs to dispatch to when this rule matches |
is_active | boolean = True |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /alert-routing-rules/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"name": "...",
"event_types": "standard",
"severity": "...",
"channel_ids": "..."
}/tenant-configs
Per-tenant (federation or standalone club) configuration. Each tenant configures its own OrgNode hierarchy depth, terminology, currency, season dates, languages, and federation metadata.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
tenant_type | string = null | Tenant classification (PL-T001). None for legacy tenants that have not been backfilled yet — treated as FEDERATION. | |
migration_source | string = null | Records how this tenant was created or where it was migrated from (PL-T001). Standalone clubs get {'created_as': 'standalone_club'} at creation. | |
archived | boolean = False | Whether this tenant is archived (PL-T001, PL-T004). Set to true after a standalone club is migrated or an event tenant's series has concluded. Archived tenants are read-only for audit purposes. | |
is_read_only | boolean = False | Whether this tenant is in read-only mode (PL-T010). Set to true when a club tenant has been migrated into a federation tenant. Data remains accessible for audit but no mutations are allowed. | |
lifecycle_state | string = active | Subscription lifecycle state (PL-T031). 'active' = normal operation; 'read_only' = subscription ended, data-export window open; 'archived' = export window ended, pending GDPR deletion; 'deleted' = data purged (GDPR retention period elapsed). | |
lifecycle_reason | string = null | Why the tenant entered a non-active lifecycle_state (PL-T047). Allows banner and email templates to distinguish voluntary cancellation from involuntary suspension due to overdue payments. | |
read_only_since | datetime = null | UTC timestamp when the tenant entered read_only state (PL-T031). Set by the subscription_read_only_transition_job. | |
subscription_archived_at | datetime = null | UTC timestamp when the tenant was archived after the read-only export window ended (PL-T031). Distinct from 'archived' (migration). | |
is_demo | boolean = False | Whether this tenant is a demo/sales-demo tenant (PL-T038). When true, all public views display a 'DEMO — simulated data' banner. Demo tenants are never indexed by search engines and live exclusively in the staging environment. | |
demo_banner_text | string = null | Custom demo banner text (PL-T038). If None, the default 'DEMO — simulerad data / simulated data' is shown. | |
migration_consent | string = null | Consent record for club-to-federation migration (PL-T010). Populated when the club admin accepts a migration invitation. | |
event_tenant_lifespan | string = null | Lifecycle configuration for event tenants (PL-T004). Only populated when tenant_type == EVENT. | |
event_tenant_invoice_config | string = null | Billing / invoice configuration for event tenants (PL-T004). Only populated when tenant_type == EVENT. | |
linked_venue_tenant_ids | array | Cross-reference links to venue tenants (PL-T004). Read-only consultation links — the venue does not own event data. | |
linked_club_or_federation_tenant_ids | array | Cross-reference links to club/federation host tenants (PL-T004). Read-only consultation links — the host does not own event data. | |
org_hierarchy_depth | integer = 1 | ||
org_node_types | array | ||
autonomous_substructure | boolean = False | When True, top-level districts are created with full autonomy flags (financial, discipline, ranking, pricing) enabled by default during onboarding (PL-T006). Used by federations like Spain where autonomous communities operate near-independently. | |
default_currency | string = EUR | ||
season_start_month | integer = 1 | ||
season_start_day | integer = 1 | ||
terminology | object | ||
supported_languages | array | ||
default_language | string = en | ||
country_code | string | required | ISO 3166-1 alpha-2 |
federation_type | string = national | 'national', 'continental', or 'world' | |
federation_name | string | Human-readable federation name, e.g. 'Svenska Bouleförbundet' | |
federation_status | string = active | ||
season_type | string = calendar_year | Default season type for this federation: 'calendar_year' (Jan–Dec), 'split_year' (e.g. Sep–Aug), or 'custom'. Used when auto-generating seasons (F03.01.15). | |
grace_period_days | integer = 0 | Default grace period (days after season end) for late license renewals (F03.01.11). Applied to new seasons when auto-generated. | |
license_number_format | string = null | Format string for license numbers. Placeholders: {country_code}, {year}, {seq}. Example: '{country_code}-{year}-{seq:06d}'. Defaults to '{country_code}-{year}-{seq:06d}' if not set. | |
umpire_grade_config | string | Configurable umpire grade system for this federation | |
transfer_config | string | Configurable transfer rules for intra-national club transfers | |
insurance_config | string | Configurable insurance requirements for this federation | |
medical_certificate_config | string | Configurable medical certificate requirements for this federation | |
unauthorized_player_penalty_config | string | Configurable penalties for unauthorized player violations (F03.01.20) | |
international_license_config | string | Configurable international license issuance settings (F03.01.18) | |
license_rule_config | string | Per-national license rules: issuer, approval chain, system toggle (F03.06) | |
sanction_config | string | Per-tenant sanction configuration: deadlines, quotas, fees, blackouts (F04.02.20-24) | |
temporary_license_config | string = null | Per-tenant temporary license / day pass configuration (F04.03.10) | |
disciplinary_config | string = null | Disciplinary structure and investigation process per nation (F05.07) | |
federation_export_configs | array | Per-tenant federation result export format configurations (F04.06.06). First entry is the default format. | |
league_config | string | Per-tenant league/series default configuration (F04.08) | |
award_voting_config | string = null | Per-tenant award voting configuration (F04.14.09) | |
ranking_algorithm_config | string = null | Per-tenant ranking algorithm configuration (F16.03.07) | |
locale_formatting_config | string | Per-tenant locale-aware formatting for dates, numbers, currency (F16.03.14) | |
branding_config | string | Per-tenant visual branding: logo, colours, fonts (F16.03.16) | |
game_variant_configs | array | Per-tenant game variant configurations (F16.03.18). Each entry enables and configures a game variant (pétanque, jeu provençal, sport-boules) for this federation. | |
branch_hierarchy_overrides | array | Per-branch OrgNode hierarchy depth overrides (F16.03.19). For nations with non-uniform hierarchy depth (e.g. Spain: Canary Islands have extra insular level). | |
fipjp_passport_sync_enabled | boolean = True | When true, new license issuances in this tenant trigger automatic passport creation/linking in the FIPJP tenant (PL-T009). | |
fipjp_passport_sync_endpoint | string = null | Base URL of the FIPJP tenant's passport API for M2M sync calls. Example: 'https://api.petanque.life/fipjp'. None = sync disabled regardless of fipjp_passport_sync_enabled. | |
fipjp_m2m_credentials_secret_ref | string = null | Reference to the secret (Azure Key Vault or env var) that holds the M2M client credentials for FIPJP passport sync (PL-T009). | |
fipjp_referee_publish_enabled | boolean = True | When true, umpire certifications in this tenant are published to the FIPJP Global Referee Registry via the daily sync job (PL-T015). | |
onboarding_completed_at | datetime = null | UTC timestamp when the tenant admin completed the first-run wizard (PL-T057). When set, the wizard disappears from admin navigation. | |
onboarding_steps_completed | datetime | Per-step completion timestamps for the admin first-run wizard (PL-T057). Keys: 'tenant_basics', 'org_hierarchy', 'seasons', 'license_types', 'stripe_connect', 'import_data'. Allows resuming the wizard from the last incomplete step. | |
stripe_connect_account_id | string = null | Stripe Connect Express account ID for this tenant (PL-T057). Set by the account.updated webhook after Connect onboarding completes. | |
tournament_refund_policy | string = null | Refund policy applied when a player cancels a tournament entry (PL-T063). full_until_deadline — full refund until registration_closes_at, none after. partial_before_event_week — 50 % refund up to 7 days before event start, none thereafter. no_refund — no refund ever. Null = per-type default: 'full_until_deadline' for club tenants, 'partial_before_event_week' for federation tenants. | |
oauth_providers | array | Per-tenant OAuth provider overrides (PL-T206). Empty list means fall back to the platform default — every gateway-configured provider is visible in every application. When non-empty, only the providers listed here are surfaced, scoped to the listed applications. Used by federations that want a curated set of providers per surface (e.g. FFPJP showing only Microsoft on admin-login because operators all use Office 365). |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /tenant-configs/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"country_code": "..."
}/seasons
Represents a competition season within a tenant (federation). Each tenant has exactly one active season at any time. Seasons are typically aligned with the federation's configured season_start_month/day, but dates can be customised per season. F03.01.15 — Season type tracks how the federation configures its seasons (calendar year, split year, or custom). F03.01.11 — Grace period days allows late renewals after season end.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
year | integer | required | Primary year, e.g. 2025 |
start_date | datetime | required | Season start date |
end_date | datetime | required | Season end date |
status | string = upcoming | 'upcoming', 'active', or 'closed' | |
season_type | string = calendar_year | How this season's boundaries are defined: calendar_year, split_year, or custom | |
license_renewal_open_date | datetime = null | Date when license renewal opens for this season | |
registration_deadline | datetime = null | Last date to register for this season | |
grace_period_days | integer = 0 | Number of days after season end during which late renewals are still accepted (F03.01.11). 0 = no grace period. |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /seasons/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"year": "1",
"start_date": "2026-04-01T08:00:00Z",
"end_date": "2026-04-01T08:00:00Z"
}/i18n/bundles
A set of translations for a specific language and namespace. Stores tenant-specific translation overrides (e.g. federation terminology) and community-contributed translations for additional languages.
Fields
| Name | Type | Flags | Description |
|---|---|---|---|
revision_id | string = null | ||
created_at | datetime | ||
updated_at | datetime | ||
tenant_id | ObjectId = null | readonly | |
is_deleted | boolean = False | ||
deleted_at | datetime = null | ||
is_depersonalized | boolean = False | ||
depersonalized_at | datetime = null | ||
external_id | string = null | ||
tags | ObjectId | ||
language | string | required | ISO 639-1 language code, e.g. 'sv', 'fr' |
namespace | string = ui | Translation namespace: 'ui', 'content', 'email', etc. | |
translations | object | Flat key-value translations, e.g. {'common.loading': 'Laddar...'} | |
is_complete | boolean = False | Whether all reference keys are translated | |
completeness_percent | integer = 0 | Percentage of reference keys that are translated | |
contributor | string = null | Who contributed these translations |
Relationships
| Field | References | On Delete |
|---|---|---|
tenant_id | /tenants | none |
Create Example
POST /i18n/bundles/
Content-Type: application/json
Authorization: Bearer eyJ...
{
"language": "..."
}