The command
curl https://httpbin.org/anything \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"query":"status:open","limit":10}'
Opens the request console with this request filled in. It is sent from api-tester.com's server rather than from your machine, so it shows what the endpoint returns, not how your own network or curl build behaves.
What the flags do
| Flag | What it does |
|---|---|
-H "Content-Type: application/json" | Says the body you are sending is JSON. |
-H "Accept: application/json" | Says you want JSON back. |
-d data | The JSON document. Makes the request a POST unless -X says otherwise. |
-X PUT / PATCH / DELETE | Sends the same kind of body with another method. |
--json data | Sets the body and both headers in one flag (curl 7.82+). |
Two headers, two directions
The pair is not redundant. Leave out the first and the server does not run its JSON parser on your body. Leave out the second and an API that supports several formats may reply in XML, or send an HTML error page that your script then tries to read as JSON. A request with no body, such as most GET and DELETE calls, needs only Accept.
The method is independent of all this. The same headers and the same kind of body work with PUT and PATCH; only -X changes.
curl -X PUT https://httpbin.org/anything/users/42 \
-H "Content-Type: application/json" -H "Accept: application/json" \
-d '{"name":"Ada","active":true}'
curl -X DELETE https://httpbin.org/anything/users/42 -H "Accept: application/json"
Building the body without quoting accidents
Pasting a shell variable into a JSON string works until the value contains a quote, a backslash or a line break, at which point the document is no longer valid. Let jq assemble it: --arg passes a value in as a correctly escaped string, --argjson passes a number or boolean as it is, and the result is piped to curl, which reads it with -d @-.
title='Disk "sda" is 91% full'
jq -n --arg title "$title" --argjson priority 2 \
'{title: $title, priority: $priority}' \
| curl -s https://httpbin.org/anything \
-H "Content-Type: application/json" -H "Accept: application/json" -d @-
Using a value from the reply
Real work is rarely one call. You create something, read its id from the response, and use the id in the next URL. Capture the field with jq -r; the -r removes the surrounding quotes, without which the next URL would contain them. Check the variable before relying on it, because a field that is absent comes out as the four letters of the word null, not as an empty string.
id=$(curl -s https://httpbin.org/anything \
-H "Content-Type: application/json" -d '{"id":"ord_123"}' | jq -r '.json.id')
curl -s "https://httpbin.org/anything/orders/$id" -H "Accept: application/json" | jq -r '.url'
Common mistakes
- JSON has no single-quoted strings and no trailing commas.
{'a':1,}is fine in several programming languages and rejected by every JSON parser. - Numbers and strings are different types.
"limit":"10"fails validation on an API that expects"limit":10. - An error reply is usually JSON too. A 4xx body often names the exact field at fault, so read it before changing the request.
Related curl examples
Curl POST JSON Example
Sending JSON takes two things: the JSON itself and a header saying that is what it is.
Curl GET JSON Example
Fetching JSON is a GET with one header that says what you want back.
Curl Content-Type Example
Content-Type tells the server how to parse the body you sent.
Curl PATCH Request Example
PATCH changes part of a resource.
JSON Validator
Check a body before sending it, with the line and column of any error.
All Curl Examples
49 worked examples, grouped by what you are trying to do.
More under Request bodies
References
- curl man page: --json — The shortcut that sets the body and both JSON headers.
- MDN: Accept — The header that asks for a JSON reply.
- jq manual — Building and reading JSON on the command line.
These links leave api-tester.com, which is independent of the projects they point to.
FAQ
How do I send a JSON request with curl?
Send the JSON with -d, add -H "Content-Type: application/json" to describe it and -H "Accept: application/json" to ask for a JSON reply.
What is the difference between Content-Type and Accept in a JSON request?
Content-Type describes the body of the request you send. Accept tells the server which format you want in the response.
How do I put a shell variable into a JSON body for curl?
Build the JSON with jq, for example jq -n --arg name "$NAME" '{name: $name}', and pipe it to curl -d @-. jq escapes the value correctly.