Environments and keys
Every organization’s content lives in environments, and every API call is made with a key bound to one of them. Knowing which environment a key is bound to tells you what that key can see.
Authoring and delivery environments
Section titled “Authoring and delivery environments”There are two kinds of environment.
- An authoring environment is a drafting space. Contracts, Templates, Components, folders, the Experience tree, Audiences, taxonomy and streams all belong to one authoring environment. Content in one authoring environment is invisible from another, as if they were separate organizations.
- A delivery environment holds published content. It is what the Content Delivery API serves, and it holds only what was published into it.
Every organization starts with one of each, and many never need more. Organizations that run a staging and production pipeline typically have several of both, such as a Staging authoring environment publishing to a Staging delivery environment, and a Live authoring environment publishing to Production.
Moving content between environments
Section titled “Moving content between environments”Three relationships connect environments. Each one is set up by an administrator in the app, under Configure → Environments.
Publishing goes from an authoring environment to a delivery environment. It copies a snapshot of the content into the delivery environment, where the Delivery API can serve it. Each delivery environment receives publishes from one authoring environment at a time; one authoring environment may publish to several delivery environments. See Publishing.
Promotion copies draft content from one authoring environment into another: a Component or page together with everything it depends on (its Contract, Template, referenced Components and so on), ready to be published there. Promotion moves drafts; it never makes anything live on its own. It is the usual way a change moves from Staging to Live.
Inheritance makes one authoring environment the parent of another. The parent’s library (Contracts, Templates, Audiences, taxonomy, folders and Components) is synced into the child as read-only copies, which the child can use and publish but not edit. It suits a shared design system used by several brand environments.
Promotion and inheritance are both done in the app. Neither is available through the Content Management API.
A published page keeps being served if the publishing relationship that produced it is later removed. Removing it only stops new publishes and unpublishes between those two environments.
API keys
Section titled “API keys”There are three families of key, each for a different API. All are shown once, when they are created, and only a hash is stored, so a lost key cannot be recovered. Revoke it and create another.
| Key | API | Bound to | Created in |
|---|---|---|---|
| Delivery key (server-side or browser-safe) | Content Delivery API | One delivery environment | Content: Settings → API Keys → Delivery keys |
| Management key | Content Management API | One authoring environment and one role | Content: Settings → API Keys → Management keys |
| Forms SDK key | Forms | The organization | Hub: API Keys |
Every key is sent the same way:
Authorization: Bearer <key>Delivery keys
Section titled “Delivery keys”A delivery key reads published content only. Draft edits never reach it. It is bound to one delivery environment, so to run the same site against development, staging and production, create one key per environment and give each deployment its own key. The site’s code stays the same.
There is one kind of delivery key, and it can be used in two ways.
Server-side (the default) has no restrictions. It works from any origin and any network, so it must stay on a server, in a build step or in an edge function. Never put a server-side key in code that reaches a browser. Use one for server-side rendering, static site generation and back-end integrations.
Browser-safe carries restrictions, turned on with the Browser-safe key switch when you create it (or later, with Manage):
- Allowed origins: the websites the key may be used from, such as
https://www.example.com. They are pre-filled from the delivery environment’s site host names. Addhttp://localhost:<port>for local development. One leading*.label is allowed as a wildcard (https://*.preview.example.com) for per-branch preview deployments. - Allowed IP ranges: CIDR ranges or single addresses the key may be used from.
A browser-safe key can safely be shipped in a website’s JavaScript. It reads the same published content a visitor to the site can already see, and its restrictions stop a key copied out of your site from being used on someone else’s. What a browser-safe key cannot do:
- It cannot be used without an
Originheader that matches its list. A non-browser caller, such as a server or a script, gets403withorigin_denied. Use a server-side key there. - It cannot be used from outside its IP ranges, when it has any (
403withip_denied). - It cannot read drafts. Draft preview for server-rendered sites is a separate permission, Allow draft preview, that only a server-side key can have.
The origin list is not authentication. The browser enforces it, and any non-browser client can send
whatever Origin header it likes. To keep a non-production environment private, restrict its key
to your office or VPN address range. The IP list is checked on the server.
The Delivery API accepts cross-origin requests from any origin, and it judges the actual request
against the key’s allowed origins. Because of this, an origin_denied error is readable by your
page rather than showing up as an opaque CORS failure.
Management keys
Section titled “Management keys”A management key lets a script, a build pipeline or an AI agent create, change and publish content through the Content Management API. Two choices decide what it can do:
- Its role decides which content it may touch. The key acts exactly as that role does: the same folder permissions, the same workflow gates.
- Its scopes decide what kind of operation it may perform:
| Scope | Allows |
|---|---|
content.management.read |
Reading content and planning a change without applying it |
content.management.write |
Applying a bundle of changes, and uploading files |
content.management.publish |
Publishing |
content.management.authoring |
Creating, editing and deleting individual items |
A key with only content.management.read can report exactly what a change would do while being
unable to make it, which makes it safe for a pull-request check.
A management key is bound to one authoring environment. To run a pipeline against staging and production, create two keys. Management keys need the Pro plan or above (a trial counts).
A management key must never reach a browser. It can be restricted to IP ranges but never to origins, and the Management API sends no CORS headers at all, so browsers cannot call it. See Content as code.
Forms SDK keys
Section titled “Forms SDK keys”A Forms SDK key reads your organization’s published form definitions, for rendering forms with
@ebitex/forms-sdk. Only an organization Owner can create one, in Hub, and it needs the
Read Forms via the SDK scope. It cannot read submissions or write anything. It is a server-side
credential: fetch the form on your server and pass the result to the browser. Submitting a form
needs no key at all. See Render a form.
Which key to use
Section titled “Which key to use”| You are building | Use |
|---|---|
| A static site or single-page app that fetches content in the browser | A browser-safe delivery key |
| A server-rendered site, a static build step, or a back-end service | A server-side delivery key |
| A server-rendered site that shows editors their drafts in live preview | A server-side delivery key with Allow draft preview |
| A pipeline or agent that writes or publishes content | A management key, with the fewest scopes that work |
| A page that renders an ebitex form | A Forms SDK key, on the server |
Errors every key shares
Section titled “Errors every key shares”| Response | Meaning |
|---|---|
401 with missing_api_key |
No Authorization header |
401 with invalid_api_key |
The key is unknown, revoked or expired. The API does not say which |
403 with scope_denied |
The key is valid but lacks the scope this operation needs. The response names it |
402 with payment_required |
The organization’s subscription needs attention |
429 |
A rate limit or quota was exceeded. Retry-After says how long to wait |
Every response carries an X-Request-Id header. Log it with any failure and quote it to support.