Skip to content

Tag Definitions API

Complete API reference for creating and managing tag definitions in Pika Platform.

The Tag Definitions API allows you to create, update, search, and delete custom UI tags that LLMs can use to render interactive components.

APIBase URLAccess Level
Admin API/api/chat-admin/tagdefFull access (create, update, delete)
Chat API/api/chat/tagdefRead-only (search enabled tags only)

All endpoints require authentication. Admin endpoints require admin privileges.

Full access to tag definitions including disabled and retired tags.

Create or update a tag definition.

Request:

{
tagDefinition: TagDefinition;
userId: string;
}

Request Body Example:

{
"tagDefinition": {
"tag": "order-status",
"scope": "acme",
"usageMode": "chat-app",
"widget": {
"type": "web-component",
"webComponent": {
"s3Bucket": "acme-widgets",
"s3Key": "order-status-v1.js",
"encoding": "gzip"
}
},
"llmInstructionsMd": "Display order status with tracking info",
"status": "enabled",
"renderingContexts": {
"inline": true,
"canvas": true,
"dialog": false,
"spotlight": false
},
"canBeGeneratedByLlm": true,
"canBeGeneratedByTool": true,
"description": "Shows order status and tracking",
"createdBy": "admin@acme.com",
"lastUpdatedBy": "admin@acme.com",
"createDate": "2024-01-15T10:00:00Z",
"lastUpdate": "2024-01-15T10:00:00Z"
},
"userId": "admin@acme.com"
}

Response:

{
success: boolean;
tagDefinition?: TagDefinition;
error?: string;
}

Notes:

  • If tag already exists (matching scope + tag), it will be updated
  • System manages createDate and lastUpdate timestamps
  • Set dontCacheThis: true during development for immediate updates

Delete a tag definition.

Request:

{
tagDefinition: TagDefinitionLite;
userId: string;
}

Request Body Example:

{
"tagDefinition": {
"scope": "acme",
"tag": "order-status"
},
"userId": "admin@acme.com"
}

Response:

{
success: boolean;
error?: string;
}

Notes:

  • Deletion is permanent
  • Consider setting status: 'retired' instead for graceful deprecation
  • LLMs will immediately stop using deleted tags

Search all tag definitions (including disabled and retired).

Request:

{
includeInstructions?: boolean;
paginationToken?: string;
}

Request Body Example:

{
"includeInstructions": true,
"paginationToken": null
}

Response:

{
success: boolean;
tagDefinitions: TagDefinition[];
paginationToken?: string;
error?: string;
}

Query Parameters:

ParameterTypeDefaultDescription
includeInstructionsbooleanfalseInclude llmInstructionsMd in response
paginationTokenstring-Token for next page of results

Notes:

  • Returns tags in all states (enabled, disabled, retired)
  • Results are paginated (100 per page)
  • Use paginationToken from response for next page

Read-only access to enabled tags only.

Search enabled tag definitions only.

Request:

{
includeInstructions?: boolean;
paginationToken?: string;
}

Response:

{
success: boolean;
tagDefinitions: TagDefinition[];
paginationToken?: string;
error?: string;
}

Differences from Admin API:

  • Only returns status: 'enabled' tags
  • Does not return disabled or retired tags
  • Intended for frontend applications
  • Lower permission requirements
FieldTypeDescription
tagstringTag name (e.g., 'chart', 'order-status')
scopestringNamespace (e.g., 'pika', 'acme')
usageMode'global' | 'chat-app'Availability mode
widgetTagDefinitionWidgetWidget configuration
status'enabled' | 'disabled' | 'retired'Lifecycle status
renderingContextsWidgetRenderingContextsWhere widget can render
canBeGeneratedByLlmbooleanLLM can use this tag
canBeGeneratedByToolbooleanTools can use this tag
descriptionstringAdmin-facing description
createdBystringCreator user ID
lastUpdatedBystringLast editor user ID
createDatestringISO 8601 creation timestamp
lastUpdatestringISO 8601 update timestamp
FieldTypeDescription
llmInstructionsMdstringMarkdown instructions for LLM
dontCacheThisbooleanSkip caching (for development)

Four widget types supported:

