Skip to content

Limits & Quotas

This page documents the rate limits, quotas, and constraints for the Centrali platform.

Note: Limits may vary by plan tier. Check your workspace settings or contact support for plan-specific limits.


API Rate Limits

Request Rates

Endpoint Type Free Tier Pro Tier Enterprise
Read Operations (GET) 1,000/min 10,000/min Custom
Write Operations (POST/PUT/PATCH) 100/min 1,000/min Custom
Delete Operations (DELETE) 50/min 500/min Custom
Query Operations 200/min 2,000/min Custom
Search Operations 100/min 1,000/min Custom

Rate Limit Headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1705351200

When Rate Limited

HTTP 429 Response:

{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded",
  "retryAfter": 60
}

Headers:

Retry-After: 60

Handling Rate Limits:

async function makeRequestWithRetry(fn) {
  try {
    return await fn();
  } catch (error) {
    if (error.response?.status === 429) {
      const retryAfter = parseInt(error.response.headers['retry-after']) || 60;
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      return await fn(); // Retry once
    }
    throw error;
  }
}


Request Size Limits

Payload Sizes

Type Maximum Size
Single Record 1 MB
Bulk Create (records array) 10 MB (max 1,000 records)
File Upload 100 MB per file
Query Response 10 MB
Function Code 5 MB (compressed)

Request Headers

Header Maximum Size
Authorization Header 8 KB
Total Request Headers 16 KB

URL Limits

Type Maximum Length
URL Path 2,048 characters
Query String 4,096 characters

Example Violations:

// ❌ Payload too large
await centrali.createRecord('Product', {
  description: 'a'.repeat(2 * 1024 * 1024) // 2 MB string
});
// Error: 413 Payload Too Large

// ❌ Too many records in bulk
await centrali.bulkCreate('Product', Array(2000).fill({ name: 'Test' }));
// Error: 400 Bad Request - Maximum 1,000 records per bulk operation


Storage Limits

Workspace Storage

Plan File Storage Record Storage Database Size
Free 1 GB Unlimited 1 GB
Pro 100 GB Unlimited 10 GB
Enterprise Custom Unlimited Custom

Per-Structure Limits

Limit Value
Fields per Structure 100
Nested Object Depth 5 levels
Array Items (stored) 10,000 per field
String Field Length 10,000 characters (text), 100,000 (longtext)
Total Structures per Workspace 1,000

File Storage

Limit Value
File Size (single upload) 100 MB
Total Files per Workspace See storage quota
File Name Length 255 characters
Allowed File Types All (no restrictions)

Compute Function Limits

Execution Limits

Limit Value
Execution Timeout 30 seconds
Memory per Function 512 MB
Concurrent Executions 100 (per workspace)
Function Code Size 5 MB (compressed)
npm Dependencies Size 50 MB

Function Constraints

Limit Value
Environment Variables 100 per function
Environment Variable Size 4 KB per variable
Triggers per Function 50
Functions per Workspace 1,000

Example:

// ❌ Function runs too long
exports.handler = async (event, context) => {
  // This will timeout after 30 seconds
  await new Promise(resolve => setTimeout(resolve, 35000));
};
// Error: Function execution timed out

Handling Timeouts:

// ✅ Break long operations into smaller chunks
exports.handler = async (event, context) => {
  const batchSize = 100;
  const records = await centrali.records.query({ limit: batchSize });

  for (const record of records) {
    await processRecord(record);
  }

  // If more records, trigger another function run
  if (records.length === batchSize) {
    await centrali.functions.invoke('processBatch', {
      offset: event.offset + batchSize
    });
  }

  return { processed: records.length };
};


Query Limits

Query Constraints

Limit Value
Results per Query 1,000 (use pagination)
Query Complexity 100 operations
Nested Includes 5 levels deep
Filter Conditions 50 per query
Sort Fields 5 per query

Example:

// ❌ Too many results
await centrali.queryRecords('Product', { limit: 10000 });
// Error: Maximum limit is 1,000

// ✅ Use pagination
let offset = 0;
const limit = 1000;
let hasMore = true;

while (hasMore) {
  const results = await centrali.queryRecords('Product', { limit, offset });
  processRecords(results);

  hasMore = results.length === limit;
  offset += limit;
}

Search Limits

Limit Value
Search Results 1,000 (use pagination)
Search Query Length 500 characters
Facets per Query 10
Indexed Fields per Structure 50

Webhook Limits

Delivery Constraints

Limit Value
Webhooks per Workspace 100
Delivery Timeout 10 seconds
Retry Attempts 3
Payload Size 1 MB

Delivery Behavior

Retry Schedule: - 1st retry: 1 minute after failure - 2nd retry: 5 minutes after first retry - 3rd retry: 15 minutes after second retry - After 3 failures: Webhook marked as failed

Example:

