Skip to main content

Command Palette

Search for a command to run...

Getting Started with cURL

The command-line tool that made me stop guessing what my API actually returns

Updated
9 min read

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 — including User-Agent which shows you sent this as "curl" version whatever
  • origin: Your public IP address
  • url: 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 perfectly
  • 201 Created — your POST request created something
  • 400 Bad Request — you sent something malformed
  • 401 Unauthorized — you need to authenticate
  • 404 Not Found — that resource doesn't exist
  • 500 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.