Sending request data correctly is what makes API tests, webhook deliveries, and automation runs trustworthy. A repeatable cURL command that puts values in the right place is easier to troubleshoot, easier to reuse in scripts, and much less likely to produce a false success against the wrong endpoint contract.

In HTTP, data can travel either in the URL query string or in the request body, and the server usually cares about both the request method and the body format. In cURL, --get and --data-urlencode build safe query strings, --data sends form-encoded fields, --json sends JSON, --data-binary preserves raw bytes, and --form builds multipart bodies for file uploads.

Most failed requests are format mismatches rather than network failures: fields end up in the URL instead of the body, a JSON payload is sent without the expected Content-Type, or binary input gets treated like text. Build commands first against an echo service such as httpbin.org, and keep secrets out of shell history unless they come from a controlled variable or secret store.

The sample IDs, email addresses, comments, and token placeholders below are masked, but they keep realistic shapes so the echoed request examples still map cleanly to production-style payloads.

Steps to send data in HTTP requests with cURL:

  1. Build a GET query string safely with --get and --data-urlencode when the server expects filters in the URL.
    $ curl --silent --show-error --get \
      --data-urlencode "query=invoice 2026/03" \
      --data-urlencode "page=7" \
      "https://httpbin.org/get"
    {
      "args": {
        "page": "7",
        "query": "invoice 2026/03"
      },
      "url": "https://httpbin.org/get?query=invoice+2026%2f03&page=7"
    }

    Query values are commonly logged by browsers, proxies, and origin servers, so use this pattern only for non-sensitive filters and identifiers.

  2. Send small key-value pairs in the request body with --data when the API expects application/x-www-form-urlencoded input.
    $ curl --silent --show-error \
      --data "ticket_id=INC-2026-0042&status=open" \
      "https://httpbin.org/post"
    {
      "form": {
        "status": "open",
        "ticket_id": "INC-2026-0042"
      },
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "url": "https://httpbin.org/post"
    }

    --data implies POST when no explicit method is set, which matches the default behavior of HTML-style form submissions.

  3. Send JSON bodies with --json when the endpoint expects application/json.
    $ curl --silent --show-error \
      --json '{"email":"ops.team@example.net","active":true}' \
      "https://httpbin.org/post"
    {
      "json": {
        "active": true,
        "email": "ops.team@example.net"
      },
      "headers": {
        "Accept": "application/json",
        "Content-Type": "application/json"
      },
      "url": "https://httpbin.org/post"
    }

    If --json is unavailable on an older curl build, send the same payload with --header "Content-Type: application/json" plus --data.

  4. Keep raw bytes and line endings intact with --data-binary when the body comes from a file or standard input.
    $ printf 'batch_id=job-2026-03-29\nstate=queued\n' > payload.txt
    $ curl --silent --show-error --request POST \
      --header "Content-Type: application/octet-stream" \
      --data-binary @payload.txt \
      "https://httpbin.org/post"
    {
      "data": "batch_id=job-2026-03-29\nstate=queued\n",
      "headers": {
        "Content-Type": "application/octet-stream"
      },
      "url": "https://httpbin.org/post"
    }

    Use --data-binary instead of --data when exact bytes matter, or newlines and other characters can be transformed before the server reads them.

  5. Use --form for multipart bodies that mix text fields with file uploads.
    $ printf 'Release notes for Q1\n' > release-notes.txt
    $ curl --silent --show-error \
      --form "file=@release-notes.txt" \
      --form "comment=Customer portal rollout" \
      "https://httpbin.org/post"
    {
      "files": {
        "file": "Release notes for Q1\n"
      },
      "form": {
        "comment": "Customer portal rollout"
      },
      "headers": {
        "Content-Type": "multipart/form-data; boundary=------------------------##### snipped #####"
      },
      "url": "https://httpbin.org/post"
    }

    Each --form flag adds one multipart section, and curl generates the boundary markers needed for the server to separate file and text fields correctly.

  6. Attach contract-specific headers with --header when the server requires authentication or extra metadata alongside the body.
    $ curl --silent --show-error \
      --header "Authorization: Bearer {{masked_api_token}}" \
      --json '{"message":"queued for delivery"}' \
      "https://httpbin.org/anything"
    {
      "headers": {
        "Authorization": "Bearer {{masked_api_token}}",
        "Content-Type": "application/json"
      },
      "json": {
        "message": "queued for delivery"
      },
      "method": "POST"
    }

    Keep real bearer tokens and API keys out of literal command lines; export them from a secure environment variable or secret store instead.

  7. Override the default verb with --request when the endpoint expects PUT, PATCH, or another method but the body format stays the same.
    $ curl --silent --show-error \
      --request PUT \
      --data "status=approved" \
      "https://httpbin.org/anything"
    {
      "form": {
        "status": "approved"
      },
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "method": "PUT",
      "url": "https://httpbin.org/anything"
    }

    --request changes the HTTP method only; keep choosing --data, --json, --data-binary, or --form based on the body format the server expects.

  8. Verify status and echoed fields with --include before reusing the command against a production endpoint.
    $ curl --silent --show-error --include \
      --request POST \
      --header "Content-Type: application/x-www-form-urlencoded" \
      --data "delivery_check=ready" \
      "https://httpbin.org/post"
    HTTP/2 200
    content-type: application/json
    content-length: 494
    
    {
      "form": {
        "delivery_check": "ready"
      },
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "url": "https://httpbin.org/post"
    }

    The request is ready to reuse when the HTTP status is successful and the echoed method, headers, and fields match the exact payload that was intended.