The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use requests.post() to send data to an HTTP endpoint and receive a Response object. In production code, choose the body argument that matches the API contract—json= for a JSON document, data= for form fields or raw content, and files= for multipart uploads—then set an explicit timeout, call raise_for_status(), and parse the response according to its documented format.
Install Requests and verify your Python version
The current Requests documentation covered here is for Requests 2.34.2 and officially supports Python 3.10 and newer. Install or upgrade it in the environment that will run your program:
python -m pip install --upgrade requests
Confirm the interpreter and package are visible from the same environment:
python --version
python -c "import requests; print(requests.__version__)"
Use a virtual environment for applications so the package version is isolated from other projects.
#1 Best Overall
The basic POST pattern
import requests
payload = {"name": "Ada", "active": True}
response = requests.post(
"https://api.example.test/items",
json=payload,
timeout=(3.05, 20),
)
response.raise_for_status()
item = response.json()
print(item)
requests.post(url, ...) opens a POST request and returns a Response. The tuple timeout sets separate connection and read limits. The values above are examples, not universal settings: choose limits that fit the endpoint and your service-level expectations.
Choose the correct request body
| API expects | Requests argument | What Requests sends | Important details |
|---|---|---|---|
| Form fields | data={...} |
URL-encoded form data | Dictionary values are encoded as form fields. |
| JSON object or array | json=payload |
JSON with the appropriate content type | Preferred for normal JSON APIs; Python booleans and nested values are serialized for you. |
| Raw text or bytes | data="..." or data=b"..." |
The supplied bytes/text | Set headers yourself when the endpoint requires a specific media type. |
| Multipart upload | files={...} |
multipart/form-data |
Open files in binary mode; large multipart bodies are not streamed by Requests by default. |
Send form-encoded data
import requests
response = requests.post(
"https://api.example.test/submit",
data={"name": "Ada", "active": "true"},
timeout=(3.05, 20),
)
response.raise_for_status()
Use the form format only when the server documents it. A Python dictionary passed to data is encoded as form data, not JSON.
Send JSON
import requests
payload = {
"name": "Ada",
"roles": ["admin", "reviewer"],
"enabled": True,
}
response = requests.post(
"https://api.example.test/items",
json=payload,
timeout=(3.05, 20),
)
response.raise_for_status()
# Call this only when the endpoint promises a JSON response.
item = response.json()
Do not manually call json.dumps(payload) and pass the resulting string to data unless you also deliberately set the required content type and encoding. The normal JSON-object case is clearer and safer with json=payload.
If you provide either data or files, Requests ignores json. Supplying both can therefore produce a body different from the one you intended.
Send repeated form keys
import requests
response = requests.post(
"https://api.example.test/form",
data=[("tag", "python"), ("tag", "http")],
timeout=(3.05, 20),
)
response.raise_for_status()
A list of two-tuples preserves repeated keys. This is useful when a form contract expects tag=python&tag=http instead of a single combined value.
Upload a file with multipart encoding
import requests
with open("report.csv", "rb") as file_obj:
response = requests.post(
"https://api.example.test/upload",
files={"file": file_obj},
timeout=(3.05, 60),
)
response.raise_for_status()
Keep the file open until the request finishes. You can include ordinary fields alongside the upload with data={...}. Requests builds the multipart body in memory; for very large uploads, check whether the API and your chosen HTTP client support a streaming upload strategy.
Rank #3
Timeouts: prevent a request that appears to hang
Without an explicit timeout, Requests does not time out. The documentation describes the timeout as the wait for socket data, not a total deadline for downloading the complete response. A server that continuously sends small pieces can therefore run longer than the read value.
Free tools Windows power users keep installed
One-click scans. No signup required.
response = requests.post(
"https://api.example.test/items",
json={"name": "Ada"},
timeout=(3.05, 20), # connect timeout, read timeout
)
- Connect timeout: how long to establish the connection.
- Read timeout: how long to wait for the next bytes from the server.
- Total runtime: not directly enforced by this tuple; apply an outer deadline in your job system when a hard wall-clock limit is required.
The Requests Quickstart says nearly all production code should use the timeout parameter in nearly all requests. Treat the example values as starting points and tune them to the endpoint’s normal response time and your retry policy.
Read responses correctly
Check HTTP status before trusting the body
response = requests.post(
"https://api.example.test/items",
json={"name": "Ada"},
timeout=(3.05, 20),
)
response.raise_for_status()
raise_for_status() raises HTTPError for unsuccessful HTTP responses. Alternatively, compare response.status_code with the exact success codes in the API contract. A 2xx status often means the HTTP exchange succeeded, but the endpoint may define additional application-level success or failure fields.
Rank #4
- Python Programming Language design with distressed logo for Python Software Engineers and Developers.
- Vintage and Distressed Python Programming Language design.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Parse the documented response format
if response.status_code == 204:
print("Success with no response body")
else:
content_type = response.headers.get("Content-Type", "")
if "application/json" in content_type:
result = response.json()
else:
result = response.text
print(result)
response.json() only decodes syntax; it can successfully parse an error payload. Parse after checking status, and only call it when the endpoint promises JSON. For binary responses use response.content; for streamed downloads, configure a streaming approach appropriate to the endpoint.
Headers, authentication, and raw bodies
import requests
response = requests.post(
"https://api.example.test/events",
json={"type": "created"},
headers={
"Authorization": "Bearer YOUR_TOKEN",
"Idempotency-Key": "event-123",
},
timeout=(3.05, 20),
)
response.raise_for_status()
Use the authentication and idempotency mechanism specified by the API. Never hard-code production secrets in source control; load them from a secret manager or environment variable. For a raw body, pass bytes or text through data and set a matching Content-Type header when required.
Sessions for repeated POST calls
import requests
with requests.Session() as session:
session.headers.update({"Authorization": "Bearer YOUR_TOKEN"})
first = session.post(
"https://api.example.test/login",
json={"user": "ada"},
timeout=(3.05, 20),
)
first.raise_for_status()
second = session.post(
"https://api.example.test/profile",
timeout=(3.05, 20),
)
second.raise_for_status()
A Session persists cookies and uses connection pooling, reducing setup work across calls. It can also hold shared headers and other request configuration. Close it with a context manager as shown.
Best Value
Exceptions, retries, and safe recovery
import requests
try:
response = requests.post(
"https://api.example.test/items",
json={"name": "Ada"},
timeout=(3.05, 20),
)
response.raise_for_status()
except requests.exceptions.ConnectTimeout:
print("The connection could not be established in time")
except requests.exceptions.Timeout:
print("The server did not provide socket data in time")
except requests.exceptions.ConnectionError:
print("A network connection failed")
except requests.exceptions.HTTPError as exc:
print(f"The server returned an HTTP error: {exc}")
except requests.exceptions.TooManyRedirects:
print("The redirect limit was exceeded")
except requests.exceptions.RequestException as exc:
print(f"Other Requests failure: {exc}")
These exceptions derive from RequestException. Requests documents a ConnectTimeout as safe to retry at the library level, but do not blindly repeat every POST: the server might have completed the operation before the client lost the response. Retry only when the endpoint defines safe semantics, preferably with an idempotency key, bounded attempts, and backoff.
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Server says “invalid JSON” | Form data or a manually serialized string was sent instead of a JSON request. | Use json=payload; do not also pass data or files. |
| Request hangs indefinitely | No timeout was supplied. | Set separate connect/read timeouts and an outer job deadline if needed. |
JSONDecodeError after a request |
The body is empty, HTML, or an error document. | Check status and Content-Type before calling response.json(). |
| Upload rejected or truncated | File was opened in text mode or closed too early. | Open with "rb" and keep the context active through the POST. |
| Duplicate records after retry | The POST was not idempotent and the first attempt may have succeeded. | Follow the API’s idempotency guidance; use a unique key where supported. |
| Cookies disappear between calls | Separate top-level requests.post calls were used. |
Use one requests.Session() for the workflow. |
Performance, reliability, and security notes
- Reuse a Session for sequences of calls to benefit from connection pooling and shared configuration.
- Keep connect and read timeouts explicit and observe their separate meanings when tuning them.
- Limit response logging; redact authorization headers, cookies, and personal data.
- Validate status codes and response schemas before acting on returned values.
- For large multipart bodies, account for Requests’ default in-memory construction and the resulting memory use.
- Use TLS URLs, certificate verification defaults, and a secret store rather than embedding credentials.
Or skip the browser setup
If your POST workflow ultimately exists to obtain website screenshots, ScreenshotNeo provides a direct HTTP endpoint instead of maintaining browser automation. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
Use the API with one GET request:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo API documentation for all 63 options, including full-page lazy-image capture, CSS-selector elements, device presets, retina scale, PDFs, custom CSS and JavaScript, clicks, waits, blocking rules, headers, cookies, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture, usage, and OpenAPI compatibility. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Recommended Free Tools
Quick decision guide
- Choose
json=when the endpoint documents JSON. - Choose
data=for URL-encoded fields, repeated keys, or a deliberately raw body. - Choose
files=for multipart uploads and open files in binary mode. - Always set a timeout, then check status before parsing.
- Use a Session for cookies, pooling, and shared settings across calls.
Frequently Asked Questions
Does requests.post return JSON automatically?
No. It returns a Response object. Call response.json() only when the endpoint returns JSON, and check the HTTP status first.
Can I use json= and data= together?
You can pass both, but Requests ignores json when data or files is supplied. Select the one body format required by the API.
Is a POST request safe to retry?
Not inherently. A timeout can occur after the server processed the request. Retry only under the endpoint’s documented idempotency rules, ideally with an idempotency key.
What does a tuple timeout mean?
timeout=(connect, read) sets separate limits for establishing the connection and waiting for socket data; it is not a total download deadline.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

