HTTPie – A Modern Curl Alternative to Test REST APIs in Linux

Testing an API with curl often means writing long commands full of -H and -d flags, then dealing with a wall of unformatted JSON. HTTPie makes API testing easier with readable request syntax, automatic JSON handling, and colorized, formatted output, letting you send requests with data, headers, and authentication directly from the terminal.

If you manage web servers or work with APIs, you probably send HTTP requests from the terminal several times a day. You might check whether a health endpoint returns HTTP 200 after a deployment, post test data to a new API, or verify which headers a reverse proxy adds.

curl handles all these tasks, but sending JSON often requires extra flags, careful quoting, and a separate tool such as jq to make the response easier to read.

HTTPie (pronounced aitch-tee-tee-pie) is an open-source command-line HTTP client written in Python, designed to make working with APIs and HTTP servers more convenient. You specify the HTTP method, URL, and request data using a readable syntax, and HTTPie handles the request formatting and displays supported responses with colors and indentation.

It provides two commands, http and https, for sending HTTP and HTTPS requests, respectively. The https command assumes the https:// scheme when one is not specified.

This updated guide replaces our older HTTPie article, which covered HTTPie 1.x. Since then, the project has moved to the httpie/cli repository on GitHub, dropped Python 2.7 support, introduced nested JSON syntax, and added the httpie cli command for managing plugins.

The latest release listed in the official documentation is HTTPie 3.2.4, released on November 1, 2024. Verify the release status again immediately before publication.

How HTTPie Builds a Request from Request Items

Before installing anything, it helps to understand how HTTPie parses a command line. Almost every example later in this guide uses the same handful of separators. Once you understand them, you can build most HTTP requests without looking up the syntax.

The general syntax looks like this:

http [FLAGS] [METHOD] URL [ITEM ...]

The HTTP method is optional. If you omit it, HTTPie uses GET when no request data is supplied and POST when request data is supplied. You can also use a shortcut for localhost: http :8080/health sends a request to http://localhost:8080/health, which is useful when testing a service running on your own machine.

Everything after the URL is a request item. HTTPie determines the type of each item from the separator between its key and value:

  • Header:Value adds an HTTP header, for example User-Agent:tecmint-check/1.0.
  • param==value adds a URL query parameter. For example, page==2 appends ?page=2, with HTTPie handling URL encoding for the parameter.
  • field=value adds a string field to the request body. By default, HTTPie serializes data fields as JSON. Use --form to send form-encoded data or --multipart to send multipart form data.
  • field:=json adds a raw JSON value, which is useful for numbers, booleans, arrays, and objects. For example, port:=8080 sends a number, while enabled:=true sends a boolean.
  • field@/path/file uploads a file as a form field. This requires --form or --multipart and results in a multipart upload when a file field is present.
  • field=@/path/file reads a file’s contents into a field as a string.
  • field:=@/path/file.json reads a file and embeds its contents as a JSON value.

The difference between = and := catches many beginners. Consider these two examples:

http POST https://api.example.com/devices port=8080
http POST https://api.example.com/devices port:=8080

The first sends "port": "8080" as a JSON string, while the second sends "port": 8080 as a JSON number. If an API schema requires an integer, sending a string may cause validation to fail. The exact response depends on how the API handles invalid input.

Remember these separators, and you’ll be able to construct headers, query parameters, JSON bodies, and file uploads directly from the command line with much less typing.

Install HTTPie: Now that the syntax makes sense, let’s install HTTPie. Most major Linux distributions package it, although the version available depends on the distribution and its release cycle.

On Ubuntu and Debian, you can install HTTPie from the distribution repositories. On Ubuntu, the package is available through the universe component, which may need to be enabled first.

sudo apt update
sudo apt install -y httpie

If you want to use the version provided by the HTTPie project, add its official APT repository and signing key:

curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" | sudo tee /etc/apt/sources.list.d/httpie.list > /dev/null
sudo apt update
sudo apt install -y httpie

