6. Status codes and inspecting responses
Before you start pulling data out of a response, pause and make sure the request actually succeeded. The Response object carries everything you need to check.
Three things to verify, in this order:
- Status. Did the request succeed (
200) or fail (404,500)? - Headers. What format did the server send back?
- Body. What data did you actually receive?
Professional developers don't assume success. They inspect first, then write parsing code against what the server really returned. The status_code property from the previous section is your first line of inspection; this section starts there and works outward to headers and metadata.
Understanding status codes
Status codes are three-digit numbers that tell you what happened with your request. They're standardised across the web, so every API uses the same codes to mean the same things. They cluster into three families based on the first digit:
- 2xx (Success). Everything worked as expected.
- 4xx (Client Error). Something is wrong with your request (bad URL, missing auth, invalid data, no permission).
- 5xx (Server Error). Something went wrong on the server (usually not your fault).
Once you know the common ones, you can glance at a code and know immediately whether the request worked, failed for something you sent, or failed for something on the other end:
| Code | Meaning | What it tells you |
|---|---|---|
200 |
OK | Success. The request worked and data was returned. |
400 |
Bad Request | The server couldn't understand the request, often because a parameter or value is malformed. |
401 |
Unauthorized | You need to provide credentials (API key, login, token). |
403 |
Forbidden | Your credentials are valid, but you're not allowed to access this resource. |
404 |
Not Found | The URL or resource doesn't exist on the server. |
429 |
Too Many Requests | You're making requests too quickly; slow down or add delays. |
500 |
Internal Server Error | The server crashed or has a bug; not your fault. |
503 |
Service Unavailable | The server is temporarily down or overloaded; try again later. |
401 and 403 look similar but mean different things. 401 means "I don't know who you are, log in"; 403 means "I know who you are, but you can't have this." You'll meet both regularly when you start working with authenticated APIs.
The response.ok property returns True for any status below 400 and False for 4xx or 5xx errors. That's a handy success check without memorising every individual code.
The fuller picture: headers and metadata
Beyond the status code, Response objects carry headers: small pieces of metadata about the response itself. Headers tell you what format the data is in, when it was generated, and what server software sent it. You won't read headers on every request, but when something feels off, they're one of the first places to look.
Here's a comprehensive inspection script, the kind of diagnostic code you might write when troubleshooting a tricky integration. Save this as inspect_response.py:
import requests
response = requests.get("https://httpbin.org/get", timeout=10)
# Examine the response object structure
print("Response Object Analysis")
print("=" * 50)
print(f"Object type: {type(response)}")
print(f"Status code: {response.status_code}")
print(f"Status text: {response.reason}")
print(f"Success check: {response.ok}")
print(f"Content length: {len(response.text)} characters")
print(f"Response URL: {response.url}")
# Show key headers
print("\nKey Response Headers:")
print(f"Content-Type: {response.headers.get('Content-Type')}")
print(f"Server: {response.headers.get('Server')}")
print(f"Date: {response.headers.get('Date')}")
Run it:
$ python inspect_response.py
Response Object Analysis
==================================================
Object type: <class 'requests.models.Response'>
Status code: 200
Status text: OK
Success check: True
Content length: 321 characters
Response URL: https://httpbin.org/get
Key Response Headers:
Content-Type: application/json
Server: gunicorn/19.9.0
Date: Sat, 06 Sep 2025 21:10:00 GMT
What each line is worth:
status_codeandreason, numeric (200) and text ("OK") indicators of success.ok, aTrue/Falseshortcut that'sTruefor any status below 400.url, the final URL used (especially useful if the server redirected you).Content-Type, the format of the response (application/json,text/html,image/png).Server, what software the server is running (rarely essential).Date, when the server generated the response.
You won't inspect every header on every request, but when something looks wrong, they're invaluable. If you expect JSON but get HTML back, checking Content-Type will tell you in one glance.
A small habit worth keeping: inspect first, trust later
When you call a new API for the first time, don't jump straight into parsing the JSON. Take a second to look at the raw response:
- Print
response.status_codeto confirm the request actually succeeded. - Print a slice of
response.text(say, the first 300 characters) to see what the server really sent. - Check
response.headers.get("Content-Type")to verify the format.
Once you know the status, format, and general shape of the data, then write the parsing code. This "inspect first" habit will save you a lot of debugging time as your projects grow.
Next, we'll handle the case where things don't go well: a 404, a 500, a dropped connection. Knowing how to catch those failures is the difference between a demo script and a program you'd ship.