Testing a REST API with curl gives you a small, reproducible way to inspect requests, responses, authentication, and transport problems. This guide provides a practical checklist for building a request, sending JSON, reading status codes and headers, reproducing failures safely, and saving a sanitized example that another developer can run.
Overview
curl is useful because it exposes the HTTP request directly from a terminal. Unlike a browser interface, it does not hide headers, redirect behavior, request methods, or response details behind a graphical workflow. That makes it a dependable part of a cloud developer toolbox when an endpoint needs to be tested from a local machine, CI job, container, or remote host.
A reliable API debugging workflow separates the request into parts:
- Method and URL: Confirm whether the endpoint expects GET, POST, PUT, PATCH, or DELETE, and check the path, query string, and API version.
- Headers: Send the required media type, authentication value, correlation identifier, or conditional request header.
- Body: Match the documented schema and encode JSON correctly.
- Transport: Check TLS, redirects, proxies, DNS, and connectivity separately from application errors.
- Response: Record the status code, headers, body, and timing rather than looking only at the visible payload.
Before starting, choose a non-production endpoint or a read-only operation when possible. Use test credentials, avoid real customer data, and treat terminal history, shell logs, CI output, and copied transcripts as potentially sensitive.
Choosing the right API debugging tool
| Tool | Best for | Important limitation |
|---|---|---|
| curl | Minimal, scriptable, shareable HTTP requests | You must assemble and inspect the request yourself |
| Browser developer tools | Requests made by a web application, including CORS and cookies | Less convenient for repeatable command-line reproduction |
| Desktop API clients | Organized collections, environments, visual request editing, and team workflows | Exported requests may include secrets or client-specific settings |
| Online request testers | Quick experiments from a controlled environment | Do not submit tokens, private payloads, or internal endpoints unless the service is approved for that data |
For formatting or inspecting payloads, a local JSON formatter or the online formatters and decoders toolbox can help. Keep confidential API responses out of third-party tools.
Checklist by scenario
1. Start with a simple GET request
Begin with the smallest request that should succeed. The -i option includes response headers, which makes the status line and content type visible alongside the body.
curl -i 'https://api.example.test/v1/items'Read the first line before interpreting the body. A successful status does not guarantee that the response contains the fields your application needs, while a client or server error may include a useful machine-readable error object.
For a cleaner diagnostic transcript, write headers and body separately:
curl -sS -D response-headers.txt -o response-body.json 'https://api.example.test/v1/items'Here, -sS suppresses the progress meter while preserving curl errors, -D saves response headers, and -o saves the body. This is useful when a response is large or needs to be attached to an issue after sanitization.
2. Send query parameters deliberately
Put query parameters in the URL when you want the exact request to be obvious. Quote the complete URL so shell characters are not interpreted unexpectedly.
curl -i 'https://api.example.test/v1/items?status=active&limit=10'When a value contains spaces, ampersands, or other reserved characters, use curl's query-parameter support where available or URL-encode the value before sending it. Do not assume that a visually similar URL produces the same request; inspect the final command and server logs when the filter behaves unexpectedly.
3. Make a POST request with JSON
A common curl POST JSON example includes both the method and the content type:
curl -i -X POST 'https://api.example.test/v1/items' \
-H 'Content-Type: application/json' \
-d '{"name":"demo-item","enabled":true}'-d supplies the request body and commonly causes curl to use POST, but writing -X POST can make the intended method clearer in a shared diagnostic example. The Content-Type header describes the body you are sending; it does not guarantee that the server will accept the schema.
For a larger body, use a file so the payload can be reviewed independently:
curl -i 'https://api.example.test/v1/items' \
-H 'Content-Type: application/json' \
--data-binary @request.jsonReview request.json with a JSON formatter before testing. Check commas, data types, required fields, and whether the API expects an object, array, or nested property.
4. Add authentication without exposing secrets
For bearer authentication, place the token in an environment variable rather than directly in a command that may be saved in shell history:
export API_TOKEN='replace-with-a-short-lived-test-token'
curl -i 'https://api.example.test/v1/profile' \
-H "Authorization: Bearer $API_TOKEN"Do not print the variable, commit it, paste it into an issue, or include it in a screenshot. If the API uses a key header, use the same pattern:
export API_KEY='replace-with-test-key'
curl -i 'https://api.example.test/v1/items' \
-H "X-API-Key: $API_KEY"When reproducing an authentication failure, first confirm that the request is using the expected environment and endpoint. Then compare the exact header name, token prefix, token audience or scope if applicable, and token expiration. A 401 commonly indicates that authentication was missing or rejected; a 403 commonly indicates that the server understood the identity but did not permit the operation. Treat those interpretations as starting points and follow the API's own error contract.
5. Inspect status, headers, and timing
Use -w to print selected response metadata after the body. This helps distinguish a server response from a client-side transport failure.
curl -sS -o response.json -w 'status=%{http_code} content_type=%{content_type} time=%{time_total}s\n' \
'https://api.example.test/v1/items'To inspect redirects or connection behavior, add verbose output temporarily:
curl -v 'https://api.example.test/v1/items'Verbose output can contain request headers, response headers, hostnames, and connection details. Never publish it without removing authorization values, cookies, internal addresses, and identifying data. Use -L only when following redirects is intentional; a redirect can change which host receives the request and may affect authentication or method handling.
6. Reproduce a browser request
If a web application works differently from curl, open the browser's Network panel, inspect the failing request, and copy a sanitized request as curl if the browser supports that action. Compare the URL, method, request headers, cookies, origin, body, and response. Browser-only failures may involve CORS or credentials behavior rather than an invalid API operation. The CORS troubleshooting checklist covers the browser-specific part of that investigation.
What to double-check
- HTTP method: Verify that a read operation was not sent as a write operation, and that a PATCH or PUT body matches the endpoint's semantics.
- URL encoding: Encode spaces and reserved characters in query values. Check whether an identifier belongs in the path or query string.
- Content negotiation:
Content-Typedescribes what you send;Acceptexpresses the response format you prefer. Add the latter when the API documents it. - Authentication scope: A valid token can still lack the permission, tenant, audience, or resource access required for an operation.
- Cookies and CSRF: Browser sessions may rely on cookies and anti-forgery tokens that a standalone curl request does not possess.
- TLS: Keep certificate verification enabled. Do not use
-kas a permanent fix; if a test environment has a private certificate authority, configure trust correctly or ask the environment owner for the supported certificate chain. - Redirects and proxies: Check whether a proxy, gateway, load balancer, or redirect changed the request before it reached the application.
- Request identifiers: Preserve a correlation or trace ID from the response when available. It can connect your local reproduction to server-side logs.
- Payload privacy: Replace names, email addresses, tokens, IDs, and proprietary values before saving or sharing the example.
For a shareable minimal request, keep only the required headers and the smallest body that demonstrates the issue. Include the command, expected result, actual status code, sanitized response, timestamp with timezone, and whether the request was sent against a test or production environment.
Common mistakes
Reading only the response body
A body can look plausible while the status code indicates failure, or an intermediary can return an HTML error page instead of the API's JSON format. Always capture the status line and content type.
Using the wrong shell syntax
Line continuations differ between shells. The backslash form shown above is intended for common Unix-like shells. In PowerShell or Windows command environments, quoting and line continuation rules differ, so test a short single-line command first and consult the local curl help output.
Guessing from a decoded token
JWT payloads can be decoded for inspection, but decoding does not validate a signature or authorize an action. Never treat visible claims as proof that a token is trustworthy. Avoid placing live tokens into online JWT decoders or other third-party utilities.
Disabling TLS verification
The -k or --insecure option can hide a certificate or hostname problem. If it is used temporarily in an isolated test, record why, limit the test, and remove it from scripts. A working insecure request is not evidence that the production TLS configuration is correct.
Copying generated examples without sanitizing them
API clients and browser tools can export cookies, authorization headers, tracking values, and internal URLs. Treat “copy as curl” output as a starting point, not a publication-ready command.
When to revisit
Return to this checklist whenever an endpoint is integrated, a production bug needs a minimal reproduction, or a response changes unexpectedly. Recheck the workflow before seasonal planning cycles and whenever the API contract, authentication provider, gateway, shell environment, curl version, or API client changes.
As part of an annual technical review, run the reusable examples against a safe test service and confirm that the syntax, status reporting, TLS guidance, and authentication instructions still reflect the team's supported workflow. Remove obsolete endpoints and rotate any credentials used for testing. If a command is shared in documentation, verify it from a clean environment rather than relying only on an old terminal session.
Use this final action list:
- Select a safe, non-production endpoint or read-only operation.
- Run the smallest request and record status, headers, body, and timing.
- Add one variable at a time: query parameters, headers, body, then authentication.
- Compare the working and failing requests character by character where practical.
- Preserve a minimal sanitized curl command and the expected result.
- Attach a correlation ID or server log reference when escalating the issue.
- Remove secrets, private data, temporary flags, and insecure TLS options before committing the example.
This method turns curl from a one-off command into a repeatable API debugging workflow that can move with the request—from a laptop to a container, CI pipeline, or cloud-hosted troubleshooting session.