User Guide mdi-view-dashboard Guide Contents

Welcome to DSiloed

mdi-link
Looking for the user guide? Documentation for the Portablemind app — getting started, AI setup, agents, chat, files, sharing, SiloLink, and orchestration — has moved to app.portablemind.ai/docs. This guide now focuses on the platform API and building your own applications.

AI Enabler Built on Enterprise Data Models

DSiloed is the platform behind Portablemind: an AI enablement engine built on comprehensive enterprise data models, exposed through a REST API, WebSockets, and MCP tools.

This guide covers the developer surface of the platform — API integration and authentication, the MCP tools your agents can call, sandboxed Dynamic Functions, and building your own applications on the data foundation. For using the Portablemind app itself (chat, agents, files, sharing, orchestration), see the user guide.

Core Architecture mdi-link

DSiloed is built on a flexible, enterprise-grade data model designed for extensibility and integration. Here are the key components:

Party Model

  • People and Organizations - Represented as Parties
  • Flexible Relationships - Connect parties with typed relationships
  • Role-based - Assign roles for different contexts

Business Transaction Events

  • Event-based Transactions - Track business events
  • Typed Event Relations - Connect related events
  • Party Roles in Events - Associates parties with roles in events

Security System

  • Capabilities - Fine-grained permissions
  • Security Roles - Group capabilities for assignment
  • Tenant Isolation - Multi-tenant architecture

AI & Memory System

  • Rich Memory Graphs - Persistent knowledge with pattern recognition
  • Real-time Chat - WebSocket-based conversations with AI models
  • Document Processing - PDF, DOCX, Markdown, and image support
  • Autonomous Agents - Self-improving AI with tool execution
AI-First, API-Driven Platform mdi-link

DSiloed is designed with an AI-first, API-driven approach. Every AI capability—from chat conversations to memory graphs to autonomous agents—is accessible through our comprehensive REST API and WebSocket connections. Build any AI-powered interface on top of our enterprise data foundation.

All sample applications in this demo are built using static JavaScript frameworks that interact with the API, demonstrating how you can create sophisticated AI-enabled applications with standard web technologies.

Quick Start

Ready to build? Head to API Documentation for authentication and endpoints, the MCP Tools Reference for agent tooling, or Building Your Own App to scaffold an application. Check out Sample Apps to see real-world AI applications in action.

MCP Tools Reference

mdi-link
About MCP Tools mdi-link

Model Context Protocol (MCP) tools provide a standardized interface for AI models to interact with your DSiloed platform. These tools enable LLMs to perform operations, access data, manage agents, handle communications, and more.

All MCP tools are available through the MCP server and can be used by external applications, AI agents, and LLM conversations. This reference lists all 35+ available MCP tools with their descriptions and use cases.

Note: These tools are automatically available to LLM agents configured in your tenant. External applications can also access these tools through the MCP protocol.
mdi-folder-multiple Tool Categories mdi-link

Tools are organized into categories for easier filtering and discovery. Use these category names with the categories query parameter to load specific tool groups.

Category Description Tools
agents Create, configure, execute, and monitor AI agents list_available_agents, execute_agent, check_agent_status, complete_agent_run, create_agent, get_tool_configuration, list_available_agent_tools, list_available_agent_resources, list_available_llm_models, list_available_prompts, set_agent_state, update_agent, delete_agent
communication Email, conversation/guest invitations, voice calls send_email, send_conversation_invitation, send_guest_invitation, outbound_call
data CRUD, schema discovery, file management, status, Tier-3 document generation general_crud, model_schema, create_llm_file, update_llm_file, read_llm_file, list_llm_files, move_llm_file, llm_cost_stats, apply_status, run_python_skill, convert_to_pdf
memory Persistent memory: store, load, and curate AI context store_memory, load_memories, update_memory, forget_memory, link_memories
conversation Chat messaging and direct messages conversation_chat, start_dm_with_user
research Web search and page fetch web_research
dynamic_functions Serverless JavaScript function management list_dynamic_functions, get_dynamic_function, execute_dynamic_function, dynamic_function_executions, manage_dynamic_function
llm_tools Custom LLM tool creation and management list_llm_tools, get_llm_tool, manage_llm_tool, test_llm_tool
documentation Platform + app-development documentation assistants dmapi_assistant, app_docs_assistant
admin Administrative tools (logs, cost statistics) tail_rails_log, llm_cost_stats
utility General utilities current_date_time
mdm Master Data Management for external system mappings external_mappings_by_system
workflow Workflow artifacts create_workflow_artifact
coordination Agent coordination / resource leases coordination_tool
Filtering Tools: Add ?categories=data,memory to your MCP endpoint URL to load only specific categories, or ?tools= to name individual tools.
mdi-email Communication Tools mdi-link

Tools for sending emails and managing conversation invitations.

send_email_tool

Send emails with customizable subject, body, recipients, and sender information.

Use Cases:

  • Send notifications to users
  • Email reports and summaries
  • Bulk communications to multiple recipients

Key Parameters:

  • subject - Email subject line
  • email_body - HTML email content
  • to_email - Recipient(s), semicolon-separated
  • from_email - Optional sender address
send_conversation_invitation_tool

Send single-use invitation links for one-time feedback in LLM conversations.

Use Cases:

  • Request specific feedback or answers
  • One-time input collection
  • Quick survey responses
send_guest_invitation_tool

Send guest trial invitations allowing multiple messages before signup.

Use Cases:

  • Progressive user engagement
  • Trial conversation access
  • Guest-to-member conversion flows
outbound_call_tool

Make outbound AI voice calls.

mdi-database Data Management Tools mdi-link

Tools for CRUD operations, schema discovery, and file management.

general_crud_tool Most Used

Comprehensive CRUD operations for all data models with advanced filtering, relationships, and aggregations.

Capabilities:

  • Create, Read, Update, Delete operations
  • Advanced search with JSON query syntax
  • Relationship management (link/unlink)
  • Aggregations and analytics
  • Field-level selection for performance

