# General Information

### Overview

Use the Live Data Golf API over REST or WebSocket.

Clients authenticate with a JWT issued by Common IAM. See [Common IAM Guide](/live-data/live-data-golf-api-design/ld-golf-api-documentation/common-iam-guide.md) for token setup, token reuse, and renewal guidance.

### Quick reference

* Authentication: JWT bearer token from Common IAM
* REST base pattern: `https://{domain}/golf/rest/v1/...`
* WebSocket base pattern: `wss://{domain}/golf/stream/v1/...`
* WebSocket messages: JSON objects wrapped in a CloudEvents envelope
* Error handling: HTTP status codes for REST, close frames for WebSocket
* Heartbeats: server sends every `10–20` seconds, client sends every `30` seconds

### Connect to REST or WebSocket endpoints

Send the JWT in the `Authorization` header as a bearer token.

#### REST connection

Example request:

{% code title="REST request" overflow="wrap" %}

```http
GET /golf/rest/v1/tournaments/1971 HTTP/1.1
Host: {domain}
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
```

{% endcode %}

#### WebSocket connection

The WebSocket handshake also uses the `Authorization` header.

{% code title="WebSocket handshake" overflow="wrap" %}

```http
GET /golf/stream/v1/tournaments/1971/round/1/events HTTP/1.1
Host: {domain}
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <generated-random-key>
Sec-WebSocket-Version: 13
Authorization: Bearer <JWT_TOKEN>
```

{% endcode %}

### Initial snapshot on WebSocket streams

WebSocket stream endpoints send the current state for the requested resource before they continue with incremental updates.

Depending on the resource, the client may need to send an initialization message first. For live event streams, the client sends `Client.Init`. That message can include `last_seen_event_id` to resume after a reconnect. See [Live Events](/live-data/live-data-golf-api-design/ld-golf-api-documentation/live-events/live-events.md) for details.

Typical snapshot content includes:

* all currently available events for the resource
* the current leaderboard
* the current hole-by-hole state

### WebSocket message envelope

WebSocket stream endpoints send JSON messages. Golf data is wrapped in a [CloudEvents](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md) envelope.

Example envelope:

{% code title="CloudEvents envelope" overflow="wrap" %}

```json
{
  "specversion": "1.0",
  "id": "0da2b5ba-b92f-42bd-b9d2-0fcd978fec85",
  "source": "/tournaments/1971",
  "type": "Event.Sport.Golf",
  "time": "2026-05-04T14:23:01.123Z",
  "tournamentid": 1971,
  "datacontenttype": "application/json",
  "data": {}
}
```

{% endcode %}

Field names are case-sensitive. For tournament-scoped messages, the envelope uses `tournamentid`.

| **Name**          | **Type**           | **Description**                                                                                                     |
| ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `specversion`     | String             | CloudEvents specification version.                                                                                  |
| `id`              | String (UUID)      | Unique identifier of the message.                                                                                   |
| `source`          | String             | Event source. Golf tournament messages use `/tournaments/{tournament_id}`. Heartbeats use `/system`.                |
| `type`            | String             | Event type, such as `Event.Sport.Golf` or `System.Heartbeat`.                                                       |
| `time`            | String (date-time) | Timestamp when the message was generated.                                                                           |
| `tournamentid`    | Integer            | Tournament identifier for tournament-scoped messages. This field is omitted for system messages such as heartbeats. |
| `datacontenttype` | String             | Content type of `data`, for example `application/json`.                                                             |
| `data`            | Object             | Event payload. The structure depends on the specific resource and event type.                                       |

### Error handling

The API returns different error signals for REST and WebSocket transports.

Common causes include:

* invalid or expired tokens
* invalid `tournamentId`, `stageId`, or `matchId`
* access to a tournament not included in your entitlement
* resources that are no longer available
* too many simultaneous connections

#### REST errors

REST endpoints return standard HTTP status codes and a JSON response body with more detail.

