HTTP API

The StaticOwl HTTP API lets you manage sites, content, content types, templates, and builds from your own code. It's the same surface the dashboard uses, so anything you do by hand you can automate: model a content type, load records, render templates, and publish to your CDN.

Create a key in your account settings and pass it on the Authorization header:

curl https://app.staticowl.com/api/sites \
  -H "Authorization: Bearer $STATICOWL_API_KEY"

Keys can be scoped to specific sites, so a key used by a deploy script or an agent only reaches the sites you grant it. Store the key as a secret and rotate it from account settings if it leaks.

Conventions

A few rules apply across the whole API.

Convention Detail
Authentication Authorization: Bearer <key> on every call. A missing or invalid key returns 401.
Selecting a site Most endpoints act on one site. Send its id on the X-Site-Id header. Get the id from GET /api/sites.
Request bodies JSON. Set Content-Type: application/json on POST, PUT, and PATCH.
Partial updates PATCH and PUT accept only the fields you want to change. Omitted fields are left as they are.
Errors Non-2xx responses return a JSON body with a code and a human-readable message.

Common status codes: 200/201 on success, 204 on delete, 400 for a bad request body, 401 for auth, 404 for a missing resource, and 413 when an import payload is too large (the response includes a suggested batch size).

Sites

A site is one published property — its content, types, templates, and build settings.

Method Path Purpose
GET /api/sites List the sites your key can reach.
POST /api/sites Create a site.
GET /api/sites/{id} Get one site's settings.
PUT /api/sites/{id} Update site settings (partial).

POST /api/sites takes name (required) and optional slug, publicUrl, description, mantra, a theme object (primary, accent), and a starterKit (designer, developer, author, or none) that seeds a site with a sensible set of types and templates.

curl -X POST https://app.staticowl.com/api/sites \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing Site",
    "slug": "marketing",
    "theme": { "primary": "#1a1a2e", "accent": "#e94560" },
    "starterKit": "author"
  }'

Content types

A content type defines a kind of record — its fields, its URL pattern, and whether it renders its own pages. See Content modeling for the full field-type reference.

Method Path Purpose
GET /api/types List content types for the site.
POST /api/types Create a content type.
GET /api/types/{name} Get one content type.
PATCH /api/types/{name} Update a content type (partial).

All four require the X-Site-Id header. A type carries fields, a routePattern (e.g. /blog/:slug), and emitPages (whether items of this type get their own rendered page).

curl -X POST https://app.staticowl.com/api/types \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "article",
    "routePattern": "/blog/:slug",
    "emitPages": true,
    "fields": [
      { "name": "title", "type": "text", "required": true },
      { "name": "slug",  "type": "text", "required": true },
      { "name": "body",  "type": "richtext" }
    ]
  }'

Partial updates replace the whole field they touch. A PATCH that sends fields replaces the entire field list. To change one field, send the full list with your edit applied.

Content

Content items are the records of a given type.

Method Path Purpose
GET /api/content/{type} List items of a type.
POST /api/content/{type} Create an item.
GET /api/content/{type}/{id} Get one item.
PATCH /api/content/{type}/{id} Update an item (partial).
DELETE /api/content/{type}/{id} Delete an item.

All require X-Site-Id. List supports limit, offset, and withMeta=1 (adds record metadata such as timestamps alongside each item). The create and update bodies are a plain object whose keys match the type's fields.

# Create
curl -X POST https://app.staticowl.com/api/content/article \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Hello world", "slug": "hello-world", "body": "<p>First post.</p>" }'

# List, newest page first, with metadata
curl "https://app.staticowl.com/api/content/article?withMeta=1&limit=20&offset=0" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID"

Writing content stages it. It goes live when you build and deploy (below). For a production build, content must be published first — do that from the dashboard or through an AI agent (see Connect your AI).

Bulk import

For loading many records or relationships at once.

Method Path Purpose
POST /api/import/json Load many records of one type.
POST /api/import/edges Create relationships between existing records.

import/json takes typeName, a records array, and options batchSize (1–500, default 100), skipExisting, and dryRun. If a payload is too large the API returns 413 with a suggested batch size and call count — split the records and retry.

curl -X POST https://app.staticowl.com/api/import/json \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "typeName": "article",
    "batchSize": 100,
    "skipExisting": true,
    "records": [
      { "title": "One", "slug": "one" },
      { "title": "Two", "slug": "two" }
    ]
  }'

