Quick Start Guide¶
Build your first Centrali application in 10 minutes. If you are setting up Centrali for the first time, start with the account and SDK auth flow so you have a workspace slug and service account credentials before you build the blog API.
Before You Begin¶
If you haven't set up your Centrali account yet, start here:
This guide walks you through: - Creating your Centrali account and workspace - Creating service account credentials - Assigning your service account to a group with the correct permissions - Getting your authentication token
Prerequisites¶
- A Centrali account (sign up at centrali.io)
- Service account credentials (
client_idandclient_secret) - see Account Setup Guide - Your workspace slug
- A REST client (curl, Postman, or your favorite HTTP library)
Step 1: Authenticate¶
All Centrali API requests require authentication via OAuth 2.0. First, exchange your service account credentials for an access token:
# Set your credentials
export CENTRALI_CLIENT_ID="ci_your_client_id"
export CENTRALI_CLIENT_SECRET="sk_your_client_secret"
export CENTRALI_WORKSPACE_SLUG="your-workspace-slug"
export CENTRALI_URL="https://api.centrali.io"
# Get access token
TOKEN_RESPONSE=$(curl -s -X POST "https://auth.centrali.io/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CENTRALI_CLIENT_ID" \
-d "client_secret=$CENTRALI_CLIENT_SECRET" \
-d "scope=openid")
# Extract token (requires jq - or copy manually from response)
export TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.access_token')
# Verify token was obtained
echo "Token obtained: ${TOKEN:0:20}..."
Note: Tokens expire after 1 hour. For production apps, use the Centrali SDK which handles token management automatically.
For more details, see the Authentication Overview.
Step 2: Create the Blog Posts Collection¶
Collections define the shape and validation rules for your records. Start with a blog-posts collection:
curl -X POST "$CENTRALI_URL/data/workspace/$CENTRALI_WORKSPACE_SLUG/api/v1/collections" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Blog Posts",
"recordSlug": "blog-posts",
"properties": [
{
"name": "title",
"type": "string",
"required": true,
"maxLength": 200
},
{
"name": "slug",
"type": "string",
"required": true,
"unique": true,
"pattern": "^[a-z0-9-]+$"
},
{
"name": "content",
"type": "string",
"required": true
},
{
"name": "author",
"type": "string",
"required": true
},
{
"name": "tags",
"type": "array",
"items": { "type": "string" }
},
{
"name": "published",
"type": "boolean",
"default": false
},
{
"name": "publishedAt",
"type": "datetime"
},
{
"name": "views",
"type": "number",
"default": 0
}
]
}'
Response:
{
"id": "col_abc123",
"name": "Blog Posts",
"recordSlug": "blog-posts",
"properties": [
{ "name": "title", "type": "string" },
{ "name": "slug", "type": "string" }
],
"createdAt": "2026-04-25T10:30:00Z"
}
Step 3: Create the Comments Collection¶
Now add a second collection that references blog posts:
curl -X POST "$CENTRALI_URL/data/workspace/$CENTRALI_WORKSPACE_SLUG/api/v1/collections" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Comments",
"recordSlug": "comments",
"properties": [
{
"name": "postId",
"type": "reference",
"target": "blog-posts",
"displayField": "title",
"relationship": "many-to-one",
"onDelete": "restrict",
"required": true
},
{
"name": "author",
"type": "string",
"required": true
},
{
"name": "email",
"type": "string",
"required": true
},
{
"name": "content",
"type": "string",
"required": true
},
{
"name": "approved",
"type": "boolean",
"default": false
}
]
}'
Step 4: Create Your First Record¶
Create a blog post using the collection slug:
curl -X POST "$CENTRALI_URL/data/workspace/$CENTRALI_WORKSPACE_SLUG/api/v1/records/slug/blog-posts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"title": "Welcome to Centrali",
"slug": "welcome-to-centrali",
"content": "Centrali makes it easy to build backend services...",
"author": "John Doe",
"tags": ["tutorial", "getting-started"],
"published": true,
"publishedAt": "2026-04-25T10:00:00Z"
}
}'
Response:
{
"id": "rec_xyz789",
"data": {
"title": "Welcome to Centrali",
"slug": "welcome-to-centrali"
},
"createdAt": "2026-04-25T10:31:00Z",
"updatedAt": "2026-04-25T10:31:00Z",
"version": 1
}
Step 5: Query Published Posts¶
Fetch the latest published posts:
curl -X POST "$CENTRALI_URL/data/workspace/$CENTRALI_WORKSPACE_SLUG/api/v1/records/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resource": "blog-posts",
"where": {
"data.published": { "eq": true }
},
"sort": [
{ "field": "data.publishedAt", "direction": "desc" }
],
"page": {
"limit": 10
}
}'
Step 6: Create a Comment¶
Use the post record ID from the previous response when creating a comment:
export POST_ID="rec_xyz789"
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/records/slug/comments" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"data\": {
\"postId\": \"$POST_ID\",
\"author\": \"Jane Reader\",
\"email\": \"jane@example.com\",
\"content\": \"Great post. I was able to get started quickly.\",
\"approved\": true
}
}"
Step 7: Query Comments With Expanded Post Data¶
Use a canonical query to fetch comments for a specific post and include the referenced blog post:
curl -X POST "$CENTRALI_URL/data/workspace/$CENTRALI_WORKSPACE_SLUG/api/v1/records/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"resource\": \"comments\",
\"where\": {
\"data.postId\": { \"eq\": \"$POST_ID\" }
},
\"include\": [
{ \"relation\": \"postId\" }
],
\"sort\": [
{ \"field\": \"createdAt\", \"direction\": \"desc\" }
],
\"page\": {
\"limit\": 20
}
}"
Complete Example: JavaScript/TypeScript¶
Use the official Centrali SDK for production apps. It handles token management and gives you a cleaner record API.
Installation¶
Usage¶
import { CentraliSDK } from '@centrali-io/centrali-sdk';
const centrali = new CentraliSDK({
baseUrl: 'https://api.centrali.io',
workspaceId: process.env.CENTRALI_WORKSPACE_SLUG, // current SDK option name; pass the workspace slug
clientId: process.env.CENTRALI_CLIENT_ID,
clientSecret: process.env.CENTRALI_CLIENT_SECRET
});
async function main() {
const post = await centrali.createRecord('blog-posts', {
title: 'My First Post',
slug: 'my-first-post',
content: 'This is the content of my first post.',
author: 'Jane Doe',
published: true,
publishedAt: new Date().toISOString()
});
const comment = await centrali.createRecord('comments', {
postId: post.id,
author: 'John Smith',
email: 'john@example.com',
content: 'Great post!',
approved: true
});
const posts = await centrali.records.query('blog-posts', {
where: {
'data.published': { eq: true }
},
sort: [{ field: 'data.publishedAt', direction: 'desc' }],
page: { limit: 10 }
});
const comments = await centrali.records.query('comments', {
where: {
'data.postId': { eq: post.id }
},
include: [{ relation: 'postId' }],
sort: [{ field: 'createdAt', direction: 'desc' }],
page: { limit: 20 }
});
console.log('Created post:', post.data);
console.log('Created comment:', comment.data);
console.log('Found posts:', posts.data.length);
console.log('Found comments:', comments.data.length);
}
main().catch(console.error);
TypeScript Support¶
import { CentraliSDK, ApiResponse } from '@centrali-io/centrali-sdk';
interface BlogPost {
title: string;
slug: string;
content: string;
author: string;
tags?: string[];
published: boolean;
publishedAt?: string;
views?: number;
}
const centrali = new CentraliSDK({
baseUrl: 'https://api.centrali.io',
workspaceId: process.env.CENTRALI_WORKSPACE_SLUG, // current SDK option name; pass the workspace slug
clientId: process.env.CENTRALI_CLIENT_ID,
clientSecret: process.env.CENTRALI_CLIENT_SECRET
});
async function createBlogPost(data: BlogPost): Promise<ApiResponse<BlogPost>> {
return await centrali.createRecord<BlogPost>('blog-posts', data);
}
async function main() {
const post = await createBlogPost({
title: 'TypeScript Blog Post',
slug: 'typescript-blog-post',
content: 'Content here...',
author: 'Developer',
published: true
});
console.log(post.data.title);
}
Advanced Features¶
// File uploads
const file = document.getElementById('file-input').files[0];
const uploadResult = await centrali.uploadFile(file, 'blog-images', true);
console.log('File URL:', uploadResult.data);
// Error handling
try {
const post = await centrali.getRecord('blog-posts', 'invalid-id');
} catch (error) {
if (error.response?.status === 404) {
console.error('Post not found');
} else {
console.error('Error:', error.message);
}
}
Learn more about the SDK: JavaScript/TypeScript SDK Documentation
What's Next?¶
Congratulations. You just:
- Created collections
- Added records
- Queried filtered data
- Modeled a relationship between two collections
- Used the current SDK flow for application code
Next Steps¶
- Collections & Records for deeper schema design
- Functions when you are ready to add compute logic
- Triggers when you want automation or endpoints
- Real-time Events for live updates
-
Authentication for production auth patterns
-
Collections & Records - Learn about all field types and validation
- Master the Records API - CRUD operations, versioning, and bulk operations
- Write Complex Functions - Access external APIs and process data
- Explore Triggers - Automate everything
- API Overview - Complete API reference
Explore More Features:¶
- File Storage - Upload and manage files
- Webhooks - Real-time notifications
- Search - Full-text search capabilities
- Access Control - Fine-grained permissions
Ready to build something more complex? Check out our complete example applications!