Skip to content

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:

Account Setup Guide →

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_id and client_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:

{
  "id": "str_abc123",
  "name": "BlogPost",
  "fields": { ... },
  "createdAt": "2024-01-15T10:30:00Z"
}

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

npm install @centrali-io/centrali-sdk

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:

  1. Structures & Records - Learn about all field types and validation
  2. Master the Records API - CRUD operations, versioning, and bulk operations
  3. Write Complex Functions - Access external APIs and process data
  4. Explore Triggers - Automate everything
  5. API Overview - Complete API reference

Explore More Features:

Ready to build something more complex? Check out our complete example applications!