Getting Started with cURL
The command-line tool that made me stop guessing what my API actually returns
In second year, a senior showed me something that felt like a superpower at the time. He opened his terminal, typed one line, and got back a full JSON response from a live API. No Postman. No browser. No code. Just the terminal.
I asked him what that was. He said "cURL" like it was obvious.
It wasn't obvious to me. I'd been building APIs for a few months and testing them by running my frontend, clicking buttons, and hoping the network tab in Chrome DevTools would show me something useful. Half the time it didn't, and I'd spend an hour not knowing whether the bug was in my frontend code or my backend.
That senior showed me in five minutes that I'd been doing it the hard way. This blog is the five-minute version I wish I'd had.
What Even is a Server?
Before cURL, let's talk about what we're actually talking to.
When you open Instagram, your phone doesn't have your feed stored locally. It sends a request to Instagram's servers — computers sitting in a data center somewhere — asking for your latest posts. Those servers process the request, fetch your data from a database, and send it back. Your app receives it and displays it.
This is the client-server model. Your phone is the client. Instagram's data center is the server. They talk to each other over HTTP — the same protocol your browser uses.
Here's the thing: your browser is a client. Postman is a client. Your mobile app is a client. And cURL? cURL is a client too — just a very stripped-down, terminal-based one.
What is cURL
cURL stands for Client URL. It's a command-line tool that lets you send HTTP requests to servers and see their responses. That's it.
No interface. No buttons. No project to set up. You type a command, you get a response. Done.
Programmers use cURL to:
- Test APIs they've built before writing frontend code
- Debug why a server is returning a certain response
- Check if an endpoint is even reachable
- Quickly inspect what a public API returns
- Automate HTTP requests in shell scripts
The reason it's worth learning isn't that it replaces Postman or your code. It's that it removes every layer between you and the server. No middleware, no framework, no library. Just your request and whatever comes back.
When something breaks and you don't know if it's your frontend, your backend, or the API you're calling — cURL isolates the answer immediately.
Your First cURL Command
Open your terminal. Type this:
curl https://httpbin.org/get
That's it. Press Enter.
You'll get back something like:
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.88.1"
},
"origin": "49.206.12.87",
"url": "https://httpbin.org/get"
}
You just made an HTTP GET request to a real server and got a real response. httpbin.org is a free service built specifically for testing HTTP requests — it echoes back information about the request you sent.
Look at what it returned:
headers: The metadata your request carried — includingUser-Agentwhich shows you sent this as "curl" version whateverorigin: Your public IP addressurl: The exact URL you requested
You didn't write any code. You didn't open a browser. You sent a network request from your terminal and read the response.
Understanding the Response
Let's slow down and understand what's happening when you make a request.
Every HTTP interaction has two parts: a request (what you send) and a response (what comes back).
The request has:
- A method — GET, POST, PUT, DELETE, etc. GET means "give me data." POST means "here's data, process it."
- A URL — where you're sending it
- Headers — metadata about the request (what format you accept, authentication tokens, etc.)
- A body — only relevant for POST and PUT requests, this is the actual data you're sending
The response has:
- A status code — a three-digit number that tells you what happened
- Headers — metadata about the response
- A body — the actual data returned, usually HTML or JSON
Status codes are the shorthand of HTTP. The ones you'll see constantly:
200 OK— worked perfectly201 Created— your POST request created something400 Bad Request— you sent something malformed401 Unauthorized— you need to authenticate404 Not Found— that resource doesn't exist500 Internal Server Error— the server broke, not you
To see the status code and response headers with cURL, add the -i flag:
curl -i https://httpbin.org/get
Now you'll see the full response, headers first:
HTTP/2 200
content-type: application/json
...
{
"args": {},
...
}
That first line — HTTP/2 200 — is the status code. 200 means success. Any time you're debugging and not sure if your request is even landing correctly, -i tells you immediately.
Making a GET Request to a Real API
GET requests are the simplest — you're asking for data, not sending any. Let's try a real public API.
curl https://api.github.com/users/torvalds
This fetches Linus Torvalds' GitHub profile via the GitHub API. You'll get back a JSON object with his username, follower count, public repository count, and more:
{
"login": "torvalds",
"name": "Linus Torvalds",
"public_repos": 8,
"followers": 240000,
...
}
No authentication, no setup. Just a GET request to a public endpoint. This is how you'd test any public API — skip Postman for a moment and just curl it.
If the JSON response is one long unreadable line, pipe it through python3 -m json.tool for pretty printing:
curl https://api.github.com/users/torvalds | python3 -m json.tool
Now it formats nicely with indentation.
Making a POST Request
POST is where things get interesting. GET fetches data. POST sends data.
When you submit a login form, fill out a survey, or create a new record via an API — that's POST. You're sending a body of data to the server and asking it to do something with it.
Here's how a POST request looks in cURL:
curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"name": "Priyanshu", "role": "developer"}'
Let's break down what's new here:
-X POST tells cURL to use the POST method instead of GET (which is the default).
-H "Content-Type: application/json" adds a header. This tells the server: "The data I'm sending is JSON." Servers use this to know how to parse your body. If you send JSON without this header, many servers will reject it or misread it.
-d '{"name": "Priyanshu", "role": "developer"}' is the body — the actual data you're sending. The -d flag means "data".
The server at httpbin.org/post echoes back what you sent:
{
"data": "{\"name\": \"Priyanshu\", \"role\": \"developer\"}",
"headers": {
"Content-Type": "application/json",
...
},
"json": {
"name": "Priyanshu",
"role": "developer"
},
...
}
Your data arrived. The server parsed it as JSON. This is exactly what happens when your frontend sends data to your backend — cURL just makes the same thing happen from your terminal.
Using cURL to Talk to Your Own API
The real power of cURL for most developers is testing their own endpoints before writing frontend code.
Say you've built a simple Express server running locally:
# GET your data
curl http://localhost:3000/api/users
# POST new data
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Test User", "email": "test@example.com"}'
Before writing a single line of React or any frontend code, you can verify your backend is working exactly as expected. The response tells you immediately: is the route registered? Is the data being parsed? Is the database connection working?
If the curl works and the frontend doesn't, the bug is in the frontend. If curl doesn't work either, the bug is in the backend. That isolation saves hours.
For endpoints that need authentication, pass the token in a header:
curl http://localhost:3000/api/profile \
-H "Authorization: Bearer your_token_here"
Common Mistakes Beginners Make
Forgetting the Content-Type header on POST requests.
If you send JSON data without -H "Content-Type: application/json", many servers won't parse the body correctly. You'll get confusing errors that look like the data isn't arriving. It is arriving — the server just doesn't know how to read it.
# Wrong - no Content-Type
curl -X POST http://localhost:3000/api/users \
-d '{"name": "Test"}'
# Correct
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Test"}'
Using single quotes on Windows. The examples in this blog use single quotes around JSON, which works perfectly on Linux and macOS. On Windows Command Prompt, single quotes aren't string delimiters — you need double quotes, and the inner quotes need escaping:
curl -X POST http://localhost:3000/api/users -H "Content-Type: application/json" -d "{\"name\": \"Test\"}"
Windows PowerShell handles this differently again. If you're on Windows and running into quote errors, this is almost certainly why.
Not checking the status code.
A request can "complete" in cURL and still have failed at the HTTP level. If you get back a 401 or 404 response, cURL by default exits with status 0 (success) because the request itself completed — it's just the server said no. Use -i to always see the status code in your response.
Curling HTTPS URLs with certificate issues.
Sometimes you'll hit a self-signed certificate on a development server and cURL refuses to connect. The temptation is to add -k (insecure) to bypass certificate verification. That's fine locally during development. Never do it in production scripts or with real credentials.
Assuming GET when you mean POST.
cURL defaults to GET. If you forget -X POST on a POST request, you'll make a GET request to the same URL and get a confusing response that has nothing to do with your intended action.
The Four Flags You'll Use 90% of the Time
Most day-to-day cURL usage is some combination of these:
curl https://api.example.com/endpoint # Simple GET
curl -i https://api.example.com/endpoint # GET with response headers
curl -X POST https://api.example.com/endpoint \
-H "Content-Type: application/json" \
-d '{"key": "value"}' # POST with JSON body
curl -H "Authorization: Bearer token" \
https://api.example.com/endpoint # Authenticated GET
That's it. You don't need to memorise the entire cURL manual. These four patterns cover almost everything you'll need when building and debugging web applications.
Where to Go From Here
Once you're comfortable with GET and POST, cURL has a lot more to offer — file uploads, cookies, following redirects, saving responses to files, verbose mode to see the full request and response headers. But none of that matters until you're fluent with the basics.
The best way to get there is to replace Postman with cURL for a week whenever you're testing your own APIs. You'll get fast at it quickly, and you'll start to read HTTP interactions more naturally — which pays off every time you're debugging.
The terminal is your most honest interface to the web. cURL is how you use it.
cURL is one of those tools that feels minor until you internalise it. Then it becomes the first thing you reach for whenever something behaves unexpectedly over HTTP. Learn the four flags, use it on your own APIs, and everything else follows naturally.