// Your webhook endpoint should respond quickly
app.post('/webhook', async (req, res) => {
  // ✅ Respond immediately
  res.status(200).send('Received');

  // ❌ Don't do heavy processing in webhook handler
  // processHeavyWorkload(req.body);

  // ✅ Queue for async processing
  await queue.add('process-webhook', req.body);
});


Service Account Limits

Limit Value
Service Accounts per Workspace 100
Active Tokens per Service Account 10
Token Lifetime 7 hours
Client Secret Length 64 characters

Workspace Limits

Limit Free Pro Enterprise
Workspaces per Account 3 10 Unlimited
Team Members per Workspace 5 25 Unlimited
API Keys per Workspace 10 50 Unlimited

Naming Constraints

Structure Names

  • Pattern: ^[A-Za-z][A-Za-z0-9_]{0,63}$
  • Length: 1-64 characters
  • Requirements: Start with letter, alphanumeric + underscore only

Field Names

  • Pattern: ^[a-z][a-zA-Z0-9_]{0,63}$
  • Length: 1-64 characters
  • Requirements: Start with lowercase letter, camelCase

Workspace Slugs

  • Pattern: ^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$
  • Length: 3-64 characters
  • Requirements: Lowercase alphanumeric + hyphens, no leading/trailing hyphens

Examples:

// ✅ Valid
name: "BlogPost"
field: "userName"
slug: "my-app-prod"

// ❌ Invalid
name: "Blog Post"  // No spaces
name: "123Post"    // Must start with letter
field: "UserName"  // Must start with lowercase
slug: "My-App"     // Must be lowercase
slug: "-myapp"     // No leading hyphen


Concurrency Limits

Operation Concurrent Limit
API Requests per IP 1,000
Concurrent File Uploads 10
Concurrent Function Executions 100
Concurrent Queries 50

Best Practices for Staying Within Limits

1. Implement Pagination

// ✅ Paginate large result sets
async function fetchAllRecords(structure) {
  const allRecords = [];
  let offset = 0;
  const limit = 1000; // Max limit

  while (true) {
    const batch = await centrali.queryRecords(structure, { limit, offset });
    allRecords.push(...batch);

    if (batch.length < limit) break;
    offset += limit;
  }

  return allRecords;
}

2. Batch Operations

// ✅ Batch creates instead of individual calls
const records = [/* 100 records */];
await centrali.bulkCreate('Product', records); // 1 API call

// ❌ Don't do this
for (const record of records) {
  await centrali.createRecord('Product', record); // 100 API calls!
}

3. Use Webhooks Instead of Polling

// ❌ Polling (many API calls)
setInterval(async () => {
  const records = await centrali.queryRecords('Order', {
    filter: 'status = "pending"'
  });
  processOrders(records);
}, 5000); // Every 5 seconds

// ✅ Webhooks (no polling needed)
// Configure webhook in dashboard for "Order created" event
app.post('/webhook/order-created', (req, res) => {
  processOrder(req.body);
  res.status(200).send('OK');
});

4. Cache Responses

// ✅ Cache frequently accessed data
const cache = new Map();

async function getStructure(id) {
  if (cache.has(id)) {
    return cache.get(id);
  }

  const structure = await centrali.getStructure(id);
  cache.set(id, structure);

  // Clear cache after 5 minutes
  setTimeout(() => cache.delete(id), 5 * 60 * 1000);

  return structure;
}

5. Monitor Your Usage

// Check rate limit headers
const response = await centrali.queryRecords('Product', { limit: 100 });

console.log('Rate limit:', response.headers['x-ratelimit-limit']);
console.log('Remaining:', response.headers['x-ratelimit-remaining']);
console.log('Resets at:', new Date(response.headers['x-ratelimit-reset'] * 1000));

Exceeding Limits

What Happens

Rate Limits: - HTTP 429 response - Retry-After header indicates wait time - Limits reset based on time window (per minute, per hour)

Storage/Quota Limits: - HTTP 413 (Payload Too Large) or 507 (Insufficient Storage) - Must upgrade plan or delete data

Hard Limits: - HTTP 400 (Bad Request) for constraint violations - Cannot be exceeded without plan upgrade

Requesting Limit Increases

For Enterprise plans or special requirements: 1. Contact support at support@centrali.io 2. Provide use case and required limits 3. Custom limits can be configured per workspace



Summary

Key Limits to Remember: - API Requests: 1,000/min (read), 100/min (write) on free tier - Record Size: 1 MB max - Query Results: 1,000 max (use pagination) - Function Timeout: 30 seconds - File Upload: 100 MB max - Bulk Operations: 1,000 records max

Always: - Implement pagination for large datasets - Use bulk operations when possible - Cache frequently accessed data - Monitor rate limit headers - Use webhooks instead of polling

Need higher limits? Upgrade your plan or contact Enterprise sales.