Data Tables API
Complete API reference for managing data tables, records, imports, and field automation jobs.
Overview
The Data Tables API provides a structured data storage layer for your agents and workflows. Tables support typed fields, record versioning, file attachments, bulk operations, CSV/JSON imports, and automated field jobs powered by AI.
Data Table Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/data-tables | List tables |
POST | /v1/data-tables | Create table |
GET | /v1/data-tables/:id | Get table |
GET | /v1/data-tables/slug/:slug | Get table by slug |
PUT | /v1/data-tables/:id | Update table |
DELETE | /v1/data-tables/:id | Delete table |
POST | /v1/data-tables/:id/duplicate | Duplicate table |
POST | /v1/data-tables/:id/archive | Archive table |
POST | /v1/data-tables/:id/restore | Restore archived table |
Record Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/data-tables/:id/records | List records |
POST | /v1/data-tables/:id/records | Create record |
GET | /v1/data-tables/:id/records/:recordId | Get record |
PUT | /v1/data-tables/:id/records/:recordId | Update record |
DELETE | /v1/data-tables/:id/records/:recordId | Delete record |
POST | /v1/data-tables/:id/records/bulk | Bulk create records |
DELETE | /v1/data-tables/:id/records/bulk | Bulk delete records |
GET | /v1/data-tables/:id/records/:recordId/history | Record history |
POST | /v1/data-tables/:id/records/:recordId/restore | Restore record version |
Field Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/data-tables/:id/fields | Add field |
PUT | /v1/data-tables/:id/fields/:fieldId | Update field |
DELETE | /v1/data-tables/:id/fields/:fieldId | Delete field |
POST | /v1/data-tables/:id/fields/reorder | Reorder fields |
File Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/data-tables/:id/files | Upload file |
GET | /v1/data-tables/:id/files/:fileId | Download file |
DELETE | /v1/data-tables/:id/files/:fileId | Delete file |
Import Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/data-tables/:id/import | List import jobs |
POST | /v1/data-tables/:id/import | Create import job |
POST | /v1/data-tables/:id/import/preview | Preview import |
GET | /v1/data-tables/:id/import/:jobId | Get job status |
PUT | /v1/data-tables/:id/import/:jobId | Update job mapping |
POST | /v1/data-tables/:id/import/:jobId/execute | Execute import |
POST | /v1/data-tables/:id/import/:jobId/cancel | Cancel import |
GET | /v1/data-tables/:id/import/:jobId/progress | Get progress |
DELETE | /v1/data-tables/:id/import/:jobId | Delete job |
Field Job Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/data-tables/:tableId/jobs | List field jobs |
POST | /v1/data-tables/:tableId/jobs | Create field job |
GET | /v1/data-tables/:tableId/jobs/:jobId | Get job |
PUT | /v1/data-tables/:tableId/jobs/:jobId | Update job |
DELETE | /v1/data-tables/:tableId/jobs/:jobId | Delete job |
POST | /v1/data-tables/:tableId/jobs/:jobId/execute | Execute job |
POST | /v1/data-tables/:tableId/jobs/:jobId/enable | Toggle enable/disable |
GET | /v1/data-tables/:tableId/jobs/:jobId/executions | Job execution history |
GET | /v1/data-tables/:tableId/records/:recordId/executions | Record job executions |
List Tables
GET /v1/data-tables
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 20 | Items per page (max 100) |
search | string | - | Search by name or description |
status | string | - | Filter: active, archived |
sort | string | -created_at | Sort field (- prefix for descending) |
Response
json{ "data": [ { "id": "dt_abc123", "name": "Customer Leads", "slug": "customer-leads", "description": "Inbound leads from marketing campaigns", "status": "active", "field_count": 8, "record_count": 1450, "created_at": "2025-11-15T09:00:00Z", "updated_at": "2025-12-10T14:20:00Z" } ], "pagination": { "page": 1, "per_page": 20, "total": 5, "total_pages": 1 } }
Example
bashcurl "https://api.arcanflows.io/v1/data-tables?status=active" \ -H "Authorization: Bearer your_api_key"
Create Table
POST /v1/data-tables
Request Body
json{ "name": "Customer Leads", "description": "Inbound leads from marketing campaigns", "fields": [ { "name": "Full Name", "slug": "full_name", "type": "text", "required": true, "description": "Contact full name" }, { "name": "Email", "slug": "email", "type": "email", "required": true, "unique": true }, { "name": "Phone", "slug": "phone", "type": "phone", "required": false }, { "name": "Lead Score", "slug": "lead_score", "type": "number", "config": { "min": 0, "max": 100, "decimal_places": 0 } }, { "name": "Status", "slug": "status", "type": "select", "config": { "options": [ { "value": "new", "label": "New", "color": "#73E0E7" }, { "value": "contacted", "label": "Contacted", "color": "#F59E0B" }, { "value": "qualified", "label": "Qualified", "color": "#10B981" }, { "value": "lost", "label": "Lost", "color": "#EF4444" } ] } }, { "name": "Tags", "slug": "tags", "type": "multi_select", "config": { "options": [ { "value": "enterprise", "label": "Enterprise" }, { "value": "smb", "label": "SMB" }, { "value": "inbound", "label": "Inbound" } ] } }, { "name": "Website", "slug": "website", "type": "url" }, { "name": "Created Date", "slug": "created_date", "type": "date" } ] }
Field Types
| Type | Description | Config Options |
|---|---|---|
text | Single-line text | max_length |
rich_text | Rich text / markdown | max_length |
number | Numeric value | min, max, decimal_places |
email | Email address | Auto-validated |
url | URL | Auto-validated |
phone | Phone number | format |
date | Date only | min_date, max_date |
datetime | Date and time | min_date, max_date, timezone |
boolean | True/false toggle | default_value |
select | Single select dropdown | options (array of value/label/color) |
multi_select | Multiple select | options, max_selections |
file | File attachment | allowed_types, max_size_mb |
reference | Link to another table | table_id, display_field |
formula | Computed field | expression |
Response
json{ "data": { "id": "dt_abc123", "name": "Customer Leads", "slug": "customer-leads", "description": "Inbound leads from marketing campaigns", "status": "active", "fields": [ { "id": "fld_001", "name": "Full Name", "slug": "full_name", "type": "text", "required": true, "order": 0 } ], "field_count": 8, "record_count": 0, "created_at": "2025-12-10T10:00:00Z", "updated_at": "2025-12-10T10:00:00Z" } }
Get Table
GET /v1/data-tables/:id
Returns the full table definition including all fields and metadata.
Response
json{ "data": { "id": "dt_abc123", "name": "Customer Leads", "slug": "customer-leads", "description": "Inbound leads from marketing campaigns", "status": "active", "fields": [ { "id": "fld_001", "name": "Full Name", "slug": "full_name", "type": "text", "required": true, "order": 0 }, { "id": "fld_002", "name": "Email", "slug": "email", "type": "email", "required": true, "order": 1 } ], "field_count": 8, "record_count": 1450, "created_at": "2025-11-15T09:00:00Z", "updated_at": "2025-12-10T14:20:00Z" } }
Get Table by Slug
GET /v1/data-tables/slug/:slug
Retrieve a table using its URL-friendly slug instead of its UUID.
bashcurl "https://api.arcanflows.io/v1/data-tables/slug/customer-leads" \ -H "Authorization: Bearer your_api_key"
Update Table
PUT /v1/data-tables/:id
Request Body
json{ "name": "Updated Lead Tracker", "description": "Updated description" }
Returns the updated table object.
Delete Table
DELETE /v1/data-tables/:id
Response
HTTP/1.1 204 No Content
Warning: This permanently deletes the table and all its records. Use archive for data retention.
Duplicate Table
POST /v1/data-tables/:id/duplicate
Creates a copy of the table structure. Optionally copies records.
Request Body
json{ "name": "Customer Leads (Copy)", "include_records": false }
Archive / Restore Table
POST /v1/data-tables/:id/archive
POST /v1/data-tables/:id/restore
Archive hides the table from default listings and prevents new records. Restore reverses this.
Field Management
Add Field
POST /v1/data-tables/:id/fields
json{ "name": "Company Size", "slug": "company_size", "type": "select", "required": false, "config": { "options": [ { "value": "1-10", "label": "1-10 employees" }, { "value": "11-50", "label": "11-50 employees" }, { "value": "51-200", "label": "51-200 employees" }, { "value": "200+", "label": "200+ employees" } ] } }
Update Field
PUT /v1/data-tables/:id/fields/:fieldId
json{ "name": "Organization Size", "required": true }
Delete Field
DELETE /v1/data-tables/:id/fields/:fieldId
Warning: Deleting a field removes that field's data from all existing records.
Reorder Fields
POST /v1/data-tables/:id/fields/reorder
json{ "field_order": ["fld_002", "fld_001", "fld_003", "fld_004"] }
File Operations
Upload File
POST /v1/data-tables/:id/files
Upload a file attachment. Use multipart/form-data.
bashcurl -X POST "https://api.arcanflows.io/v1/data-tables/dt_abc123/files" \ -H "Authorization: Bearer your_api_key" \ -F "[email protected]" \ -F "record_id=rec_xyz789" \ -F "field_id=fld_005"
Response
json{ "data": { "id": "file_001", "filename": "document.pdf", "mime_type": "application/pdf", "size_bytes": 245000, "record_id": "rec_xyz789", "field_id": "fld_005", "created_at": "2025-12-10T10:00:00Z" } }
Download File
GET /v1/data-tables/:id/files/:fileId
Returns the file binary with the appropriate Content-Type header.
Delete File
DELETE /v1/data-tables/:id/files/:fileId
List Records
GET /v1/data-tables/:id/records
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 50 | Items per page (max 200) |
sort | string | -created_at | Sort by field slug (- for descending) |
search | string | - | Full-text search across all text fields |
filter | string | - | JSON-encoded filter object |
Filter Syntax
Filters are passed as a JSON-encoded query parameter. Operators: eq, neq, gt, gte, lt, lte, contains, not_contains, starts_with, ends_with, is_empty, is_not_empty, in, not_in.
bash# Filter by status = "qualified" and lead_score >= 70 curl "https://api.arcanflows.io/v1/data-tables/dt_abc123/records?filter=%7B%22and%22%3A%5B%7B%22field%22%3A%22status%22%2C%22op%22%3A%22eq%22%2C%22value%22%3A%22qualified%22%7D%2C%7B%22field%22%3A%22lead_score%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A70%7D%5D%7D" \ -H "Authorization: Bearer your_api_key"
The decoded filter:
json{ "and": [ { "field": "status", "op": "eq", "value": "qualified" }, { "field": "lead_score", "op": "gte", "value": 70 } ] }
You can also use or for disjunctive filters:
json{ "or": [ { "field": "status", "op": "eq", "value": "new" }, { "field": "status", "op": "eq", "value": "contacted" } ] }
Response
json{ "data": [ { "id": "rec_xyz789", "values": { "full_name": "Jane Smith", "email": "[email protected]", "phone": "+1-555-987-6543", "lead_score": 85, "status": "qualified", "tags": ["enterprise", "inbound"], "website": "https://acme.com", "created_date": "2025-12-01" }, "created_at": "2025-12-01T08:30:00Z", "updated_at": "2025-12-09T16:45:00Z" } ], "pagination": { "page": 1, "per_page": 50, "total": 1450, "total_pages": 29 } }
Create Record
POST /v1/data-tables/:id/records
Request Body
json{ "values": { "full_name": "John Doe", "email": "[email protected]", "phone": "+1-555-123-4567", "lead_score": 60, "status": "new", "tags": ["smb", "inbound"], "website": "https://example.com", "created_date": "2025-12-10" } }
Response
json{ "data": { "id": "rec_new001", "values": { "full_name": "John Doe", "email": "[email protected]", "phone": "+1-555-123-4567", "lead_score": 60, "status": "new", "tags": ["smb", "inbound"], "website": "https://example.com", "created_date": "2025-12-10" }, "created_at": "2025-12-10T10:00:00Z", "updated_at": "2025-12-10T10:00:00Z" } }
Get Record
GET /v1/data-tables/:id/records/:recordId
Returns a single record with all field values.
Update Record
PUT /v1/data-tables/:id/records/:recordId
Only include the fields you want to update:
json{ "values": { "lead_score": 85, "status": "qualified" } }
Delete Record
DELETE /v1/data-tables/:id/records/:recordId
Response
HTTP/1.1 204 No Content
Bulk Create Records
POST /v1/data-tables/:id/records/bulk
Create up to 1000 records in a single request.
json{ "records": [ { "values": { "full_name": "Alice Johnson", "email": "[email protected]", "status": "new" } }, { "values": { "full_name": "Bob Williams", "email": "[email protected]", "status": "new" } } ] }
Response
json{ "data": { "created": 2, "failed": 0, "errors": [] } }
Bulk Delete Records
DELETE /v1/data-tables/:id/records/bulk
json{ "record_ids": ["rec_001", "rec_002", "rec_003"] }
Response
json{ "data": { "deleted": 3 } }
Record History
GET /v1/data-tables/:id/records/:recordId/history
Returns a version history of all changes to the record.
Response
json{ "data": [ { "version": 3, "changed_fields": ["lead_score", "status"], "previous_values": { "lead_score": 60, "status": "contacted" }, "new_values": { "lead_score": 85, "status": "qualified" }, "changed_by": "user_abc", "changed_at": "2025-12-09T16:45:00Z" }, { "version": 2, "changed_fields": ["status"], "previous_values": { "status": "new" }, "new_values": { "status": "contacted" }, "changed_by": "user_abc", "changed_at": "2025-12-05T11:30:00Z" } ] }
Restore Record Version
POST /v1/data-tables/:id/records/:recordId/restore
json{ "version": 2 }
Restores the record to a previous version from its history.
Data Import
Create Import Job
POST /v1/data-tables/:id/import
Upload a CSV or JSON file to create an import job. Use multipart/form-data.
bashcurl -X POST "https://api.arcanflows.io/v1/data-tables/dt_abc123/import" \ -H "Authorization: Bearer your_api_key" \ -F "[email protected]" \ -F "format=csv" \ -F "has_header=true"
Response
json{ "data": { "id": "imp_001", "status": "pending", "format": "csv", "total_rows": 500, "column_mapping": { "Name": null, "Email Address": null, "Score": null }, "created_at": "2025-12-10T10:00:00Z" } }
Preview Import
POST /v1/data-tables/:id/import/preview
Returns a sample of rows and detected columns without creating a job.
bashcurl -X POST "https://api.arcanflows.io/v1/data-tables/dt_abc123/import/preview" \ -H "Authorization: Bearer your_api_key" \ -F "[email protected]" \ -F "format=csv"
Response
json{ "data": { "columns": ["Name", "Email Address", "Score", "Status"], "sample_rows": [ ["Jane Smith", "[email protected]", "85", "qualified"], ["John Doe", "[email protected]", "60", "new"] ], "total_rows": 500, "suggested_mapping": { "Name": "full_name", "Email Address": "email", "Score": "lead_score", "Status": "status" } } }
Update Job Mapping
PUT /v1/data-tables/:id/import/:jobId
Set the column-to-field mapping before executing:
json{ "column_mapping": { "Name": "full_name", "Email Address": "email", "Score": "lead_score" }, "on_duplicate": "skip" }
on_duplicate | Behavior |
|---|---|
skip | Skip rows that match an existing record |
update | Update existing records with new values |
create | Always create new records (allow duplicates) |
Execute Import
POST /v1/data-tables/:id/import/:jobId/execute
Starts the import. Large imports run asynchronously.
Response
json{ "data": { "id": "imp_001", "status": "processing", "total_rows": 500, "processed_rows": 0 } }
Get Import Progress
GET /v1/data-tables/:id/import/:jobId/progress
json{ "data": { "id": "imp_001", "status": "processing", "total_rows": 500, "processed_rows": 320, "created": 310, "updated": 0, "skipped": 8, "failed": 2, "errors": [ { "row": 145, "error": "Invalid email format" }, { "row": 289, "error": "Required field 'full_name' is empty" } ], "percent_complete": 64 } }
Cancel Import
POST /v1/data-tables/:id/import/:jobId/cancel
Cancels a running import. Records already imported are retained.
List Import Jobs
GET /v1/data-tables/:id/import
Returns all import jobs for the table with their statuses.
Delete Import Job
DELETE /v1/data-tables/:id/import/:jobId
Removes a completed or cancelled import job record (does not delete imported data).
Field Jobs (Automation)
Field jobs allow you to automate data enrichment, transformation, and AI-powered field population across your table records.
Create Field Job
POST /v1/data-tables/:tableId/jobs
json{ "name": "Enrich Lead Score", "description": "Use AI to score leads based on company and title", "target_field_id": "fld_004", "source_field_ids": ["fld_001", "fld_002"], "job_type": "ai_enrichment", "config": { "model": "gpt-4o", "prompt": "Based on the contact name and email domain, estimate a lead quality score from 0-100.", "output_type": "number" }, "trigger": "on_create", "is_enabled": true }
Job Configuration
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Job name |
target_field_id | string | Yes | Field to populate |
source_field_ids | array | Yes | Fields used as input |
job_type | string | Yes | ai_enrichment, formula, lookup, transform |
config | object | Yes | Type-specific configuration |
trigger | string | Yes | on_create, on_update, manual, scheduled |
is_enabled | boolean | No | Default true |
Execute Field Job
POST /v1/data-tables/:tableId/jobs/:jobId/execute
Run the job manually against all records (or a filtered subset):
json{ "filter": { "field": "lead_score", "op": "is_empty" } }
Response
json{ "data": { "execution_id": "exec_001", "status": "processing", "total_records": 230, "processed": 0 } }
Toggle Enable/Disable
POST /v1/data-tables/:tableId/jobs/:jobId/enable
json{ "is_enabled": false }
Job Execution History
GET /v1/data-tables/:tableId/jobs/:jobId/executions
json{ "data": [ { "id": "exec_001", "status": "completed", "total_records": 230, "processed": 230, "succeeded": 225, "failed": 5, "started_at": "2025-12-10T10:00:00Z", "completed_at": "2025-12-10T10:02:30Z" } ] }
Record Executions
GET /v1/data-tables/:tableId/records/:recordId/executions
Shows all field job executions that have run against a specific record.
Code Examples
Python
pythonimport requests API_URL = "https://api.arcanflows.io/v1" HEADERS = {"Authorization": "Bearer your_api_key"} # Create a table table = requests.post(f"{API_URL}/data-tables", headers=HEADERS, json={ "name": "Contacts", "fields": [ {"name": "Name", "slug": "name", "type": "text", "required": True}, {"name": "Email", "slug": "email", "type": "email", "required": True}, {"name": "Score", "slug": "score", "type": "number"} ] }).json()["data"] # Add records requests.post( f"{API_URL}/data-tables/{table['id']}/records", headers=HEADERS, json={"values": {"name": "Alice", "email": "[email protected]", "score": 90}} ) # List records with filter records = requests.get( f"{API_URL}/data-tables/{table['id']}/records", headers=HEADERS, params={"filter": '{"field":"score","op":"gte","value":80}'} ).json()["data"] for rec in records: print(f"{rec['values']['name']}: {rec['values']['score']}")
JavaScript
javascriptconst API_URL = 'https://api.arcanflows.io/v1'; const headers = { 'Authorization': 'Bearer your_api_key', 'Content-Type': 'application/json', }; // Create table const table = await fetch(`${API_URL}/data-tables`, { method: 'POST', headers, body: JSON.stringify({ name: 'Contacts', fields: [ { name: 'Name', slug: 'name', type: 'text', required: true }, { name: 'Email', slug: 'email', type: 'email', required: true }, ], }), }).then(r => r.json()); // Bulk create records await fetch(`${API_URL}/data-tables/${table.data.id}/records/bulk`, { method: 'POST', headers, body: JSON.stringify({ records: [ { values: { name: 'Alice', email: '[email protected]' } }, { values: { name: 'Bob', email: '[email protected]' } }, ], }), }); // Import from CSV const formData = new FormData(); formData.append('file', csvFile); formData.append('format', 'csv'); formData.append('has_header', 'true'); const importJob = await fetch( `${API_URL}/data-tables/${table.data.id}/import`, { method: 'POST', headers: { Authorization: headers.Authorization }, body: formData } ).then(r => r.json());