POST JSON data with cURL

Last Updated 2023-01-05

TLDR, a basic example:

 # curl 7.82.0 and later (released March 2022)
 $ curl --json ‘{“foo”:  “bar”, “+baz”: “faz”}’
 # before 7.82.0
 curl -X POST -H ‘Content-Type: application/json’ \ 
 -d ‘{“foo”:  “bar”, “baz”: “faz”}’

cURL is an excellent tool for interacting with applications over HTTP and HTTPS. In this post, we will cover how to send JSON to a web server via cURL and review some possible gotchas you might run into when constructing the payload.

Digging into the legacy example from above:

 curl -X POST -H ‘Content-Type: application/json’ \
 -d ‘{“foo”:  “bar”, “baz”: “faz”}’

Take note how in the above example we construct the JSON payload directly on the command line, and pass the [.inline-code]Content-Type[.inline-code] header to [.inline-code]application/json[.inline-code] to allow our server to understand that what we are sending is in JSON format. 

[#post-a-json-file]cURL POST a JSON file[#post-a-json-file]

Sometimes, we cannot construct the JSON directly on the command line as shown above. Perhaps the payload is very large or requires complex constructs such as nested arrays. In this scenario it would be preferable to construct the JSON using another method (e.g. a Python script) and dump it into a file. Then, when the JSON file is in place, we can send it via cURL.

 # assume your file is named test.json
 curl -X POST -H ‘Content-Type: application/json’ -d @test.json

[#json-option]cURL with --json[#json-option]

With the  March 2022 release of cURL version 7.82.0, a new [.inline-code]—json[.inline-code] option became available. Back to the example from the top:

 $ curl --json ‘{“foo”:  “bar”, “baz”: “faz”}’

Take note that we don’t need to pass the [.inline-code]Content-Type[.inline-code] header, nor the [.inline-code]-X POST[.inline-code]. cURL handles these bits internally as a result of [.inline-code]--json[.inline-code].We can further shorten the above by putting our JSON in a file called test.json and running this command:

 $ curl --json @test.json

[#format-json]Make sure you format your JSON correctly[#format-json]

It is recommended to pass your intended JSON payload through jq to verify the syntax. For example:

 $ echo '{"foo":  "bar", "baz": "faz"}' | jq
 # or
 $ cat test.json | jq

[#double-quotes-inside-single-quotes]Use double quotes inside single quotes[#double-quotes-inside-single-quotes]

If building JSON on the command line, keep in mind single quotes on the outside and double quotes on the inside. For example:

 $ curl --json ‘{“foo”:  “bar”, “baz”: “faz”}’

[#enquote-or-escape-special-chars]Escape or enquote special characters in the URL[#enquote-or-escape-special-chars]

 # use quotes when trying to do curl --json
 $ curl --json “”
 # or escape it
 $ curl\&hello

[#charset-in-content-type]The server may require a charset in the content-type[#charset-in-content-type]

If so, you can pass it like this:

 $ curl --json ‘{“foo”:  “bar”, “baz”: “faz”}’ \
 -H "Content-Type: application/json; charset=UTF-8"

[#405-error-on-post]Solving HTTP status code 405 (Method Not Allowed)[#405-error-on-post]

This means that an HTTP POST is not accepted on the endpoint. Try another method, such as PUT or PATCH, that aligns with the API specification of the server you are trying to hit.

This post was all about cURL with JSON payloads - read more about cURL POST requests more generally in our other post.