The HTTP QUERY method is a new request method, defined in RFC 10008 (June 2026), that sends a query in the request body and is both safe and idempotent. Think of it as GET with a body: you get POST's room for complex filters and GET's guarantees for caching and automatic retries.
If you've stuffed a 3 KB filter into a URL, or sent a read-only search as POST and watched your cache and retry logic ignore it, QUERY is the fix. This guide covers what the spec says, how QUERY compares to GET and POST, what supports it today, and how to test a QUERY endpoint with your coding agent.
What is the HTTP QUERY method?
QUERY is an HTTP method that asks the target resource to run the query described in the request content and return the result. The request body and its Content-Type define the query. The method is safe (the client expects no state change) and idempotent (repeating it has the same effect), so clients, proxies and caches can retry and cache it like GET.
The spec is RFC 10008, "The HTTP QUERY Method", a Proposed Standard published in June 2026 by Julian Reschke (greenbytes), James M. Snell (Cloudflare) and Mike Bishop (Akamai). IANA has added it to the HTTP Method Registry with "safe: yes, idempotent: yes", right next to the WebDAV-era SEARCH method it almost became.
A QUERY request looks like this:
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json
select=surname,givenname,email&limit=10&match=%22email=*@example.*%22
The server answers with 200 OK and the result in the body.
Why GET and POST weren't enough
You had two options for a complex read before QUERY, and both leak.
GET puts everything in the URL. RFC 10008 lists four problems with that:
- Size limits are unknown ahead of time, because a request crosses many systems. RFC 9110 only recommends that senders and recipients support at least 8,000 octets.
- Encoding structured data into a valid URI is wasteful.
- URIs get logged and bookmarked far more often than request bodies, which is a privacy problem for sensitive filters.
- Every combination of query inputs becomes its own resource.
GET with a body isn't the answer either. RFC 9110 says content in a GET request has no defined semantics. Some servers read it, some drop it, and some proxies reject the request. You can't count on it across the path.
POST works, but it lies about intent. A POST search runs fine, yet nothing tells a client, cache, proxy or retry library that the operation is read-only. So caches skip it and clients won't retry it after a dropped connection. If you've had to bolt an idempotency key onto a pure read just to make retries safe, you've felt this.
QUERY keeps POST's body and adds GET's guarantees.
QUERY vs GET vs POST
Here's the comparison, based on Table 1 of RFC 10008:
| Property | GET | QUERY | POST |
|---|---|---|---|
| Safe | Yes | Yes | Potentially no |
| Idempotent | Yes | Yes | Potentially no |
| Request body | No defined semantics | Expected, defines the query | Expected |
| URI for the query itself | Yes, by definition | Optional, via Location
|
No |
| URI for the result | Optional, via Content-Location
|
Optional, via Content-Location
|
Optional, via Content-Location
|
| Cacheable | Yes | Yes, body is part of the cache key | Only for later GET or HEAD |
| CORS preflight from browsers | Not for simple requests | Always | Not for simple requests |
The short version: use GET when the query fits comfortably in the URL, QUERY when it doesn't, and POST only when the request changes state. For a refresher on the classic methods, see our guides to HTTP methods and GET vs POST.
What RFC 10008 defines
Content-Type is mandatory
Servers MUST fail a QUERY whose Content-Type is missing or inconsistent with the body. The RFC recommends these status codes:
- 400 Bad Request: no media type, or a type that doesn't match the content. Servers can't sniff the body and override it.
- 415 Unsupported Media Type: the resource doesn't support that query format.
- 422 Unprocessable Content: the format is fine but the query can't run, such as SQL naming a table that doesn't exist.
- 406 Not Acceptable: the client asked for a response type the resource can't produce.
Location and Content-Location
A server can return two optional headers that turn a QUERY into something you can GET later:
-
Content-Locationpoints to the stored result of this specific run. It might be temporary. -
Locationpoints to the stored query itself. A GET on it reruns the query with fresh data, without resending the body.
The RFC suggests clients switch to GET on the Location URI for repeat requests, since GET caching is simpler. If you return either header for a query with sensitive data, the URI SHOULD NOT contain sensitive parts of the original body.
Caching
QUERY responses are cacheable. The cache key MUST include the request content and related metadata such as the media type. Caches MAY normalize the body first, for example by removing content encoding or normalizing JSON for a +json type, to get more hits. The spec warns that bad normalization can return the wrong response, so expect CDNs to be careful here.
Redirects
A 301, 302, 307 or 308 means "send the same QUERY to the new URI". Unlike POST, a QUERY must not be rewritten to GET on a 301 or 302. A 303 See Other means "fetch the result with a GET on this URI".
The Accept-Query header
Accept-Query is a new response header that advertises QUERY support and the query formats a resource accepts. It's a Structured Field list, so parse it as one:
Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
Clients can also discover support with OPTIONS and read the Allow header, or just send the QUERY and handle a 405 Method Not Allowed.
Which tools support QUERY today?
Support is uneven, so test your own stack. Here's what we confirmed on October 28, 2026:
| Tool | Result |
|---|---|
Node.js 24 http server |
http.METHODS includes QUERY; a plain server received the method and body |
Node.js 24 fetch
|
Sent a QUERY with a JSON body |
| curl 8.7 |
curl -X QUERY with -d sent the method and body |
Python 3.14 http.client
|
Sent a QUERY with a body |
| OpenAPI 3.2 | The Path Item Object has a query field for QUERY operations |
| Apidog CLI 2.2.12 | The endpoint-create schema accepts "method": "query"
|
Here's the curl call we used against a local Node server:
curl -i -X QUERY http://localhost:3000/products \
-H "Content-Type: application/json" \
-d '{"q":"running shoe","limit":2}'
The Fetch Standard only forbids a body on GET and HEAD, so browsers can send QUERY with a body. QUERY is not a CORS-safelisted method, though, so every cross-origin QUERY triggers a preflight. Your server must list QUERY in Access-Control-Allow-Methods.
The gaps are in the middle of the network: reverse proxies, API gateways, WAFs and CDNs that allowlist methods or don't key their cache on the body. Check each hop before you ship. The APIs You Won't Hate newsletter notes that many web frameworks already handle QUERY directly or through custom-method routing.
How to adopt QUERY without breaking clients
You don't have to rip out your POST search endpoints.
- Add QUERY alongside the POST route. Point both at the same handler. New clients use QUERY; old ones keep working.
-
Advertise it. Return
Accept-Queryon the resource and includeQUERYinAllowonOPTIONSand405responses. - Enforce Content-Type. Return 400 or 415 as the RFC recommends, and 422 for queries that parse but can't run.
- Fall back on 405 or 501. Clients should retry the same body as POST when a hop rejects QUERY.
-
Fix CORS. Add
QUERYtoAccess-Control-Allow-Methodsfor browser clients. -
Decide on caching. Only enable shared caching where your cache keys on the body. Otherwise return a
LocationURI and let clients GET it. -
Document it. In OpenAPI 3.2, define the operation under
query:on the path item:
openapi: 3.2.0
paths:
/products:
query:
summary: Search products
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductQuery'
responses:
'200':
description: Matching products
Short, simple filters can stay as query strings on GET. RFC 10008 itself says that if your query is that short, GET is probably the better choice.
Let your coding agent test a QUERY endpoint with Apidog CLI
A new method means checking the happy path, every error code and the fallback route. Hand that to Claude Code, Codex or Cursor and let it drive the Apidog CLI.
Install the CLI, log in, and add the Apidog skill to your agent:
npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com # pick your agent when prompted
Then give your agent one prompt:
In Apidog project <projectId>, add a QUERY /products endpoint that takes a
JSON body {q, limit}. Create test cases that assert 200 with an array for a
valid body, 415 for Content-Type text/plain, and 400 with no Content-Type.
Run them against the staging environment and summarize any failures.
The agent reads each schema, validates its payload and only then writes:
apidog cli-schema get endpoint-create
apidog cli-schema validate endpoint-create --file endpoint.json
apidog endpoint create --project <projectId> --file endpoint.json
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <projectId> --file case.json
apidog run --test-case <caseId> --project <projectId> -e <envId> -r cli,json
The endpoint.json it writes sets "method": "query", which the CLI's endpoint-create schema lists alongside get, post and the WebDAV methods. Add --upload-report to see the run in the Apidog app. The same apidog run command with -r junit drops into CI; see how to run API tests in CI with apidog run and how to use the Apidog CLI in Claude Code. Apidog's Free plan covers up to 4 users.
FAQ
Is the HTTP QUERY method an official standard? Yes. RFC 10008 is a Standards Track, Proposed Standard RFC published in June 2026, and IANA lists QUERY in the HTTP Method Registry as safe and idempotent.
Is QUERY just GET with a body? Close, but it's better defined. RFC 9110 gives a GET body no semantics, so intermediaries can ignore or reject it. QUERY makes the body the query, requires a Content-Type, and folds the body into the cache key.
When should I use QUERY instead of POST? Use QUERY for any read-only search or filter that's too large or too sensitive for a URL. Keep POST for requests that create or change something.
Can browsers send QUERY requests? Yes, through fetch with a custom method. Cross-origin QUERY requests always need a CORS preflight, so your server must allow the method.
Are QUERY responses cached? They can be. Caches must include the request body and its metadata in the cache key. Many CDNs and proxies don't do that yet, so check yours or return a Location URI that clients can GET.
Does OpenAPI support QUERY? OpenAPI 3.2 adds a query field to the Path Item Object for QUERY operations, so you can document them without extensions.

Top comments (0)