# Pagination Guide - Cursor-Based Batching
URL: https://sportsgameodds.com/docs/guides/data-batches

Pagination Guide - Cursor-Based Batching [#pagination-guide---cursor-based-batching]

This following information only applies to the `/events/`, `/teams`, and `/players` endpoints. Other endpoints will always return all of the results which match your query. However, there may be hundreds or even thousands of results to these endpoints, so they must be fetched in batches.

How It Works [#how-it-works]

1. Make a request. Each request has a limit on the number of items returned.
2. If there are more items to show, you'll get a `nextCursor` in the response.
3. Repeat the query but put the value from last request's `nextCursor` in the `cursor` parameter.
4. Repeat this until you no longer receive a `nextCursor` in the response in order to get all of the results.

The cursor Parameter [#the-cursor-parameter]

This tells the API where to pick up from. If you received a response from the API and there are more items to show, you'll get a `nextCursor` at the top level of the response. Use this value in the `cursor` parameter of your next request to pick up where you left off.

Notes on using `cursor`:

* Always use the value from the last response's `nextCursor` property. Don't try to reverse-engineer the cursor value yourself
* Don't change any query parameters between cursor requests. This will cause the cursor to not function properly.
* Don't try to reverse-engineer the cursor value yourself. Just use the value from the last response's `nextCursor` property instead.
* In some cases, the API may return a `nextCursor` when in fact there are no more items to show. So if you include a `cursor` parameter and get 404 (no results) back, that just means you've reached the end of the results.

The limit Parameter [#the-limit-parameter]

The `limit` parameter determines the max number of items to return in each request. It has a default value which can be overridden.

* If you don't specify a `limit` parameter, then a limit of `10` will be used.
* If you specify a `limit` above `300`, then you'll receive an error.
* Otherwise, the limit applied is the smaller value between the `limit` parameter you supplied and the max-limit for the endpoint.
* If you're making a request to the `/players` or `/teams` endpoints, the max-limit is `250`
* If you're making a request to the `/events` endpoint, the max-limit varies from 25-100 depending on the query. Factors affecting this include:
  * If the query filters for specific fields (ex: `oddIDs`)
  * If the query is for upcoming or past events
  * If the query includes alt lines

Example [#example]

Let's take the following example, where we want to grab all unfinalized NBA events:

<Tabs items={['Javascript', 'Python', 'Ruby', 'PHP', 'Java']}>
  <Tab value="Javascript">
    ```js
    const allEvents = [];
    let nextCursor = null;
    let hasMore = true;
    while (hasMore) {
      try {
        const response = await axios.get("https://api.sportsgameodds.com/v2/events", {
          params: {
            leagueID: "NBA",
            finalized: false,
            limit: 100,
            cursor: nextCursor,
          },
          headers: {
            "x-api-key": YOUR_API_KEY,
          },
        });
        allEvents.push(...response.data.data);
        nextCursor = response.data.nextCursor;
        hasMore = Boolean(nextCursor);
      } catch (error) {
        hasMore = false;
      }
    }

    console.log(`Found ${allEvents.length} events`);
    allEvents.forEach((event) => console.log(event.eventID));

    return allEvents;
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import requests

    all_events = []
    next_cursor = None
    has_more = True

    while has_more:
        try:
            response = requests.get(
                "https://api.sportsgameodds.com/v2/events",
                params={
                    "leagueID": "NBA",
                    "finalized": "false",
                    "limit": 100,
                    "cursor": next_cursor
                },
                headers={"x-api-key": YOUR_API_KEY}
            )
            response.raise_for_status()
            data = response.json()

            all_events.extend(data.get("data", []))
            next_cursor = data.get("nextCursor")
            has_more = next_cursor is not None
        except requests.RequestException:
            has_more = False

    print(f"Found {len(all_events)} events")
    for event in all_events:
        print(event["eventID"])

    return all_events
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby
    require "net/http"
    require "json"
    require "uri"

    def fetch_all_events(api_key)
      all_events = []
      next_cursor = nil
      has_more = true

      while has_more
        begin
          uri = URI("https://api.sportsgameodds.com/v2/events")
          params = {
            leagueID: "NBA",
            finalized: false,
            limit: 100,
            cursor: next_cursor
          }.compact
          uri.query = URI.encode_www_form(params)

          req = Net::HTTP::Get.new(uri)
          req["x-api-key"] = api_key

          res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
            http.request(req)
          end

          data = JSON.parse(res.body)
          all_events.concat(data["data"] || [])
          next_cursor = data["nextCursor"]
          has_more = !next_cursor.nil? && !next_cursor.empty?
        rescue StandardError
          has_more = false
        end
      end

      puts "Found #{all_events.length} events"
      all_events.each { |event| puts event["eventID"] }

      all_events
    end
    ```
  </Tab>

  <Tab value="PHP">
    ```php
    $allEvents = [];
    $nextCursor = null;
    $hasMore = true;

    while ($hasMore) {
        try {
            $params = [
                'leagueID' => 'NBA',
                'finalized' => 'false',
                'limit' => 100,
            ];
            if ($nextCursor !== null) {
                $params['cursor'] = $nextCursor;
            }

            $ch = curl_init("https://api.sportsgameodds.com/v2/events?" . http_build_query($params));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                "x-api-key: " . YOUR_API_KEY
            ]);

            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            if ($httpCode !== 200) {
                throw new Exception("HTTP Error: " . $httpCode);
            }

            $data = json_decode($response, true);
            $events = $data['data'] ?? [];
            $allEvents = array_merge($allEvents, $events);
            $nextCursor = $data['nextCursor'] ?? null;
            $hasMore = $nextCursor !== null;
        } catch (Exception $e) {
            $hasMore = false;
        }
    }

    echo "Found " . count($allEvents) . " events\n";
    foreach ($allEvents as $event) {
        echo $event['eventID'] . "\n";
    }

    return $allEvents;
    ```
  </Tab>

  <Tab value="Java">
    ```java
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.util.ArrayList;
    import java.util.List;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;

    List<JsonObject> allEvents = new ArrayList<>();
    String nextCursor = null;
    boolean hasMore = true;
    HttpClient client = HttpClient.newHttpClient();

    while (hasMore) {
        try {
            String url = String.format(
                "https://api.sportsgameodds.com/v2/events?leagueID=NBA&finalized=false&limit=100%s",
                nextCursor != null ? "&cursor=" + nextCursor : ""
            );

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("x-api-key", YOUR_API_KEY)
                .GET()
                .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            JsonObject data = JsonParser.parseString(response.body()).getAsJsonObject();

            data.getAsJsonArray("data").forEach(event ->
                allEvents.add(event.getAsJsonObject())
            );

            nextCursor = data.has("nextCursor") && !data.get("nextCursor").isJsonNull()
                ? data.get("nextCursor").getAsString()
                : null;
            hasMore = nextCursor != null;
        } catch (Exception e) {
            hasMore = false;
        }
    }

    System.out.println("Found " + allEvents.size() + " events");
    allEvents.forEach(event ->
        System.out.println(event.get("eventID").getAsString())
    );

    return allEvents;
    ```
  </Tab>
</Tabs>