SDK and HTTP quickstarts

Install the public Python SDK or copy an HTTP example for JavaScript, Go, Ruby, Java, PHP, C#, or Rust. The HTTP examples are standalone reference code: you do not need to download a separate ParlayAPI client file.

First, get a free API key and set PARLAY_API_KEY in your terminal. Keep your key on your server; do not put it in browser code or commit it to Git. For a request without an account, start with the live demo.

export PARLAY_API_KEY='paste_your_key_here'

On Windows PowerShell, use $env:PARLAY_API_KEY = "paste_your_key_here". The examples request MLB moneylines. Coverage varies by sport, market, and time; an empty response is possible.

Python

Python 3.10+ · public SDK · no required runtime dependencies.

PyPI release 0.3.2 · Public source and examples. This SDK uses the /v4 compatibility endpoints and passes the key as apiKey; redact query strings from request logs.

Setup

python -m pip install parlay-api==0.3.2

Save the example as quickstart.py.

First call

import os
from parlay_api import ParlayAPI

api_key = os.environ["PARLAY_API_KEY"]
if not api_key.strip():
    raise ValueError("Set PARLAY_API_KEY first")
client = ParlayAPI(api_key=api_key, timeout=30)
events = client.odds("baseball_mlb", regions="us", markets="h2h")
print(events[0] if events else "No events match this request right now.")

Run

python quickstart.py

JavaScript / Node.js

Node 18+ · standalone HTTP reference · built-in fetch.

The JavaScript/TypeScript SDK source is public. The example below uses native HTTP and does not depend on an npm release.

Setup

No package install needed. Save the example as quickstart.mjs so Node can run the top-level await.

First call

const apiKey = process.env.PARLAY_API_KEY;
if (!apiKey?.trim()) throw new Error("Set PARLAY_API_KEY first");

const response = await fetch(
  "https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h",
  {
    headers: { "X-API-Key": apiKey },
    signal: AbortSignal.timeout(30_000),
  }
);
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const events = await response.json();
if (!Array.isArray(events)) throw new Error("Expected an event array");
console.log(events[0] ?? "No events match this request right now.");

Run

node quickstart.mjs

Go

Go 1.21+ · standalone HTTP reference · standard library.

Setup

Save the example as main.go. No third-party dependencies.

First call

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    key := os.Getenv("PARLAY_API_KEY")
    if strings.TrimSpace(key) == "" { panic("Set PARLAY_API_KEY first") }
    req, err := http.NewRequest("GET", "https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h", nil)
    if err != nil { panic(err) }
    req.Header.Set("X-API-Key", key)
    client := &http.Client{Timeout: 30 * time.Second}
    resp, err := client.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil { panic(err) }
    if resp.StatusCode != http.StatusOK {
        panic(fmt.Sprintf("HTTP %d: %s", resp.StatusCode, body))
    }
    var events []json.RawMessage
    if err := json.Unmarshal(body, &events); err != nil { panic(err) }
    if len(events) == 0 {
        fmt.Println("No events match this request right now.")
        return
    }
    fmt.Println(string(events[0]))
}

Run

go run main.go

Ruby

Ruby 3.0+ · standalone HTTP reference · net/http and json.

Setup

Save the example as quickstart.rb. No gem install needed.

First call

require 'net/http'
require 'json'

key = ENV.fetch('PARLAY_API_KEY')
raise 'Set PARLAY_API_KEY first' if key.strip.empty?
uri = URI('https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h')
request = Net::HTTP::Get.new(uri)
request['X-API-Key'] = key
response = Net::HTTP.start(uri.host, uri.port,
  use_ssl: true, open_timeout: 10, read_timeout: 30) do |http|
  http.request(request)
end
unless response.is_a?(Net::HTTPSuccess)
  raise "HTTP #{response.code}: #{response.body}"
end
events = JSON.parse(response.body)
raise 'Expected an event array' unless events.is_a?(Array)
puts(events.empty? ? 'No events match this request right now.' : JSON.pretty_generate(events.first))

Run

ruby quickstart.rb

Java

Java 17+ · standalone HTTP reference · java.net.http.

Setup

Save the example as Main.java. It prints the JSON response as text, so no JSON library is required.

First call

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Main {
    public static void main(String[] args) throws Exception {
        String key = System.getenv("PARLAY_API_KEY");
        if (key == null || key.isBlank()) {
            throw new IllegalStateException("Set PARLAY_API_KEY first");
        }
        var client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10)).build();
        var request = HttpRequest.newBuilder(URI.create(
            "https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h"))
            .header("X-API-Key", key)
            .timeout(Duration.ofSeconds(30)).GET().build();
        var response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() != 200) {
            throw new IllegalStateException("HTTP " + response.statusCode() + ": " + response.body());
        }
        String json = response.body().trim();
        System.out.println(json.matches("\\[\\s*\\]")
            ? "No events match this request right now." : json);
    }
}