Supported Models:

Party, Individual, Organization, Contact, BizTxnEvent, Project, Task, LlmConversation, and 30+ more

model_schema_tool

Discover schema information, available columns, required fields, and data types for any model.

Use Cases:

  • Understand model structure before queries
  • Identify required fields for creation
  • Discover available relationships
create_llm_file_tool

Create text-based documents (Markdown, TXT, CSV, PDF, DOCX) programmatically.

Use Cases:

  • Generate reports and summaries
  • Create documentation
  • Save analysis results
update_llm_file_tool

Update existing documents with new content, titles, or move to different directories.

read_llm_file_tool

Read file contents including text files, documents (PDF/DOCX), images, and media files.

llm_cost_stats_tool

Retrieve comprehensive LLM usage statistics, costs, and token consumption by model, user, and conversation.

apply_status_tool

Apply tracked statuses to entities (Tasks, Projects, BizTxnEvents, etc.) with proper history tracking.

run_python_skill_tool

Run an admin-reviewed, registered Python script (Tier-3, sandboxed subprocess) by id — e.g. generate a .pptx deck or a print-quality PDF — and persist the output as an attached file. Generates .pptx decks and print-quality PDFs from registered scripts.

convert_to_pdf_tool

Convert an existing Office document (.pptx/.docx/.xlsx) already stored as a file into a PDF, attached back to the conversation.

list_llm_files_tool

List files and directories in the LLM file system.

move_llm_file_tool

Move files or directories to a new location in the LLM file system.

mdi-robot Agent Management Tools mdi-link

Tools for creating, managing, and executing autonomous AI agents.

create_agent_tool

Create complete LLM agents with custom tools, resources, prompts, and role assignments.

update_agent_tool

Modify existing agent configurations, prompts, tools, and settings.

delete_agent_tool

Permanently remove agents from the system.

list_available_agents_tool

List all available agents with their capabilities and descriptions.

execute_agent_tool

Execute an agent with specific prompts and monitor execution status.

check_agent_status_tool

Check the execution status and output of running agents.

complete_agent_run_tool

Mark agent runs as complete with success/failure status.

list_available_agent_tools_tool

List all tools that can be assigned to agents during creation.

list_available_agent_resources_tool

List all resources available for agent configuration.

list_available_llm_models_tool

List configured LLM models available for agent creation.

list_available_prompts_tool

List available system and user prompts for agents.

get_tool_configuration_tool

Get configuration requirements for specific tools before assigning to agents.

mdi-brain Memory Tools mdi-link

Tools for persistent memory management across AI sessions.

store_memory_tool

Store facts, insights, decisions, preferences, and context as persistent memories.

Memory Types:

  • Fact - Specific data points and verified information
  • Preference - User settings and choices
  • Decision - Important choices made
  • Insight - Analysis and patterns
  • Solution - Technical fixes and configurations
  • Goal - User objectives
load_memories_tool

Retrieve relevant memories to provide context for AI conversations.

Retrieval Modes:

  • Search - Content-based keyword search
  • Semantic - Vector similarity search
  • Recent - Recently created memories
  • Important - High-importance memories
  • Conversation/Agent specific
update_memory_tool

Correct or refine a memory you own (title, content, importance, tags) in place.

forget_memory_tool

Retire (soft-archive) a memory you own so it stops surfacing in recall.

link_memories_tool

Create a typed relationship between two memories (builds the memory graph).

mdi-chat Conversation Tools mdi-link

Tools for managing LLM conversations and messaging.

conversation_chat_tool

Send messages to LLM conversations and trigger AI responses.

Use Cases:

  • External system integration
  • Automated message sending
  • Custom chat interfaces
mdi-book-open Documentation Tools mdi-link

Tools for accessing platform documentation.

dmapi_assistant_tool

Ask questions about the Data Model API platform implementation and features.

Topics Covered:

  • Security and capability system
  • API endpoints and responses
  • Model relationships
  • MCP integration
  • Webhook system
app_docs_assistant_tool

Access app development documentation for building applications on the platform.

Topics Covered:

  • Authentication setup
  • API client usage
  • Shared components
  • Best practices
mdi-tools Utility & Admin Tools mdi-link

Utility and administrative tools for system operations.

current_date_time_tool

Get current date and time with timezone support and multiple formats.

tail_rails_log_tool Admin Only

Root tenant only: Tail Rails application logs for debugging and monitoring.

external_mappings_by_system_tool

Get external system mappings for MDM integration and data synchronization.

mdi-function Dynamic Functions Tools mdi-link

Tools for creating, managing, and executing serverless JavaScript functions.

list_dynamic_functions_tool

List available dynamic functions with their status, schedule, and recent execution info.

Filtering Options:

  • active_only - Only show active functions
  • scheduled_only - Only show scheduled functions
  • callbacks_only - Only show callback functions
  • callback_model - Filter by callback model name
  • name - Filter by function name (partial match)
get_dynamic_function_tool

Get full details of a specific function by ID or name, including JavaScript code and execution history.

Key Parameters:

  • id or name - Function identifier
  • include_executions - Include recent execution history
  • execution_limit - Number of executions to include (max 20)
execute_dynamic_function_tool

Execute a dynamic function by ID or name and return results.

Key Parameters:

  • function_id or function_name - Function to execute
  • params - Parameters passed to the function
  • async - Execute asynchronously (queued)

Returns:

  • success - Execution status
  • result - Function return value
  • execution_id - For tracking history
  • execution_time_ms - Duration
manage_dynamic_function_tool CRUD

Create, update, or delete dynamic functions with full configuration support.

Actions:

  • create - Create new function with name, code, schedule, callbacks
  • update - Modify existing function (can rename with new_name)
  • delete - Remove function

Configuration Options:

  • schedule - Cron expression for scheduled execution
  • callback_model - Model to trigger callback on
  • callback_event - Event type (create, update, destroy, all)
  • timeout_seconds - Max execution time (1-300)
  • configuration - Custom config including OAuth
