Search documentation

Search documentation

Developers

API Documentation

Management and delivery API guidance for integrations and frontend consumers.

Start with the delivery API#

The Contoprix delivery API is how a website reads the pages, content, navigation, and media that editors have published. The easiest path is the JavaScript SDK, but the same published data is also available through REST and GraphQL.

Use delivery APIs to read published content. Use the admin application for modeling, editing, publishing, and media administration.

Choose the right tool#

NeedRecommended starting pointRequired API-client scope
Render a page, list content, navigation, search, or sitemap@contoprix/client or REST delivery routesdelivery:read
Fetch one standalone media item by IDSDK or GET /api/delivery/media/{id}media:read
Select a custom GraphQL response shapeGraphQL at POST /graphqlgraphql:read
Download or push the content modelContoprix CLI / SDK schema routesschema:read, plus schema:write to push
Show draft content in a protected previewSDK preview methodspreview:read

Scopes are deliberately separate. A REST-only delivery key does not grant GraphQL access, and a GraphQL-only key does not grant normal REST delivery access.

Warning

Treat delivery keys, client secrets, preview keys, and API tokens as server-side secrets. Do not put them in NEXT_PUBLIC_ variables, browser bundles, screenshots, or source control.

First request with the SDK#

Install the core client:

Terminal
npm install @contoprix/client @contoprix/types

Store the API origin and a scoped delivery key in server-side environment variables:

.env.local
CONTOPRIX_BASE_URL=https://cms.example.com
CONTOPRIX_DELIVERY_KEY=your-delivery-key

Create one shared client at a server-side integration boundary:

lib/contoprix.ts
import { ContoprixClient } from "@contoprix/client";

export const contoprix = new ContoprixClient({
  baseUrl: process.env.CONTOPRIX_BASE_URL!,
  auth: {
    type: "deliveryKey",
    deliveryKey: process.env.CONTOPRIX_DELIVERY_KEY!,
  },
  languageCode: "en",
});

Now a server component, route handler, or data loader can read a published page:

app/about/page.tsx
import { contoprix } from "@/lib/contoprix";

const page = await contoprix.pages.getBySlug("/about");

console.log(page.name, page.slug, page.blocks);

Pass ordinary application paths such as /about or /products/widgets. The SDK encodes page paths for the delivery route.

Common SDK calls#

Examples
const home = await contoprix.pages.get();
const about = await contoprix.pages.getBySlug("/about");
const children = await contoprix.pages.getAllChildPages("/products");

const result = await contoprix.content.list({
  contentType: "article",
  take: 10,
  skip: 0,
  sort: "newest",
});

const article = await contoprix.content.getBySlug("article", "hello-contoprix");
const navigation = await contoprix.navigation.get();
const searchResults = await contoprix.search.query("pricing", 10);

Content fields are schema-defined, so a content entry stores them in data, not as fixed properties on the entry itself:

Reading a schema-defined field
const first = result.items[0];
const title = String(first?.data.title ?? first?.slug ?? "Untitled");

Do not assume every content type has a title field. Use the field codes from the content model or generated types from the CLI.

REST routes at a glance#

All routes below are relative to CONTOPRIX_BASE_URL. The value should be the API origin, such as https://cms.example.com, not a URL ending in /api.

RoutePurposeScope
GET /api/delivery/pages?languageCode=enThe published / pagedelivery:read
GET /api/delivery/pages/{path}?languageCode=enA published page by pathdelivery:read
GET /api/delivery/pages/children?slug=/productsPublished child-page summariesdelivery:read
GET /api/delivery/content/{contentType}A paginated published content listdelivery:read
GET /api/delivery/content/{contentType}/{entryId}One entry by IDdelivery:read
GET /api/delivery/content/{contentType}/slug/{slug}One entry by slugdelivery:read
GET /api/delivery/navigation?languageCode=enNavigation treedelivery:read
GET /api/delivery/search?q=pricingSearch pages and contentdelivery:read
GET /api/delivery/sitemap?languageCode=enSitemap entriesdelivery:read
GET /api/delivery/media/{mediaId}One media record and its variantsmedia:read

The SDK uses these routes for you. Use raw REST only when you are integrating from a language or runtime that cannot use the JavaScript SDK.

Raw REST example#

This example fetches a page on the server and handles an error before parsing its JSON.

lib/get-page.ts
export async function getPage(path: string) {
  const url = new URL(
    `/api/delivery/pages/${path.replace(/^\/+/, "")}`,
    process.env.CONTOPRIX_BASE_URL!,
  );
  url.searchParams.set("languageCode", "en");

  const response = await fetch(url, {
    headers: {
      "x-contoprix-delivery-key": process.env.CONTOPRIX_DELIVERY_KEY!,
    },
  });

  if (response.status === 404) return null;
  if (!response.ok) throw new Error(`Contoprix request failed: ${response.status}`);

  return response.json();
}

For a page at /, call GET /api/delivery/pages instead of appending an empty path segment.

Language and pagination#

Most delivery routes accept languageCode. Set a default on the client, then override only when a request needs another language:

French article list
const frenchArticles = await contoprix.content.list({
  contentType: "article",
  languageCode: "fr",
  take: 12,
  skip: 0,
  sort: "newest",
});

Content lists return items and pagination. Use take, skip, and pagination.hasNext rather than requesting every record at once.

Delivery-key checklist#

  1. Create an API client for the intended website.
  2. Grant only the scopes the application needs.
  3. Give the server CONTOPRIX_BASE_URL and the credential as private environment variables.
  4. Make calls from a server component, route handler, backend, or worker.
  5. Test with a published page or entry in the correct language.
  6. Add a webhook or suitable cache policy so published changes reach visitors promptly.

Common problems#

SymptomLikely causeFix
401 or "missing delivery key"No credential reached the API.Set the correct header or use the SDK.
403The key lacks the route's scope.Add delivery:read, media:read, or the exact required scope.
404 for content that exists in AdminThe entry is not published, the key belongs to another website, or the language differs.Check publication status, website, and languageCode.
Browser CORS or secret exposureA privileged request is running in browser code.Move it to the server.
Wrong content shapeThe code assumed a field that is not in the model.Read entry.data using the actual schema field code or generate types.

Continue with the detailed SDK guide, use GraphQL when you need a custom response shape, or set up Webhooks for cache refreshes.