2608 Advanced Api Operations
Advanced API Operations
Overview
Beyond basic CRUD operations, the Tadabase API offers advanced capabilities for batch processing, PDF generation, triggering scheduled tasks, and more. This article explores these powerful features that enable sophisticated integrations and automation workflows.
Batch Operations
Batch operations allow you to create, update, or delete multiple records in a single API call—dramatically improving performance and reducing API rate limit consumption.
Batch Create
Create multiple records at once: Endpoint:POST /tables/{table_id}/records/batch
Request body (array of records):
{
"records": [
{
"field_1": "John Smith",
"field_2": "john@email.com",
"field_3": "555-1234"
},
{
"field_1": "Jane Doe",
"field_2": "jane@email.com",
"field_3": "555-5678"
},
{
"field_1": "Bob Johnson",
"field_2": "bob@email.com",
"field_3": "555-9999"
}
]
}
JavaScript example:
const batchCreateRecords = async (tableId, records) => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/batch`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ records })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage
const newRecords = [
{ field_1: 'John Smith', field_2: 'john@email.com' },
{ field_1: 'Jane Doe', field_2: 'jane@email.com' },
{ field_1: 'Bob Johnson', field_2: 'bob@email.com' }
];
batchCreateRecords('abc123', newRecords)
.then(result => {
console.log(`Created ${result.created.length} records`);
console.log('New record IDs:', result.created.map(r => r.id));
})
.catch(error => console.error('Error:', error));
Python example:
import requests
def batch_create_records(table_id, records):
url = f'https://api.tadabase.io/api/v1/tables/{table_id}/records/batch'
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
payload = {'records': records}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 201:
data = response.json()
print(f"Created {len(data['created'])} records")
return data
else:
print(f"Error: {response.status_code}")
print(response.json())
return None
# Usage
new_records = [
{'field_1': 'John Smith', 'field_2': 'john@email.com'},
{'field_1': 'Jane Doe', 'field_2': 'jane@email.com'},
{'field_1': 'Bob Johnson', 'field_2': 'bob@email.com'}
]
batch_create_records('abc123', new_records)
Response format:
{
"created": [
{
"id": "rec_abc123",
"field_1": "John Smith",
"field_2": "john@email.com",
"field_3": "555-1234"
},
{
"id": "rec_def456",
"field_1": "Jane Doe",
"field_2": "jane@email.com",
"field_3": "555-5678"
}
],
"failed": [],
"total_created": 2,
"total_failed": 0
}
Batch Update
Update multiple records at once: Endpoint:PATCH /tables/{table_id}/records/batch
Request body:
{
"records": [
{
"id": "rec_abc123",
"field_2": "john.smith@newemail.com"
},
{
"id": "rec_def456",
"field_2": "jane.doe@newemail.com"
}
]
}
JavaScript example:
const batchUpdateRecords = async (tableId, updates) => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/batch`;
const response = await fetch(url, {
method: 'PATCH',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ records: updates })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage
const updates = [
{ id: 'rec_abc123', field_2: 'john.smith@newemail.com' },
{ id: 'rec_def456', field_2: 'jane.doe@newemail.com' }
];
batchUpdateRecords('abc123', updates)
.then(result => {
console.log(`Updated ${result.updated.length} records`);
})
.catch(error => console.error('Error:', error));
Batch Delete
Delete multiple records at once: Endpoint:DELETE /tables/{table_id}/records/batch
Request body:
{
"record_ids": ["rec_abc123", "rec_def456", "rec_ghi789"]
}
JavaScript example:
const batchDeleteRecords = async (tableId, recordIds) => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/batch`;
const response = await fetch(url, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ record_ids: recordIds })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage
const idsToDelete = ['rec_abc123', 'rec_def456', 'rec_ghi789'];
batchDeleteRecords('abc123', idsToDelete)
.then(result => {
console.log(`Deleted ${result.deleted_count} records`);
})
.catch(error => console.error('Error:', error));
Batch Operation Best Practices
- Batch size: Limit to 100 records per batch (optimal performance)
- Error handling: Check for partial failures (some succeed, some fail)
- Validation: Validate all records before sending
- Progress tracking: Log progress for long-running imports
- Retry logic: Retry failed batches separately
- Transaction awareness: Batch operations are not atomic
const importRecords = async (tableId, allRecords) => {
const batchSize = 100;
const results = {
created: 0,
failed: 0,
errors: []
};
// Split into batches
for (let i = 0; i 0) {
results.errors.push(...result.failed);
}
console.log(`Batch ${Math.floor(i / batchSize) + 1}: Created ${result.total_created}, Failed ${result.total_failed}`);
// Rate limiting - wait between batches
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
console.error(`Batch ${Math.floor(i / batchSize) + 1} failed:`, error);
results.failed += batch.length;
results.errors.push({ batch: i, error: error.message });
}
}
return results;
};
// Usage
const importData = [
// ... array of 500 records
];
importRecords('abc123', importData)
.then(results => {
console.log('Import complete!');
console.log(`Success: ${results.created}`);
console.log(`Failed: ${results.failed}`);
if (results.errors.length > 0) {
console.log('Errors:', results.errors);
}
});
PDF Generation
Generate PDFs programmatically from your Tadabase templates.
Generate PDF from Template
Endpoint:POST /tables/{table_id}/records/{record_id}/pdf
Request body:
{
"template_id": "template_123",
"return_type": "url" // or "base64"
}
JavaScript example:
const generatePDF = async (tableId, recordId, templateId, returnType = 'url') => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/${recordId}/pdf`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: templateId,
return_type: returnType
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage - Get URL
generatePDF('abc123', 'rec_xyz789', 'template_123', 'url')
.then(result => {
console.log('PDF URL:', result.pdf_url);
// URL is temporary and expires after 24 hours
})
.catch(error => console.error('Error:', error));
// Usage - Get base64
generatePDF('abc123', 'rec_xyz789', 'template_123', 'base64')
.then(result => {
console.log('PDF base64:', result.pdf_data);
// Can be embedded or downloaded directly
})
.catch(error => console.error('Error:', error));
Response (URL type):
{
"pdf_url": "https://tadabase-assets.s3.amazonaws.com/pdfs/temp_abc123.pdf",
"expires_at": "2026-01-29T10:30:00Z",
"file_size": 245678
}
Response (base64 type):
{
"pdf_data": "JVBERi0xLjQKJeLjz9...", // Base64 encoded PDF
"file_size": 245678,
"filename": "document_rec_xyz789.pdf"
}
Batch PDF Generation
Generate PDFs for multiple records: Endpoint:POST /tables/{table_id}/records/batch/pdf
Request body:
{
"record_ids": ["rec_123", "rec_456", "rec_789"],
"template_id": "template_123",
"return_type": "url"
}
JavaScript example:
const batchGeneratePDF = async (tableId, recordIds, templateId) => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/batch/pdf`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
record_ids: recordIds,
template_id: templateId,
return_type: 'url'
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage
const recordIds = ['rec_123', 'rec_456', 'rec_789'];
batchGeneratePDF('abc123', recordIds, 'template_123')
.then(result => {
console.log(`Generated ${result.pdfs.length} PDFs`);
result.pdfs.forEach(pdf => {
console.log(`Record ${pdf.record_id}: ${pdf.pdf_url}`);
});
})
.catch(error => console.error('Error:', error));
PDF Use Cases
1. Invoice generation:- Generate invoice PDF when order is completed
- Email PDF to customer automatically
- Store PDF URL in record for future access
- Generate certificates for course completions
- Batch generate for all completed students
- Provide download links in user portal
- Generate monthly reports for clients
- Email PDFs to stakeholders
- Archive in cloud storage
const generateAndEmailInvoice = async (orderId) => {
try {
// 1. Generate PDF
const pdfResult = await generatePDF(
'orders_table',
orderId,
'invoice_template',
'url'
);
// 2. Get order details
const order = await getRecord('orders_table', orderId);
// 3. Send email with PDF link
await sendEmail({
to: order.data.customer_email,
subject: `Invoice #${order.data.order_number}`,
body: `
Dear ${order.data.customer_name},
Your invoice is ready. Please download it here:
${pdfResult.pdf_url}
This link expires in 24 hours.
Thank you for your business!
`
});
// 4. Update order record
await updateRecord('orders_table', orderId, {
invoice_pdf_url: pdfResult.pdf_url,
invoice_sent_date: new Date().toISOString()
});
console.log('Invoice generated and sent successfully');
} catch (error) {
console.error('Error generating invoice:', error);
}
};
Triggering Scheduled Tasks
Trigger scheduled tasks programmatically via the API.
Trigger Task
Endpoint:POST /tasks/{task_id}/trigger
JavaScript example:
const triggerTask = async (taskId) => {
const url = `https://api.tadabase.io/api/v1/tasks/${taskId}/trigger`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage
triggerTask('task_abc123')
.then(result => {
console.log('Task triggered successfully');
console.log('Execution ID:', result.execution_id);
})
.catch(error => console.error('Error:', error));
Python example:
import requests
def trigger_task(task_id):
url = f'https://api.tadabase.io/api/v1/tasks/{task_id}/trigger'
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
data = response.json()
print('Task triggered successfully')
print(f"Execution ID: {data['execution_id']}")
return data
else:
print(f"Error: {response.status_code}")
return None
# Usage
trigger_task('task_abc123')
Response format:
{
"execution_id": "exec_xyz789",
"task_id": "task_abc123",
"status": "queued",
"triggered_at": "2026-01-28T10:30:00Z"
}
Check Task Status
Endpoint:GET /tasks/{task_id}/executions/{execution_id}
JavaScript example:
const checkTaskStatus = async (taskId, executionId) => {
const url = `https://api.tadabase.io/api/v1/tasks/${taskId}/executions/${executionId}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage with polling
const waitForTaskCompletion = async (taskId, executionId, maxWait = 300000) => {
const startTime = Date.now();
const pollInterval = 5000; // Check every 5 seconds
while (Date.now() - startTime setTimeout(resolve, pollInterval));
}
throw new Error('Task execution timeout');
};
// Usage
const result = await triggerTask('task_abc123');
const completion = await waitForTaskCompletion('task_abc123', result.execution_id);
if (completion.success) {
console.log('Task completed successfully');
} else {
console.error('Task failed:', completion.error);
}
Task Use Cases
1. Data processing:- Trigger nightly data cleanup task on demand
- Run complex calculations outside normal schedule
- Process batch operations triggered by external events
- Generate reports on demand via API
- Scheduled task creates PDF reports
- External system triggers when report needed
- Manual trigger of sync with external system
- Webhook triggers task to process data
- On-demand backup operations
File Uploads
Upload files to file and image fields via API.
Upload File
Endpoint:POST /tables/{table_id}/records/{record_id}/files
JavaScript example with FormData:
const uploadFile = async (tableId, recordId, fieldSlug, file) => {
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records/${recordId}/files`;
const formData = new FormData();
formData.append('field', fieldSlug);
formData.append('file', file);
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
// Don't set Content-Type - browser sets it with boundary
},
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};
// Usage in browser
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
try {
const result = await uploadFile('abc123', 'rec_xyz789', 'field_5', file);
console.log('File uploaded:', result.file_url);
} catch (error) {
console.error('Upload failed:', error);
}
});
Python example:
import requests
def upload_file(table_id, record_id, field_slug, file_path):
url = f'https://api.tadabase.io/api/v1/tables/{table_id}/records/{record_id}/files'
headers = {
'Authorization': 'Bearer YOUR_API_KEY'
}
with open(file_path, 'rb') as file:
files = {
'file': file
}
data = {
'field': field_slug
}
response = requests.post(url, headers=headers, files=files, data=data)
if response.status_code == 200:
result = response.json()
print(f"File uploaded: {result['file_url']}")
return result
else:
print(f"Error: {response.status_code}")
return None
# Usage
upload_file('abc123', 'rec_xyz789', 'field_5', '/path/to/document.pdf')
Response format:
{
"file_url": "https://tadabase-assets.s3.amazonaws.com/files/document_xyz.pdf",
"file_name": "document.pdf",
"file_size": 1048576,
"field": "field_5"
}
Advanced Filtering
Complex filter combinations for sophisticated queries.
Logical Operators
AND conditions (default):GET /tables/{table_id}/records?filter[status]=Active&filter[amount][gt]=100
OR conditions:
GET /tables/{table_id}/records?filter[status][in]=Active,Pending
Complex combinations:
// (status = Active OR status = Pending) AND amount > 100
GET /tables/{table_id}/records?filter[status][in]=Active,Pending&filter[amount][gt]=100
Date Range Filters
Specific date range:GET /tables/{table_id}/records?filter[created_date][gte]=2026-01-01&filter[created_date][lte]=2026-01-31
Relative dates:
// Last 7 days
GET /tables/{table_id}/records?filter[created_date][gte]=today-7
JavaScript helper for date ranges:
const getRecordsByDateRange = async (tableId, field, startDate, endDate) => {
const params = new URLSearchParams({
[`filter[${field}][gte]`]: startDate,
[`filter[${field}][lte]`]: endDate
});
const url = `https://api.tadabase.io/api/v1/tables/${tableId}/records?${params}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
return await response.json();
};
// Usage - Get records from last month
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
const startDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth(), 1).toISOString().split('T')[0];
const endDate = new Date(lastMonth.getFullYear(), lastMonth.getMonth() + 1, 0).toISOString().split('T')[0];
getRecordsByDateRange('abc123', 'created_date', startDate, endDate)
.then(data => console.log(`Found ${data.total} records`));
Connection Field Filters
Filter by related record:GET /tables/{table_id}/records?filter[customer_connection]=rec_customer123
Filter by related field value:
GET /tables/{table_id}/records?filter[customer_connection.status]=Active
API Performance Optimization
Optimize API usage for better performance.
Field Selection
Request only needed fields:GET /tables/{table_id}/records?fields=id,field_1,field_2
Benefits:
- Smaller response size
- Faster transfer
- Reduced bandwidth
- Lower API processing time
Caching Strategies
Implement client-side caching:class CachedAPI {
constructor(apiKey, cacheDuration = 300000) { // 5 minutes default
this.apiKey = apiKey;
this.cache = new Map();
this.cacheDuration = cacheDuration;
}
async getRecords(tableId, options = {}) {
const cacheKey = `${tableId}-${JSON.stringify(options)}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp
Parallel Requests
Make independent requests in parallel:const fetchDashboardData = async () => {
const [customers, orders, products] = await Promise.all([
getRecords('customers_table', { filters: { status: 'Active' } }),
getRecords('orders_table', { sort: ['-created_date'], perPage: 10 }),
getRecords('products_table', { filters: { stock: { gt: '0' } } })
]);
return { customers, orders, products };
};
// Much faster than sequential requests
Error Handling Patterns
Robust error handling for production systems.
Complete error handling class:
class RobustAPI {
constructor(apiKey, maxRetries = 3) {
this.apiKey = apiKey;
this.maxRetries = maxRetries;
}
async request(method, endpoint, data = null, attempt = 1) {
try {
const options = {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
};
if (data) {
options.body = JSON.stringify(data);
}
const response = await fetch(endpoint, options);
// Handle rate limiting
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Retrying after ${retryAfter}s`);
await this.sleep(retryAfter * 1000);
return this.request(method, endpoint, data, attempt);
}
// Handle server errors with retry
if (response.status >= 500 && attempt setTimeout(resolve, ms));
}
}
class APIError extends Error {
constructor(status, message, details) {
super(message);
this.status = status;
this.details = details;
}
}
// Usage
const api = new RobustAPI('YOUR_API_KEY');
try {
const result = await api.request('GET', 'https://api.tadabase.io/api/v1/tables/abc123/records');
console.log('Success:', result);
} catch (error) {
if (error instanceof APIError) {
console.error(`API Error ${error.status}:`, error.message);
} else {
console.error('Unexpected error:', error);
}
}
Best Practices
Advanced API best practices:
- Batch operations: Use batch endpoints for bulk operations
- Field selection: Request only needed fields
- Caching: Cache frequently accessed data
- Parallel requests: Make independent requests simultaneously
- Error handling: Implement retry logic with exponential backoff
- Rate limiting: Monitor and respect rate limits
- Logging: Log all operations for debugging
- Testing: Test edge cases and failure scenarios
Key Takeaways
Advanced API capabilities:
- Batch operations: Create, update, delete multiple records efficiently
- PDF generation: Generate PDFs from templates programmatically
- Task triggering: Execute scheduled tasks on demand
- File uploads: Upload files to records via API
- Performance: Optimize with caching, field selection, parallel requests
- Error handling: Implement robust retry and fallback logic
Next: Article 7.10 - Third-Party Integrations
We'd love to hear your feedback.