dynamic_function_executions_tool

View execution history and logs for debugging and monitoring.

Filtering Options:

  • function_id or function_name - Filter by function
  • execution_id - Get specific execution details
  • trigger_type - Filter by trigger (manual, api, schedule, mcp_tool, webhook, nested_call, callback)
  • success_only / failed_only - Filter by status
  • limit - Number of records (max 100)
Tip: Dynamic Functions can access tenant data via executeAction(), make HTTP requests with fetch(), call other functions with executeFunction(), and integrate with external systems via OAuth. See the Dynamic Functions section for full documentation.
mdi-webResearch research

web_research_tool — Search and fetch the public web (DuckDuckGo / Tavily / Brave / Wikipedia).

mdi-toolsLLM Tools llm_tools

list_llm_tools_tool — List available custom LLM Tools with their status and configuration.

get_llm_tool_tool — Get details of a specific custom LLM Tool by ID or name.

manage_llm_tool_tool — Create, update, and delete custom LLM Tools.

test_llm_tool_tool — Test-execute a custom LLM Tool with provided parameters.

mdi-database-syncMDM mdm

external_mappings_by_system_tool — Get external-system ID mappings for integrated systems (Master Data Management).

mdi-shield-accountAdmin admin

tail_rails_log_tool — Tail Rails logs for debugging (tenant-scoped access).

llm_cost_stats_tool — Get LLM cost and token-usage statistics.

mdi-cog-transferWorkflow & Coordination workflow coordination

create_workflow_artifact_tool — File an organized, work-item-linked structured-work artifact (any domain).

coordination_tool — Claim / release / inspect advisory leases on shared resources (e.g. the shared DEV/PROD environment).

Using MCP Tools

MCP tools can be accessed in multiple ways:

In LLM Agents

Agents can be granted these tools and use them autonomously during execution.

In Conversations

LLMs in conversations can invoke tools as needed to answer questions, retrieve data, or perform actions.

External Applications

Connect external applications via MCP protocol to access all tools programmatically.

Custom Tools

Create custom JavaScript tools for tenant-specific functionality via the Dynamic Functions system.

Pro Tip: Combine multiple tools in agent workflows for complex automation. For example, use general_crud_tool to fetch data, create_llm_file_tool to generate a report, and send_email_tool to distribute it.

API Documentation

mdi-link
RESTful API Overview mdi-link

DSiloed provides a comprehensive RESTful API for building applications. All endpoints follow consistent RESTful conventions with JSON responses.

Authentication

Authentication uses JWT (JSON Web Tokens) passed in the Authorization header.

curl -X GET "https://example-model-api.com/api/v1/parties" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

Content Types

All API requests should use JSON for request bodies and accept JSON responses.

-H "Content-Type: application/json" \
-H "Accept: application/json"

Response Format

Responses follow a consistent format with data returned in an object named after the resource.

// Single resource example (e.g., GET /api/v1/users/123)
{
  "success": true,
  "user": {
    "id": 123,
    "description": "John Doe",
    "created_at": "2025-05-01T12:34:56Z",
    "updated_at": "2025-05-02T10:11:12Z"
  }
}

// Multiple resources example (e.g., GET /api/v1/users)
{
  "success": true,
  "total_count": 42,
  "users": [
    {
      "id": 123,
      "description": "John Doe",
      "created_at": "2025-05-01T12:34:56Z"
    },
    {
      "id": 124,
      "description": "Jane Smith",
      "created_at": "2025-05-02T08:15:30Z"
    }
    // ... more users
  ]
}

Error Handling

Errors return a simple format with success set to false and an error message.

{
  "success": false,
  "message": "Invalid Access"
}
Core Resources mdi-link Parties Contacts Business Events Security LLM Integration

Parties API

Parties represent individuals and organizations. The Party model is the foundation of your application's data model.

List all parties

curl -X GET "https://example-model-api.com/api/v1/parties" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

Get a specific party

curl -X GET "https://example-model-api.com/api/v1/parties/123" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

Create an individual

curl -X POST "https://example-model-api.com/api/v1/individuals" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id" \
    -H "Content-Type: application/json" \
    -d '{
      "first_name": "John",
      "last_name": "Doe",
      "dob": "1990-01-01"
    }'

Create an organization

curl -X POST "https://example-model-api.com/api/v1/organizations" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id" \
    -H "Content-Type: application/json" \
    -d '{
      "description": "Acme Corporation"
    }'

Contacts API

Contacts represent various contact methods like email addresses, phone numbers, and postal addresses.

List all contacts

curl -X GET "https://example-model-api.com/api/v1/contacts" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

Create an email address

curl -X POST "https://example-model-api.com/api/v1/email_addresses" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id" \
    -H "Content-Type: application/json" \
    -d '{
      "party_id": 123,
      "description": "Work Email",
      "email_address": "john.doe@example.com"
    }'

Create a phone number

curl -X POST "https://example-model-api.com/api/v1/phone_numbers" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id" \
    -H "Content-Type: application/json" \
    -d '{
      "party_id": 123,
      "description": "Mobile",
      "phone_number": "+15551234567"
    }'

Business Events API

Business events track activities and transactions within your application.

List all business events

curl -X GET "https://example-model-api.com/api/v1/biz_txn_events" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

Create a business event

curl -X POST "https://example-model-api.com/api/v1/biz_txn_events" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id" \
    -H "Content-Type: application/json" \
    -d '{
      "biz_txn_event_type_id": 1,
      "description": "Order Placed",
      "event_date": "2025-05-11T14:30:00Z",
      "amount": 99.99,
      "payload": {
        "order_number": "ORD-12345",
        "items": 3
      }
    }'

Security API

Manage security, roles, and capabilities within your application.

List all security roles

curl -X GET "https://example-model-api.com/api/v1/security_roles" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

List all capabilities

