Sending HTTP data reliably enables automation of web forms, interaction with REST APIs, and integration between services. Parameters and payloads carry identifiers, filters, and content that determine how servers behave and what responses they return, so consistent encoding is critical for predictable results.

HTTP requests can deliver data through query strings, encoded bodies such as application/x-www-form-urlencoded or application/json, and headers containing metadata or credentials. cURL exposes options like --data, --data-urlencode, --data-binary, --form, --header, and --request to control where and how that data is attached to each request.

Mismatched Content-Type headers, incorrect methods (GET vs POST vs PUT), or improper encoding can cause servers to ignore fields or reject requests. Secrets embedded in headers or bodies travel in plain text at the HTTP layer and may be logged in shells or proxies, so data-sending patterns must account for TLS, shell history, and access control on any system where cURL runs.

Steps to send data in HTTP requests using cURL:

  1. Use query string parameters in the URL to send simple key-value data in an HTTP GET request with cURL.
    $ curl --silent "https://httpbin.org/get?user=alice&debug=true"
    {
      "args": {
        "debug": "true",
        "user": "alice"
      },
    ##### snipped #####
    }

    Query strings appear after ? and are best suited to idempotent GET requests where small, non-sensitive parameters are acceptable in URLs and logs.

  2. Use --data to send application/x-www-form-urlencoded form fields in the request body.
    $ curl --silent --data "user=alice&role=admin" "https://httpbin.org/post"
    {
      "form": {
        "role": "admin",
        "user": "alice"
      },
    ##### snipped #####
    }

    --data implies POST and sets Content-Type: application/x-www-form-urlencoded by default, encoding ampersands and equals as form separators.

  3. Combine --get with --data-urlencode to build a properly encoded query string from separate parameters.
    $ curl --silent --get \
      --data-urlencode "query=spaces & symbols" \
      --data-urlencode "page=1" \
      "https://httpbin.org/get"
    {
      "args": {
        "page": "1",
        "query": "spaces & symbols"
      },
    ##### snipped #####
    }

    --data-urlencode percent-encodes reserved characters, while --get moves the encoded fields into the URL instead of the request body.

  4. Set Content-Type: application/json and pass a JSON string when sending structured data in the body.
    $ curl --silent --request POST \
      --header "Content-Type: application/json" \
      --data '{"email":"user@example.com","active":true}' \
      "https://httpbin.org/post"
    {
      "data": "email:user@example.com",
    ##### snipped #####
      "headers": {
    ##### snipped #####
        "content-type": "application/json",
    ##### snipped #####
      }
    ##### snipped #####
    }

    Servers that expect JSON often reject requests when the payload is malformed or the Content-Type header does not match, which can result in 400 Bad Request errors or ignored fields.

  5. Override the method with --request PUT when updating a resource that expects HTTP PUT semantics while still sending a payload.
    $ curl --silent --request PUT \
      --data "status=active" \
      "https://httpbin.org/put"
    {
      "form": {
        "status": "active"
      },
    ##### snipped #####
    }

    --request changes only the verb, so options like --data continue to control how the body is constructed.

  6. Use --data-binary to send raw bodies such as newline-sensitive text, binary blobs, or data that must not be URL-encoded.
    $ printf 'line1\nline2&raw\n' > payload.txt
    $ curl --silent --request POST \
      --header "Content-Type: application/octet-stream" \
      --data-binary @payload.txt \
      "https://httpbin.org/post"
    {
      "data": "line1\nline2&raw\n",
    ##### snipped #####
    }

    --data-binary preserves bytes exactly as read from the file or argument, which is important for signatures, compressed content, and binary protocols tunneled over HTTP.

  7. Use --form to construct a multipart/form-data request for transmitting files and associated fields.
    $ curl --silent --form "file=@/work/example.txt" \
      --form "comment=Quarterly upload" \
      "https://httpbin.org/post"
    {
      "files": {
        "file": "example file content"
      },
      "form": {
        "comment": "Quarterly upload"
      },
    ##### snipped #####
    }

    --form automatically generates boundaries and sets Content-Type: multipart/form-data, so each --form argument appears as a separate part in the server-side parser.

  8. Add authentication or custom metadata with --header when interacting with protected APIs that expect headers such as Authorization.
    $ curl --silent --header "Authorization: Bearer REPLACE_WITH_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{"message":"hello"}' \
      "https://httpbin.org/post"
    {
      "headers": {
    ##### snipped #####
        "authorization": "Bearer REPLACE_WITH_TOKEN",
    ##### snipped #####
        "content-type": "application/json",
    ##### snipped #####
      },
      "data": "{message:hello}"
    ##### snipped #####
    }

    Bearer tokens and API keys in headers are sensitive secrets and can leak through terminal history, process listings, or proxy logs if not handled carefully.

  9. Use --insecure only against known endpoints with self-signed certificates when TLS verification would otherwise block testing of request data.
    $ curl --silent --insecure --data "param=value" "https://self-signed.badssl.com/"
    <!doctype html>
    <html>
    <head>
    ##### snipped #####

    --insecure disables certificate validation and exposes traffic to man-in-the-middle attacks on untrusted networks, so it should not be used in production or on unknown hosts.

  10. Verify the transmitted fields and status code by sending data to a known echo endpoint and reviewing the response for matching keys and values.
    $ curl --silent --show-error --include --data "check=ok" "https://httpbin.org/post"
    HTTP/2 200 
    alt-svc: h3=":443"; ma=2592000
    content-type: application/json
    date: Sun, 21 Dec 2025 10:23:35 GMT
    ##### snipped #####
    {
      "form": {
        "check": "ok"
      }
    ##### snipped #####
    }

    Successful transmission is indicated by an HTTP 200 OK status and response bodies where echoed fields such as check match the values that were sent.

Discuss the article:

Comment anonymously. Login not required.