{
type: 'built-in';
builtInType: 'chart' | 'image' | 'prompt';
}
{
type: 'custom-compiled-in';
}
{
type: 'web-component';
webComponent: {
s3Bucket: string;
s3Key: string;
encoding?: 'gzip' | 'none';
};
}
{
type: 'pass-through';
}
interface WidgetRenderingContexts {
inline?: boolean; // In message text
canvas?: boolean; // Full-width area
dialog?: boolean; // Modal overlay
spotlight?: boolean; // Featured display
}
Terminal window
curl -X POST https://your-domain.com/api/chat-admin/tagdef \
-H "Content-Type: application/json" \
-H "Cookie: session=xxx" \
-d '{
"tagDefinition": {
"tag": "chart",
"scope": "pika",
"usageMode": "global",
"widget": {
"type": "built-in",
"builtInType": "chart"
},
"llmInstructionsMd": "Use for visualizing numerical data",
"status": "enabled",
"renderingContexts": {
"inline": false,
"canvas": true,
"dialog": true,
"spotlight": true
},
"canBeGeneratedByLlm": true,
"canBeGeneratedByTool": true,
"description": "Interactive charts",
"createdBy": "system",
"lastUpdatedBy": "system",
"createDate": "2024-01-01T00:00:00Z",
"lastUpdate": "2024-01-01T00:00:00Z"
},
"userId": "system"
}'
const tagDef = {
tag: 'product-card',
scope: 'acme',
usageMode: 'chat-app',
widget: {
type: 'web-component',
webComponent: {
s3Bucket: 'acme-widgets',
s3Key: 'product-card-v2.js.gz',
encoding: 'gzip'
}
},
llmInstructionsMd: `
# Product Card Widget
Display product information with image and price.
## Usage
\`\`\`xml
<product-card productId="123" />
\`\`\`
`,
status: 'enabled',
renderingContexts: {
inline: true,
canvas: true,
dialog: false,
spotlight: false
},
canBeGeneratedByLlm: true,
canBeGeneratedByTool: true,
description: 'Product information card',
createdBy: 'admin@acme.com',
lastUpdatedBy: 'admin@acme.com',
createDate: new Date().toISOString(),
lastUpdate: new Date().toISOString()
};
const response = await fetch('/api/chat-admin/tagdef', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
tagDefinition: tagDef,
userId: 'admin@acme.com'
})
});
// Disable a tag
const disableTag = {
tag: 'old-widget',
scope: 'acme',
status: 'disabled' // Change from 'enabled'
// ... other fields remain the same
};
await fetch('/api/chat-admin/tagdef', {
method: 'POST',
body: JSON.stringify({
tagDefinition: disableTag,
userId: 'admin@acme.com'
})
});
// Retire deprecated tag
const retireTag = {
tag: 'deprecated-widget',
scope: 'acme',
status: 'retired',
description: 'DEPRECATED: Use new-widget instead'
// ... other fields
};
await fetch('/api/chat-admin/tagdef', {
method: 'POST',
body: JSON.stringify({
tagDefinition: retireTag,
userId: 'admin@acme.com'
})
});
// Get all enabled tags with instructions
const response = await fetch('/api/chat/tagdef/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
includeInstructions: true
})
});
const { tagDefinitions } = await response.json();
await fetch('/api/chat-admin/tagdef', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
tagDefinition: {
scope: 'acme',
tag: 'old-widget'
},
userId: 'admin@acme.com'
})
});
enabled → disabled → retired
↑ ↓
└──────────┘

Typical Flow:

  1. Development - Create with status: 'enabled', dontCacheThis: true
  2. Testing - Test in development environment
  3. Production - Remove dontCacheThis, deploy to production
  4. Deprecation - Change to status: 'disabled' to stop new usage
  5. Retirement - Change to status: 'retired' when fully deprecated

Invalid Widget Type:

{
"success": false,
"error": "Invalid widget type. Must be one of: built-in, custom-compiled-in, web-component, pass-through"
}

Missing Required Fields:

{
"success": false,
"error": "Missing required field: llmInstructionsMd"
}

Tag Not Found:

{
"success": false,
"error": "Tag definition not found: acme/old-widget"
}

Permission Denied:

{
"success": false,
"error": "Insufficient permissions to manage tag definitions"
}
FieldValidation
tagAlphanumeric, hyphens, underscores only. No spaces.
scopeAlphanumeric, hyphens, underscores only. No spaces.
statusMust be 'enabled', 'disabled', or 'retired'
usageModeMust be 'global' or 'chat-app'
widget.typeMust be valid widget type
s3BucketValid S3 bucket name (if web component)
s3KeyValid S3 key (if web component)
EndpointLimitWindow
Admin endpoints100 requests1 minute
Chat endpoints1000 requests1 minute

Tag definitions are cached by the system:

  • Default TTL: 5 minutes
  • Bypass cache: Set dontCacheThis: true
  • Clear cache: Deploy with updated tags or use cache-clearing endpoint
import { useState, useEffect } from 'react';
import type { TagDefinition } from 'pika-shared';
function TagManager() {
const [tags, setTags] = useState<TagDefinition[]>([]);
useEffect(() => {
fetchTags();
}, []);
async function fetchTags() {
const response = await fetch('/api/chat-admin/tagdef/search', {
method: 'POST',
body: JSON.stringify({ includeInstructions: true })
});
const data = await response.json();
if (data.success) {
setTags(data.tagDefinitions);
}
}
async function createTag(tagDef: TagDefinition) {
const response = await fetch('/api/chat-admin/tagdef', {
method: 'POST',
body: JSON.stringify({
tagDefinition: tagDef,
userId: 'admin'
})
});
return response.json();
}
return (
<div>
{tags.map(tag => (
<div key={`${tag.scope}/${tag.tag}`}>
{tag.scope}/{tag.tag} - {tag.status}
</div>
))}
</div>
);
}
import requests
from typing import Dict, List, Optional
class TagDefClient:
def __init__(self, base_url: str, session_cookie: str):
self.base_url = base_url
self.cookies = {"session": session_cookie}
def create_tag(self, tag_def: Dict, user_id: str) -> Dict:
"""Create or update a tag definition."""
response = requests.post(
f"{self.base_url}/api/chat-admin/tagdef",
json={"tagDefinition": tag_def, "userId": user_id},
cookies=self.cookies
)
return response.json()
def search_tags(self, include_instructions: bool = False) -> List[Dict]:
"""Search all tag definitions."""
response = requests.post(
f"{self.base_url}/api/chat-admin/tagdef/search",
json={"includeInstructions": include_instructions},
cookies=self.cookies
)
data = response.json()
return data.get("tagDefinitions", [])
def delete_tag(self, scope: str, tag: str, user_id: str) -> Dict:
"""Delete a tag definition."""
response = requests.delete(
f"{self.base_url}/api/chat-admin/tagdef",
json={
"tagDefinition": {"scope": scope, "tag": tag},
"userId": user_id
},
cookies=self.cookies
)
return response.json()

Complete TypeScript types available in pika-shared:

import type {
TagDefinition,
TagDefinitionLite,
TagDefinitionWidget,
WidgetRenderingContexts,
TagInstructionForLlm
} from 'pika-shared/types/chatbot/chatbot-types';

See Types Reference for complete type documentation.