curl -X GET "https://example-model-api.com/api/v1/capabilities" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

LLM Integration API

APIs for managing LLM models, tools, and conversations.

List all LLM models

curl -X GET "https://example-model-api.com/api/v1/llm_models" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"

List all LLM tools

curl -X GET "https://example-model-api.com/api/v1/llm_tools" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "Tenant-Id: your-tenant-id"
Swagger Documentation mdi-link

For complete API documentation, refer to the Swagger UI which provides interactive documentation for all available endpoints.

Open Swagger Documentation

Dynamic Functions

mdi-link
Serverless JavaScript Functions mdi-link

Dynamic Functions provide a serverless JavaScript execution environment within the DSiloed platform. They allow you to create, manage, and execute custom JavaScript functions that can integrate with external APIs, process data, and automate workflows—all without managing any infrastructure.

mdi-shield-lock Sandboxed Execution JavaScript runs in a secure V8 sandbox with memory and CPU limits. Functions are tenant-isolated with no filesystem access. mdi-key OAuth Integration Configuration-based OAuth 2.0 support for any provider. Automatic token refresh keeps your integrations running. mdi-clock-outline Scheduled Execution Use cron expressions to schedule functions to run automatically. Perfect for data syncs, reports, and automated workflows. mdi-webhook Model Callbacks Trigger functions automatically when records are created, updated, or deleted. Build event-driven automation workflows. mdi-database Data Access Full access to tenant data via executeAction. Query, create, update, and delete records from your functions. mdi-robot MCP Integration AI agents can manage and execute functions via MCP tools. Empower your AI to automate complex workflows.
Creating Your First Function mdi-link

Create a dynamic function using the REST API. Functions receive a context object with parameters, configuration, OAuth tokens, and tenant information.

Tip: Function names must be 1-128 characters using alphanumeric characters, underscores, or hyphens.
// Create a function via REST API
POST /api/v1/dynamic_functions
Content-Type: application/json

{
  "dynamic_function": {
    "name": "hello_world",
    "description": "A simple greeting function",
    "javascript_code": "return { message: 'Hello, ' + (params.name || 'World') + '!' };",
    "active": true,
    "timeout_seconds": 30
  }
}

Execute the function by ID or name:

// Execute by name
POST /api/v1/dynamic_functions/hello_world/execute
Content-Type: application/json

{
  "params": {
    "name": "DSiloed"
  }
}

// Response:
{
  "success": true,
  "result": { "message": "Hello, DSiloed!" },
  "execution_id": 456,
  "execution_time_ms": 12
}
JavaScript Execution Context mdi-link

Functions receive a rich context with access to parameters, configuration, and built-in functions for data access and HTTP requests.

// Available context properties
params                    // Parameters passed when executing
config                    // Function configuration (excluding secrets)
functionId                // Database ID of this function
functionName              // Function name
tenantId                  // Current tenant ID

// OAuth tokens (if connected)
oauth.accessToken         // OAuth access token
oauth.tokenType           // Token type (usually "Bearer")

// Callback context (only in callback executions)
event                     // 'create', 'update', or 'destroy'
model_name                // Model class name (e.g., 'Task')
record_id                 // ID of the affected record
record                    // Full record data
changes                   // Changed attributes (update only)
// Make HTTP requests to external APIs
const response = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${oauth.accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ key: 'value' })
});

const data = await response.json();
return { fetched: data };
// Query tenant data
var customers = executeAction('Individual', 'list', {
  filters: { role_type_id: 'customer' },
  limit: 100
});

// Create records
var newContact = executeAction('PhoneNumber', 'create', {
  attributes: {
    party_id: 123,
    phone_number: '555-1234'
  }
});

// Update records
executeAction('Individual', 'update', {
  id: 456,
  attributes: { custom_fields: { synced: true } }
});

// Convenience wrappers also available:
listRecords(modelName, options)
getRecord(modelName, id)
createRecord(modelName, attributes)
updateRecord(modelName, id, attributes)
deleteRecord(modelName, id)
findOrCreateRecord(modelName, findAttrs, createAttrs)
// Execute another DynamicFunction by name (synchronous by default)
const result = executeFunction('helper_function', { key: 'value' });

if (result.success) {
  console.log('Helper returned:', result.result);
} else {
  console.error('Helper failed:', result.error);
}

// Execute asynchronously (queued for background execution)
const asyncResult = executeFunction('long_running_task', { data: params.input }, true);
// Returns immediately: { success: true, message: '...', execution_id: ... }

// Chain multiple functions together
const validation = executeFunction('validate_data', { data: params.input });
if (!validation.success || !validation.result.valid) {
  return { success: false, error: 'Validation failed' };
}

const processed = executeFunction('process_data', {
  data: params.input,
  validationResult: validation.result
});

return processed.result;

// executeFunction(functionNameOrId, params, async)
// - functionNameOrId: Name or ID of the function
// - params: Parameters object (optional)
// - async: If true, queues for background execution (optional, default: false)
// Look up external ID for a local record
var result = getExternalId('Party', partyId, 'xero', 'xero_user_id');
if (result.found) {
  console.log('Xero user ID:', result.external_id);
}

// Find local record by external ID
var projectMapping = findByExternalId('Project', 'xero', xeroProjectId);
if (projectMapping.found) {
  var localProject = projectMapping.record;
}

// Store a new mapping
storeExternalMapping('Project', localProjectId, 'xero', xeroProjectId, {
  column_name: 'xero_project_id',
  table_name: 'xero_projects',
  is_primary_key: true
});
Scheduling Functions

Functions can be scheduled to run automatically using cron expressions. The scheduler checks every 30 seconds for functions due to execute.

