You have heard the word "API" a hundred times. Every tutorial assumes you know what it is. Every job post asks for it. And somehow nobody ever shows you the very first step: how do you actually make one request and see data come back?
This guide does exactly that. No theory dump, no assumed knowledge. You will make a real request in your terminal, then in Python, then in JavaScript. You will learn to read the response, understand what went wrong when it fails, and finish with a small working project.
What you will learn:
What an API request is, in plain English
The four parts of every request: method, URL, headers and body
How to read JSON and HTTP status codes
How to make your first request with curl, Python and JavaScript
How to handle errors, timeouts and rate limits
How to keep your API key safe
How to build a tiny command-line tool that fetches live data
What you need: a terminal, Node.js 18+ and/or Python 3.9+, and a free API key. For practice data we will use a sports API, because sports data is fun, changes constantly and has clear, readable responses.
- What is an API request, really?
An API (Application Programming Interface) lets your code ask another system for data. An API request is that question. The answer is the response.
Think of a restaurant:
You are your program.
The waiter is the API.
The kitchen is the server with the data.
You do not walk into the kitchen. You tell the waiter what you want, in a format the waiter understands, and the waiter brings back the result.
The whole conversation looks like this:
Your code ──── request ────▶ API server
Your code ◀─── response ──── API server
A real request is one line:
GET https://api.orbistats.com/v1/football/live
And the response is data in a format called JSON:
json
{
"match_id": "match_50231",
"status": "live",
"minute": 72,
"home": { "name": "Manchester City", "score": 2 },
"away": { "name": "Arsenal", "score": 1 }
}
That shape follows the live-score example on the Orbistats Live Scores API page. Everything in this guide is a variation on that one exchange.
- Beginner vocabulary (read once, save hours) Term Meaning Request The question your code sends Response The answer the server sends back Endpoint A specific URL that returns specific data, like /v1/football/live Base URL The shared start of every endpoint, like https://api.orbistats.com/v1 HTTP method The action: GET (read), POST (create), PUT (replace), DELETE (remove) Header Extra information sent with a request, like your API key Body Data you send along with a POST or PUT request JSON The text format most APIs use to send data Status code A number saying what happened: 200 ok, 401 bad key, 429 too many requests API key A secret string that identifies you Rate limit How many requests your plan allows in a time window Latency How long the round trip takes
If you later meet sports terms like xG or implied probability, the glossary explains them in plain language.
- The four parts of every request
Every request, to every API in the world, is made of the same four parts.
Part 1: The method
What do you want to do?
Method Meaning Example
GET Read data Get today's live matches
POST Create something Create a new user or webhook
PUT / PATCH Update something Change a setting
DELETE Remove something Delete a saved item
As a beginner, 99% of what you do will be GET.
Part 2: The URL
Where do you want to send it? A URL has a pattern:
https://api.orbistats.com/v1/football/live
└─────────┬──────────────┘└┬┘└───┬───┘└─┬─┘
base URL version sport resource
Reading left to right: the server, the API version, the sport, and the thing you want. Change football to basketball and you get a different sport. Change live to fixtures and you get a schedule instead.
Part 3: The headers
Extra information about you and your request. The most important header is the one carrying your key:
Authorization: Bearer your_key_here
This is how the server knows who is asking and what plan you are on.
Part 4: The body (only sometimes)
Data you send to the server. GET requests usually have no body. POST requests do.
That is the entire anatomy. Method, URL, headers, body.
- HTTP status codes: the server's reply in one number
Before the data, the server sends a number saying whether it worked. Memorize these:
Code Meaning What to do
200 Success Use the data
400 Bad request Check your URL and parameters
401 Missing or wrong key Check your key and header
403 Not allowed on your plan Check your plan or the endpoint
404 Not found Check the sport or resource name for typos
429 Too many requests Slow down, wait, retry
500, 502, 503 Server problem Wait and retry
Groups to remember: 2xx = good, 4xx = your mistake, 5xx = their mistake. That one rule makes debugging ten times faster.
- Choosing an API to practice with
You can learn on any API, but good practice APIs share a few traits: a free tier, clear documentation, a sandbox to preview responses, and data you actually find interesting.
Sports data works well because it has a clear structure (teams, scores, times), updates constantly and is easy to verify against what you see on TV. Orbistats offers a free key with no card needed, a public sandbox and documentation aimed at developers, and it covers 13 sports:
Football, Basketball, American Football, Cricket, Tennis, Baseball, Esports, Combat Sports, Volleyball, Handball, Ice Hockey, Golf and Horse Racing.
Everything you learn here transfers to any other API. Only the base URL, headers and field names change.
Step 1: Get your free API key
Open the sign-up page and create a free account. No card is needed to start.
Copy your API key.
Store it as an environment variable, never directly in your code.
macOS or Linux:
bash
export ORBISTATS_API_KEY="your_key_here"
Windows PowerShell:
powershell
$env:ORBISTATS_API_KEY = "your_key_here"
An environment variable keeps your secret out of your source files, which keeps it out of Git. The quickstart and documentation cover authentication in more detail.
Step 2: Look before you code (the sandbox)
Before writing anything, see what a real response looks like. Open the public sandbox and try a request in the browser.
This is a pro habit. Always look at a real response before writing code to parse it. Guessing field names is the source of half of all beginner bugs. Keep the API reference open in a second tab while you work.
Step 3: Your first request with curl
curl is a command-line tool for making requests. It is the fastest way to test any API, and it is already installed on macOS, Linux and modern Windows.
bash
curl -s \
-H "Authorization: Bearer $ORBISTATS_API_KEY" \
"https://api.orbistats.com/v1/football/live"
Let's break it down:
curl runs the tool.
-s means silent (hide the progress bar).
-H "..." adds a header, here carrying your key.
The quoted URL is the endpoint.
No method is given, so it defaults to GET.
If you have jq installed, make the output readable:
bash
curl -s -H "Authorization: Bearer $ORBISTATS_API_KEY" \
"https://api.orbistats.com/v1/football/live" | jq
Want to see the status code too? Add -i to include the response headers:
bash
curl -i -H "Authorization: Bearer $ORBISTATS_API_KEY" \
"https://api.orbistats.com/v1/football/live"
The first line of the output will look like HTTP/2 200. You just made your first API request.
Step 4: Read the response
The body comes back as JSON. Here is how to read it:
json
{
"match_id": "match_50231",
"status": "live",
"minute": 72,
"home": { "name": "Manchester City", "score": 2 },
"away": { "name": "Arsenal", "score": 1 }
}
{ } curly braces mean an object (a set of named fields).
[ ] square brackets mean a list.
Strings are in quotes, numbers are not.
Objects can nest: home is an object inside the match object.
To reach nested data you chain names: home.name is "Manchester City".
Many APIs wrap their results in a data field that holds a list of such objects. Check a real response in the sandbox to see exactly what yours looks like, and confirm field names in the API reference.
Step 5: The same request in Python
Install two libraries:
bash
pip install requests python-dotenv
Create a .env file in your project folder, and add .env to .gitignore:
ORBISTATS_API_KEY=your_key_here
Now first_request.py:
python
import os
import requests
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("ORBISTATS_API_KEY")
BASE_URL = "https://api.orbistats.com/v1"
response = requests.get(
f"{BASE_URL}/football/live",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=10,
)
print("Status:", response.status_code)
response.raise_for_status() # raise an error for 4xx / 5xx
payload = response.json() # turn the JSON text into Python data
for match in payload.get("data", []):
print(
f'{match["minute"]}\' '
f'{match["home"]["name"]} {match["home"]["score"]} - '
f'{match["away"]["score"]} {match["away"]["name"]}'
)
Run it:
bash
python first_request.py
Three habits to notice, because they separate beginner code from professional code:
timeout=10 stops your script hanging forever if the server never answers.
raise_for_status() makes failures loud instead of silent.
.get("data", []) returns an empty list instead of crashing if the field is missing.
Step 6: The same request in JavaScript
Node.js 18+ has fetch built in, so no installs are needed. Save as first_request.mjs:
javascript
const API_KEY = process.env.ORBISTATS_API_KEY;
const BASE_URL = "https://api.orbistats.com/v1";
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 10_000); // 10s timeout
try {
const res = await fetch(${BASE_URL}/football/live, {
headers: { Authorization: Bearer ${API_KEY} },
signal: controller.signal,
});
console.log("Status:", res.status);
if (!res.ok) throw new Error(Request failed with ${res.status});
const payload = await res.json();
for (const m of payload.data ?? []) {
console.log(
${m.minute}' ${m.home.name} ${m.home.score} - ${m.away.score} ${m.away.name}
);
}
} catch (err) {
console.error("Something went wrong:", err.message);
} finally {
clearTimeout(timer);
}
Run it:
bash
node first_request.mjs
One crucial warning: do not put your API key in JavaScript that runs in a browser. Anyone can open the developer tools and copy it. Keep calls with secret keys on a server (like this Node script), and let your web page talk to your server instead. We build exactly that in the project below.
Prefer a library over raw HTTP? There are SDKs, and the examples page has copy-ready snippets.
Step 7: Change the request (swap the sport, swap the data)
Once your first request works, the fun starts. Most of the time you only change one word in the URL.
Different sport:
/v1/football/live
/v1/basketball/live
/v1/tennis/live
Different data type for the same sport:
GET /v1/football/live # what is happening now
GET /v1/football/fixtures # the schedule
GET /v1/football/standings # the league table
Each maps to a different product. Fixtures and standings come from the Sports Data API, live matches from the Live Scores API, team and player numbers from the Sports Statistics API, prices from the Odds API and past seasons from the Historical Sports Data API.
Query parameters let you filter a request. They go after a ? in the URL, like ?name=value. Many APIs support filters such as dates or competitions. Which parameters exist is specific to each endpoint, so check the documentation instead of guessing. In Python, requests builds them for you safely:
python
response = requests.get(
f"{BASE_URL}/football/fixtures",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"example_filter": "value"}, # replace with a real parameter from the docs
timeout=10,
)
print(response.url) # see the final URL that was sent
Note that example_filter above is a placeholder, not a real parameter. Swap in a real one from the API reference.
One warning when swapping sports: the response shape may be consistent, but the meaning of fields differs. A football match has minutes, a tennis match has sets and a golf event has a leaderboard. Read the sport's page before assuming a field exists.
Step 8: Handle errors like a professional
Beginners write code for the day everything works. Professionals write code for the day it does not. Here is a reusable Python helper:
python
import os
import time
import requests
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("ORBISTATS_API_KEY")
BASE_URL = "https://api.orbistats.com/v1"
class ApiError(Exception):
pass
def retry_delay(res, attempt):
value = res.headers.get("Retry-After", "")
return int(value) if value.isdigit() else 2 ** attempt
def get_json(path, retries=3):
url = f"{BASE_URL}/{path.lstrip('/')}"
headers = {"Authorization": f"Bearer {API_KEY}"}
for attempt in range(retries):
try:
res = requests.get(url, headers=headers, timeout=10)
except requests.RequestException:
time.sleep(2 ** attempt) # network problem: wait, retry
continue
if res.status_code in (401, 403):
raise ApiError("Auth problem: check your key and plan")
if res.status_code == 404:
raise ApiError(f"Not found: {path}")
if res.status_code == 429 or res.status_code >= 500:
time.sleep(retry_delay(res, attempt))
continue
res.raise_for_status()
return res.json()
raise ApiError("Gave up after retries")
print(get_json("football/live"))
The logic worth remembering:
Never retry 401, 403 or 404. Retrying will not fix a bad key or a typo.
Do retry 429 and 5xx, waiting longer each time. This is called exponential backoff.
Respect Retry-After when the server sends it.
Always set timeouts.
If something looks broken on the provider's side, check the status page and the changelog before you debug your own code.
Step 9: Rate limits (the maths nobody warns you about)
Free plans have limits. At the time of writing, Orbistats documents roughly 150 requests per day on the free tier, but always check the live pricing page for current numbers.
That sounds like plenty until you loop. Suppose you check every sport once a minute:
13 sports × 1,440 minutes = 18,720 requests per day
That exhausts a small allowance in minutes. Smart habits:
Cache results so you do not repeat the same request.
Request only what you need.
Never put a request inside an unbounded loop while you are testing.
Use push instead of polling when you need live updates: a WebSocket sends data when it changes, and webhooks call your server when events happen.
Here is a tiny cache you can drop into any project:
python
import time
_cache = {}
def cached(key, fetch_fn, ttl=60):
now = time.time()
hit = _cache.get(key)
if hit and now - hit["t"] < ttl:
return hit["v"]
value = fetch_fn()
_cache[key] = {"v": value, "t": now}
return value
data = cached("football-live", lambda: get_json("football/live"), ttl=20)
Step 10: Mini project, a command-line live score checker
Time to combine everything into one useful tool. It accepts a sport, validates it, calls the API with a timeout, handles errors and prints a clean result.
Save as scores.mjs:
javascript
const KEY = process.env.ORBISTATS_API_KEY;
const BASE = "https://api.orbistats.com/v1";
const SPORTS = [
"football", "basketball", "american-football", "cricket", "tennis",
"baseball", "esports", "combat-sports", "volleyball", "handball",
"ice-hockey", "golf", "horse-racing",
];
const sport = process.argv[2] ?? "football";
if (!SPORTS.includes(sport)) {
console.error(Unknown sport "${sport}". Try one of:\n ${SPORTS.join(", ")});
process.exit(1);
}
if (!KEY) {
console.error("Set ORBISTATS_API_KEY first. Get a free key at https://orbistats.com/signup.html");
process.exit(1);
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 10_000);
try {
const res = await fetch(${BASE}/${sport}/live, {
headers: { Authorization: Bearer ${KEY} },
signal: controller.signal,
});
if (res.status === 401 || res.status === 403) {
throw new Error("Auth problem: check your key and plan.");
}
if (res.status === 429) {
throw new Error("Rate limited. Wait a bit and try again.");
}
if (!res.ok) throw new Error(Request failed with status ${res.status});
const { data = [] } = await res.json();
if (data.length === 0) {
console.log(No live ${sport} matches right now.);
} else {
for (const m of data) {
const clock = m.status === "live" && m.minute ? ${m.minute}' : m.status;
console.log(
${clock} ${m.home?.name} ${m.home?.score} - ${m.away?.score} ${m.away?.name}
);
}
}
} catch (err) {
console.error("Error:", err.name === "AbortError" ? "Request timed out" : err.message);
process.exit(1);
} finally {
clearTimeout(timer);
}
Run it:
bash
node scores.mjs football
node scores.mjs basketball
node scores.mjs tennis
Why this is a good beginner project:
Input validation. We only accept sports from a fixed list, so no random text ends up in a URL.
Clear errors. Every failure tells the user what to do next.
Exit codes. process.exit(1) signals failure to other tools.
One-word extensibility. Adding a feature is trivial because the structure is clean.
Honest limitation: the print format assumes a football-style home-vs-away shape. Cricket, tennis and golf look different. When you extend it, write one small formatter function per sport instead of piling up if statements.
Security checklist for beginners
Never commit your API key. Add .env to .gitignore.
Never put the key in browser JavaScript.
Validate user input before placing it in a URL.
Always set a timeout.
If you accidentally paste your key somewhere public, rotate it immediately.
Do not log full request headers in production.
Read the provider's data licensing terms before building anything commercial.
REST, WebSocket and webhooks: a quick comparison
Your first request used REST: you ask, the server answers. It is the right starting point. But as you build more, you will meet two other styles:
REST WebSocket Webhooks
Who starts it? You ask Connection stays open, server pushes Server calls your URL
Best for Pages, lookups, stats Live screens Alerts, automation
Complexity Low Medium Medium
Good for beginners? Yes, start here Next step Later
REST for pages. WebSocket for live screens. Webhooks for alerts.
If you want a score display with almost no code, ready-made widgets can be embedded directly.
Why APIs matter beyond tutorials (the business angle)
Learning to call an API is not just a classroom skill. It is one of the most commercially useful abilities in software, because almost every modern product is built by connecting to other services. Sports data is a good example of the pattern:
Media and publishers add live scoreboards to keep readers on the page. See Media & Publishers.
Fantasy and AI products need instant player updates and deep history. See Fantasy & AI Data.
Sportsbooks and trading desks need fast, normalized prices. See Sportsbooks and Trading Desks.
Analytics and data science teams build models from live and historical data. See Analytics & Data Science.
Clubs, federations and leagues use data for performance analysis and fan engagement. See Teams & Clubs and Federations & Leagues.
What this means for you: collecting data yourself is slow and expensive, so businesses buy it and spend their effort on the product. You can do the same. Good ways to use a new API skill:
Portfolio project. A small tool with validation, timeouts and clear errors shows real engineering habits.
Niche apps. One sport, one league, one audience.
Freelance work. Small clubs, blogs and shops often need dashboards or widgets.
Content and tools. Explainers and calculators attract search traffic. The Orbistats tools and guides pages show the idea.
No guarantees on income, of course. The point is that the barrier is now your idea, not the data.
Building data yourself vs using an API: honest comparison
Thinking about skipping the API? Compare:
Scraping websites
Free to start, fragile in practice.
Breaks when layouts change, may violate terms, no guarantees.
Collecting your own data
Total control, but you need people, tooling and constant maintenance.
Using an API
Fastest path to launch, one clean format, documentation and support.
You depend on the provider's coverage, speed and terms.
For nearly every learner and startup, the API wins. To compare providers, start with the comparison and alternatives pages. Some providers focus only on odds, some are enterprise suites and some cover many sports under one API.
10 mistakes every beginner makes (and the fix)
Hardcoding the API key. Use environment variables.
Calling the API from browser JavaScript with a secret key. Use a small server in the middle.
Guessing field names. Look at a real response first, in the sandbox.
Forgetting a timeout. One hung request can freeze your program.
Ignoring status codes. Always check before using the data.
Retrying 401, 403 and 404. Retrying will not fix a typo or a bad key.
Looping requests with no delay or cache. You will hit your rate limit fast.
Assuming every response has every field. Use safe access like .get() or ?..
Assuming all sports share identical fields. Read each sport's docs.
Not reading the docs. Ten minutes in the documentation saves hours of confusion.
Troubleshooting: what does this error mean?
You see Probably Try
401 Key missing or wrong Print API_KEY is None? Check env var and header spelling
403 Endpoint not in your plan Check your plan and the docs
404 Typo in sport or resource Compare your URL with the docs
429 Too many requests Add caching, slow down, respect Retry-After
ConnectionError Network or DNS problem Check your internet, retry
Timeout Server slow or unreachable Retry with backoff
KeyError Field missing Print the whole response, use safe access
Empty list Nothing live right now Try another sport or the fixtures endpoint
When in doubt: print the status code and the raw response. Ninety percent of API bugs become obvious the moment you do.
Where to go next
Once your first request works, here is a learning path:
Add a second endpoint (fixtures or standings).
Add caching.
Build a small web page with a server in the middle.
Try WebSocket for real-time updates with the WebSocket API.
Try webhooks for alerts with the Webhooks API.
Use historical data to answer questions like "how often did the home team win?"
For more code to learn from, Orbistats' team has published tutorials on a live scoreboard in 50 lines of JavaScript with WebSocket, consuming a sports API in Python with FastAPI, consuming it in .NET Core and building a live dashboard with Next.js.
FAQ
What is an API request?
A message your code sends to a server asking for data or an action. The server replies with a response containing a status code and usually JSON.
Do I need to know a lot of programming first?
No. If you can run a command and read a few lines of Python or JavaScript, you can make a request. Start with curl, which needs no programming at all.
What is the difference between GET and POST?
GET reads data. POST sends data to create something. Beginners mostly use GET.
What is JSON?
A simple text format for structured data, made of objects { }, lists [ ], strings, numbers and booleans.
What does an API key do?
It identifies you to the server, so it can apply your plan and limits. Treat it like a password.
Why is my request returning 401?
Your key is missing, mistyped or sent in the wrong header. Check that the environment variable is set and the header reads Authorization: Bearer ....
Is there a free API to practice with?
Many exist. Orbistats offers a free key with no card required, a public sandbox and 13 sports of data.
Which sports does Orbistats cover?
13: Football, Basketball, American Football, Cricket, Tennis, Baseball, Esports, Combat Sports, Volleyball, Handball, Ice Hockey, Golf and Horse Racing.
Can I use the data in a commercial product?
Check the provider's data licensing and terms first.
Final thoughts
Your first API request feels intimidating until you realize the whole thing is four parts: a method, a URL, some headers and sometimes a body. Everything else is detail.
The recipe is short. Get a key and store it safely. Look at a real response before you code. Test with curl. Check the status code. Set a timeout. Handle errors. Cache. Validate input. Keep secrets on the server.
Now open a terminal, run the command from Step 3 and watch real data come back. That small moment is where every developer's API journey starts.
👉 Get a free API key and make your first request today.
📚 Explore the developer hub for docs, guides and examples.
🔬 Like data-driven reads? Bookmark the research section.
🏢 Curious who is behind it? Visit the About page, or explore the full platform at Orbistats.
What was the hardest part of your first API request? Tell me in the comments. I read every one.
Top comments (0)