KQL (Kirby Query Language)
Kirby Headless provides an enhanced KQL endpoint at /api/kql with bearer token authentication, automatic caching, and multi-language support. This extends the official KQL plugin with features commonly needed in headless setups, so that plugin has to be installed as well: composer require getkirby/kql.
Configuration
Enable bearer token authentication in your config.php:
return [
'headless' => [
'token' => 'your-secret-token'
],
'kql' => [
'auth' => 'bearer'
]
];
Making Requests
Send KQL queries to /api/kql with the bearer token in the Authorization header:
const response = await fetch("https://example.com/api/kql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
},
body: JSON.stringify({
query: "site",
select: {
title: true,
children: {
query: "site.children",
select: ["title", "url"],
},
},
}),
});
const data = await response.json();
Multi-Language Support
For multi-language sites, set the language using the X-Language header or a ?language= query parameter. Kirby's API reads the query parameter first, so it wins where a request carries both:
const response = await fetch("https://example.com/api/kql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
"X-Language": "de",
},
body: JSON.stringify({
query: "page('home')",
select: {
title: true,
},
}),
});
Cache Control
Query responses are cached only once Kirby's pages cache is enabled:
return [
'cache' => [
'pages' => [
'active' => true
]
]
];
Once the cache is on, disable it per request with the X-Cacheable header:
const response = await fetch("https://example.com/api/kql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
"X-Cacheable": "false",
},
body: JSON.stringify({
query: "site",
select: { title: true },
}),
});
Each language is cached separately. Pick one way to name the language and keep to it: the same query sent once with ?language=de and once with X-Language: de is cached twice.