This repository configuration specifies amd64. If you use ARM64 or another architecture, check the repository’s supported architectures before using this entry.

On Fedora, HTTPie is available in Fedora’s standard repositories, so you can install it directly with DNF:

sudo dnf install -y httpie

On Enterprise Linux distributions such as Rocky Linux, AlmaLinux, and RHEL, HTTPie is available through EPEL for some releases. You may also need the CRB repository, which provides dependencies required by certain EPEL packages.

For Rocky Linux 9 and 10, enable CRB and install EPEL:

sudo dnf install -y epel-release
sudo dnf config-manager --set-enabled crb
sudo dnf install -y httpie

For Rocky Linux 8, enable PowerTools instead of CRB:

sudo dnf install -y epel-release
sudo dnf config-manager --set-enabled powertools
sudo dnf install -y httpie

Package availability varies by release. The Fedora package index lists HTTPie in EPEL 8 and EPEL 9, but does not currently list it for EPEL 10. Check the HTTPie package index before assuming the package is available for your specific Enterprise Linux release.

Install HTTPie with pipx

If your distribution does not provide HTTPie, you can install it using pipx. It creates an isolated Python environment for HTTPie and exposes its commands on your PATH, avoiding conflicts with system-managed Python packages.

On Ubuntu or Debian, install pipx with:

sudo apt update
sudo apt install -y pipx
pipx ensurepath

On Fedora or a compatible DNF-based distribution where the package is available, use:

sudo dnf install -y pipx
pipx ensurepath

Then install HTTPie:

pipx install httpie

If pipx ensurepath updates your shell configuration, open a new terminal or follow its instructions to update your current PATH. On Rocky Linux or RHEL, the availability of pipx itself depends on the enabled repositories.

On Arch Linux, HTTPie is available through the official repositories:

sudo pacman -Syu httpie

Verify the installation

Regardless of which installation method you choose, check the version and confirm that both HTTP commands are available:

http --version
https --version

Example output:

3.2.4
3.2.4

Your output may differ depending on the package source. The examples in this guide target HTTPie 3.x, and the nested JSON syntax used in Example 3 requires HTTPie 3.0 or later. If you install an older distribution package, check its version before running the examples.

Example 1: Check HTTP Status and Response Headers with HTTPie

One of the most common tasks for a sysadmin is checking what a web server returns. In this example, the lab server is 192.168.122.248 (also reachable as server1.tecmint.lan), with a web server listening on port 80.

Running HTTPie with just a URL sends a GET request by default and displays the response status, headers, and body:

http http://192.168.122.248/

When troubleshooting caching, redirects, or server configuration, you may only need the status and response headers. Use the -h flag (--headers) to display the response headers without the body. Unlike curl -I, which sends a HEAD request, HTTPie still sends a normal GET request:

http -h http://192.168.122.248/

Example output:

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 615
Content-Type: text/html
Date: Mon, 26 Oct 2026 06:40:12 GMT
ETag: "6714a2b1-267"
Last-Modified: Sun, 25 Oct 2026 10:12:33 GMT
Server: nginx/1.26.3

The actual headers depend on the server and its configuration. Start with the status line: 200 OK indicates a successful request, while codes such as 301 or 302 indicate redirects.

The remaining headers provide details about the response, including its content type, caching metadata, and server information when exposed.

When you need to inspect both the outgoing request and the incoming response, use -v (--verbose). This is useful for confirming that a custom header was sent correctly:

http -v GET http://192.168.122.248/ User-Agent:tecmint-check/1.0

For more precise output, use --print (or -p) to select which parts of the exchange HTTPie displays:

  • H prints request headers.
  • B prints the request body.
  • h prints response headers.
  • b prints the response body.

For example, to display only the request and response headers, run:

http -p Hh http://192.168.122.248/

This is particularly useful when debugging reverse proxies, checking forwarded headers, or verifying custom authentication headers without displaying the response body.

