Back to all posts
Tutorial
8 min read

How to Use curl: 12 Commands for APIs

DevToolLab Team

DevToolLab Team

September 27, 2026

How to Use curl: 12 Commands for APIs

curl sends a single HTTP request from the terminal and prints whatever comes back: curl -X POST https://api.example.com/users -H "Content-Type: application/json" -d '{"name":"Ada"}' runs a POST with a JSON body. Swap the method, the header and the -d payload and the same shape covers GET, PUT, DELETE, file uploads and authenticated requests.

Every flag is easy to look up on its own. Stringing enough of them together to actually test an endpoint, the JSON quoting, the headers, the auth token, the redirect handling, is where most people give up and reach for Postman instead. Worth checking first: curl --version. The machine this post was written on reports curl 8.7.1, the build Apple ships with macOS. The curl project itself shipped 8.22.0 on September 2, 2026, with the next release planned for October 14, so a flag that doesn't work as documented is sometimes just a newer feature than the curl on your system.

curl.se release table showing version 8.22.0 released September 2, 2026 as the newest entry, with 8.21.0 and 8.20.0 listed below it and a note that the next release is planned for October 14, 2026
curl.se release table showing version 8.22.0 released September 2, 2026 as the newest entry, with 8.21.0 and 8.20.0 listed below it and a note that the next release is planned for October 14, 2026

Every command below runs against httpbin.org, a public test API built for exactly this, and every response pasted in is real output from actually running it, not a reconstruction. The trace ID and timing will differ if you run the same command yourself, everything else will match.

The Fastest Way

Paste any command below into the cURL to Code Converter to get the equivalent JavaScript fetch, Axios or Python requests call without mapping every flag to its option name by hand. It parses the command text in your browser; it doesn't send the request itself. Think of it as a translation step before you write the calling code, not a substitute for running curl to see what the endpoint actually returns.

The DevToolLab cURL to Code Converter tool page with a sample curl POST command containing an Authorization header and a JSON body in the input pane, and an empty JavaScript fetch output pane on the right
The DevToolLab cURL to Code Converter tool page with a sample curl POST command containing an Authorization header and a JSON body in the input pane, and an empty JavaScript fetch output pane on the right

Reading a Response

A GET request needs no flags at all:

curl https://httpbin.org/get
JSON
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/8.7.1",
    "X-Amzn-Trace-Id": "Root=1-6ab8f9ef-298006f263ff54c24c9fc41a"
  },
  "origin": "44.227.128.71",
  "url": "https://httpbin.org/get"
}

Add -i to see the status line and response headers above the body, which is the first thing to check when an API returns something unexpected:

curl -i https://httpbin.org/get
HTTP/2 200
content-type: application/json
content-length: 254
server: gunicorn/19.9.0
access-control-allow-origin: *

Add -o <file> to write the body to a file instead of printing it, which matters the moment a response is larger than a terminal scrollback:

Bash
curl -o response.json https://httpbin.org/get
cat response.json

Sending Data to an API

A POST needs a method flag, a content-type header and a body. For JSON, quote the whole payload as a single string and escape nothing except the outer quotes:

Bash
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada Lovelace","role":"engineer"}'
JSON
{
  "data": "{\"name\":\"Ada Lovelace\",\"role\":\"engineer\"}",
  "json": {
    "name": "Ada Lovelace",
    "role": "engineer"
  },
  "url": "https://httpbin.org/post"
}

Drop the -H flag and curl defaults to form encoding, which is what an HTML <form> sends and what a lot of older APIs still expect:

Bash
curl -X POST https://httpbin.org/post -d "name=Ada&role=engineer"
JSON
{
  "form": {
    "name": "Ada",
    "role": "engineer"
  },
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  }
}

-F builds a multipart form and uploads a real file when the value starts with @:

Bash
curl -F "file=@notes.txt" https://httpbin.org/post
JSON
{
  "files": {
    "file": "curl is great for automation\n"
  },
  "headers": {
    "Content-Type": "multipart/form-data; boundary=------------------------RJw5UaJnNLyLdCifwgd4a1"
  }
}

-X PUT replaces a resource, and -X DELETE needs no body at all:

