Entity Lifecycle & Runtime Usage¶
Toolkit manifests define entities declaratively — but after installation, your partner app needs to use those entities at runtime via the Partner User API. This guide covers the bridge between manifest authoring and runtime operations.
The Entity Map¶
When you install a toolkit, the response includes an entity map — a mapping of every manifest $id to its corresponding database UUID. This is how your app discovers the IDs it needs for downstream API calls.
Install response¶
POST /v1/partner/user/toolkits/{toolkitId}/install
Authorization: Bearer {oauth_token}
Content-Type: application/json
{ "workspace_id": "ws-abc-123" }
{
"id": "inst-uuid-001",
"toolkit_id": "tk-uuid-001",
"workspace_id": "ws-abc-123",
"installed_at": "2026-04-12T10:00:00Z",
"entities": {
"templates": {
"discovery-call": "tpl-uuid-111"
},
"next_steps": {
"meeting-summary": "ns-uuid-222",
"follow-up-email": "ns-uuid-333"
},
"action_buttons": {
"copy-summary": "ab-uuid-444",
"push-to-crm": "ab-uuid-555",
"send-email": "ab-uuid-666",
"copy-email": "ab-uuid-777"
},
"shortcuts": {}
}
}
Each key in the entities sub-objects is the $id you assigned in the manifest. Each value is the UUID that the Contio database assigned to the created entity.
Persistence & stability¶
The entity map is persisted on the installation record. Subsequent GET calls return the same mapping:
Each item in the response includes the full installation.entities object, identical to what was returned at install time. You can safely cache these UUIDs or re-fetch them at any time.
Only spec-created entities appear
If your manifest references an existing entity by database UUID (using the id field instead of spec), that entity does not appear in the entity map — you already know its ID.
Using Entities at Runtime¶
Once you have the entity map, you use the resolved UUIDs with the standard Partner User API endpoints. Here's the typical flow for a CRM integration toolkit:
1. Apply a template to a meeting¶
Using the entity map from above, template_uuid = tpl-uuid-111 (the resolved ID for $id: "discovery-call").
2. Execute a next step after the meeting¶
Where next_step_uuid = ns-uuid-222 (resolved from $id: "meeting-summary").
3. Retrieve the result¶
The result_id is returned in the execute response.
4. Trigger an action button¶
Where button_uuid = ab-uuid-555 (resolved from $id: "push-to-crm").
End-to-end example (SDK)¶
// After installing a toolkit, capture the entity map
const install = await sdk.user.installToolkit(toolkitId, {
workspace_id: workspaceId
});
const entities = install.entities;
// Later, when a meeting completes...
// 1. Apply the template
await sdk.user.applyTemplate(entities.templates['discovery-call'], meetingId);
// 2. Execute a next step
const result = await sdk.user.executeNextStep(
meetingId,
entities.next_steps['meeting-summary']
);
// 3. Trigger an action button on the result
await sdk.user.triggerActionButton(
meetingId,
entities.action_buttons['push-to-crm']
);
Managing Entities Through Toolkit Versions¶
Entities defined in a toolkit manifest are managed exclusively through the toolkit lifecycle. There are no standalone CRUD endpoints for next steps, action buttons, or shortcuts.
| Task | How |
|---|---|
| Create an entity | Add it to the manifest spec with a $id |
| Update an entity | Modify its spec in a new toolkit version, then publish and upgrade |
| Remove an entity | Remove it from the manifest in a new toolkit version |
| Rewire relationships | Change $ref pointers in next step ↔ action button or template ↔ next step |
Version → publish → upgrade workflow¶
1. Create a new version POST /v1/partner/admin/toolkits/{id}/versions
2. Update the manifest (included in the version body)
3. Publish the version POST /v1/partner/admin/toolkits/{id}/versions/{vid}/publish
4. Upgrade installations (automatic or triggered per workspace)
When a workspace upgrades to a new version, the installation composite reconciles entities — creating new ones, updating changed ones, and removing those no longer in the manifest. The entity map is updated accordingly.
Templates are an exception
Templates also have standalone Admin CRUD (/v1/partner/admin/templates). This is because templates are container entities that partners may need to manage independently — for example, creating a template from an existing meeting or updating template metadata without touching the toolkit version.
Relationship Wiring¶
In the standalone API model, wiring a next step to an action button required a separate API call. In the toolkit model, relationships are declared inline in the manifest:
Next step → action button¶
{
"next_steps": [{
"spec": {
"$id": "summary",
"name": "Meeting Summary",
"type": "ai",
"ai_prompt": "Generate a summary of the meeting."
},
"action_buttons": [
{ "action_button": { "$ref": "copy-btn" }, "sort_order": 1, "is_default": true }
]
}]
}
Template → next step¶
{
"templates": [{
"spec": {
"$id": "standup",
"name": "Daily Standup",
"description": "Daily team standup meeting template"
},
"next_steps": [
{ "next_step": { "$ref": "summary" }, "sort_order": 1, "autopilot": true }
]
}]
}
The $ref values are resolved during installation. You never need to make a separate "wire" API call — the manifest declares the full entity graph.
Recommended Patterns¶
Store the entity map on install¶
Persist the entity map in your own database keyed by (workspace_id, toolkit_id). This avoids repeated lookups:
// On install callback
const install = await sdk.user.installToolkit(toolkitId, { workspace_id });
await db.upsert('toolkit_entities', {
workspace_id,
toolkit_id: toolkitId,
entities: install.entities,
});
Re-fetch on upgrade¶
When a workspace upgrades to a new toolkit version, the entity map may change (new entities added, old ones removed). Re-fetch and update your stored mapping:
// After upgrade, re-fetch the installation
const toolkits = await sdk.user.listInstalledToolkits(workspaceId);
const installation = toolkits.items.find(t => t.toolkit.id === toolkitId);
await db.upsert('toolkit_entities', {
workspace_id: workspaceId,
toolkit_id: toolkitId,
entities: installation.installation.entities,
});
Use descriptive $id values¶
Since $id values become the keys in your entity map, use human-readable names that are stable across versions:
| ✅ Good | ❌ Avoid |
|---|---|
"meeting-summary" | "ns1" |
"push-to-crm" | "btn-3" |
"discovery-call" | "template" |
Changing a $id value in a new version creates a new entity and orphans the old one.
See Also¶
- Reference Patterns —
$idand$refsyntax details - Examples — Complete manifest examples
- JSON Schema — Full field reference