By default, HTTPie does not follow redirects. This lets you inspect the initial response when checking an HTTP-to-HTTPS redirect or diagnosing a redirect loop. To follow redirects, add --follow (or -F). To display the intermediate responses as well as the final response, use --all:

http --follow --all http://192.168.122.248/

These options give you a quick way to inspect server responses and trace redirect behavior without building long curl commands.

If this finally made checking response headers quick and readable, share it with someone who still scrolls through curl -v output to find a single status line.

Example 2: Send JSON Data and Query Parameters to a REST API

Checking a page is only part of API testing. You often need to submit data, too. This is where HTTPie saves typing compared with curl, it builds the JSON request body from readable field assignments and automatically sets the Content-Type: application/json header.

For this example, we’ll use httpbin.org, a public test service that echoes request details so you can inspect what the server received. The following command sends two string fields, one number, and one boolean:

http POST https://httpbin.org/post name=web01 role=frontend port:=8080 enabled:=true

In the json section of the response, you should see the submitted data represented like this:

{
  "enabled": true,
  "name": "web01",
  "port": 8080,
  "role": "frontend"
}

Notice that port arrives as a number and enabled as a boolean. This demonstrates the difference between = and := discussed earlier. If you use port=8080, HTTPie sends the value as the JSON string "8080" rather than the number 8080.

Query parameters use ==. HTTPie handles URL encoding, so you can pass values containing spaces without manually escaping them:

http GET https://httpbin.org/get search=='disk full' limit==10

The request includes the search and limit query parameters. You can inspect the url field in httpbin’s response to see the resulting URL and how the parameters were encoded.

If an API expects form data instead of JSON, add --form (or -f). HTTPie then sends the same key=value items as URL-encoded form data using application/x-www-form-urlencoded:

http --form POST https://httpbin.org/post user=tecmint comment='Hello World'

In the response, check the form section to see the submitted fields. Unlike JSON, form-encoded values are transmitted as strings, so this format is appropriate when an API expects traditional HTML form submissions.

Example 3: Build Nested JSON and Preview Requests with –offline

The flat JSON in the previous example covers many APIs, but real-world payloads often contain nested objects and arrays. Before HTTPie 3.0, building these structures from individual request items was less convenient and often required passing raw JSON with :=.

HTTPie 3.0 introduced nested JSON syntax, which lets you describe the structure directly using square brackets in field names.

Before sending a complex payload to a real API, it is good practice to preview the request. The --offline flag builds and prints the request without sending it over the network, allowing you to inspect the JSON body first.

For example, the following command creates a nested network object containing an IP address and an array of numeric ports, along with a top-level array of tags:

http --offline --print=B POST https://httpbin.org/post \
    name=web01 \
    'network[ip]=192.168.122.248' \
    'network[ports][]:=80' \
    'network[ports][]:=443' \
    'tags[]=nginx' \
    'tags[]=production'

Output:

{
    "name": "web01",
    "network": {
        "ip": "192.168.122.248",
        "ports": [
            80,
            443
        ]
    },
    "tags": [
        "nginx",
        "production"
    ]
}

The important part is how HTTPie interprets the field names:

  • network[ip] places the IP address inside a nested network object.
  • network[ports][] appends each supplied value to the ports array.
  • tags[] appends values to a top-level array.
  • := preserves the port values as JSON numbers rather than strings.

Because --offline automatically prints the request headers and body, adding --print=B narrows the output to the body. This keeps the example focused on the generated JSON and avoids distracting differences in headers such as Content-Length or User-Agent across HTTPie versions.

Once the payload looks correct, remove --offline and run the command again to send the request:

http POST https://httpbin.org/post \
    name=web01 \
    'network[ip]=192.168.122.248' \
    'network[ports][]:=80' \
    'network[ports][]:=443' \
    'tags[]=nginx' \
    'tags[]=production'

HTTPie 3.0 or later is required for this nested JSON syntax. Check your installed version with http --version if you encounter errors. The official version covers nested objects, arrays, and offline request previews.

Example 4: Authenticate with Basic Auth, Bearer Tokens, and Sessions

