# Quickstart

https://gorally.games/en/developers/quickstart

This guide takes you from nothing to a category’s standings, read through the API. It takes about ten minutes.

## Before you start

- Your organization has the Leagues plan: it is what allows issuing a key.
- You manage the organization: only those people see the Integrations screen.
- Your software runs on a server. The API does not answer calls from a browser.

There is no sandbox. An `rk_live_` key acts on your organization’s real data. So start with a `read` key, which cannot change anything.

## Create a key

Rally Leagues screens are in French. Labels are quoted as they appear, with a translation.

1. In Rally Leagues, open your organization’s page.
2. Click “Réglages : intégrations (clés d’API et webhooks)” (Settings: integrations).
3. In “Émettre une clé” (Issue a key), give it a name, such as your software’s name.
4. Check only the `read` permission.
5. Click “Émettre la clé” (Issue the key).
6. Copy the secret with “Copier le secret” (Copy the secret). Rally shows it only once.

Store the secret in an environment variable on your server, never in your source code. The examples in this guide read it from `RALLY_API_KEY`.

## First call: list your leagues

Every operation starts from `https://gorally.games/v1`. The key travels in the `Authorization` header.

**curl**

```bash
curl https://gorally.games/v1/leagues \
  -H "Authorization: Bearer $RALLY_API_KEY"
```

**JavaScript**

```js
const response = await fetch('https://gorally.games/v1/leagues', {
  headers: {
    Authorization: `Bearer ${process.env.RALLY_API_KEY}`,
  },
});
const data = await response.json();
```

**Python**

```python
import os

import requests

response = requests.get(
    "https://gorally.games/v1/leagues",
    headers={"Authorization": f"Bearer {os.environ['RALLY_API_KEY']}"},
    timeout=10,
)
data = response.json()
```

The response is a list. The leagues are in `data`, and `has_more` tells you whether another page remains.

```json
{
  "object": "list",
  "data": [
    {
      "id": "5b0c2f9e-8a41-4d6b-9f3e-1a2b3c4d5e6f",
      "name": "Ligue du mardi",
      "sport": "CURLING",
      "sportLabel": null,
      "profile": {
        "key": "CURLING",
        "label": "Curling",
        "version": 3,
        "resourceKind": "SHEET",
        "cadence": {
          "unitsPerMatch": 8,
          "minutesPerUnit": 15,
          "matchesPerNight": 1,
          "scoreTarget": null,
          "seasonWeeks": {
            "min": 10,
            "max": 30
          }
        },
        "vocabulary": {
          "resource": {
            "one": "feuille",
            "many": "feuilles",
            "genre": "F"
          },
          "unit": {
            "one": "bout",
            "many": "bouts",
            "genre": "M"
          },
          "match": {
            "one": "partie",
            "many": "parties",
            "genre": "F"
          },
          "scoreUnit": {
            "one": "point",
            "many": "points",
            "genre": "M"
          }
        }
      },
      "timeZone": "America/Toronto"
    }
  ],
  "has_more": false
}
```

## Find a category

Standings belong to a category, which belongs to a season. Walk down this path once, then keep the identifiers.

1. `GET /leagues/{leagueId}` returns the league and its seasons, in `seasons`.
2. `GET /seasons/{seasonId}/categories` returns the season’s categories.

## Read the standings

**curl**

```bash
curl https://gorally.games/v1/categories/e2b4d6f8-1a3c-4e5b-9d7f-0c2e4a6b8d1f/standings \
  -H "Authorization: Bearer $RALLY_API_KEY"
```

**JavaScript**

```js
const response = await fetch('https://gorally.games/v1/categories/e2b4d6f8-1a3c-4e5b-9d7f-0c2e4a6b8d1f/standings', {
  headers: {
    Authorization: `Bearer ${process.env.RALLY_API_KEY}`,
  },
});
const data = await response.json();
```

**Python**

```python
import os

import requests

response = requests.get(
    "https://gorally.games/v1/categories/e2b4d6f8-1a3c-4e5b-9d7f-0c2e4a6b8d1f/standings",
    headers={"Authorization": f"Bearer {os.environ['RALLY_API_KEY']}"},
    timeout=10,
)
data = response.json()
```

Teams come in standings order. `rank` gives the position, and `tied` is `true` when two teams share it.

```json
{
  "object": "list",
  "data": [
    {
      "leagueTeamId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "name": "Les Pierres",
      "rank": 1,
      "tied": false,
      "played": 4,
      "wins": 3,
      "draws": 0,
      "losses": 1,
      "scoreFor": 29,
      "scoreAgainst": 18,
      "diff": 11,
      "gamePointsFor": 0,
      "gamePointsAgainst": 0,
      "points": 9
    },
    {
      "leagueTeamId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
      "name": "Les Balais",
      "rank": 2,
      "tied": false,
      "played": 4,
      "wins": 2,
      "draws": 1,
      "losses": 1,
      "scoreFor": 24,
      "scoreAgainst": 21,
      "diff": 3,
      "gamePointsFor": 0,
      "gamePointsAgainst": 0,
      "points": 7
    }
  ]
}
```

Standings are computed on every read. To follow them, listen to the `match.completed` event by webhook, then read the standings again.

## Next steps

- Read the “Authentication and scopes” guide before asking for more than `read`.
- Set up webhooks so you stop polling the API.
- Keep the “Errors” guide at hand: every error carries a stable `code`.
