975bf280-fd91-488c-994c-2f04416e5ee3, and it is both the first path segment of every call and the only credential a published read needs.
Optionally store a Delivery API key (Project settings, API keys) as the account’s delivery_api_key. It is needed for two things: preview: true reads, which go to the Preview API with a key that has preview access, and every read in an environment with secure access turned on. The key is stored encrypted with the account and is never a call argument.
Things to know before you call:
- The Delivery API reads published content only. It has no write routes, so every operation here is a read. Draft and unpublished content comes from a separate host,
preview-deliver.kontent.ai; passpreview: trueand the plugin sends the call there with the storeddelivery_api_key. A key sent to the published host is ignored, so preview never works without the switch. depthis bounded at 0 to 2, and Kontent clamps silently. A live probe ofdepth=99answered200with depth 2 applied, so an out-of-range value looks like a complete answer. The plugin rejects anything outside 0 to 2 rather than returning a response that quietly disagrees with the request.- Paging is
skipandlimit. A list answers apaginationblock whosenext_pageis a full URL, or an empty string on the last page. The plugin returnsnext_skip, the number to pass back, and null when the page is the last. - An element’s
valuetype follows itstype. Atextelement is a string, anumbera number, amodular_contentan array of codenames, and anassetan array of objects. Some types carry no value at all: aurl_slugelement arrives as{ type, name }with novaluekey. - Linked items come back under
modular_content, keyed by codename, and only whendepthis above 0. - Filters go in
in_filterin Kontent’s own syntax, such aselements.price[gt]=10, with several joined by&(system.type[in]=article,coffee&elements.title[nempty]). Each filter becomes its own query parameter, which is what Kontent reads.typeandcollectionare sent assystem.typeandsystem.collection, since Kontent ignores the bare names and answers every item. elementsis sent as one comma-separated value. Kontent answers repeatedelementskeys with a 400.- Without
limit, a list returns everything fromskipon in one answer. - A 404 does not say what is missing. Three different codes answer 404:
105is an unknown environment, which is a configuration mistake, while100and101are a missing item or type. A failed HTTP call is core’sApiErrorwith Kontent’s envelope asbody, soerror.body.error_codetells them apart, andkontentErrorFields(error)reads it out with anisEnvironmentNotFoundflag. A call the plugin refuses before sending it (no environment ID, orpreview: truewithout a stored key) and a network failure throwKontentAPIErrorinstead, with nobody;kontentErrorFieldsreturns no code for those. - Keep the
request_id. Kontent support asks for it, so when Kontent returns one, the error message ends with it and it is inerror.body.request_id. - No webhooks. The Delivery API does not push; a caller polls, or uses Kontent’s own webhook configuration outside this plugin.
- 6 typed API operations
Setup
1
Install
2
Add the plugin
corsair.ts
multiTenancy: true, scope calls with corsair.withTenant(id). See Quick start for KEK + Hub keys, and Multi-tenancy for account isolation.3
Choose authentication
- API Key (Recommended)
Store the Kontent.ai API key before the first call: More: API Key
pnpm corsair setup --plugin=kontentai --tenant=acme api_key=<your-key> (leave out --tenant without multiTenancy), or pass it as key in the plugin options. With Hub, each tenant enters their own key on the connect page. See API key auth.4
Connect a tenant
Mint a connect link and send the tenant to it. Hub hosts the page and delivers the result to your app — see Connect / OAuth.
Example API calls
List the first page of published itemsWhat’s next
API reference
Every
kontentai.api.* operation with input and output types.Connect / OAuth
createLink, Hub delivery, and tenant connect flows.
Use with agents
Expose this plugin’s operations as MCP tools.