So far, every request has been anonymous, but most real-world APIs require authentication. HTTPie supports common authentication schemes directly and can also save credentials, headers, and cookies between requests using sessions.

Basic authentication: For HTTP Basic authentication, pass the username to -a (--auth) and omit the password. HTTPie prompts you to enter it before sending the request, keeping it out of the command itself:

http -a tecmint https://httpbin.org/basic-auth/tecmint/Secret123

When prompted, enter Secret123. A successful request returns a response similar to this:

{
    "authenticated": true,
    "user": "tecmint"
}

Entering the password at the prompt is safer than writing it directly in the command, where it could be saved in shell history or exposed through process arguments. However, if you use a session, HTTPie can save the prompted password in its session file.

Bearer token authentication: Many modern APIs use bearer tokens instead of usernames and passwords. Specify the bearer authentication scheme with -A bearer and pass the token using -a.

For this example, store a test token in an environment variable rather than typing it directly into the command:

export API_TOKEN='your-token-here'
http -A bearer -a "$API_TOKEN" https://httpbin.org/bearer

HTTPie sends an Authorization: Bearer ... header with the request, and the httpbin endpoint echoes the authentication result and token information when the request succeeds.

An environment variable avoids placing the literal token in the command text, but it is not a complete secret-management solution. Depending on your system and permissions, environment variables may be accessible to other processes or users. Unset the variable when you finish testing:

unset API_TOKEN

Reuse authentication with sessions: When you send multiple requests to the same API, entering credentials repeatedly becomes inconvenient. HTTPie sessions let you persist authentication, custom headers, and cookies between requests to the same host.

Create a named session by adding --session=lab to the first request:

http --session=lab -a tecmint https://httpbin.org/basic-auth/tecmint/Secret123

Enter the password when prompted. HTTPie saves the session information locally.

You can then reuse the session without specifying the credentials again:

http --session=lab https://httpbin.org/basic-auth/tecmint/Secret123

HTTPie reuses the saved authentication information and any applicable session headers or cookies. The named session is associated with the host, so it can be reused for other requests to httpbin.org.

On Linux, named session files are typically stored under:

~/.config/httpie/sessions//.json

For this example, the file is:

~/.config/httpie/sessions/httpbin.org/lab.json
Security warning: HTTPie stores session data, including credentials, prompted passwords, cookies, and custom headers, in plain text. Protect session files from unauthorized access and avoid sharing them or committing them to version control. Check the file permissions and delete sessions when you no longer need them.

For more details, see the official HTTPie authentication and sessions documentation.

If sessions just saved you from pasting the same token into every request, share this with a teammate who’s testing an authenticated API by hand.

Example 5: Upload and Download Files with HTTPie

Authentication covered sending credentials, and the next common job is moving files. The old version of this article used the public transfer.sh service for this, but that service has changed hands and gone through several shutdown announcements over the years, so it’s no longer a dependable example. Instead, we’ll upload to httpbin and download from our own lab server.

To upload a file as a multipart form field, the way a browser upload form does, combine --form with the field@path item from the syntax section:

echo "backup completed on $(hostname)" > report.txt
http --form POST httpbin.org/post [email protected]

The files section of the response shows the field name and the file contents that the server received. HTTPie also sets the file’s Content-Type based on its extension.

You can also send a file as the raw request body, which is how many APIs accept JSON or binary uploads. Use input redirection, and HTTPie sends the file contents as-is:

http POST httpbin.org/post Content-Type:application/json < payload.json

For downloads, the --download (-d) flag makes HTTPie behave like wget. It saves the body to a file, shows a progress bar, and takes the file name from the URL or from the server’s Content-Disposition header.

To try it in the lab, start a temporary web server on server1 that serves the current directory on port 8000:

python3 -m http.server 8000

If firewalld is running on a Rocky Linux server, you will also need to open port 8000 temporarily with sudo firewall-cmd –add-port=8000/tcp, which is not permanent and goes away at the next reload or reboot.

Back on your admin machine, download a file from that directory:

