Cookies & analytics

We'd like to use analytics to understand how this site is used. Nothing loads or fires until you agree. See our privacy policy for the full list of processors.

webclaw
PricingDemo
2,430
curl POST JSON: Body, Headers and File Examples
Back to blog
June 18, 2026Updated September 26, 2026Massi

curl POST JSON: Body, Headers and File Examples

On this page

  • What --json sends
  • Send JSON without --json
  • POST JSON from a file
  • Read JSON from stdin
  • Windows and PowerShell
  • Add authentication to a JSON request
  • Handle HTTP errors in scripts
  • Common curl JSON errors
  • Frequently asked questions
  • Do I need -X POST with --json or -d?
  • Can I use several --json options to merge objects?
  • Does --json replace the Authorization header?
  • Can I POST JSON with Linux curl?
  • Why does a valid JSON body still fail?

To POST JSON with curl, use --json followed by the request body and the endpoint URL. curl selects POST and sets both Content-Type: application/json and Accept: application/json:

curl --json '{"name":"Ada","role":"developer"}' \
  https://api.example.com/users

Replace https://api.example.com/users with your endpoint; it is a placeholder, not a working API. These shell examples use Bash or Zsh. --json requires curl 7.82.0 or newer; check your installed version with curl --version. The curl option history records that version requirement.

What --json sends

The --json shortcut combines binary-preserving request data with two JSON headers. You do not need -X POST for this request. curl explains the equivalence in its JSON POST guide.

Request partValue in the example
MethodPOST
Content-Typeapplication/json
Acceptapplication/json
Body{"name":"Ada","role":"developer"}

Content-Type describes the body you send. Accept tells the server which response format you prefer; the server can still return an error page or another content type.

curl does not validate JSON. It can transmit malformed JSON and let the server reject it. Keep JSON property names and string values in double quotes, even when the shell wraps the whole body in single quotes.

Send JSON without --json

For an older curl installation, write out the headers and use --data-binary:

curl --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data-binary '{"name":"Ada","role":"developer"}' \
  https://api.example.com/users

The data option selects POST here too. Plain -d defaults to a form content type unless you override it. A server expecting JSON may reject that mismatch with 415 Unsupported Media Type, or return an API-specific validation error.

POST JSON from a file

Save this content as payload.json:

{
  "name": "Ada",
  "role": "developer"
}

Then send the file:

curl --json @payload.json https://api.example.com/users

The @ tells curl to read the file. Without it, --json payload.json sends the literal text payload.json as the body. Keep a reusable request file separate from credentials so you can review or version the payload without exposing a key.

For the manual-header form, use --data-binary @payload.json. The curl manual's data options distinguish this from -d @payload.json: --data strips carriage returns, newlines and null bytes when reading a file; --data-binary preserves the bytes. Removing formatting newlines from valid pretty-printed JSON does not by itself make that JSON invalid, but exact bytes matter for signatures and debugging.

Read JSON from stdin

Use @- to read the request body from standard input. A quoted here-document keeps the shell from expanding $variables or command substitutions inside your JSON:

curl --json @- https://api.example.com/users <<'JSON'
{
  "name": "Ada",
  "role": "developer"
}
JSON

For generated data, use a JSON serializer rather than concatenating user input into a string. An apostrophe in a name can break a shell-quoted body; an unescaped double quote can break JSON even if the shell accepts the command.

Windows and PowerShell

Use a UTF-8 payload.json file to avoid inline-quote differences between shells. Call the executable as curl.exe on Windows. Microsoft's curl on Windows guide notes that Windows PowerShell 5.1 maps the curl alias to Invoke-WebRequest; PowerShell 7+ does not:

curl.exe --json "@payload.json" "https://api.example.com/users"

The PowerShell line is a file-based variant. The request checks for this article ran on Bash and Zsh, not on Windows. Check curl.exe --version before using --json there.

Add authentication to a JSON request

A bearer token belongs in the Authorization header. Supply WEBCLAW_API_KEY through your environment before running this Webclaw example:

