Quick Start Guide¶
Build your first Centrali application in 10 minutes! We'll create a simple blog API with posts and comments.
Before You Begin¶
If you haven't set up your Centrali account yet, start here:
This guide walks you through: - Creating your Centrali account - Setting up your first workspace - Creating service account credentials - 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 WORKSPACE="your-workspace-slug"
export CENTRALI_URL="https://api.centrali.io"
# Get access token
TOKEN_RESPONSE=$(curl -s -X POST "https://auth.centrali.io/oidc/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 7 hours. For production apps, use the Centrali SDK which handles token management automatically.
For more details, see the Authentication Overview.
Step 2: Create Your First Structure¶
Let's define a schema for blog posts. Structures are like database tables that define your data model.
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/structures" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "BlogPost",
"fields": {
"title": {
"type": "text",
"required": true,
"maxLength": 200
},
"slug": {
"type": "text",
"required": true,
"unique": true,
"pattern": "^[a-z0-9-]+$"
},
"content": {
"type": "longtext",
"required": true
},
"author": {
"type": "text",
"required": true
},
"tags": {
"type": "array",
"items": {
"type": "text"
}
},
"published": {
"type": "boolean",
"default": false
},
"publishedAt": {
"type": "datetime"
},
"views": {
"type": "number",
"default": 0
}
}
}'
Response:
Step 3: Create Your First Record¶
Now let's create a blog post using our new structure:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/records" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"structureId": "str_abc123",
"data": {
"title": "Welcome to Centrali",
"slug": "welcome-to-centrali",
"content": "Centrali makes it incredibly easy to build backend services...",
"author": "John Doe",
"tags": ["tutorial", "getting-started"],
"published": true,
"publishedAt": "2024-01-15T10:00:00Z"
}
}'
Response:
{
"id": "rec_xyz789",
"structureId": "str_abc123",
"data": {
"title": "Welcome to Centrali",
"slug": "welcome-to-centrali",
...
},
"createdAt": "2024-01-15T10:31:00Z",
"updatedAt": "2024-01-15T10:31:00Z",
"version": 1
}
Step 4: Query Your Data¶
Fetch all published blog posts:
curl "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/records?structureId=str_abc123&filter=published:true" \
-H "Authorization: Bearer $TOKEN"
Or use Centrali's powerful query language:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "FROM BlogPost WHERE published = true ORDER BY publishedAt DESC LIMIT 10"
}'
Step 5: Add a Compute Function¶
Let's create a function that automatically generates slugs from titles:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/functions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "generateSlug",
"description": "Generates URL-friendly slugs from titles",
"code": "exports.handler = async (event, context) => {\n const { title } = event.data;\n \n // Convert to lowercase and replace spaces with hyphens\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n \n return {\n success: true,\n data: { slug }\n };\n};"
}'
Step 6: Create a Trigger¶
Automatically generate slugs when new posts are created:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/triggers" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "AutoGenerateSlug",
"type": "record",
"config": {
"structureId": "str_abc123",
"event": "beforeCreate",
"condition": "!data.slug"
},
"functionId": "fn_sluggen123",
"transform": {
"data.slug": "result.data.slug"
}
}'
Step 7: Add Comments Structure¶
Let's create a structure for comments with a reference to blog posts:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/structures" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Comment",
"fields": {
"postId": {
"type": "reference",
"structure": "BlogPost",
"required": true
},
"author": {
"type": "text",
"required": true
},
"email": {
"type": "email",
"required": true
},
"content": {
"type": "longtext",
"required": true
},
"approved": {
"type": "boolean",
"default": false
}
}
}'
Step 8: Query with Relationships¶
Get a blog post with its comments:
curl -X POST "$CENTRALI_URL/data/workspace/$WORKSPACE/api/v1/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "FROM BlogPost WHERE slug = \"welcome-to-centrali\" INCLUDE comments FROM Comment WHERE postId = BlogPost.id AND approved = true"
}'
Complete Example: JavaScript/TypeScript¶
Use the official Centrali SDK for easier integration:
Installation¶
Usage¶
import { CentraliSDK } from '@centrali-io/centrali-sdk';
// Initialize the SDK with service account credentials
// The SDK automatically handles token fetching, caching, and refresh
const centrali = new CentraliSDK({
baseUrl: 'https://api.centrali.io',
workspaceId: 'my-workspace',
clientId: process.env.CENTRALI_CLIENT_ID,
clientSecret: process.env.CENTRALI_CLIENT_SECRET
});
// Usage
async function main() {
// Create a blog post
const post = await centrali.createRecord('BlogPost', {
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()
});
console.log('Created post:', post.data);
// Query published posts
const posts = await centrali.queryRecords('BlogPost', {
filter: 'published = true',
sort: '-publishedAt',
limit: 10
});
console.log('Found posts:', posts.data.length);
// Update post views
await centrali.updateRecord('BlogPost', post.id, {
views: 1
});
// Create a comment
const comment = await centrali.createRecord('Comment', {
postId: post.id,
author: 'John Smith',
email: 'john@example.com',
content: 'Great post!',
approved: true
});
console.log('Created comment:', comment.id);
// Execute a compute function
const result = await centrali.invokeFunction('generateSlug', {
title: 'My Amazing Blog Post Title'
});
console.log('Generated slug:', result.data.slug);
}
main().catch(console.error);
TypeScript Support¶
The SDK includes full TypeScript definitions:
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: 'my-workspace',
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>('BlogPost', data);
}
// Type-safe operations
async function main() {
const post = await createBlogPost({
title: 'TypeScript Blog Post',
slug: 'typescript-blog-post',
content: 'Content here...',
author: 'Developer',
published: true
});
// TypeScript knows post.data is of type BlogPost
console.log(post.data.title);
}
Advanced Features¶
// Bulk operations
const posts = [
{ title: 'Post 1', content: '...', author: 'Author 1' },
{ title: 'Post 2', content: '...', author: 'Author 2' }
];
const results = await Promise.all(
posts.map(post => centrali.createRecord('BlogPost', post))
);
// 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('BlogPost', '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've just: - Created data structures - Added records - Queried data - Written a compute function - Set up automation with triggers - Established relationships between data
Next Steps:¶
- Structures & 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!