http --download http://192.168.122.248:8000/report.txt

Use --output (-o) to choose a different file name, and add --continue (-c) together with --output to resume a large download that was interrupted. When you are finished, press Ctrl+C on server1 to stop the temporary web server.

Example 6: Use HTTPie in Scripts to Check Service Health

The examples so far were interactive, but HTTPie is also useful in shell scripts and cron jobs, for example, to check a health endpoint after a deploy. By default, HTTPie exits with status 0 even when the server returns an error such as 404 or 500, because the HTTP exchange itself worked. That isn’t what a script wants.

The --check-status flag fixes this by making HTTPie exit with a code based on the HTTP status: 3 for an unfollowed 3xx redirect, 4 for a 4xx client error, and 5 for a 5xx server error. Let’s deliberately trigger a failure with httpbin to see it:

http --check-status --quiet httpbin.org/status/503
echo $?

Output:

http: warning: HTTP 503 SERVICE UNAVAILABLE
5

The warning goes to standard error, and the exit code is 5, which a script can test. Connection problems give other codes. For example, a timeout set with –timeout exits with 2, and an error such as a refused connection exits with 1.

There is one more flag that matters in scripts. When standard input isn’t a terminal, which is the case in cron jobs and many CI systems, HTTPie tries to read the request body from it.

When you combine redirected input with request data items such as key=value, HTTPie reports an error because raw request bodies and structured request data cannot be used together. The error message may read:

http: error: Request body (from stdin, --raw or a file) and request data (key=value) cannot be mixed

Without request items, HTTPie may wait for standard input if it is not connected to a terminal and no end-of-file signal is received. Add --ignore-stdin when you want to prevent HTTPie from reading standard input:

http --ignore-stdin GET https://httpbin.org/get

Putting these together, here is a small health check script. Create it with nano on Ubuntu and Debian:

nano ~/check-web.sh

On Rocky Linux, AlmaLinux, and RHEL, minimal installs include vi rather than nano, so use vi there:

vi ~/check-web.sh

Then add the following content to the file:

#!/usr/bin/env bash
# ~/check-web.sh
# Check a web endpoint and report its HTTP status using HTTPie.

URL="${1:-http://192.168.122.248/}"

if http --check-status --ignore-stdin --quiet --timeout=5 GET "$URL"; then
    echo "OK: $URL is responding"
else
    code=$?
    echo "FAIL: $URL check failed with HTTPie exit code $code" >&2
    exit "$code"
fi

Save the file and exit the editor. The flags in the http line work together like this:

  • --check-status turns 3xx, 4xx, and 5xx responses into non-zero exit codes, so the if statement can detect them.
  • --ignore-stdin stops HTTPie from waiting for a request body on standard input, which keeps the script working under cron.
  • --quiet suppresses the normal output, so the script only prints its own OK or FAIL line.
  • --timeout=5 gives up after 5 seconds without a response, instead of hanging on an unreachable server.

Make the script executable and run it against the lab server, and then against a URL that returns an error:

chmod +x ~/check-web.sh
~/check-web.sh
~/check-web.sh httpbin.org/status/404

Output:

OK: http://192.168.122.248/ is responding
http: warning: HTTP 404 NOT FOUND
FAIL: httpbin.org/status/404 check failed with HTTPie exit code 4

Change the default URL value to your own server’s health endpoint. Since the lab server gets its address from DHCP, reserve or set a static address for it first, so the hardcoded IP keeps pointing at the right machine.

If --check-status just fixed a health check that always reported success, share it with someone whose monitoring script trusts every response.

Pro Tips for Using HTTPie Safely and Efficiently

With HTTPie running interactively and in scripts, a few settings make day-to-day use smoother and safer, especially when you test internal services.

If you find yourself adding the same flags to every command, such as a particular colour style or always following redirects, you can set them as defaults in HTTPie’s configuration file. Open it with nano on Ubuntu and Debian:

mkdir -p ~/.config/httpie
nano ~/.config/httpie/config.json