Run

java Main.java

PHP

PHP 8.1+ · standalone HTTP reference · cURL extension.

Setup

Enable the PHP cURL extension and save the example as quickstart.php. No Composer package needed.

First call

<?php
$key = getenv('PARLAY_API_KEY');
if ($key === false || trim($key) === '') {
    throw new RuntimeException('Set PARLAY_API_KEY first');
}
$curl = curl_init('https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h');
curl_setopt_array($curl, [
    CURLOPT_HTTPHEADER => ['X-API-Key: ' . $key],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$error = curl_error($curl);
curl_close($curl);
if ($body === false) { throw new RuntimeException($error); }
if ($status !== 200) { throw new RuntimeException("HTTP $status: $body"); }
$events = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($events) || !array_is_list($events)) {
    throw new RuntimeException('Expected an event array');
}
if (count($events) === 0) {
    echo "No events match this request right now.\n";
} else {
    print_r($events[0]);
}

Run

php quickstart.php

C# / .NET

.NET 6+ · standalone HTTP reference · built-in HTTP and JSON libraries.

Setup

dotnet new console -o parlay-quickstart
cd parlay-quickstart

Replace Program.cs with the example.

First call

using System;
using System.Net.Http;
using System.Text.Json;

var key = Environment.GetEnvironmentVariable("PARLAY_API_KEY");
if (string.IsNullOrWhiteSpace(key))
    throw new InvalidOperationException("Set PARLAY_API_KEY first");

using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
client.DefaultRequestHeaders.Add("X-API-Key", key);
using var response = await client.GetAsync(
    "https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h");
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
    throw new HttpRequestException($"HTTP {(int)response.StatusCode}: {body}");
using var document = JsonDocument.Parse(body);
var events = document.RootElement;
if (events.ValueKind != JsonValueKind.Array)
    throw new InvalidOperationException("Expected an event array");
Console.WriteLine(events.GetArrayLength() == 0
    ? "No events match this request right now." : events[0].GetRawText());

Run

dotnet run

Rust

Rust with Cargo · standalone HTTP reference · reqwest and serde_json.

Setup

cargo new parlay-quickstart
cd parlay-quickstart

Add these entries under [dependencies] in Cargo.toml, then replace src/main.rs with the example.

reqwest = { version = "0.12", default-features = false, features = ["blocking", "rustls-tls"] }
serde_json = "1"

First call

use std::{env, error::Error, time::Duration};
use serde_json::Value;

fn main() -> Result<(), Box<dyn Error>> {
    let key = env::var("PARLAY_API_KEY")?;
    if key.trim().is_empty() { return Err("Set PARLAY_API_KEY first".into()); }
    let client = reqwest::blocking::Client::builder()
        .timeout(Duration::from_secs(30)).build()?;
    let response = client.get(
        "https://parlay-api.com/v1/sports/baseball_mlb/odds?regions=us&markets=h2h")
        .header("X-API-Key", key).send()?;
    let status = response.status();
    let body = response.text()?;
    if !status.is_success() {
        return Err(format!("HTTP {status}: {body}").into());
    }
    let value: Value = serde_json::from_str(&body)?;
    let events = value.as_array().ok_or("Expected an event array")?;
    match events.first() {
        Some(event) => println!("{event}"),
        None => println!("No events match this request right now."),
    }
    Ok(())
}

Run

cargo run

Empty responses, errors, and retries

A successful odds call returns a JSON array. [] means no events were returned for that request. Check the sport key, filters, and current availability using the sports catalogue and the live demo. Do not assume that every event contains every sportsbook or market.

The Python 0.3.2 SDK and these HTTP examples do not automatically retry requests. For production reads, add bounded retries for HTTP 429 and transient 5xx errors, honoring Retry-After when present. Check the status and error body before retrying: authentication and plan errors need a configuration or account change. See production best practices and limits.

The Python SDK raises ParlayAPIError subclasses and exposes credit headers through client.last_quota. The HTTP examples check the response status directly. When debugging an HTTP request, save its X-Request-ID response header if present and include it when contacting support. Do not share your API key.

More ways to integrate

Use the OpenAPI specification with your preferred client generator, or start from the curl cookbook. These are REST examples; live streaming requires Business tier or above. See current plans.

Report SDK issues in the public Python issue tracker or JavaScript issue tracker.