curl --fail-with-body --silent --show-error \
  https://api.webclaw.io/v1/scrape \
  --header "Authorization: Bearer ${WEBCLAW_API_KEY:?Set WEBCLAW_API_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  -d '{"url":"https://example.com","formats":["markdown"],"only_main_content":true}'

This endpoint returns extracted page content. The scrape API reference documents its fields; the link-to-text guide shows how to use plain text and Markdown in an application.

Environment variables keep literal credentials out of a reusable command, but they do not make every execution context private. An expanded header may still appear in process inspection or diagnostic logs. Avoid sharing verbose output from authenticated requests without removing credentials.

Handle HTTP errors in scripts

Without a fail option, curl can exit with code zero after receiving an HTTP error response. --fail-with-body returns a failure status for HTTP 400 and above while retaining the response body. It requires curl 7.76.0 or newer.

Save the body and print the HTTP status as a separate line:

curl --fail-with-body --silent --show-error \
  --json @payload.json \
  --output response.json \
  --write-out 'HTTP %{http_code}\n' \
  https://api.example.com/users

Check the command's exit status before consuming response.json. The filename does not guarantee JSON: a gateway or application can return HTML. The curl fail-with-body reference documents the option and its limits, including authentication-related cases.

During debugging, -i includes response headers in the output. -v also exposes request details, so treat its output as sensitive when authentication is involved. Avoid adding automatic POST retries unless the API documents how to prevent duplicate side effects.

Common curl JSON errors

SymptomLikely check
option --json: is unknowncurl is older than 7.82.0; use the manual headers or update curl
415 Unsupported Media TypeConfirm the endpoint accepts JSON and the request's Content-Type is correct
400 Bad RequestValidate JSON syntax, then check required fields and types against the API contract
401 or 403Inspect authentication, permissions and the response body; JSON syntax may be fine
Server receives payload.jsonAdd @ before the filename
Body works from a file but not inlineCheck shell quoting and variable expansion
HTML returned instead of JSONInspect status, Content-Type and the destination; Accept does not force a JSON response

Frequently asked questions

Do I need -X POST with --json or -d?

No, those data options select POST for the examples above. Use an explicit method only when the endpoint requires a different method, and check redirect behavior before adding --location to authenticated requests.

Can I use several --json options to merge objects?

curl concatenates their text. It does not merge JSON objects. Two complete objects sent in separate --json options can produce an invalid body. Build one valid JSON document before sending it.

Does --json replace the Authorization header?

No. It handles the body and JSON content negotiation headers. Authentication remains a separate API requirement.

Can I POST JSON with Linux curl?

Yes. The Bash examples work on a Linux installation with a compatible curl version. Check the installed curl version rather than assuming the distribution ships the newest release.

Why does a valid JSON body still fail?

Valid JSON syntax does not guarantee valid API input. An endpoint can reject an unknown field, a missing value or the wrong type. Read the response body and the endpoint's request schema before changing the transport flags.

Start building

Turn pages into clean agent context.

Cancel anytime. Use the dashboard, API, CLI, or MCP server from the same account.

Read the docs

Get started

Ship your agent today. Scrape forever.

Cancel anytime. Migrate from Firecrawl in 60 seconds with the compatibility layer.

Read the docs
webclaw

Clean, structured web data for LLMs and agents. Open source, built in Rust — run it on our cloud or your own hardware.

Book a call

Product

  • Cloud API
  • CLI Tool
  • MCP Server
  • Pricing

Free tools

  • All free tools
  • Website to Markdown
  • Website Table to CSV
  • Pricing Page Extractor
  • Brand Kit Extractor

Developers

  • Documentation
  • API Reference
  • SDKs
  • Changelog

Resources

  • Startup Dataset
  • Compare
  • Self-hosting
  • For OSS

Company

  • Blog
  • About
  • Sponsor
  • Affiliate
  • Contact
webclaw
webclaw
© 2026 webclaw · AGPL-3.0 · Built in RustAll systems operational
PrivacyTerms

Webclaw · Valerio Massimiani · P.IVA 17669361002 · Rome, Italy