Schedule Cron Expression
Every minute* * * * *
Every hour0 * * * *
Daily at 9am0 9 * * *
Every Monday at 8am0 8 * * 1
First of month at midnight0 0 1 * *
Every 15 minutes*/15 * * * *
Required: Scheduled functions must specify run_as_user_id to define which user's permissions are used during background execution. The user must belong to the same tenant.
// Create a scheduled function
POST /api/v1/dynamic_functions
{
  "dynamic_function": {
    "name": "daily_sync",
    "description": "Sync contacts with CRM every morning",
    "javascript_code": "/* sync logic */",
    "schedule": "0 9 * * *",
    "timeout_seconds": 120,
    "run_as_user_id": 123,
    "active": true
  }
}
Model Lifecycle Callbacks mdi-link

Functions can be triggered automatically when records are created, updated, or destroyed. This enables event-driven automation without polling.

Supported Models

Individual Organization Party Task Project TimeEntry BizTxnEvent BizTxnAccount

Callback Events

create update destroy all
Required: Callback functions must specify run_as_user_id to define which user's permissions are used during callback execution. The user must belong to the same tenant.
// Create a callback function for task creation
POST /api/v1/dynamic_functions
{
  "dynamic_function": {
    "name": "on_task_created",
    "description": "Notify team when tasks are created",
    "callback_model": "Task",
    "callback_event": "create",
    "run_as_user_id": 123,
    "javascript_code": `
      // Context includes: event, model_name, record_id, record
      console.log('Task created:', record.name);

      // Send notification to external system
      await fetch('https://slack.com/api/chat.postMessage', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer ' + oauth.accessToken,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          channel: '#tasks',
          text: 'New task created: ' + record.name
        })
      });

      return { notified: true };
    `
  }
}
OAuth Integration mdi-link

Dynamic Functions support OAuth 2.0 for integrating with external services. OAuth is configuration-based, meaning any OAuth 2.0 provider can be used without code changes.

OAuth Configuration

{
  "oauth": {
    "provider": "xero",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "authorize_url": "https://login.xero.com/identity/connect/authorize",
    "token_url": "https://identity.xero.com/connect/token",
    "scopes": ["openid", "profile", "accounting.transactions.read"]
  }
}

OAuth Flow

1. Configure - Set OAuth config on the function 2. Authorize - Call /oauth/authorize to get authorization URL 3. Redirect - User authorizes access at the provider 4. Callback - Provider redirects with authorization code 5. Token Exchange - System exchanges code for tokens 6. Usage - Access tokens via oauth.accessToken Auto-refresh: Tokens are automatically refreshed before execution when they are expired or expiring within 5 minutes.
REST API Reference mdi-link
Endpoint Description
GET /api/v1/dynamic_functions List all functions
POST /api/v1/dynamic_functions Create a new function
GET /api/v1/dynamic_functions/:id Get function details
PUT /api/v1/dynamic_functions/:id Update a function
DELETE /api/v1/dynamic_functions/:id Delete a function
POST /api/v1/dynamic_functions/:id/execute Execute a function (sync or async)
GET /api/v1/dynamic_functions/:id/export Export function configuration
POST /api/v1/dynamic_functions/import Import a function
POST /api/v1/dynamic_functions/:id/oauth/authorize Start OAuth authorization
GET /api/v1/dynamic_functions/:id/oauth/status Check OAuth connection status
POST /api/v1/dynamic_functions/:id/oauth/disconnect Disconnect OAuth
Tip: Functions can be referenced by ID (numeric) or name (string) in URLs. For example: /api/v1/dynamic_functions/my_function/execute
MCP Tools for AI Agents mdi-link

AI agents can manage and execute Dynamic Functions via five dedicated MCP tools. This enables intelligent automation where AI can create, modify, and run custom code.

list_dynamic_functions_tool List functions with filtering by active status, schedule, callbacks, and name. get_dynamic_function_tool Get full function details including JavaScript code and execution history. execute_dynamic_function_tool Execute a function by ID or name with parameters (sync or async). manage_dynamic_function_tool Create, update, or delete functions. Supports scheduling and callbacks. Use run_as_user_id: "current_user" for scheduled/callback functions. dynamic_function_executions_tool View execution history with filtering by function, trigger type, and status.
Example: Xero Integration Function mdi-link

Here's a complete example of a function that syncs time entries to Xero, demonstrating OAuth, data access, and MDM mapping helpers.

// Function: sync_time_entries_to_xero
// Schedule: 0 * * * * (every hour)

// Get unsynced time entries
var entries = listRecords('TimeEntry', {
  filters: { status: 'approved' },
  limit: 50
});

var synced = 0;
var skipped = 0;

for (var entry of entries.data) {
  // Skip if already synced
  var existingMapping = getExternalId('TimeEntry', entry.id, 'xero', 'xero_timeentry_id');
  if (existingMapping.found) {
    skipped++;
    continue;
  }

  // Look up Xero user ID for this party
  var userMapping = getExternalId('Party', entry.party_id, 'xero', 'xero_user_id');
  if (!userMapping.found) {
    console.log('No Xero user mapping for party:', entry.party_id);
    continue;
  }

  // Create time entry in Xero
  var xeroResponse = await fetch('https://api.xero.com/projects/timeEntries', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + oauth.accessToken,
      'Content-Type': 'application/json',
      'Xero-Tenant-Id': config.xero_tenant_id
    },
    body: JSON.stringify({
      userId: userMapping.external_id,
      projectId: entry.custom_fields.xero_project_id,
      duration: entry.hours * 60,
      description: entry.description
    })
  });

  var xeroEntry = await xeroResponse.json();

  // Store mapping for future reference
  storeExternalMapping('TimeEntry', entry.id, 'xero', xeroEntry.timeEntryId, {
    column_name: 'xero_timeentry_id'
  });

  synced++;
}

return {
  success: true,
  synced: synced,
  skipped: skipped,
  message: `Synced ${synced} entries, skipped ${skipped} already synced`
};

Sample Applications

mdi-link
Available Sample Apps mdi-link

DSiloed comes with several sample applications that demonstrate different capabilities of the platform. Each app is built as a static JavaScript application that interacts with the API.

