uiTx is the client-side SDK for building Mini Apps - custom HTML/CSS/JavaScript applications that run in a sandboxed iframe and can interact with 1Flow data.
Mini Apps are perfect for:
Mini Apps run inside the 1Flow web app in an iframe. Load the SDK via a script tag:
<!DOCTYPE html>
<html>
<head>
<title>My Mini App</title>
<style>
body { font-family: system-ui; padding: 20px; }
</style>
</head>
<body>
<h1>My Mini App</h1>
<div id="app">Loading...</div>
<!-- Load the SDK -->
<script src="https://zdocs.io/sdk/ui-tx/v1.js"></script>
<script>
const { uiTx } = window.zDocs;
async function loadData() {
const results = await uiTx.searchEntities({
query: "AWS",
limit: 10
});
const app = document.getElementById("app");
app.innerHTML = results.results.map(item => `
<div>
<strong>${item.preview.description || "No description"}</strong><br>
<small>${item.preview.date || ""} • $${item.preview.amount || 0}</small>
</div>
`).join("");
}
loadData().catch(err => {
document.getElementById("app").innerHTML = `Error: ${err.message}`;
});
</script>
</body>
</html>
// Get current session info
const session = await uiTx.getSession();
// Returns: { orgId, userId, orgCurrency, permissions, mode, appId, runId }
// Search entities
const results = await uiTx.searchEntities({
query: "AWS",
limit: 25,
filters: {
docType: "INVOICE",
date: { gte: "2025-01-01", lte: "2025-12-31" },
amount: { gte: 100 },
currency: "USD"
},
orderBy: { field: "date", dir: "desc" }
});
// Results structure:
// {
// total: number,
// results: Array<{
// ref: { entityId, documentId, schemaType, ... },
// preview: { date, amount, currency, description }
// }>
// }
// Get full entity data with schema
const entity = await uiTx.getEntity({ entityId: "doc123_items_0" });
// Returns: { ref, data, schema, document }
// List documents
const documents = await uiTx.listDocuments({
docType: "INVOICE",
folderId: "folder123",
date: { gte: "2025-01-01" },
orderBy: { field: "documentDate", dir: "desc" }
});
// Aggregate data
const aggregated = await uiTx.aggregate({
from: "entities",
metrics: [
{ op: "sum", field: "amount", as: "total" },
{ op: "count", as: "count" }
],
groupBy: ["month", "docType"],
where: [
{ field: "docType", op: "=", value: "INVOICE" }
],
limit: 500
});
// Returns: { rows: Array<Record<string, unknown>> }
// Update entity fields
const result = await uiTx.updateEntityFields({
entityId: "doc123_items_0",
changes: {
description: "Updated description",
category: "Electronics"
}
});
if (result.ok) {
console.log("Updated successfully");
} else {
console.error("Error:", result.error);
}
// Create reconciliation link
const linkResult = await uiTx.createReconciliationLink({
sourceRef: { entityId: "invoice123", ... },
targetRef: { entityId: "payment456", ... },
amount: 1000.00,
currency: "USD",
edgeType: "paid_by"
});
// List reconciliation links
const links = await uiTx.listReconciliationLinks({
entityId: "invoice123",
limit: 50
});
// Trace money flow
const trace = await uiTx.traceReconciliation({
startEntityId: "invoice123",
direction: "both",
maxDepth: 10,
limit: 50
});
// Show toast notification
await uiTx.ui.toast({
message: "Operation completed",
level: "success"
});
// Show confirmation dialog
const confirmed = await uiTx.ui.confirm({
title: "Confirm Action",
message: "Are you sure you want to proceed?",
confirmText: "Yes",
cancelText: "No"
});
if (confirmed.confirmed) {
// User confirmed
}
// Open entity in main app
await uiTx.ui.openEntity({ entityId: "doc123_items_0" });
// Open document in main app
await uiTx.ui.openDocument({ documentId: "doc123" });
// Open folder in main app
await uiTx.ui.openFolder({ folderId: "folder123" });
// Upload file to folder
await uiTx.ui.uploadToFolder({ folderId: "folder123" });
<!DOCTYPE html>
<html>
<head>
<title>Monthly Spending Dashboard</title>
<style>
body { font-family: system-ui; padding: 20px; max-width: 1200px; margin: 0 auto; }
.chart-bar { height: 30px; background: var(--primary, #007bff); margin: 4px 0; border-radius: 4px; }
.item { padding: 10px; border-bottom: 1px solid #eee; cursor: pointer; }
.item:hover { background: #f5f5f5; }
</style>
</head>
<body>
<h1>Monthly Spending by Category</h1>
<div id="chart"></div>
<script src="https://zdocs.io/sdk/ui-tx/v1.js"></script>
<script>
const { uiTx } = window.zDocs;
async function loadDashboard() {
try {
// Get current month
const now = new Date();
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1)
.toISOString().split('T')[0];
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0)
.toISOString().split('T')[0];
// Aggregate spending by category
const data = await uiTx.aggregate({
from: "entities",
metrics: [{ op: "sum", field: "amount", as: "total" }],
groupBy: ["category"],
where: [
{ field: "docType", op: "=", value: "INVOICE" },
{ field: "date", op: ">=", value: firstDay },
{ field: "date", op: "<=", value: lastDay }
]
});
// Display chart
const chart = document.getElementById("chart");
const maxVal = Math.max(...data.rows.map(r => r.total || 0));
chart.innerHTML = data.rows.map(row => `
<div style="display: flex; align-items: center; gap: 10px; margin: 8px 0;">
<span style="width: 150px;">${row.category || "Uncategorized"}</span>
<div class="chart-bar" style="width: ${(row.total / maxVal) * 400}px;"></div>
<span>$${row.total.toLocaleString(undefined, { minimumFractionDigits: 2 })}</span>
</div>
`).join("");
} catch (error) {
document.getElementById("chart").innerHTML = `Error: ${error.message}`;
}
}
loadDashboard();
</script>
</body>
</html>
For local development or external integrations, you can use the HTTP transport:
import { UiTx, HttpTransport } from "@zdocs/ui-tx";
const uiTx = new UiTx(
new HttpTransport({
baseUrl: "https://zdocs.io",
apiKey: "zdocs_xxxxx",
})
);
const results = await uiTx.searchEntities({ query: "AWS", limit: 10 });
Mini Apps can detect the parent theme:
const theme = window.__PARENT_THEME__; // "dark" or "light"
if (theme === "dark") {
document.body.style.background = "#1a1a1a";
document.body.style.color = "#fff";
}
preview fields for better performanceui.toast() and ui.confirm() for better UXui.openEntity() instead of manual navigationMini Apps run in a sandboxed iframe for security. All data access goes through the uiTx SDK, ensuring proper validation and audit logging.