Developer Tools

Runtime API

The Cellpy custom element interface and REST API reference.

Cellpy exposes two surfaces for programmatic control: the custom element API for interacting with rendered blocks on the page, and the REST management API for managing blocks, containers, and tokens from your backend or CI pipeline.

Custom element API

Attributes, events, and JavaScript methods on the <cellpy-block> element.

REST API

Programmatically manage blocks, containers, and tokens via HTTPS.


Authentication

REST API requests require a Bearer token.

Create an API token in the Cellpy dashboard under Account → API Tokens. Include it in every REST request as an Authorization header:

bash
curl https://api.cellpy.com/v1/blocks \
  -H "Authorization: Bearer your_token_here"
Never expose your API token in client-side code or public repositories. REST API calls should always be made server-side.
NameTypeDescription
Base URLhttps://api.cellpy.com/v1
FormatAll requests and responses use JSON (Content-Type: application/json).
AuthorizationheaderBearer <token>

Custom element

The <cellpy-block> HTML custom element — attributes, CSS variables, and events.

The runtime registers the <cellpy-block> custom element when https://cdn.cellpy.com/runtime.js is loaded. Each element manages its own Shadow DOM and fetches the assigned block from the CDN.

Attributes

NameTypeDescription
slugrequiredstringThe container slug from your dashboard. This is the permanent embed identifier — the assigned block can change without modifying the attribute.
envstring'production' (default) | 'staging'. Controls which published version is loaded.
cachenumberCache TTL override in seconds. Overrides the plan-level CDN cache. Use with caution in production.
loadingstring'eager' (default) | 'lazy'. 'lazy' defers loading until the element is near the viewport.

CSS custom properties

Blocks expose CSS custom properties for theming. Set them on the element or any ancestor — they cascade into the Shadow DOM as inherited properties.

html
<!-- On the element -->
<cellpy-block slug="pricing" style="--cellpy-primary: #e11d48;"></cellpy-block>

<!-- On an ancestor (e.g. your brand theme) -->
<div style="--cellpy-primary: #6366f1;">
  <cellpy-block slug="hero-main"></cellpy-block>
  <cellpy-block slug="cta-footer"></cellpy-block>
</div>

Events

NameTypeDescription
cellpy:loadCustomEventFires when the block has finished loading and is rendered. detail: { blockId, version, slug }.
cellpy:errorCustomEventFires if the block fails to load. detail: { slug, status, message }.
cellpy:refreshCustomEventFires after a manual refresh() call completes.

JavaScript API

Imperative control of cellpy-block elements from JavaScript.

Every <cellpy-block> element exposes a JavaScript API. Access it like any custom element:

ts
const block = document.querySelector('cellpy-block[slug="pricing"]')

// Force a fresh fetch from the CDN, bypassing cache
await block.refresh()

// Get info about the currently loaded block
const info = block.blockInfo
// → { blockId: "abc123", version: 3, slug: "pricing", env: "production" }

// Listen for load events
block.addEventListener('cellpy:load', (e: CustomEvent) => {
  console.log('Block loaded:', e.detail.blockId)
})

// Switch environments at runtime
block.setAttribute('env', 'staging')

Instance methods

NameTypeDescription
refresh()() => Promise<void>Force reload the block from the CDN, bypassing the browser cache.
blockInfoBlockInfo | nullReturns { blockId, version, slug, env } once loaded, null while loading or on error.
shadowRootShadowRootThe element's Shadow DOM root — for advanced DOM inspection only. Do not mutate.
The refresh() method respects your CDN cache TTL — calling it rapidly won't bypass the CDN. For instant updates during development, use the env="staging" attribute, which has no CDN caching.

REST — Blocks

Manage blocks in your Workspace programmatically.

GET/blocks

List all blocks in your Workspace. Supports ?status=pending|saved|archived and ?q= for keyword search.

GET/blocks/:id

Get a single block by ID. Returns full HTML, CSS, metadata, and version history.

POST/blocks

Create a new block in your Workspace (equivalent to 'Push to Workspace').

PATCH/blocks/:id

Update an existing block's HTML, CSS, name, or status.

DELETE/blocks/:id

Archive a block. Archived blocks are not deleted — they can be restored.

