Content-Type: application/json, what curl, Python and fetch actually send

Most 'my API ignores the JSON body' bugs are a missing or wrong Content-Type. We logged what each common client really sends.

1. What arrived at the server

Client codeContent-Type sent
curl -d '{"a":1}' URLapplication/x-www-form-urlencoded
curl -H 'Content-Type: application/json' -d '{"a":1}' URLapplication/json
curl --json '{"a":1}' URLapplication/json (and Accept: application/json)
Python requests.post(url, data={"a": 1})application/x-www-form-urlencoded, body a=1
Python requests.post(url, data=json.dumps({"a": 1}))none at all
Python requests.post(url, json={"a": 1})application/json
fetch(url, {method: "POST", body: JSON.stringify(obj)}) (Chrome and Node 24)text/plain;charset=UTF-8
same, with headers: {"Content-Type": "application/json"}application/json

The body was identical JSON in most rows; only the header differed. Servers that pick a parser by Content-Type (Express express.json(), Spring, ASP.NET, PHP's $_POST) see an empty or form body in the bold rows.

2. Copy-paste versions that work

# curl 7.82+
curl --json '{"name":"Ada"}' https://api.example.com/users

# older curl
curl -H 'Content-Type: application/json' -d '{"name":"Ada"}' https://api.example.com/users

# Python
import requests
r = requests.post("https://api.example.com/users", json={"name": "Ada"})

// JavaScript (browser or Node 18+)
const r = await fetch("https://api.example.com/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Ada" }),
});

Need the same request in another language? Paste the curl command into the free curl converter.

3. Accept vs Content-Type

Content-Type describes the body you send; Accept says what you want back. Only curl --json set Accept: application/json by itself; every other client sent Accept: */*. Add it when an API can answer in several formats.

4. Two pitfalls

Frequently asked questions

Does curl -d send application/json?

No. In our test curl -d sent application/x-www-form-urlencoded. Add -H 'Content-Type: application/json' or use --json (curl 7.82+).

What is the difference between data= and json= in Python requests?

json= serialises the object and sets Content-Type: application/json. data=json.dumps(...) sent the same text with no Content-Type at all; data={...} sent a form body.

Does fetch set Content-Type for JSON.stringify bodies?

No. Chrome and Node 24 both sent text/plain;charset=UTF-8. Set the header yourself.

Is it application/json; charset=utf-8?

application/json is enough: JSON is UTF-8 by definition, and a charset parameter is allowed but has no effect for compliant parsers.

Written with AI assistance. Measured on 2026-10-01: a local server logged the Content-Type, Accept and body of POSTs sent by curl 8.14.1, Python requests 2.32.3, Node 24 fetch and Chromium 153 fetch (same-origin page). How Express, Spring, ASP.NET and PHP react is from their documentation, not this test. PlainHeaders is our extension; curl, requests and fetch are free.