Bash
curl -X PUT https://httpbin.org/put \
  -H "Content-Type: application/json" \
  -d '{"status":"active"}'

curl -X DELETE https://httpbin.org/delete

Both echo back the same shape as the POST above, with "url" pointing at /put and /delete and the method's own JSON in "json".

Authenticating a Request

-u sends HTTP Basic auth as a base64-encoded header, which curl builds for you:

Bash
curl -u ada:secret123 https://httpbin.org/basic-auth/ada/secret123
{ "authenticated": true, "user": "ada" }

A bearer token is just a header, so most APIs are one -H away from working:

Bash
curl -H "Authorization: Bearer demo-token-123" https://httpbin.org/bearer
JSON
{ "authenticated": true, "token": "demo-token-123" }

Following Redirects and Measuring Latency

curl doesn't follow redirects by default, which trips people up constantly, since a browser does it silently. Add -L, and -w to print exactly what happened after -o /dev/null throws away the body:

Bash
curl -L -o /dev/null \
  -w "final_url=%{url_effective} redirects=%{num_redirects} status=%{http_code}\n" \
  https://httpbin.org/redirect/2
final_url=https://httpbin.org/get redirects=2 status=200

The same -w format string reports timing without ever printing the response body, which is the fastest way to check whether a slow page load is the network or the server:

Bash
curl -s -o /dev/null -w "status=%{http_code} time_total=%{time_total}s\n" https://httpbin.org/get
status=200 time_total=1.385114s

Common Errors

curl: (6) Could not resolve host: <hostname> means DNS lookup failed, almost always a typo in the domain, a missing VPN connection, or no internet at all. Run nslookup <hostname> to confirm it independently of curl before assuming the flag syntax is wrong.

curl: (7) Failed to connect to <host> port <port> after 0 ms: Couldn't connect to server means nothing answered on that port. It's the standard error when a local dev server hasn't started yet, the port number is wrong, or a firewall is blocking it. Check with the DevToolLab HTTP Status Checker if the target is a public URL, so you know whether the problem is your machine or theirs.

curl: (28) Operation timed out after 2004 milliseconds with 0 bytes received shows up when --max-time or --connect-timeout is set lower than the server actually needs. Raise the limit if the endpoint is just slow, or go investigate the server if it shouldn't be.

curl: (60) SSL certificate problem: self signed certificate means curl cannot verify who it is talking to. On a local dev server with a self-signed cert, point curl at the certificate with --cacert path/to/cert.pem rather than reaching for -k / --insecure, which skips verification entirely and should never touch anything that isn't your own throwaway setup.

When Not to Do This

A token or password passed as a command-line argument lands in your shell history file and is briefly visible to any other process on the machine that runs ps aux while the command executes. Prefer -H "Authorization: Bearer $TOKEN" with the token read from an environment variable, or a --config file with its permissions set to chmod 600, over typing a live secret directly into a command you might paste into a script, a chat message or a ticket.

  • cURL to Code Converter - paste any command above and get the equivalent fetch, Axios or Python call, the fastest way to turn a one-liner into application code without hand-translating flags.
  • HTTP Status Checker - see the status code, every redirect hop and the response time for a URL from a browser tab when you want confirmation outside the terminal.
  • CORS Tester - curl requests are never blocked by CORS, since browsers enforce that policy, not servers, so check here whether a request that works in curl will actually work from JavaScript in a browser.
  • API Key Generator - generate a throwaway key in the browser to test the auth commands above without reusing a real production credential.

Related Posts

Local AI Git Commit Message Generator

Build a Python CLI and a prepare-commit-msg hook that turn a staged diff into a Conventional Commits message using a model on your own machine.

By DevToolLab Team•

AI-Powered Webhook Handlers: Smart Event Processing for Developers in 2026

Learn how to build AI-powered webhook handlers that classify events, extract structured data, auto-generate responses, and detect anomalies - with real code examples in Node.js and Python.

By DevToolLab Team•

Encoding Text to Morse Code: A Guide to Optical Signals

Learn how digital text data is serialized into Morse code patterns and explore techniques for translating text inputs into visual flashlight signals.

By DevToolLab Team•