Posting request bodies from the terminal is useful for API checks, form replay, webhook tests, and small automation tasks that need more than a simple GET. In wget, that keeps the transfer and the request body handling in one tool, which is often enough for straightforward HTTP endpoints.

The two core switches are --post-data for short inline bodies and --post-file for larger or reusable payloads. Pair the chosen body option with the correct Content-Type header, then inspect the response to confirm that the endpoint received the exact fields or JSON structure that was intended.

GNU wget does not support multipart/form-data uploads, so browser-style file form posts still need another client. For ordinary POST bodies, the main failure points are bad shell quoting, leftover payload files, and secrets exposed through shell history when sensitive values are typed directly into the command line.

Steps to send POST data with wget:

  1. Send URL-encoded form data with --post-data and save the response for inspection.
    $ wget -S -O post-form.json \
      --header='Content-Type: application/x-www-form-urlencoded' \
      --post-data='account_id=acct_01JQF6Z2M9R4********5T7V8W1X3Y&role=report-reader' \
      https://httpbin.org/post 2>&1 | sed -n '1,12p'
    --2026-03-29 11:35:56--  https://httpbin.org/post
    Resolving httpbin.org (httpbin.org)... 52.71.170.232, 52.71.108.149, 34.234.203.36, ...
    Connecting to httpbin.org (httpbin.org)|52.71.170.232|:443... connected.
    HTTP request sent, awaiting response...
      HTTP/1.1 200 OK
      Content-Type: application/json
      Content-Length: 532
    Length: 532 [application/json]
    Saving to: 'post-form.json'

    --post-data is the fastest option for short form bodies that fit cleanly on one shell line.

  2. Inspect the returned form fields to confirm that the server parsed the body as expected.
    $ jq '.form' post-form.json
    {
      "account_id": "acct_01JQF6Z2M9R4********5T7V8W1X3Y",
      "role": "report-reader"
    }

    A correct form echo proves both the body string and the application/x-www-form-urlencoded content type were accepted.

  3. Send JSON inline only when the payload is short and the quoting is easy to audit.
    $ wget -qO- \
      --header='Content-Type: application/json' \
      --post-data='{"service":"billing-webhook","environment":"staging","run_mode":"dry-run"}' \
      https://httpbin.org/post | jq '{json, headers: {"Content-Type": .headers["Content-Type"], "Content-Length": .headers["Content-Length"]}}'
    {
      "json": {
        "environment": "staging",
        "run_mode": "dry-run",
        "service": "billing-webhook"
      },
      "headers": {
        "Content-Type": "application/json",
        "Content-Length": "74"
      }
    }

    Inline JSON is convenient for quick checks, but credentials, tokens, or other sensitive values typed into --post-data remain in shell history unless the history is disabled or cleaned.

  4. Move longer or reusable JSON into a file and send it with --post-file.
    $ cat > post-body.json <<'JSON'
    {
      "account_id": "acct_01JQF6Z2M9R4********5T7V8W1X3Y",
      "workflow": "billing-sync",
      "labels": ["staging", "finance-report", "wget-client"]
    }
    JSON
    $ wget -qO- \
      --header='Content-Type: application/json' \
      --post-file=post-body.json \
      https://httpbin.org/post | jq '{json, headers: {"Content-Type": .headers["Content-Type"], "Content-Length": .headers["Content-Length"]}}'
    {
      "json": {
        "account_id": "acct_01JQF6Z2M9R4********5T7V8W1X3Y",
        "labels": [
          "staging",
          "finance-report",
          "wget-client"
        ],
        "workflow": "billing-sync"
      },
      "headers": {
        "Content-Type": "application/json",
        "Content-Length": "146"
      }
    }

    --post-file avoids complex shell escaping and sends the file contents as stored, which makes it the safer choice for longer payloads.

  5. Remove temporary payload and response files after the test run.
    $ rm -f post-form.json post-body.json

    Cleanup prevents sample payloads, secrets, and echoed responses from lingering in the working directory after the POST test finishes.