{{ app.name }}

{{ app.description }}

{{ feature }}
Open App
App Architecture mdi-link

Each sample application follows a similar architecture pattern:

Static HTML/CSS/JavaScript Apps are built with HTML, CSS, and JavaScript without a server-side component. Vue.js + Vuetify Front-end built with Vue.js and styled with Vuetify components. RESTful API Integration Apps communicate with the DSiloed backend using RESTful endpoints. JWT Authentication Authentication managed through JWT tokens stored in localStorage. Responsive Design Applications are designed to work on desktop and mobile devices.

Building Your Own App

mdi-link
Getting Started with App Development mdi-link

Building your own application on top of DSiloed is straightforward. You can use any modern JavaScript framework that can make HTTP requests to the API.

Vue.js + Vuetify React + Material UI

Step 1: Create a directory structure for your Vue app

Create a new project directory with the following structure. You can place this directory anywhere on your system or web server:

# Create the main app directory
mkdir -p myapp

# Create subdirectories for CSS, JavaScript, and documentation
mkdir -p myapp/css
mkdir -p myapp/js
mkdir -p myapp/js/components
mkdir -p myapp/docs

# Create basic files
touch myapp/index.html
touch myapp/css/styles.css
touch myapp/js/app.js

mdi-information Note: When deploying your app, make sure to place it in a location accessible to your web server. If you're using this app with DSiloed, you might place it in a directory like /apps/myapp/.

Step 2: Download Essential Components

Next, download these essential components and place them in your application directory structure:

auth.js Authentication utilities Core authentication utility for handling JWT tokens, login state, and session management.

Place in: myapp/js/auth.js
Download
LoginDialog.js Login UI component Ready-to-use login dialog component for handling user authentication and tenant selection.

Place in: myapp/js/components/LoginDialog.js
Download
Documentation API & development guides Comprehensive documentation for building applications with DSiloed, organized into focused topics.

Download and extract docs.zip to: myapp/docs/
CLAUDE.md Download Docs
ChatAssistant.js AI chat component Reusable chat assistant component for adding AI-powered chat to any application.

Place in: myapp/js/components/ChatAssistant.js
Download

Step 3: Set up basic HTML structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My App - DSiloed</title>

    <!-- Vue and Vuetify -->
    <link href="https://cdn.jsdelivr.net/npm/vuetify@3.5.11/dist/vuetify.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">

    <!-- Custom styles -->
    <link rel="stylesheet" href="css/styles.css?v=1771863622">

    <!-- Auth helper -->
    <script src="js/auth.js?v=1771863622"></script>
    <script src="js/components/LoginDialog.js?v=1771863622"></script>

    <!-- App scripts -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3.4.21/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@3.5.11/dist/vuetify.min.js"></script>
    <script src="js/app.js?v=1771863622" defer></script>
</head>
<body>
    <div id="app" v-cloak>
        <v-app>
            <v-app-bar color="primary" app>
                <v-app-bar-title>My App</v-app-bar-title>
            </v-app-bar>

            <v-main>
                <v-container>
                    <h1>My Custom App</h1>
                    <p>Welcome to my custom DSiloed application!</p>
                </v-container>
            </v-main>
        </v-app>
    </div>
</body>
</html>

Step 4: Initialize Vue app with authentication

// Initialize Vue app
document.addEventListener('DOMContentLoaded', function() {
  const { createApp } = Vue;
  const { createVuetify } = Vuetify;
  
  // Initialize authentication
  const authManager = new AuthManager('myapp');
  
  // Create Vuetify instance
  const vuetify = createVuetify();
  
  const app = createApp({
    data() {
      return {
        authManager: authManager,
        isAuthenticated: false,
        user: null,
      }
    },
    
    methods: {
      async initialize() {
        // Initialize authentication
        const authResult = await this.authManager.initialize();
        this.isAuthenticated = authResult.authenticated;
        this.user = authResult.user;
        
        // Show login if not authenticated
        if (!this.isAuthenticated) {
          this.showLogin();
        }
      },
      
      showLogin() {
        const loginDialog = new LoginDialog('myapp');
        loginDialog.onLogin = (result) => {
          if (result.success) {
            this.isAuthenticated = true;
            this.user = result.user;
            console.log('Logged in as:', this.user.email);
          }
        };
        loginDialog.show();
      },
      
      logout() {
        this.authManager.logout();
        this.isAuthenticated = false;
        this.user = null;
      }
    },
    
    mounted() {
      this.initialize();
    }
  });
  
  app.use(vuetify);
  app.mount('#app');
});

Step 1: Create a new React app

Start by creating a new React application using Create React App or your preferred tool:

# Create a new React app
npx create-react-app my-model-api-app

# Navigate to the app directory
cd my-model-api-app

# Install Material UI and other dependencies
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled

mdi-information Note: You can also use other UI libraries like Chakra UI, Ant Design, or Tailwind CSS if preferred.

Step 2: Set up Authentication Utilities

Create authentication utilities to work with DSiloed:

// src/utils/auth.js
export class AuthManager {
  constructor(appName) {
    this.appName = appName;
    this.authToken = localStorage.getItem('auth_token');
    this.tenantId = localStorage.getItem('tenant_id');
    this.user = null;
  }

  isAuthenticated() {
    return !!this.authToken;
  }

  getToken() {
    return this.authToken;
  }

  getTenantId() {
    return this.tenantId;
  }

  async loadUserInfo() {
    if (!this.isAuthenticated()) {
      return null;
    }

    try {
      const response = await fetch('https://modelapi.russonrails.com/api/v1/users/current', {
        headers: {
          'Authorization': 'Bearer ' + this.authToken,
          'Tenant-Id': this.tenantId || 'root-tenant'
        }
      });

      const data = await response.json();
      
      if (data.success) {
        this.user = data.user;
        return this.user;
      } else {
        this.logout();
        return null;
      }
    } catch (error) {
      console.error('Error loading user info:', error);
      return null;
    }
  }