{% code title="REST error response" overflow="wrap" %}

```json
{
  "reason": "Resource not found",
  "details": "Tournament with id 9999 does not exist.",
  "status": 404
}
```

{% endcode %}

| **HTTP status code** | **Reason**         | **What to do**                                                                                                                              |
| -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `401`                | Invalid token      | Refresh or replace the token. Check [Common IAM Guide](/live-data/live-data-golf-api-design/ld-golf-api-documentation/common-iam-guide.md). |
| `403`                | Forbidden          | Verify entitlement for the requested resource. Contact Sportradar support if needed.                                                        |
| `404`                | Resource not found | Check the requested identifier. Confirm that the resource still exists and is available to your account.                                    |

#### WebSocket errors

WebSocket stream endpoints do not send JSON error messages. They terminate the connection with a close frame. Application-specific error codes use the `4000–4999` range defined for private use by RFC 6455.

Example:

`Server → Client: close frame [4401, "Invalid token"]`

The client should inspect the close code and decide whether to reconnect.

| **Code** | **Reason**           | **What to do**                                                                                           |
| -------- | -------------------- | -------------------------------------------------------------------------------------------------------- |
| `4029`   | Too many connections | Close unused connections before reconnecting.                                                            |
| `4401`   | Invalid token        | Refresh or replace the token, then open a new connection.                                                |
| `4403`   | Forbidden            | Verify entitlement for the requested resource. Contact Sportradar support if needed.                     |
| `4404`   | Resource not found   | Check the requested identifier. Confirm that the resource still exists and is available to your account. |

The close frame always ends the session. No further messages can be exchanged after it is sent.

### WebSocket heartbeat mechanism

All WebSocket stream endpoints use an application-level heartbeat. This heartbeat is separate from WebSocket ping and pong frames.

* Server heartbeat interval: approximately every `10–20` seconds
* Client heartbeat interval: every `30` seconds
* Client reconnect threshold: `60` seconds without any inbound message
* Server disconnect threshold: `90` seconds without a client heartbeat

#### Server heartbeat

The server sends heartbeat messages as CloudEvents with `type` set to `System.Heartbeat`.

These messages:

* use `source` = `/system`
* do not include `tournamentid`
* indicate that the event stream pipeline is still healthy

If the client receives no message for `60` seconds, including heartbeats and domain events, it should treat the stream as unhealthy and reconnect.

{% code title="Server heartbeat" overflow="wrap" %}

```json
{
  "specversion": "1.0",
  "id": "0da2b5ba-b92f-42bd-b9d2-0fcd978fec85",
  "source": "/system",
  "type": "System.Heartbeat",
  "time": "2026-05-04T14:23:01.123Z",
  "datacontenttype": "application/json",
  "data": {
    "heartbeat_time": "2026-05-04T14:23:01.123Z"
  }
}
```

{% endcode %}

| **Name**         | **Type**           | **Description**                                    |
| ---------------- | ------------------ | -------------------------------------------------- |
| `heartbeat_time` | String (date-time) | Timestamp when the server generated the heartbeat. |

#### Client heartbeat

Clients must send a heartbeat every `30` seconds to confirm that they are still consuming the stream. The client heartbeat is a plain JSON object. It is not a CloudEvent.

{% code title="Client heartbeat" overflow="wrap" %}

```json
{
  "type": "Client.Heartbeat"
}
```

{% endcode %}

If the server does not receive a client heartbeat within `90` seconds, it closes the connection with status code `1000`. That code indicates a normal connection closure.

### Client implementation checklist

* Cache and reuse JWTs until they near expiry
* Send resource-specific initialization messages where required
* Reset the inbound timeout on every received message
* Send `Client.Heartbeat` every `30` seconds
* Reconnect with backoff after transient failures


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sportradar.com/live-data/live-data-golf-api-design/ld-golf-api-documentation/general-information.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
