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.
DSiloed is built on a flexible, enterprise-grade data model designed for extensibility and integration. Here are the key components:
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.
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.
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.
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 |
|---|---|---|
| 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 | |
| Email, conversation/guest invitations, voice calls | send_email, send_conversation_invitation, send_guest_invitation, outbound_call | |
| 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 | |
| Persistent memory: store, load, and curate AI context | store_memory, load_memories, update_memory, forget_memory, link_memories, update_memory_profile | |
| Chat messaging and direct messages | conversation_chat, start_dm_with_user | |
| Web search and page fetch | web_research | |
| Serverless JavaScript function management | list_dynamic_functions, get_dynamic_function, execute_dynamic_function, dynamic_function_executions, manage_dynamic_function | |
| Custom LLM tool creation and management | list_llm_tools, get_llm_tool, manage_llm_tool, test_llm_tool | |
| Platform + app-development documentation assistants | dmapi_assistant, app_docs_assistant | |
| Administrative tools (logs, cost statistics) | tail_rails_log, llm_cost_stats | |
| General utilities | current_date_time | |
| Master Data Management for external system mappings | external_mappings_by_system | |
| Workflow artifacts | create_workflow_artifact | |
| Agent coordination / resource leases | coordination_tool |
?categories=data,memory to your MCP endpoint URL
to load only specific categories, or ?tools= to name individual tools.
Tools for sending emails and managing conversation invitations.
Send emails with customizable subject, body, recipients, and sender information.
Use Cases:
Key Parameters:
subject - Email subject lineemail_body - HTML email contentto_email - Recipient(s), semicolon-separatedfrom_email - Optional sender addressSend single-use invitation links for one-time feedback in LLM conversations.
Use Cases:
Send guest trial invitations allowing multiple messages before signup.
Use Cases:
Make outbound AI voice calls.
Tools for CRUD operations, schema discovery, and file management.
Comprehensive CRUD operations for all data models with advanced filtering, relationships, and aggregations.
Capabilities:
Supported Models:
Party, Individual, Organization, Contact, BizTxnEvent, Project, Task, LlmConversation, and 30+ more
Discover schema information, available columns, required fields, and data types for any model.
Use Cases:
Create text-based documents (Markdown, TXT, CSV, PDF, DOCX) programmatically.
Use Cases:
Update existing documents with new content, titles, or move to different directories.
Read file contents including text files, documents (PDF/DOCX), images, and media files.
Retrieve comprehensive LLM usage statistics, costs, and token consumption by model, user, and conversation.
Apply tracked statuses to entities (Tasks, Projects, BizTxnEvents, etc.) with proper history tracking.
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 an existing Office document (.pptx/.docx/.xlsx) already stored as a file into a PDF, attached back to the conversation.
List files and directories in the LLM file system.
Move files or directories to a new location in the LLM file system.
Tools for creating, managing, and executing autonomous AI agents.
Create complete LLM agents with custom tools, resources, prompts, and role assignments.
Modify existing agent configurations, prompts, tools, and settings.
Permanently remove agents from the system.
List all available agents with their capabilities and descriptions.
Execute an agent with specific prompts and monitor execution status.
Check the execution status and output of running agents.
Mark agent runs as complete with success/failure status.
List all tools that can be assigned to agents during creation.
List all resources available for agent configuration.
List configured LLM models available for agent creation.
List available system and user prompts for agents.
Get configuration requirements for specific tools before assigning to agents.
Tools for persistent memory management across AI sessions.
Save a short memory (title and content required; optional memory_type, importance_score 0–1, tags, private). A save in a private conversation (except a group DM) or by a private agent is private automatically; a shared save is screened for secrets.
Recommended Memory Types:
Other canonical types (e.g. insight, solution, goal) are still accepted.
Search or browse the memories the caller may read. Each result is tagged provenance: own or shared.
Retrieval Modes:
Optional as_of (ISO-8601) answers “what did we know on that date”, including versions since corrected.
Correct a memory you authored. A new title or content creates a new version (the new id is returned; the old version is kept as history and no longer recalled). Importance or tags alone are edited in place.
Retire (soft-archive, recoverable) a memory you authored so it stops surfacing in recall. Pass superseded_by_memory_id to mark it as replaced by a newer memory instead.
Create a typed relationship between two memories (builds the memory graph). Recommended types: related_to, supersedes, exemplifies; also caused_by, depends_on, leads_to, references, spawns, validates.
Agents only: rewrite the agent's own always-on “About me” block (up to 1,500 characters), injected into every prompt the agent runs with. Every change is versioned.
Tools for managing LLM conversations and messaging.
Send messages to LLM conversations and trigger AI responses.
Use Cases:
Tools for accessing platform documentation.
Ask questions about the Data Model API platform implementation and features.
Topics Covered:
Access app development documentation for building applications on the platform.
Topics Covered:
Utility and administrative tools for system operations.
Get current date and time with timezone support and multiple formats.
Root tenant only: Tail Rails application logs for debugging and monitoring.
Get external system mappings for MDM integration and data synchronization.
Tools for creating, managing, and executing serverless JavaScript functions.
List available dynamic functions with their status, schedule, and recent execution info.
Filtering Options:
active_only - Only show active functionsscheduled_only - Only show scheduled functionscallbacks_only - Only show callback functionscallback_model - Filter by callback model namename - Filter by function name (partial match)Get full details of a specific function by ID or name, including JavaScript code and execution history.
Key Parameters:
id or name - Function identifierinclude_executions - Include recent execution historyexecution_limit - Number of executions to include (max 20)Execute a dynamic function by ID or name and return results.
Key Parameters:
function_id or function_name - Function to executeparams - Parameters passed to the functionasync - Execute asynchronously (queued)Returns:
success - Execution statusresult - Function return valueexecution_id - For tracking historyexecution_time_ms - DurationCreate, update, or delete dynamic functions with full configuration support.
Actions:
create - Create new function with name, code, schedule, callbacksupdate - Modify existing function (can rename with new_name)delete - Remove functionConfiguration Options:
schedule - Cron expression for scheduled executioncallback_model - Model to trigger callback oncallback_event - Event type (create, update, destroy, all)timeout_seconds - Max execution time (1-300)configuration - Custom config including OAuthView execution history and logs for debugging and monitoring.
Filtering Options:
function_id or function_name - Filter by functionexecution_id - Get specific execution detailstrigger_type - Filter by trigger (manual, api, schedule, mcp_tool, webhook, nested_call, callback)success_only / failed_only - Filter by statuslimit - Number of records (max 100)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.
web_research_tool — Search and fetch the public web (DuckDuckGo / Tavily / Brave / Wikipedia).
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.
external_mappings_by_system_tool — Get external-system ID mappings for integrated systems (Master Data Management).
tail_rails_log_tool — Tail Rails logs for debugging (tenant-scoped access).
llm_cost_stats_tool — Get LLM cost and token-usage statistics.
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).
MCP tools can be accessed in multiple ways:
Agents can be granted these tools and use them autonomously during execution.
LLMs in conversations can invoke tools as needed to answer questions, retrieve data, or perform actions.
Connect external applications via MCP protocol to access all tools programmatically.
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.
DSiloed provides a comprehensive RESTful API for building applications. All endpoints follow consistent RESTful conventions with JSON responses.
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"
All API requests should use JSON for request bodies and accept JSON responses.
-H "Content-Type: application/json" \
-H "Accept: application/json"
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
]
}
Errors return a simple format with success set to false and an error message.
{
"success": false,
"message": "Invalid Access"
}
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 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 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
}
}'
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"
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"
Share a private memory with the workspace
For people holding the share LlmMemories capability (workspace admins; basic members do not hold it), on a live, current private memory they may both write and read. The confirmation confirm_audience: "workspace" is required. Shared text is screened for secrets. Sharing creates a new, shared version; the private version is retired (kept as history) and the share is recorded on the audit trail. Response: { success, llm_memory, shared_from_id }. 403 when the memory is not yours, 422 without the confirmation, on a replaced version or on refused content, 409 on a concurrent edit.
curl -X POST "https://example-model-api.com/api/v1/llm_memories/123/share" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{"confirm_audience": "workspace"}'
For complete API documentation, refer to the Swagger UI which provides interactive documentation for all available endpoints.
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.
executeAction.
Query, create, update, and delete records from your functions.
Create a dynamic function using the REST API. Functions receive a context object with parameters, configuration, OAuth tokens, and tenant information.
// 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
}
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
});
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 hour | 0 * * * * |
| Daily at 9am | 0 9 * * * |
| Every Monday at 8am | 0 8 * * 1 |
| First of month at midnight | 0 0 1 * * |
| Every 15 minutes | */15 * * * * |
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
}
}
Functions can be triggered automatically when records are created, updated, or destroyed. This enables event-driven automation without polling.
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 };
`
}
}
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": {
"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/authorize to get authorization URL
oauth.accessToken
| 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 |
/api/v1/dynamic_functions/my_function/execute
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.
run_as_user_id: "current_user" for scheduled/callback functions.
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`
};
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.description }}
Each sample application follows a similar architecture pattern:
An app built on PortableMind lives on its own origin (your domain, your hosting)
and talks to the platform API from its own server. The browser talks to your
server; your server holds the credentials and forwards authenticated requests to
https://www.dsiloed.com/api/v1/.... Never ship a platform credential to the browser.
Exchange a user's credentials for a session token with POST /api/v1/authenticate
(email or username, plus password). A successful response
carries the token as jwt; a user with multi-factor authentication gets an MFA
challenge instead, which your app must complete.
curl -X POST "https://www.dsiloed.com/api/v1/authenticate" \
-H "Content-Type: application/json" \
-H "Tenant-Id: your-tenant-id" \
-d '{"email": "user@example.com", "password": "..."}'
Send the token on every later call, together with the tenant header, exactly as described in API Documentation:
curl "https://www.dsiloed.com/api/v1/parties" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id"
Request and response schemas for every public endpoint are in the interactive API reference.
Two complete open-source apps are published as public repos, each structured as a template you can fork. Both use the same minimal architecture: a single-page HTML + vanilla JavaScript frontend and a tiny zero-dependency Node proxy that injects runtime configuration and forwards authenticated requests to the platform. No framework, no build step.
| Repo | What it is |
|---|---|
| pm-ticket-portal | White-label customer support portal: clients register with an access key, submit tickets, and chat with an AI support agent, with human staff able to step in at any time. |
| pm-payer-portal | White-label healthcare payer portal: prior-authorization workflows driven by intake agents, with turnaround-time tracking and clinician-controlled denials. |
Each repo's README and integration guide cover setup, the role files it ships and its deployment. The fastest path to a custom app is to hand one of them to a coding agent and describe what you want to build; see the developer resources page for a ready-made prompt.
Your app's security role is part of your app, not the platform. Build it once in a development
workspace (Administration → Roles), export it (GET /api/v1/security_roles/:id/export
or the Export button), keep the JSON file in your repo, and import it into each workspace on every
release:
curl -X POST "https://www.dsiloed.com/api/v1/security_roles/import" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Tenant-Id: your-tenant-id" \
-H "Content-Type: application/json" \
-d "$(jq -n --slurpfile d roles/my_role.json '{data: $d[0], overwrite: false}')"
app_chat, app_files, app_projects, app_tickets; never app_admin) when the same call also assigns an external role; any other internal role is assigned by an admin.
To drop your app's signed-in users into the full PortableMind web app under your branding, with no
second login, a workspace admin enables white-label (PUT /api/v1/white_label) and mints a
sign-on key (POST /api/v1/white_label/sso_key, shown once). Your server then signs a
short-lived, single-use assertion (HS256, with sub, tenant_enterprise_identifier,
jti, iat and an exp at most two minutes out) and redirects the
browser to the web app's /sso?assertion=... route, which exchanges it through
POST /api/v1/sso/exchange for an ordinary session.
Keep the sign-on key on your server: whoever holds it can sign in as anyone in the workspace. Setup is described in the user guide under White-label Branding & Single Sign-on.
Your app's end users (customers, clients, anyone outside the organization running the workspace) should be external members: they hold at least one role marked external. For them:
Give such users External Member plus your app's own role, marked external, with every read scoped to the records they should see (for example, conversations they are a member of).
Now that you've explored the DSiloed platform, here are some next steps to continue your journey:
Need help with the DSiloed platform? Here are some resources to assist you:
Access comprehensive documentation for the DSiloed platform.