  async login(email, password, tenantId) {
    try {
      const response = await fetch('https://modelapi.russonrails.com/api/v1/users/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Tenant-Id': tenantId
        },
        body: JSON.stringify({
          email: email,
          password: password
        })
      });

      const data = await response.json();
      
      if (data.success) {
        this.authToken = data.token;
        this.tenantId = tenantId;
        
        localStorage.setItem('auth_token', this.authToken);
        localStorage.setItem('tenant_id', this.tenantId);
        
        await this.loadUserInfo();
        
        return { success: true, user: this.user };
      } else {
        return { success: false, message: data.message || 'Invalid email or password' };
      }
    } catch (error) {
      console.error('Login error:', error);
      return { success: false, message: 'An error occurred during login. Please try again.' };
    }
  }

  logout() {
    this.authToken = null;
    this.user = null;
    localStorage.removeItem('auth_token');
    localStorage.removeItem('tenant_id');
    window.location.href = window.location.pathname;
  }

  async initialize() {
    if (this.isAuthenticated()) {
      const user = await this.loadUserInfo();
      return { authenticated: true, user: user };
    }
    return { authenticated: false };
  }
}

Step 3: Create a Login Dialog Component

// src/components/LoginDialog.jsx
import React, { useState } from 'react';
import {
  Dialog, DialogTitle, DialogContent, DialogActions,
  TextField, Button, CircularProgress, Alert
} from '@mui/material';

function LoginDialog({ open, onClose, onLogin, authManager }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [tenantId, setTenantId] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError('');
    setLoading(true);

    try {
      if (!tenantId) {
        setError('Tenant ID is required');
        setLoading(false);
        return;
      }

      const result = await authManager.login(email, password, tenantId);

      if (result.success) {
        onLogin(result);
        onClose();
      } else {
        setError(result.message || 'Login failed');
      }
    } catch (err) {
      setError('An unexpected error occurred. Please try again.');
    } finally {
      setLoading(false);
    }
  };

  return (
    
      Login to {authManager.appName}
      
{error && {error}} setEmail(e.target.value)} required /> setPassword(e.target.value)} required /> setTenantId(e.target.value)} required />
); } export default LoginDialog;

Step 4: Create Main App Component

// src/App.jsx
import React, { useState, useEffect, useRef } from 'react';
import { 
  Container, AppBar, Toolbar, Typography, Button, 
  ThemeProvider, createTheme, CssBaseline, Box
} from '@mui/material';
import { AuthManager } from './utils/auth';
import LoginDialog from './components/LoginDialog';

const theme = createTheme({
  palette: {
    primary: {
      main: '#3161FF',
    },
    secondary: {
      main: '#6C63FF',
    },
  },
});

function App() {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [user, setUser] = useState(null);
  const [loginOpen, setLoginOpen] = useState(false);
  const authManager = useRef(new AuthManager('myapp')).current;
  
  useEffect(() => {
    const initializeAuth = async () => {
      try {
        const authResult = await authManager.initialize();
        setIsAuthenticated(authResult.authenticated);
        setUser(authResult.user);
      } catch (error) {
        console.error('Auth initialization error:', error);
      }
    };
    
    initializeAuth();
  }, []);
  
  const handleLogin = (result) => {
    if (result.success) {
      setIsAuthenticated(true);
      setUser(result.user);
    }
  };
  
  const handleLogout = () => {
    authManager.logout();
    setIsAuthenticated(false);
    setUser(null);
  };
  
  return (
    
      
      
My App {isAuthenticated ? ( <> {user?.email} ) : ( )} {isAuthenticated ? ( My Custom App Welcome to my custom DSiloed application! ) : ( Welcome to My App Please log in to access the application. )} setLoginOpen(false)} onLogin={handleLogin} authManager={authManager} />
); } export default App;

Step 5: Make API Requests

// Example API hook (src/hooks/useApi.js)
import { useState, useCallback } from 'react';

export function useApi(authManager) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const headers = useCallback(() => ({
    'Authorization': 'Bearer ' + authManager.getToken(),
    'Tenant-Id': authManager.getTenantId(),
    'Content-Type': 'application/json'
  }), [authManager]);

  const fetchData = useCallback(async (endpoint, options = {}) => {
    if (!authManager.isAuthenticated()) {
      setError('Authentication required');
      return null;
    }

    setLoading(true);
    setError(null);

    try {
      const response = await fetch(`https://modelapi.russonrails.com/api/v1/${endpoint}`, {
        ...options,
        headers: {
          ...headers(),
          ...(options.headers || {})
        }
      });

      const data = await response.json();

      if (!data.success) {
        throw new Error(data.error?.message || 'API request failed');
      }

      return data;
    } catch (err) {
      setError(err.message);
      return null;
    } finally {
      setLoading(false);
    }
  }, [authManager, headers]);

  return { loading, error, fetchData };
}

// Using the hook in a component:
function PartyList() {
  const [parties, setParties] = useState([]);
  const authManager = useRef(new AuthManager('myapp')).current;
  const { loading, error, fetchData } = useApi(authManager);

  const loadParties = useCallback(async () => {
    const data = await fetchData('parties');
    if (data) {
      setParties(data.parties);
    }
  }, [fetchData]);

  useEffect(() => {
    if (authManager.isAuthenticated()) {
      loadParties();
    }
  }, [authManager, loadParties]);

  if (loading) return ;
  if (error) return {error};

  return (
    
      {parties.map(party => (
        
          
        
      ))}
    
  );
}
Making API Requests mdi-link Vue.js React

Here's how to make API requests to the DSiloed backend with Vue.js:

// Example method to fetch parties
async fetchParties() {
  try {
    const response = await fetch('https://modelapi.russonrails.com/api/v1/parties', {
      headers: {
        'Authorization': 'Bearer ' + this.authManager.getToken(),
        'Tenant-Id': this.authManager.getTenantId()
      }
    });
    
    const data = await response.json();
    
    if (data.success) {
      this.parties = data.parties;
    } else {
      console.error('Error fetching parties:', data.error);
    }
  } catch (error) {
    console.error('API request failed:', error);
  }
}

