How to test API with curl
curl builds the whole request for you: curl -s -X POST https://api.example.com/orders -H 'Content-Type: application/json' -d '{"order":1042}' sends the method, the header and the body, then prints the response body on stdout. Add -i to keep the status line and headers, and -v to see what curl actually sent.
Why check this
Run this the first time an endpoint reaches staging, before anyone writes an automated test against it. curl sends the exact bytes a client would send, so a contract mismatch appears here instead of inside a failing suite three days later. The failure it prevents is specific: a POST answered with 200 while the service ignores the payload, because curl encoded the body as a form and the handler parses JSON.
Prerequisites
- curl 7.0 or later. Every example below works on any build. See the curl manual.
- The endpoint URL, the method, and the token if the route is protected.
- A shell that keeps single quotes intact. Git Bash, WSL, macOS Terminal and Linux shells do. In PowerShell, wrap the body in double quotes and escape the inner ones.
- The examples run against httpbin.org, which echoes the request back as JSON, so you can read what the server received.
Steps
- Step 1.
Send a GET with query parameters and the
Acceptheader the client uses.curl -s -X GET 'https://httpbin.org/get?order=1042&status=open' -H 'Accept: application/json'{ "args": { "order": "1042", "status": "open" }, "headers": { "Accept": "application/json", "Host": "httpbin.org", "User-Agent": "curl/8.21.0", … }, "url": "https://httpbin.org/get?order=1042&status=open" }argsshows the parameters arrived parsed, not glued into one string. - Step 2.
Send a POST with a JSON body and declare the content type.
curl -s -X POST 'https://httpbin.org/post' -H 'Content-Type: application/json' -d '{"order":1042,"qty":2}'{ "data": "{\"order\":1042,\"qty\":2}", "headers": { "Content-Length": "22", "Content-Type": "application/json", … }, "json": { "order": 1042, "qty": 2 }, … }A populated
jsonobject means the server parsed the body. A populateddatawithjson: nullmeans it received text it did not parse. - Step 3.
Add the credential the route requires and read the response.
curl -s -w '\nstatus %{http_code}\n' 'https://httpbin.org/bearer' -H 'Authorization: Bearer h2check-demo-token'{ "authenticated": true, "token": "h2check-demo-token" } status 200Repeat the same command without the
-Hflag. The same route answeredstatus 401here, which confirms the guard is on the route and not on a gateway in front of it. - Step 4.
Print the request curl built, before trusting any of the above.
curl -sv -o /dev/null -d '{"order":1042}' 'https://httpbin.org/post' 2>&1 | grep -E '^[<>]'> POST /post HTTP/2 > Host: httpbin.org > User-Agent: curl/8.21.0 > Accept: */* > Content-Length: 14 > Content-Type: application/x-www-form-urlencoded > < HTTP/2 200 < date: Fri, 11 Sep 2026 18:58:29 GMT < content-type: application/json < content-length: 437 < server: gunicorn/19.9.0 …Lines starting with
>are what curl sent. This command carried JSON text under a form content type, which is the mistake step 2 avoids.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| A JSON body and nothing else | The request succeeded and curl hid the metadata | Add -i when you also need the status line and headers. |
| > Content-Type: application/x-www-form-urlencoded | You sent -d without declaring JSON | Add -H 'Content-Type: application/json' and rerun. |
| Empty output, no error text | -s silenced a transport failure | Use -sS, which keeps errors while hiding the progress meter. |
| "json": null with a filled "data" | The server got the bytes and refused to parse them | Compare the content type you sent with the one the route documents. |
Common mistakes
What to check next
- How to check HTTP status code: the number is the first assertion any API test makes.
- How to check HTTP response headers with curl: read the content type, cache rules and cookies the same request returned.
- How to check API endpoint: turn this manual request into a probe a monitor can run.
- How to test CORS with curl: the same call from a browser adds one header that changes the outcome.
- Api testing checklist: the full pass before an API ships.
FAQ
How to test a REST API using a curl command?
Send one request per operation. -X names the method, -H adds each header, -d carries the body, and the response body lands on stdout. Read the status with -i or -w '%{http_code}'. Nothing else is required for a first contract check.
Can curl send PUT and DELETE?
Yes. curl -X PUT and curl -X DELETE work the same way, and -d attaches a body to either. For DELETE most routes take the identifier in the path, so the command is the URL plus the method.
How do I send a JSON file as the body?
Prefix the filename with an at sign: -d '@order.json'. curl reads the file as is. Keep -H 'Content-Type: application/json', because reading a body from a file does not change the content type curl sets.
How do I see the response headers and the body together?
Use -i. It prints the status line and the response headers, a blank line, then the body. -v adds the request side and the TLS handshake, which is what step 4 filters down to two symbols.
Verified
Verified by Maks Vernycurl 8.21.0
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
basic6 minpublished updated Maks Verny