Skip to content

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:

GET /v1/partner/user/workspaces/{workspace_id}/toolkits

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

POST /v1/partner/user/meeting-templates/{template_uuid}/apply

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

POST /v1/partner/user/meetings/{meeting_id}/next-steps/{next_step_uuid}/execute

Where next_step_uuid = ns-uuid-222 (resolved from $id: "meeting-summary").

3. Retrieve the result

GET /v1/partner/user/next-step-results/{result_id}

The result_id is returned in the execute response.

4. Trigger an action button

POST /v1/partner/user/meetings/{meeting_id}/action-buttons/{button_uuid}/trigger

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.

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