Here's how to make API requests to the DSiloed backend with React:

// Using React hooks and fetch API
import { useState, useEffect, useCallback } from 'react';

function PartyList({ authManager }) {
  const [parties, setParties] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchParties = useCallback(async () => {
    if (!authManager.isAuthenticated()) return;
    
    setLoading(true);
    try {
      const response = await fetch('https://modelapi.russonrails.com/api/v1/parties', {
        headers: {
          'Authorization': 'Bearer ' + authManager.getToken(),
          'Tenant-Id': authManager.getTenantId()
        }
      });
      
      const data = await response.json();
      
      if (data.success) {
        setParties(data.parties);
      } else {
        setError(data.error?.message || 'Failed to load parties');
      }
    } catch (error) {
      setError('API request failed: ' + error.message);
    } finally {
      setLoading(false);
    }
  }, [authManager]);

  useEffect(() => {
    fetchParties();
  }, [fetchParties]);

  // UI components to display the data...
}
Adding AI Chat to Your Application mdi-link

The ChatAssistant component provides a reusable, framework-independent chat interface that you can easily add to any application. It works with Vue.js, React, vanilla JavaScript, or any other framework.

ChatAssistant Features
  • Framework independent - works with any JavaScript application
  • Responsive design with quarter-screen flyout that expands to fullscreen
  • Modern UI with dark mode support
  • Real-time chat with AI assistants
  • Model selection when multiple models are available
  • Automatic conversation management

Basic Usage

// Include the ChatAssistant component
<script src="js/components/ChatAssistant.js?v=1771863622"></script>

// Initialize in your application
const chatAssistant = new ChatAssistant('MyApp', {
    apiClient: apiClient,  // Your API client instance
    title: 'AI Assistant',
    placeholder: 'Ask me anything...',
    contextMessage: 'Assistant has access to your application data'
});

// Show/hide the chat
chatAssistant.toggle();

Vue.js Integration Example

// In your Vue app
methods: {
    initChatAssistant() {
        this.chatAssistant = new ChatAssistant('MyApp', {
            apiClient: apiClient,
            title: 'MyApp Assistant',
            placeholder: 'Ask about your data...',
            contextMessage: 'Assistant can help with your application',
            onError: (error) => {
                this.showSnackbar('Chat error: ' + error.message, 'error');
            }
        });
    },
    
    toggleChat() {
        if (this.chatAssistant) {
            this.chatAssistant.toggle();
        }
    }
},

mounted() {
    this.initChatAssistant();
}

React Integration Example

import { useEffect, useRef } from 'react';

function MyApp() {
    const chatAssistantRef = useRef(null);
    
    useEffect(() => {
        // Initialize ChatAssistant
        chatAssistantRef.current = new ChatAssistant('MyApp', {
            apiClient: apiClient,
            title: 'MyApp Assistant',
            onError: (error) => {
                showErrorToast(error.message);
            }
        });
        
        // Cleanup on unmount
        return () => {
            if (chatAssistantRef.current) {
                chatAssistantRef.current.destroy();
            }
        };
    }, []);
    
    const toggleChat = () => {
        if (chatAssistantRef.current) {
            chatAssistantRef.current.toggle();
        }
    };
    
    return (
        <div>
            <button onClick={toggleChat}>
                Toggle Chat Assistant
            </button>
            {/* Your app content */}
        </div>
    );
}

Configuration Options

const chatAssistant = new ChatAssistant('AppName', {
    // Required
    apiClient: apiClientInstance,
    
    // UI Configuration
    title: 'AI Assistant',
    placeholder: 'Ask me anything...',
    contextMessage: 'Assistant has access to your data',
    position: 'right', // 'left' or 'right'
    width: '400px',
    height: '600px',
    zIndex: 1000,
    
    // Event Callbacks
    onToggle: (isVisible) => {
        console.log('Chat toggled:', isVisible);
    },
    onMessage: (message) => {
        console.log('New message:', message);
    },
    onError: (error) => {
        console.error('Chat error:', error);
    }
});

The ChatAssistant automatically handles authentication using your existing apiClient instance. It will create conversations, manage message history, and provide a seamless chat experience without additional configuration.

LLM-Powered App Development mdi-link

You can use Large Language Models (LLMs) like Claude to help you build applications on top of DSiloed. Here's a prompt template to help you get started:

LLM Prompt Template

Use this prompt template with Claude or other AI assistants to help build your application. For best results, download and extract the docs.zip file to your myapp/docs/ directory and provide the documentation files to the AI for comprehensive guidance.

Copy Prompt Download Docs.zip

Simply modify the prompt template above to specify your application's requirements, then paste it to an LLM like Claude or GPT to get help building your application.

When using LLMs for app development, provide as much context as possible about your specific requirements and the data models you plan to use. This will help the LLM generate more relevant and usable code.

Next Steps

mdi-link
Continue Your Journey mdi-link

Now that you've explored the DSiloed platform, here are some next steps to continue your journey:

Create Your Tenant

Set up your tenant environment to begin building applications (see the user guide for a walkthrough).
Sign Up

Explore Sample Apps

Review the sample applications to understand the platform's capabilities.
Open Dashboard

Read API Documentation

Understand the API endpoints available for your application.
API Docs

Build Your First App

Create a simple application using the DSiloed platform.
Read Guide

Launch Your Application

Deploy your application and share it with users.
Get Help mdi-link

Need help with the DSiloed platform? Here are some resources to assist you:

mdi-book-open-variant Documentation

Access comprehensive documentation for the DSiloed platform.

Open Documentation
mdi-home Intro mdi-rocket-launch Start mdi-api API mdi-apps Apps mdi-code-tags Build {{ snackbar.text }}