import/edges links records that already exist. Each edge has a from, an edge label (uppercase), a to, and optional props; batchSize defaults to 500.

curl -X POST https://app.staticowl.com/api/import/edges \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{ "edges": [ { "from": "article/hello-world", "edge": "WRITTEN_BY", "to": "author/jane" } ] }'

Templates

Templates render content into HTML. They use LiquidJS syntax and are versioned — each update creates a new version at head.

Method Path Purpose
GET /api/templates List templates for the site.
POST /api/templates Create a template.
GET /api/templates/{name} Get a template at its current version.
PUT /api/templates/{name} Update a template (creates a new version).

Send name and the template body as content (html is accepted as an alias). Set boundType to bind the template to a content type so its pages render with it.

curl -X POST https://app.staticowl.com/api/templates \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "article",
    "boundType": "article",
    "content": "<article><h1>{{ title }}</h1>{{ body }}</article>"
  }'

Builds

A build renders the site and deploys it to the CDN.

Method Path Purpose
POST /api/build Build and deploy a site.
GET /api/build/status/{buildId} Poll an async build.

Both require X-Site-Id. Pick an environment with env (e.g. prod) and a mode: full, incremental, or validate. With no mode, the API runs a full build; pass incremental to rebuild only what changed (much faster on a large site). validate is a dry run that renders and reports without deploying. Pass async=1 to return immediately with a buildId you can poll.

# Synchronous production build
curl -X POST "https://app.staticowl.com/api/build?env=prod" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{ "env": "prod", "mode": "full" }'

# Async build, then poll
curl -X POST "https://app.staticowl.com/api/build?env=prod&async=1" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID"
# -> 202 { "buildId": "b_123", "statusUrl": "/api/build/status/b_123" }

curl https://app.staticowl.com/api/build/status/b_123 \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID"

A synchronous build returns a build result describing what rendered and deployed. An async build returns 202 with a buildId; poll the status URL until it finishes.

Audit

If your site uses the compliance features, you can verify that its content trail is intact.

Method Path Purpose
GET /api/audit/verify Check that a site's audit trail is intact.
POST /api/audit/checklist Run the compliance checklist and return its rows.

Both take a required graph query parameter — the site's content-store name, shown in your site settings. verify returns a status of ok, broken, or empty.

curl "https://app.staticowl.com/api/audit/verify?graph=$SITE_GRAPH" \
  -H "Authorization: Bearer $STATICOWL_API_KEY"

Search index maintenance

Related-content and similarity features read a per-type index. After a large import you can rebuild it for one type. The call is idempotent.

curl -X POST "https://app.staticowl.com/api/maintenance/embeddings/materialize?type=article" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: $SITE_ID"

Content label integrity

Every content item carries a shared label so site-wide features — the sitemap and feeds, search, the compliance scan, and content counts — can find it. A drift check reports how many items are missing it; the repair stamps only the ones that need it. Both are read- and write-safe to re-run (idempotent).

# How many items are missing the shared label?
curl "https://app.staticowl.com/api/maintenance/content-labels/drift" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" -H "X-Site-Id: $SITE_ID"
# -> { "total": 186, "labeled": 180, "missing": 6, "byType": [ ... ] }

# Repair (stamps only the missing items, in safe batches).
curl -X POST "https://app.staticowl.com/api/maintenance/content-labels/repair" \
  -H "Authorization: Bearer $STATICOWL_API_KEY" -H "X-Site-Id: $SITE_ID"
# -> { "stampedNow": 6, "perType": [ ... ], "errors": [] }

Health

A public liveness check, no auth required. Useful for uptime monitoring.

curl https://app.staticowl.com/api/health
# -> { "status": "ok", ... }

Working beyond the REST API

This page covers the core content lifecycle. Media, forms, redirects, custom domains, webhooks, SEO settings, and releases have their own REST endpoints too — each is documented in its own guide (Media, Forms, Redirects, Distribution) — and all of them are available from the dashboard and through the MCP server as well.

Everything above — and those additional resources — is also available to AI agents through the StaticOwl MCP server:

Point a compatible agent at the endpoint and it can model types, write and publish content, and run builds on your behalf. See Connect your AI for setup.

See also

Related docs

Resolved at build time via {% similar %} — cosine similarity over embeddings, not tag overlap. Zero arguments.

Zero to deployed — the 5-minute quickstart
75% match
Content modeling & field types
71% match
Publishing & environments
71% match