On Rocky Linux, AlmaLinux, and RHEL, use vi:

mkdir -p ~/.config/httpie
vi ~/.config/httpie/config.json

Add the following configuration. JSON doesn’t allow comments, so the file path is given here instead of on the first line: ~/.config/httpie/config.json.

{
    "default_options": [
        "--style=monokai",
        "--follow",
        "--timeout=10"
    ]
}

Save the file and exit the editor. The options are applied to every http and https command:

  • --style=monokai sets the colour scheme for terminal output. Run http --help and look at the --style option to see the styles available in your version.
  • --follow follows redirects automatically, which suits API testing but hides redirects you might want to see when checking server rules.
  • --timeout=10 stops requests from hanging forever on an unreachable host.

Adjust the list to your own habits. For a single command, you can still override a default, for example by adding --style=auto.

On the security side, avoid writing passwords and tokens directly on the command line, since they end up in your shell history and are visible to other users through ps while the command runs. Use the password prompt from -a username, an environment variable, or a session file with restricted permissions instead.

Internal servers often use self-signed certificates, and HTTPie will refuse them with an SSL certificate verification error. Rather than turning off checking with --verify=no, point HTTPie at your internal CA with --verify=/path/to/ca.crt, which keeps protection against a man-in-the-middle while still trusting your own certificates.

Make sure you are running HTTPie 3.2.4 or later, because version 3.2.2 had a known issue with SSL certificate validation, and 3.2.4 fixed how the default certificates are loaded.

Finally, remember that HTTPie formats JSON output only when printing to a terminal. When you redirect output to a file or pipe it to another command, HTTPie sends the raw body, which is usually what you want for tools like jq. Add --pretty=all if you want the formatted version saved instead.

Conclusion

HTTPie turns everyday HTTP work into short, readable commands, with automatic JSON bodies, readable output, built-in auth, sessions, and downloads. With --check-status and --ignore-stdin, the same tool also works reliably in scripts and cron jobs for health checks after deploys.

If you want to get faster with the commands that sit around tools like HTTPie, such as curl, ss, grep, and journalctl, our 100+ Essential Linux Commands course walks through them with practical examples.

And if the health check script made you want to write more of your own automation, Bash Scripting for Beginners covers exit codes, conditions, and error handling step by step.

We’d love to hear how you’re using HTTPie in your own setup. Do you still reach for curl for some jobs, and if so, which ones? Have you used HTTPie sessions or plugins with an internal API? Feel free to share your favourite one-liners or any error you hit in the comments below.

Two small things before you go

If something didn’t work on your setup, leave a comment and tell me which distro and version you’re on. I read every one, and most of these articles got better because a reader pointed out what was missing.

And if it did work, share it. TecMint has stayed free for 14 years because people pass these articles around, and that traffic is what pays for writing the next one.

Leave a comment
Get two free Linux courses

Learn the Linux basics with two free courses and join 34,000+ readers getting practical TecMint tutorials and selected Pro TecMint articles every week.

Pro TecMint
Get lifetime access for $99

If you want to go beyond the free tutorials, Pro gives you 18 courses, 5 ebooks, and every future course I add. One payment, lifetime access, no renewals.

Aaron Kili
Aaron Kili
Contributor
About the author

Aaron Kili is a Linux and F.O.S.S enthusiast, an upcoming Linux SysAdmin, web developer, and currently a content creator for TecMint who loves working with computers and strongly believes in sharing knowledge.

2 Comments

Leave a Reply
  1. It’s good.

    BTW I’m working on a pure terminal REST client: resteasycli.readthedocs.io

    Going to release version 1 soon.

    Reply

Got Something to Say? Join the Discussion...

Thank you for taking the time to share your thoughts with us. We appreciate your decision to leave a comment and value your contribution to the discussion. It's important to note that we moderate all comments in accordance with our comment policy to ensure a respectful and constructive conversation.

Rest assured that your email address will remain private and will not be published or shared with anyone. We prioritize the privacy and security of our users.