bash
# Create a block (push to Workspace)
curl -X POST https://api.cellpy.com/v1/blocks \
  -H "Authorization: Bearer your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "pricing-cards",
    "html": "<div class=\"card\">...</div>",
    "css": ".card { padding: 24px; }",
    "environment": "staging"
  }'

# Response
{
  "id": "blk_x7qP2kLm",
  "name": "pricing-cards",
  "status": "pending",
  "environment": "staging",
  "createdAt": "2026-06-04T10:00:00Z"
}

Block object

NameTypeDescription
idstringUnique block ID. Prefixed with blk_.
namestringHuman-readable name for the block in your Workspace.
htmlstringThe block's HTML markup.
cssstringThe block's CSS. Always scoped to Shadow DOM at render time.
statusstring'pending' | 'saved' | 'archived'.
environmentstring'staging' | 'production'.
versionnumberIncrements with each update. The CDN serves the latest saved version.
createdAtstringISO 8601 timestamp.
updatedAtstringISO 8601 timestamp of the most recent update.

REST — Containers

Manage container assignments and publishing.

GET/containers

List all containers in your organization.

GET/containers/:slug

Get a container's current state — assigned block, live version, and embed metadata.

PATCH/containers/:slug

Update the assigned block and/or trigger a publish to production.

bash
# Assign a block and publish to production
curl -X PATCH https://api.cellpy.com/v1/containers/pricing \
  -H "Authorization: Bearer your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "blockId": "blk_x7qP2kLm",
    "publish": true
  }'

# Response
{
  "slug": "pricing",
  "blockId": "blk_x7qP2kLm",
  "liveVersion": 1,
  "publishedAt": "2026-06-04T10:05:00Z",
  "cdnUrl": "https://cdn.cellpy.com/b/blk_x7qP2kLm/v1.js"
}

REST — Tokens

Manage API tokens programmatically.

GET/tokens

List all API tokens for your account (secrets are never returned after creation).

POST/tokens

Create a new API token. The secret is returned only once in the response.

DELETE/tokens/:id

Revoke a token immediately. All requests using that token will return 401.

Revoked tokens cannot be restored. Create a new token if you need to replace a revoked one.

CDN delivery

How blocks are served to end users.

When a container is published, Cellpy generates an immutable versioned bundle and stores it on Cloudflare's edge network. The runtime fetches this bundle for each <cellpy-block> element.

NameTypeDescription
CDN URL formathttps://cdn.cellpy.com/b/:blockId/v:version.js
Cache-ControlImmutable bundles: max-age=31536000, immutable. Container resolution: max-age varies by plan (1h – 24h).
Edge locationsCloudflare's global network — 300+ PoPs. Sub-100ms TTFB from most locations.
Staging CDNStaging blocks use no-store, no-cache — every request fetches a fresh version. Use staging for development.
bash
# Fetch block metadata (no auth required for public containers)
GET https://cdn.cellpy.com/c/:container-slug/meta.json

# Response
{
  "slug": "pricing",
  "blockId": "blk_x7qP2kLm",
  "version": 3,
  "bundleUrl": "https://cdn.cellpy.com/b/blk_x7qP2kLm/v3.js",
  "updatedAt": "2026-06-04T10:05:00Z"
}

Errors & rate limits

HTTP error codes

NameTypeDescription
400Bad RequestThe request body is malformed or missing required fields.
401UnauthorizedMissing or invalid API token.
403ForbiddenYour token doesn't have permission for this resource or action.
404Not FoundThe requested block, container, or token does not exist.
409ConflictA container slug or block name already exists.
422Unprocessable EntityValidation failed — check the errors array in the response body.
429Too Many RequestsRate limit exceeded. See Retry-After header.
500Internal Server ErrorUnexpected server error. Retry with exponential back-off.

Error response format

json
{
  "error": "validation_failed",
  "message": "Block name is required",
  "errors": [
    { "field": "name", "message": "Required" }
  ]
}

Rate limits

NameTypeDescription
Free plan60 requests / minute per token.
Pro plan300 requests / minute per token.
Enterprise planCustom. Contact sales.
Retry-AfterheaderSeconds until the rate limit window resets — included in 429 responses.