API & SDK
Integrate Helix into your applications with our type-safe Client SDK and Content Delivery API.
Client SDK (@helix/client)
The SDK provides a Drizzle-style query builder for type-safe data fetching and a high-level Document API for expanding content graphs.
Installation
npm install @helix/client
Initialization
The getClient() function reads credentials from environment variables (HELIX_API_URL, HELIX_API_KEY, HELIX_SPACE_ID).
import { getClient, tables, eq } from '@helix/client';
import * as schema from './types'; // Your exported Entity classes
const client = getClient();
const { pages, articles } = tables(schema);
Query API (Recommended)
Build type-safe queries with full autocompletion using a Drizzle-style API.
Basic Queries
// Fetch a list of published articles with specific fields
const posts = await client
.select({
title: articles.title,
slug: articles.slug,
authorName: articles.author.name // Dotted access for relations
})
.from(articles)
.where(eq(articles.status, 'published'))
.orderBy(articles.publishedAt, 'desc')
.limit(10)
.execute({ locale: 'en' });
Advanced Filtering
Use powerful operators for complex queries:
import { eq, ilike, gt, and, or } from '@helix/client';
// Case-insensitive search with multiple conditions
const searchResults = await client
.select()
.from(articles)
.where(
and(
ilike(articles.title, '%typescript%'), // Case-insensitive LIKE
eq(articles.status, 'published'),
gt(articles.views, 1000) // Greater than
)
)
.execute({ locale: 'en' });
// OR conditions
const featuredOrPopular = await client
.select()
.from(articles)
.where(
or(
eq(articles.featured, true),
gt(articles.views, 10000)
)
)
.execute({ locale: 'en' });
Filtering on Relational Data
One of the most powerful features is the ability to filter on related entity fields:
// Find articles by a specific author
const adaArticles = await client
.select({
title: articles.title,
authorName: articles.author.name,
authorBio: articles.author.bio
})
.from(articles)
.where(eq(articles.author.name, 'Ada Lovelace'))
.execute({ locale: 'en' });
// Complex relational filtering
const techArticlesByVerifiedAuthors = await client
.select()
.from(articles)
.where(
and(
eq(articles.category.slug, 'technology'),
eq(articles.author.verified, true),
gt(articles.author.followerCount, 1000)
)
)
.execute({ locale: 'en' });
Pagination & Sorting
// Offset-based pagination
const page2 = await client
.select()
.from(articles)
.orderBy(articles.createdAt, 'desc')
.limit(20)
.offset(20)
.execute({ locale: 'en' });
// Cursor-based pagination (recommended for large datasets)
const nextPage = await client
.select()
.from(articles)
.orderBy(articles.createdAt, 'desc')
.limit(20)
.cursor('article_xyz123') // ID of last item from previous page
.execute({ locale: 'en' });
Multi-Locale Queries
// Fetch the same content in different locales
const enVersion = await client
.select()
.from(pages)
.where(eq(pages.slug, 'about'))
.execute({ locale: 'en' });
const svVersion = await client
.select()
.from(pages)
.where(eq(pages.slug, 'about'))
.execute({ locale: 'sv' });
Document API
A simpler API for fetching fully expanded content documents.
// Get a single page by its slug, expanding relations 2 levels deep
const homePage = await client
.entities(pages)
.getBySlug('home', { locale: 'en', depth: 2 });
// Get a list of articles
const recentArticles = await client
.entities(articles)
.list({ locale: 'en', limit: 5, depth: 1 });
Content Delivery API
The REST API is available at space-scoped endpoints and provides high-performance, read-only content delivery.
Authentication
Use bearer tokens (API keys) and specify the space in the X-Space-ID header.
curl -H "Authorization: Bearer your-api-key" \
-H "X-Space-ID: your-space-id" \
https://api.helix.dev/api/content?type=Article&locale=en
Endpoints
POST /api/query
The primary endpoint for the SDK's Query API. It accepts a JSON query plan. It is recommended to use the SDK instead of calling this directly.
GET /api/content
Query and expand entities.
GET /api/content?type=Article&locale=en&depth=2&limit=10
GET /api/content/{id}
Fetch a single entity by ID.
GET /api/content/article-123?locale=en&depth=2
All PATCH requests to update content require an If-Match header containing the entity's current ETag to prevent lost updates.