Endpoint API Reference

Endpoint API Reference

This page documents the customer-facing route for fetching data from a Spartera Endpoint. This is the route buyers (or their apps and agents) call after subscribing.


Base URL

Endpoints are served from a per-seller subdomain:

https://{seller_handle}.api.spartera.com

The {seller_handle} is the subdomain identifier for the company that owns the endpoint. For example, an endpoint owned by txodds lives at https://txodds.api.spartera.com.

In stage:

https://{seller_handle}.stage.api.spartera.com

Fetching Data

Endpoint

GET /endpoints/v1/{endpoint_slug}

The slug is human-readable and unique within the seller's company (e.g., nfl-passing-yards-by-team).

Headers

HeaderRequiredDescription
x-api-keyAn endpoint-type API key (ep_...) scoped to this endpoint

Query Parameters

ParameterRequiredDefaultDescription
start0Pagination cursor — row offset
limitseller's capNumber of rows to return (capped by max_records_per_request)
Any column name or alias from the endpoint schemaDynamic filter (e.g., ?team=ARI)

Dynamic filters support operator prefixes: ?yards=>=100 (greater-than-or-equal), ?team=!=BUF (not-equal). Supported operators: =, !=, <, >, <=, >=.


Example Request

curl "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?start=0&limit=100" \
  -H "x-api-key: ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi"

Response Envelope

Every successful response has the same three-block shape:

{
  "message": "success",
  "data": {
    "spartera": {
      "request_id": "d23e815b-a490-495a-8b07-4eee717f2d08",
      "generated_at": "2026-04-28T20:37:25.493556+00:00",
      "billed": true,
      "bill_trigger": "200_OK",
      "credits_consumed": 2,
      "page": 1,
      "page_size": 100,
      "total_returned": 37,
      "has_more": false,
      "next_start": null,
      "next_page": null
    },
    "request": {
      "endpoint": "nfl-passing-yards-by-team",
      "endpoint_id": "a72b8513-a6e8-4b38-9982-3ccd0d64339a",
      "limit": 100,
      "params": {},
      "source": "nflverse.com",
      "start": 0
    },
    "response": {
      "data": [
        { "team": "ARI", "passing_yards": 4150 },
        { "team": "BUF", "passing_yards": 4892 }
      ]
    }
  }
}

spartera block

Request metadata and billing info.

FieldDescription
request_idUnique ID for this request — useful for support tickets
generated_atUTC timestamp when the response was generated
billedtrue if credits were deducted, false if seller-owned
bill_triggerWhen billing happened — currently always 200_OK
credits_consumedCredits deducted for this request (0 for free or seller-owned)
page, page_size, total_returnedCurrent page info
has_moretrue if there are more rows beyond this page
next_start, next_pageCursors for the next page (null if has_more is false)

request block

Echo of the request — what was actually queried.

response.data block

The rows. Always an array. Empty array if no rows match.


Pagination

Pagination uses start and limit query parameters. To paginate through results:

import requests

URL = "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team"
HEADERS = {"x-api-key": "ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi"}

start = 0
limit = 100

while True:
    response = requests.get(URL, headers=HEADERS, params={"start": start, "limit": limit})
    body = response.json()["data"]

    for row in body["response"]["data"]:
        print(row)

    if not body["spartera"]["has_more"]:
        break
    start = body["spartera"]["next_start"]

The seller sets max_records_per_request per endpoint (default 1,000). Requesting limit=10000 against an endpoint with a cap of 1,000 will silently return at most 1,000 rows.


Filtering

Pass any non-hidden column from the endpoint's schema as a query parameter to filter rows server-side:

# Equality
curl "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?team=ARI" \
  -H "x-api-key: ep_..."

# Greater-than
curl "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?passing_yards=>4000" \
  -H "x-api-key: ep_..."

# Combined with pagination
curl "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?team=BUF&start=0&limit=50" \
  -H "x-api-key: ep_..."

Operators: = (default), !=, <, >, <=, >=. Use the operator inline with the value.

Buyer-supplied filters are translated into SQL WHERE conditions and combined with any seller-configured filters using AND.


Code Examples

Python

import requests

response = requests.get(
    "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team",
    headers={"x-api-key": "ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi"},
    params={"start": 0, "limit": 100}
)
body = response.json()
print(f"{body['data']['spartera']['total_returned']} rows returned")
for row in body["data"]["response"]["data"]:
    print(row)

JavaScript

const response = await fetch(
  "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?start=0&limit=100",
  {
    method: "GET",
    headers: { "x-api-key": "ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi" }
  }
);
const { data } = await response.json();
console.log(`${data.spartera.total_returned} rows returned`);
data.response.data.forEach(row => console.log(row));

Go

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET",
        "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?start=0&limit=100",
        nil)
    req.Header.Set("x-api-key", "ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(body, &result)
    fmt.Println(result)
}

cURL

curl "https://txodds.api.spartera.com/endpoints/v1/nfl-passing-yards-by-team?start=0&limit=100" \
  -H "x-api-key: ep_HeRGNo0qyvi64sRVAZI3I0GW77LpCYWi"

HTTP Status Codes

CodeMeaning
200 OKSuccess — data returned, credits deducted (if applicable)
400 Bad RequestInvalid parameters or subdomain mismatch
401 UnauthorizedMissing or invalid API key
403 ForbiddenKey valid but not permitted (e.g., IP not whitelisted, or key scoped to a different endpoint)
404 Not FoundEndpoint slug doesn't exist (or company subdomain doesn't match the endpoint's company)
429 Too Many RequestsSeller-configured rate limit exceeded
502 Bad GatewaySeller-side error (database unreachable, query timeout)
503 Service UnavailableEndpoint is not in ACTIVE status
500 Internal Server ErrorSpartera platform error

Error Responses

Errors return a structured body with message and data.error_type:

{
  "message": "Insufficient credits. Required: 2, Available: 0",
  "data": {
    "error_type": "INSUFFICIENT_CREDITS",
    "error_source": "BUYER",
    "request_id": "d23e815b-a490-495a-8b07-4eee717f2d08",
    "endpoint_id": "a72b8513-a6e8-4b38-9982-3ccd0d64339a"
  }
}
error_sourceWho's responsible
BUYERThe caller (insufficient credits, bad params, IP not whitelisted)
SELLERThe data provider (database unreachable, query failed)
SPARTERAThe platform

You are never charged credits for non-200 responses. If a request fails for any reason — bad input, seller-side database error, platform error — no credits are deducted.


Rate Limiting

Sellers can configure per-buyer rate limits on their endpoints. When a limit is exceeded, you'll receive a 429 with details:

{
  "error": "Rate limit exceeded",
  "message": "Endpoint allows 100 requests per minute at USER level",
  "rate_limit": {
    "limit": 100,
    "period": "minute",
    "granularity": "USER",
    "remaining": 0,
    "reset_in_seconds": 47
  },
  "retry_after": 47
}

Granularity options: IP, USER, COMPANY, API_KEY, GLOBAL.


Related Pages