Embeds API
Embeddable widget management — create, list, revoke embed tokens and fetch public embed data
Embeds API
The embeds API manages read-only embeddable widget tokens for sharing live data with external stakeholders. Widgets render boards, KPI charts, portfolios, and dashboards in iframes without requiring authentication. All management procedures require the manage_settings permission. The public data endpoint requires only a valid embed token.
Entity Types
Embed tokens can be created for the following entity types, each with a dedicated renderer:
| Entity Type | Renderer | Description |
|---|---|---|
board | Table/Kanban | Full board view with groups, columns, and items with cell values |
kpi_chart | KPI Grid | KPI definition cards with recent values, thresholds, and trend indicators |
portfolio | Overview | Portfolio-level summary with project metadata |
dashboard | Dashboard | Custom dashboard layout with board data |
Rate Limiting
The public getPublicData endpoint is rate-limited to 60 requests per minute per token. This is enforced via an in-memory per-process rate limiter. When the limit is exceeded, the endpoint returns a TOO_MANY_REQUESTS error.
embeds.create
Generate a new embed token for a board, KPI chart, portfolio, or dashboard. Returns the token value, the full record, and a ready-to-paste iframe HTML snippet.
Type: Mutation
Input Schema:
{
entityType: "board" | "kpi_chart" | "portfolio" | "dashboard";
entityId: string; // ID of the resource to embed
label?: string; // Human-readable label for the token
config?: {
theme?: string; // Visual theme for the embed
refreshInterval?: number; // Auto-refresh interval in seconds
showTitle?: boolean; // Show/hide the resource title
showTimestamp?: boolean; // Show/hide last-updated timestamp
};
expiresAt?: string; // Optional ISO 8601 expiration date
}
Output:
{
token: {
id: string;
organizationId: string;
entityType: string;
entityId: string;
token: string; // Cryptographic cuid2 token string
label: string | null;
config: Record<string, unknown>;
createdById: string;
expiresAt: Date | null;
createdAt: Date;
};
embedUrl: string; // e.g., "https://app.probeya.com/api/embed/{token}"
iframeHtml: string; // Ready-to-paste HTML: <iframe src="..." ...>
}
Side Effects:
- Logs
embed_token.createdactivity with entity type, entity ID, and label.
embeds.list
Return all embed tokens for the organization. Optionally filter by a specific entity ID or include revoked tokens.
Type: Query
Input Schema:
{
entityId?: string; // Filter by a specific entity
includeRevoked?: boolean; // Include revoked tokens (default: false)
}
Output:
Array<{
id: string;
organizationId: string;
entityType: string;
entityId: string;
token: string;
label: string | null;
config: Record<string, unknown>;
createdById: string;
expiresAt: Date | null;
createdAt: Date;
embedUrl: string; // Computed embed URL
iframeHtml: string; // Computed iframe snippet
}>
Results are sorted by creation date descending (newest first).
embeds.revoke
Soft-revoke an embed token by setting its expiresAt to the current timestamp. The record is preserved for audit trail purposes rather than being hard-deleted. Once revoked, the getPublicData endpoint will reject the token with a FORBIDDEN error.
Type: Mutation
Input Schema:
{
tokenId: string; // The record ID (not the token string)
}
Output: Returns the updated embed token record with expiresAt set to the revocation time.
Error Codes:
| Code | Condition |
|---|---|
NOT_FOUND | Token not found or belongs to another organization |
Side Effects:
- Logs
embed_token.revokedactivity with entity type, entity ID, and label.
embeds.getPublicData
Public endpoint to fetch embed data by token. This is the primary data source consumed by the embed viewer page. It does not require authentication — the token itself is the credential.
Type: Query (public procedure)
Input Schema:
{
token: string; // The embed token string (not the record ID)
}
Security Measures:
- Token must exist and not be expired or revoked (
expiresAtcheck) - Rate-limited to 60 requests/minute per token
- Sensitive fields (user emails, internal IDs like
createdById,assigneeId) are stripped - Data is strictly read-only
Output (board/dashboard):
{
entityType: "board" | "dashboard";
boardName: string;
config: Record<string, unknown>;
items: Array<{
id: string;
name: string;
values: Record<string, unknown>; // columnId -> cell value
// Note: createdById, assigneeId stripped for security
}>;
groups: Array<{
id: string;
name: string;
color: string;
sortOrder: number;
}>;
columns: Array<{
id: string;
name: string;
type: string;
config: Record<string, unknown>;
sortOrder: number;
width: number;
}>;
}
Output (kpi_chart):
{
entityType: "kpi_chart";
config: Record<string, unknown>;
kpis: Array<{
id: string;
name: string;
category: string;
unit: string;
direction: string;
thresholds: Record<string, number> | null;
frequency: string;
values: Array<{
id: string;
date: string;
value: string;
comment: string | null;
}>; // Last 30 values, ordered by date descending
}>;
}
Error Codes:
| Code | Condition |
|---|---|
NOT_FOUND | Invalid or unknown token |
FORBIDDEN | Token has been revoked or has expired |
TOO_MANY_REQUESTS | Rate limit exceeded (60 req/min per token) |
Permissions
| Procedure | Required Role |
|---|---|
embeds.create | manage_settings permission (typically Admin/Owner) |
embeds.list | manage_settings permission |
embeds.revoke | manage_settings permission |
embeds.getPublicData | Anyone with a valid, non-expired token |
Security
- Management procedures use
createRoleProtectedProcedure("manage_settings")for access control. - Embed tokens are generated using
cuid2, which produces cryptographically random, unguessable identifiers. - The public data endpoint strips sensitive fields (user IDs, emails) before returning data.
- Revocation is immediate: once
expiresAtis set to the current time, subsequent requests are rejected. - All data fetched through the public endpoint is scoped to the token’s
organizationId, preventing cross-tenant data access.
Was this page helpful?