Skip to content

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:

Account Setup Guide →

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_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 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

npm install @centrali-io/centrali-sdk

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

Explore More Features:

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