From a terminal, cURL can send JSON straight to a REST API. You need an HTTP method, a Content-Type: application/json header, and a request body containing valid JSON.
The Short Version
For a POST request, use this command:
curl -X POST 'https://api.example.com/users' \
-H 'Content-Type: application/json' \
-d '{"name":"Alex","email":"alex@example.com"}'Here, -X POST chooses the request method. The -H option adds the JSON content type, while -d provides the body.
Handy shortcut: If you’re running cURL 7.82.0 or newer, --json sends the data and adds the proper JSON headers for you:
curl 'https://api.example.com/users' \
--json '{"name":"Alex","email":"alex@example.com"}'Before You Start
First, check that cURL is installed:
curl --versionRecent versions of Windows 10 and Windows 11 include curl.exe. You’ll also find it preinstalled on most macOS and Linux systems. In every example below, replace the sample URL, IDs, credentials, and field names with values your API accepts.
JSON Options in cURL
| Option | What it does |
|---|---|
-X or --request | Chooses POST, PUT, PATCH, DELETE, or another HTTP method. |
-H or --header | Adds a request header, such as a content type or authorization token. |
-d or --data | Puts data in the request body. Without -X, using this option makes cURL send a POST request. |
--json | Sends JSON and adds the Content-Type and Accept headers. |
-i | Prints response headers along with the response body. |
-v | Displays detailed connection and request diagnostics. |
Sending JSON with POST
POST is commonly used to create a resource or submit an operation. A typical request looks like this:
curl -X POST 'https://api.example.com/orders' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{"product_id":42,"quantity":2}'The Accept header tells the server you expect JSON back. Some APIs don’t require it, but including the header can head off content-negotiation trouble.
Sending JSON with PUT or PATCH
PUT generally replaces the server’s representation of a resource. PATCH changes selected fields instead, though the exact behavior is up to the API.
PUT Example
curl -X PUT 'https://api.example.com/users/123' \
-H 'Content-Type: application/json' \
-d '{"name":"Alex Morgan","email":"alex@example.com","active":true}'PATCH Example
curl -X PATCH 'https://api.example.com/users/123' \
-H 'Content-Type: application/json' \
-d '{"active":false}'Sending JSON with DELETE
A lot of DELETE endpoints need nothing more than the URL:
curl -X DELETE 'https://api.example.com/users/123'Sometimes the endpoint accepts a JSON body. If it does, send that body the same way you would with another method:
curl -X DELETE 'https://api.example.com/sessions' \
-H 'Content-Type: application/json' \
-d '{"session_id":"abc123"}'But support for request bodies on DELETE isn’t universal. Check the API documentation before relying on one.
Using JSON with GET
GET requests usually put their parameters in the URL, rather than a JSON body:
curl --get 'https://api.example.com/users' \
--data-urlencode 'status=active' \
--data-urlencode 'limit=20'That produces a URL similar to https://api.example.com/users?status=active&limit=20. cURL can attach a body to GET, technically, but a proxy, framework, or server may ignore it. Stick with query parameters unless the API specifically asks for a GET body.
Sending JSON from a File
For a nested payload, or one you’ll send more than once, save the JSON in a file named payload.json:
{
"name": "Alex",
"roles": ["editor", "reviewer"],
"preferences": {
"notifications": true
}
}Put @ before the file path to send its contents:
curl -X POST 'https://api.example.com/users' \
-H 'Content-Type: application/json' \
--data-binary '@payload.json'The --data-binary option preserves the file exactly as written. With newer cURL versions, the command gets shorter:
curl 'https://api.example.com/users' --json '@payload.json'Adding API Authentication
Bearer Token
curl 'https://api.example.com/profile' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"display_name":"Alex"}'Basic Authentication
curl -u 'username:password' \
-H 'Content-Type: application/json' \
-d '{"enabled":true}' \
'https://api.example.com/settings'Don’t put real secrets in scripts, shell history, screenshots, or shared logs. For commands you’ll reuse, environment variables or a secret manager are safer.
Quoting in Windows PowerShell
Under Windows PowerShell 5.1, curl may resolve to an Invoke-WebRequest alias. Use curl.exe when you want the actual cURL program:
curl.exe -X POST "https://api.example.com/users" `
-H "Content-Type: application/json" `
-d '{"name":"Alex","active":true}'PowerShell 7 normally runs cURL directly when you enter curl. Keep the JSON body inside single quotes so PowerShell doesn’t interpret the double quotes within it.
Checking the Response and Status
Use -i if you want response headers included. Or save the body and print only the final HTTP status code:
curl -sS -o response.json -w '%{http_code}\n' \
-H 'Content-Type: application/json' \
-d '{"name":"Alex"}' \
'https://api.example.com/users'In this example, the response body goes into response.json. Common status codes include 200 for success and 201 when a resource has been created. You’ll often see 400 for invalid input, 401 for missing or invalid authentication, and 415 when the content type isn’t supported.
Mistakes That Cause Trouble
- Invalid JSON: Property names and string values need double quotes. JSON doesn’t allow trailing commas.
- No content type: Add
Content-Type: application/jsonunless you’re using--json. - Broken shell quoting: On macOS, Linux, and PowerShell where appropriate, wrap the whole payload in single quotes.
- Form data instead of JSON: A plain
-d 'name=Alex'sends form-style data. It isn’t JSON. - Credentials in logs: Verbose output can expose authorization headers, so sanitize logs before sharing them.
Debugging a Failed JSON Request
- Add
-vand inspect the outgoing method and headers. - Use
-ito view the server’s response headers and status. - Check the payload with a JSON validator or
jq. - Make sure the endpoint supports the HTTP method you selected.
- Compare the field names and data types against the API documentation.
curl -v -X POST 'https://api.example.com/users' \
-H 'Content-Type: application/json' \
-d '{"name":"Alex"}'Security note: Don’t treat -k or --insecure as a routine answer to TLS certificate errors. It turns off certificate verification, which can leave the connection open to interception.