Pages And Components Api
Pages and Components API
Learn how to programmatically access pages, components, and their data using the REST API (v1.1). This allows you to build custom interfaces and workflows that interact with your Tadabase pages.
API Version Required
Pages and Components API requires API v1.1. These endpoints are not available in v1.0.
List Pages
Get all pages in your application:
GET /api/v1.1/{appId}/pages
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"pages": [
{
"id": "page_abc123",
"name": "Dashboard",
"slug": "dashboard",
"type": "builder",
"is_public": false
},
{
"id": "page_def456",
"name": "Customer Portal",
"slug": "customer-portal",
"type": "builder",
"is_public": true
}
]
}
Get Page Details
Get information about a specific page:
GET /api/v1.1/{appId}/pages/{pageId}
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"page": {
"id": "page_abc123",
"name": "Dashboard",
"slug": "dashboard",
"type": "builder",
"is_public": false,
"layout": "default"
}
}
List Page Components
Get all components on a specific page:
GET /api/v1.1/{appId}/pages/{pageId}/components
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"components": [
{
"id": "comp_xyz789",
"name": "Active Orders",
"type": "table",
"table_id": "lGArg7rmR6",
"settings": {
"show_search": true,
"records_per_page": 25
}
},
{
"id": "comp_uvw456",
"name": "Order Form",
"type": "form",
"table_id": "lGArg7rmR6"
}
]
}
Get Component Records
Retrieve records from a specific component with filters:
POST /api/v1.1/{appId}/pages/{pageId}/components/{componentId}/records
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Content-Type: application/json
Body:
{
"filters": {
"condition": "AND",
"items": [
{
"field_id": "status",
"operator": "is",
"val": "Active"
}
]
},
"limit": 50,
"page": 1
}
Response
{
"type": "success",
"total": 125,
"records": [
{
"id": "rec_123",
"field_1": "Order #1001",
"field_2": "Active",
"date_created": "2024-01-27 14:30:00"
}
]
}
Save Component Record
Create a new record through a component (respects component rules and permissions):
POST /api/v1.1/{appId}/pages/{pageId}/components/{componentId}/save
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Content-Type: application/json
Body:
{
"field_12": "New Order",
"field_13": "2024-01-27",
"field_14": "Pending"
}
Response
{
"type": "success",
"id": "rec_new123",
"msg": "Record created successfully"
}
Working with Pages
async function getPageComponents(appId, pageId) {
const response = await fetch(
`https://api.tadabase.io/api/v1.1/${appId}/pages/${pageId}/components`,
{
method: 'GET',
headers: {
'X-Tadabase-App-id': 'your_app_id',
'X-Tadabase-App-Key': 'your_app_key',
'X-Tadabase-App-Secret': 'your_app_secret'
}
}
);
const data = await response.json();
if (data.type === 'success') {
console.log(`Found ${data.components.length} components on page`);
return data.components;
} else {
throw new Error(`Failed to get components: ${data.msg}`);
}
}
// Usage
const components = await getPageComponents('74QY8R4ENB', 'page_abc123');
components.forEach(comp => {
console.log(`${comp.name} (${comp.type}) - Table: ${comp.table_id}`);
});
Fetch Component Data with Filters
async function getComponentData(appId, pageId, componentId, filters = null) {
const body = filters ? { filters } : {};
const response = await fetch(
`https://api.tadabase.io/api/v1.1/${appId}/pages/${pageId}/components/${componentId}/records`,
{
method: 'POST',
headers: {
'X-Tadabase-App-id': 'your_app_id',
'X-Tadabase-App-Key': 'your_app_key',
'X-Tadabase-App-Secret': 'your_app_secret',
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
);
const data = await response.json();
if (data.type === 'success') {
return {
total: data.total,
records: data.records
};
} else {
throw new Error(`Failed to get component data: ${data.msg}`);
}
}
// Usage: Get active orders from a component
const activeOrdersFilter = {
condition: "AND",
items: [
{
field_id: "status",
operator: "is",
val: "Active"
},
{
field_id: "priority",
operator: "is",
val: "High"
}
]
};
const { total, records } = await getComponentData(
'74QY8R4ENB',
'page_abc123',
'comp_xyz789',
activeOrdersFilter
);
console.log(`Found ${total} active high-priority orders`);
records.forEach(order => {
console.log(`Order: ${order.field_1}`);
});
Create Record via Component
async function createComponentRecord(appId, pageId, componentId, recordData) {
const response = await fetch(
`https://api.tadabase.io/api/v1.1/${appId}/pages/${pageId}/components/${componentId}/save`,
{
method: 'POST',
headers: {
'X-Tadabase-App-id': 'your_app_id',
'X-Tadabase-App-Key': 'your_app_key',
'X-Tadabase-App-Secret': 'your_app_secret',
'Content-Type': 'application/json'
},
body: JSON.stringify(recordData)
}
);
const data = await response.json();
if (data.type === 'success') {
console.log(`Record created: ${data.id}`);
return data.id;
} else {
throw new Error(`Failed to create record: ${data.msg}`);
}
}
// Usage: Submit form through component
const newOrder = {
field_12: "Order #1234",
field_13: "2024-01-27",
field_14: "Pending",
field_15: "John Doe"
};
const recordId = await createComponentRecord(
'74QY8R4ENB',
'page_abc123',
'comp_form_456',
newOrder
);
console.log(`New order created: ${recordId}`);
Page Manager Class
class PageManager {
constructor(appId, headers) {
this.appId = appId;
this.headers = headers;
this.baseUrl = `https://api.tadabase.io/api/v1.1/${appId}/pages`;
}
async listPages() {
const response = await fetch(this.baseUrl, {
headers: this.headers
});
const data = await response.json();
if (data.type !== 'success') {
throw new Error(`Failed to list pages: ${data.msg}`);
}
return data.pages;
}
async getPage(pageId) {
const response = await fetch(
`${this.baseUrl}/${pageId}`,
{ headers: this.headers }
);
const data = await response.json();
if (data.type !== 'success') {
throw new Error(`Failed to get page: ${data.msg}`);
}
return data.page;
}
async getComponents(pageId) {
const response = await fetch(
`${this.baseUrl}/${pageId}/components`,
{ headers: this.headers }
);
const data = await response.json();
if (data.type !== 'success') {
throw new Error(`Failed to get components: ${data.msg}`);
}
return data.components;
}
async getComponentRecords(pageId, componentId, filters = null, page = 1, limit = 50) {
const body = {
page,
limit
};
if (filters) {
body.filters = filters;
}
const response = await fetch(
`${this.baseUrl}/${pageId}/components/${componentId}/records`,
{
method: 'POST',
headers: {
...this.headers,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
);
const data = await response.json();
if (data.type !== 'success') {
throw new Error(`Failed to get component records: ${data.msg}`);
}
return {
total: data.total,
records: data.records,
page,
totalPages: Math.ceil(data.total / limit)
};
}
async saveComponentRecord(pageId, componentId, recordData) {
const response = await fetch(
`${this.baseUrl}/${pageId}/components/${componentId}/save`,
{
method: 'POST',
headers: {
...this.headers,
'Content-Type': 'application/json'
},
body: JSON.stringify(recordData)
}
);
const data = await response.json();
if (data.type !== 'success') {
throw new Error(`Failed to save record: ${data.msg}`);
}
return data.id;
}
async findComponentByName(pageId, componentName) {
const components = await this.getComponents(pageId);
return components.find(c => c.name === componentName);
}
async getAllComponentRecords(pageId, componentId, filters = null) {
const allRecords = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await this.getComponentRecords(
pageId,
componentId,
filters,
page,
100
);
allRecords.push(...result.records);
hasMore = page setTimeout(resolve, 100));
}
}
return allRecords;
}
}
// Usage
const pageManager = new PageManager('74QY8R4ENB', headers);
// List all pages
const pages = await pageManager.listPages();
console.log('Available pages:', pages.map(p => p.name));
// Get components on a page
const components = await pageManager.getComponents('page_abc123');
console.log('Page components:', components);
// Find specific component
const ordersTable = await pageManager.findComponentByName(
'page_abc123',
'Active Orders'
);
// Get records from component
const { total, records } = await pageManager.getComponentRecords(
'page_abc123',
ordersTable.id,
{
condition: "AND",
items: [
{ field_id: "status", operator: "is", val: "Active" }
]
}
);
console.log(`Found ${total} active orders`);
// Get all records (handles pagination)
const allRecords = await pageManager.getAllComponentRecords(
'page_abc123',
ordersTable.id
);
console.log(`Retrieved all ${allRecords.length} records`);
// Create new record via component
const newRecordId = await pageManager.saveComponentRecord(
'page_abc123',
'comp_form_456',
{
field_12: "New Order",
field_13: "2024-01-27"
}
);
console.log(`Created record: ${newRecordId}`);
Use Cases
1. Custom Dashboard Builder
// Build custom dashboard by aggregating data from multiple page components
async function buildCustomDashboard(appId, dashboardPageId) {
const pageManager = new PageManager(appId, headers);
// Get all components on dashboard
const components = await pageManager.getComponents(dashboardPageId);
const dashboardData = {};
for (const component of components) {
try {
const { total, records } = await pageManager.getComponentRecords(
dashboardPageId,
component.id,
null,
1,
10 // Get top 10 records
);
dashboardData[component.name] = {
type: component.type,
total,
recentRecords: records
};
} catch (error) {
console.error(`Failed to load ${component.name}:`, error.message);
}
}
return dashboardData;
}
// Usage
const dashboard = await buildCustomDashboard('74QY8R4ENB', 'page_dashboard');
console.log('Dashboard Data:');
Object.entries(dashboard).forEach(([name, data]) => {
console.log(`${name}: ${data.total} total records`);
});
2. Component-Based Data Export
// Export data from a specific component with its filters
async function exportComponentData(pageId, componentId, outputFormat = 'json') {
const pageManager = new PageManager('74QY8R4ENB', headers);
// Get all records from component
const records = await pageManager.getAllComponentRecords(pageId, componentId);
if (outputFormat === 'csv') {
// Convert to CSV
const fields = Object.keys(records[0] || {});
const csv = [
fields.join(','),
...records.map(record =>
fields.map(field => `"${record[field] || ''}"`).join(',')
)
].join('\n');
return csv;
}
// Return as JSON
return JSON.stringify(records, null, 2);
}
// Usage
const csvData = await exportComponentData('page_abc123', 'comp_xyz789', 'csv');
console.log('CSV Export:', csvData);
3. Multi-Component Form Submission
// Submit data to multiple related components
async function submitMultiComponentForm(pageId, formData) {
const pageManager = new PageManager('74QY8R4ENB', headers);
try {
// Create main record
const mainRecordId = await pageManager.saveComponentRecord(
pageId,
'comp_main_form',
{
field_1: formData.customerName,
field_2: formData.email,
field_3: formData.orderDate
}
);
console.log(`Main record created: ${mainRecordId}`);
// Create related records
for (const item of formData.orderItems) {
await pageManager.saveComponentRecord(
pageId,
'comp_items_form',
{
field_10: mainRecordId, // Connection field
field_11: item.product,
field_12: item.quantity,
field_13: item.price
}
);
}
console.log(`Order with ${formData.orderItems.length} items created`);
return mainRecordId;
} catch (error) {
console.error('Multi-component submission failed:', error.message);
throw error;
}
}
// Usage
const orderId = await submitMultiComponentForm('page_order', {
customerName: "John Doe",
email: "john@example.com",
orderDate: "2024-01-27",
orderItems: [
{ product: "Widget A", quantity: 2, price: 29.99 },
{ product: "Widget B", quantity: 1, price: 49.99 }
]
});
4. Dynamic Component Discovery
// Automatically discover and work with page components
async function discoverPageStructure(pageId) {
const pageManager = new PageManager('74QY8R4ENB', headers);
const page = await pageManager.getPage(pageId);
const components = await pageManager.getComponents(pageId);
const structure = {
page: {
name: page.name,
slug: page.slug,
isPublic: page.is_public
},
components: []
};
for (const component of components) {
// Get sample records to understand structure
const { total, records } = await pageManager.getComponentRecords(
pageId,
component.id,
null,
1,
1 // Just get 1 record as sample
);
structure.components.push({
id: component.id,
name: component.name,
type: component.type,
tableId: component.table_id,
recordCount: total,
sampleFields: records[0] ? Object.keys(records[0]) : []
});
}
return structure;
}
// Usage
const structure = await discoverPageStructure('page_abc123');
console.log(`Page: ${structure.page.name}`);
console.log(`Components: ${structure.components.length}`);
structure.components.forEach(comp => {
console.log(`\n${comp.name} (${comp.type})`);
console.log(` Records: ${comp.recordCount}`);
console.log(` Fields: ${comp.sampleFields.join(', ')}`);
});
Component Types
Different component types available through the API:
- table: Display records in tabular format with filters and sorting
- form: Input forms for creating/editing records
- details: Display single record details
- gallery: Card-based display of records
- list: List view of records
- calendar: Calendar display of date-based records
- chart: Data visualization components
Component Permissions
Component-level security is enforced through the API:
- Component visibility rules apply to API requests
- Record rules and filters configured in the component are respected
- User permissions based on authentication determine access
- Public pages allow unauthenticated access if configured
Best Practices
- Use component endpoints for UI consistency: Component endpoints respect all builder settings and rules
- Cache component IDs: Component IDs don't change, cache them to reduce API calls
- Respect pagination: Use pagination when fetching large datasets from components
- Handle component types: Different component types may have different capabilities
- Test with authentication: Component access may vary based on user permissions
- Use filters appropriately: Component filters apply on top of any configured component rules
- Monitor rate limits: Component API calls count toward your rate limits
- Validate before save: Validate data before submitting through component forms
Common Patterns
Find Component by Type
async function findComponentsByType(pageId, type) {
const pageManager = new PageManager('74QY8R4ENB', headers);
const components = await pageManager.getComponents(pageId);
return components.filter(c => c.type === type);
}
// Find all tables on a page
const tables = await findComponentsByType('page_abc123', 'table');
console.log(`Found ${tables.length} table components`);
Batch Component Updates
async function batchUpdateComponentRecords(pageId, componentId, updates) {
const pageManager = new PageManager('74QY8R4ENB', headers);
const results = [];
for (const update of updates) {
try {
const recordId = await pageManager.saveComponentRecord(
pageId,
componentId,
update
);
results.push({ success: true, recordId });
// Rate limit friendly
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
results.push({ success: false, error: error.message });
}
}
return results;
}
Troubleshooting
Component Not Found
If you get a "component not found" error:
- Verify the component ID is correct
- Check that the component exists on the specified page
- Ensure your API key has access to the page
- Verify you're using API v1.1, not v1.0
Permission Denied
If you get permission errors:
- Check component visibility settings in the builder
- Verify your authentication provides access to the component
- Review record rules that may restrict access
- Ensure API key has appropriate permissions
Filter Not Working
If filters don't work as expected:
- Remember component has its own filters that always apply
- Your API filters are applied ON TOP of component filters
- Use correct field IDs from the component's table
- Verify operator and val syntax (not condition/value)
Next Steps
You've now learned about all major aspects of the Tadabase REST API. Here are some additional resources:
- Webhooks API - Set up webhooks to receive real-time notifications (Coming Soon)
- REST API Overview - Review the complete API documentation structure
- Best Practices - Review security and performance best practices
For questions or support, visit the Tadabase Community.
We'd love to hear your feedback.