General guide
Authentication, response envelope, paging, rate limits and errors shared by all REST endpoints.
Authentication
Every request needs your API key, preferably in the X-API-Key header. Authorization: Bearer <key> also works. The ?key= query parameter is still accepted but discouraged: the key ends up in URLs, browser history and the logs of any proxy on the way, so use it for ad-hoc debugging only. Keep the key on your server, never in front-end code.
curl "https://api.sports.csap.ai/api/v1/categories?limit=1" -H "X-API-Key: YOUR_API_KEY"
Response envelope
Every endpoint returns a JSON envelope; the HTTP status matches code (200 / 0 on success).
{
"code": 0,
"message": "success",
"success": true,
"time": 1794201504407,
"data": [
{ "id": 1, "name_en": "England", "alpha2": "EN", "slug": "england", "priority": 10, "updated_at": 1794136080165 }
]
}{
"code": 404,
"message": "unknown interface /api/v1/nope",
"success": false,
"time": 1794201504847,
"data": []
}| code | integer | 0 on success; otherwise equals the HTTP status |
| message | string | "success" or the error reason |
| success | boolean | true on success |
| time | integer | Server time, Unix milliseconds |
| data | array | Rows (a list for most endpoints, an object for a few summary endpoints) |
Paging and incremental sync
List endpoints return at most limit rows (default and maximum 1000).
Full sync: start at id=1 and use the largest id of the page + 1 as the next id until fewer than limit rows come back.
Incremental: pass time=
Rate limits
Per key: requests per minute (rate_per_min) and a daily quota (quota_daily), set by your plan. Exceeding them returns HTTP 429 with rate limit exceeded or daily quota exceeded.
Sync lists incrementally by id / time and use WebSocket / SSE / MQTT for live data instead of polling.
Scope of external keys
| Available | Any valid API key can call this endpoint. |
| Available (scoped) | External keys can call it, but only data inside the open scope is returned. |
| Requires entitlement | The endpoint and its data domain must be granted to the key; otherwise 403. |
| Internal only | Internal use only; external keys get 403 interface is internal only. |
- Only matches inside the open coverage are returned; others return 404 by id.
- Logo fields only carry platform-hosted URLs (/logos/… or /logo/{type}/{id}); empty string otherwise.
- Highlight videos, the animation widget and lottery endpoints are not open to external keys (403).
- Old match ids that were merged return the new match id.
- The source field in rows is a source code (S1, S2, …), not a source name.
Errors
| HTTP | message | When |
|---|---|---|
| 400 | bad param … | Malformed parameter (e.g. non-numeric id) |
| 401 | missing API key / unauthorized | Missing, invalid or disabled key |
| 403 | interface is internal only | Internal endpoint |
| 403 | explicit endpoint and data-domain entitlement required | Endpoint or data domain not granted |
| 403 | source IP not allowed for this API key | Client IP not in the key allowlist |
| 404 | not found | Entity not found or outside the key scope |
| 404 | unknown interface … | Unknown path |
| 429 | rate limit exceeded | Per-minute rate limit exceeded |
| 429 | daily quota exceeded | Daily quota exceeded |
| 500 | query error | Server-side query failure; retry later |