Template vs Instance Passports
TL;DR
- Template Passport = the canonical identity of an agent created by the builder (who/what it is, baseline capabilities, Agent Passport Page, badge).
- Instance Passport = a tenant/platform-specific install of that agent (who controls it here, local limits/regions/status, webhooks, suspend).
- A Template can have many Instances. Instances inherit and can override only operational fields (limits, regions, status, contact/webhook), never the agent's core identity.
Why two kinds?
- Platforms think in tenants (workspaces/stores/projects). They need per-tenant limits, assurance, audit, and suspend.
- Builders need one canonical identity and badge for their agent, independent of where it runs.
- This mirrors real-world IDs: model of a car (template) vs VIN of a car unit (instance).
Quick comparison
| Aspect | Template Passport (Builder) | Instance Passport (Tenant/Platform) |
|---|---|---|
| Purpose | Canonical identity & baseline policy | Enforced, tenant-scoped runtime policy |
| Owner/Controller |
creator_* (builder org or user)
|
controller_* (tenant org/user), platform_id, tenant_ref
|
| Inheritance | Source of truth for name/role/capabilities/description | Inherits from template; can override limits/regions/status/contact/webhook |
| Status scope | Global (revocation cascades) | Local (can suspend one tenant only) |
| Webhooks | Optional (builder notifications) | Recommended (status/assurance/limits updates) |
| Verify usage | For read-only identity or dev docs | For gating routes (refunds, data export, PR merge) |
| Badge | "Trusted Agent" (public Agent Passport page) | "Verified Instance" (tenant-visible) |
| Billing | Owned inside an APort org subscription | Covered by the same org subscription or enterprise rollout |
| Suspend behavior | Cascades to ALL instances | Local only (one tenant) |
When to use which ID?
Use the Template ID when:
- Linking an About page or public badge.
- Documenting the agent's baseline capabilities/description.
- A platform is evaluating an agent before install (no tenant yet).
- You want to fetch canonical metadata only.
Use the Instance ID when:
- Enforcing risky routes (e.g.,
finance.payment.refund.v1,data.export.create.v1,repo.prcreate.v1). - You need tenant-specific limits/regions/assurance and per-tenantsuspend.
- Emitting webhooks for one tenant's install.
- Auditing who did what in this tenant.
Schema Differences
Template Passport Fields
{
agent_id: "ap_template1234567890abcdef1234567890ab", // Template passport ID
kind: "template", // Explicit template type
name: "HappyRefunds Bot", // Canonical name
role: "CX refunds assistant", // Canonical role
description: "AI agent for...", // Canonical description
capabilities: [{"id": "finance.payment.refund", "params": {}}], // Core capabilities
limits: { // Baseline limits
refund_amount_max_per_tx: 100,
refund_amount_daily_cap: 500
},
regions: ["US", "CA"], // Baseline regions
status: "active", // Global status
assurance_level: "L2", // Builder's assurance level
creator_id: "ap_org_builderco", // Who created the template
creator_type: "org",
// ... other standard passport fields
}
Instance Passport Fields
{
agent_id: "ap_instance1234567890abcdef1234567890ab", // Instance passport ID
kind: "instance", // Explicit instance type
parent_agent_id: "ap_template1234567890abcdef1234567890ab", // Link to template
platform_id: "gorgias", // Which platform
controller_id: "ap_org_acme", // Tenant controller
controller_type: "org", // Controller type
tenant_ref: "store_987", // Platform's tenant ID
// Inherited from template (can be overridden)
name: "HappyRefunds Bot", // Copied from template
role: "CX refunds assistant", // Copied from template
description: "AI agent for...", // Copied from template
capabilities: [{"id": "finance.payment.refund", "params": {}}], // Inherited
// Tenant-specific overrides
limits: { // Tenant-specific limits
refund_amount_max_per_tx: 50, // Override: lower limit
refund_amount_daily_cap: 200 // Override: lower cap
},
regions: ["US"], // Override: US only
status: "active", // Tenant-specific status
contact: "[email protected]", // Tenant contact
webhook_url: "https://acme.com/webhook", // Tenant webhook
// Owner is the tenant, not the builder
owner_id: "ap_org_acme", // Tenant owns this instance
owner_type: "org",
owner_display: "Acme Corp",
// Timestamps
created_at: "2024-01-16T10:00:00Z",
updated_at: "2024-01-16T10:00:00Z",
updated_from_parent_at: "2024-01-16T10:00:00Z", // When template last updated
}
Billing Implications
Template Passports
- Subscription owner: The APort organization that owns the template.
- Commercial model: Covered by Free, Team, Enterprise, or manual pilot access depending on the organization workspace.
- Value: Public identity, badges, documentation, baseline policy, and shared setup for instance issuance.
Instance Passports
- Subscription owner: Usually the same organization workspace or the enterprise rollout account managing the deployment.
- Commercial model: Covered by the org subscription or enterprise agreement; do not create a separate per-instance billing source of truth.
- Scale-aware: More tenants means more operational evidence, controls, and support scope, but entitlement checks should still be org-scoped.
- Value: Policy enforcement, per-tenant controls, webhooks, and Verifiable Attestation.
Billing Example
Template: "HappyRefunds Bot" (ap_template1234567890abcdef1234567890ab)
āāā Owner workspace: Acme AI Apps (Team or Enterprise)
āāā Instance 1: Gorgias tenant "store_987" (ap_instance1234567890abcdef10000001)
ā āāā Covered by Acme AI Apps subscription or rollout agreement
āāā Instance 2: Zendesk tenant "workspace_456" (ap_instance1234567890abcdef10000002)
ā āāā Covered by Acme AI Apps subscription or rollout agreement
āāā Instance 3: Shopify tenant "shop_789" (ap_instance1234567890abcdef10000003)
āāā Covered by Acme AI Apps subscription or rollout agreement
Total: one org-scoped commercial relationship, not separate billing truth per passport.
Suspension Behavior
Template Suspension (Cascading)
When a template is suspended or revoked:
- All instances are automatically suspended
- Webhooks are sent to each tenant with suspension reason
- Verifiable Attestation is created for each instance suspension
- Policy enforcement immediately blocks all instance usage
- Builder can resume template to unsuspend all instances
// Template suspension cascades to all instances
await suspendTemplateInstances(kv, templateId, webhookConfig, registryPrivateKey, actor);
// Result: { suspended: 15, errors: [] } // 15 instances suspended
Instance Suspension (Local)
When an instance is suspended:
- Only that tenant is affected
- Other instances continue working normally
- Template remains active
- Platform can suspend/resume per tenant
// Instance suspension is local only
await updatePassportStatus(kv, instanceId, "suspended", reason, actor);
// Result: Only ap_instance1234567890abcdef10000001 is suspended
// Other instances remain active
Creation Flow
1. Template Creation (Builder)
curl -X POST "https://api.aport.io/api/admin/create" \
-H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
-d '{
"name": "HappyRefunds Bot",
"role": "Support Refunds",
"description": "Refund helper for customer support",
"capabilities": [{"id": "finance.payment.refund", "params": {}}],
"limits": {
"refund_amount_max_per_tx": 100,
"refund_amount_daily_cap": 500
},
"regions": ["US", "CA"],
"contact": "[email protected]",
"kind": "template",
"status": "active"
}'
# Response: { "agent_id": "ap_template1234567890abcdef1234567890ab", "kind": "template" }
2. Instance Creation (Platform)
curl -X POST "https://api.aport.io/api/passports/ap_template1234567890abcdef1234567890ab/instances" \
-H "Authorization: Bearer YOUR_PLATFORM_API_KEY" \
-d '{
"platform_id": "gorgias",
"controller_id": "ap_org_acme",
"controller_type": "org",
"tenant_ref": "store_987",
"overrides": {
"limits": {
"refund_amount_max_per_tx": 50,
"refund_amount_daily_cap": 200
},
"regions": ["US"],
"status": "active",
"contact": "[email protected]"
}
}'
# Response: { "agent_id": "ap_instance1234567890abcdef1234567890ab", "kind": "instance" }
Policy Enforcement
Template Verification
curl "https://api.aport.io/api/verify/ap_template1234567890abcdef1234567890ab"
# Returns: Canonical identity and baseline policy
# Use case: Documentation, badges, public Agent Passport pages
Instance Verification (Runtime Enforcement)
curl -X POST "https://api.aport.io/api/verify/policy/finance.payment.refund.v1" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "ap_instance1234567890abcdef1234567890ab",
"context": {
"amount": 25,
"currency": "USD",
"tenant_id": "store_987"
}
}'
# Returns: { "allow": true, "passport": {...}, "evaluation": {...} }
# Use case: Gating refunds, data exports, PR merges
Inheritance Rules
Fields Inherited from Template (Read-Only)
name- Agent's canonical namerole- Agent's canonical roledescription- Agent's canonical descriptioncapabilities- Core capability setassurance_level- Builder's assurance levelattestations- Builder's attestationslinks- Builder's links (homepage, repo, docs)categories- Agent categoriesframework- Agent frameworkmodel_info- Model information
Fields Overrideable in Instance
limits- Tenant-specific limitsregions- Tenant-specific regionsstatus- Tenant-specific statuscontact- Tenant contact informationwebhook_url- Tenant webhook endpointowner_id- Tenant ownerowner_type- Tenant owner typeowner_display- Tenant display name
Fields Unique to Instance
parent_agent_id- Link to templateplatform_id- Platform identifiercontroller_id- Tenant controllercontroller_type- Controller typetenant_ref- Platform's tenant IDupdated_from_parent_at- Last template sync
Webhook Events
Template Events
passport.created- Template createdpassport.updated- Template updatedstatus.changed- Template status changed (cascades to instances)
Instance Events
passport.created- Instance createdpassport.updated- Instance updatedstatus.changed- Instance status changed (local only)assurance.updated- Instance assurance updatedlimits.exceeded- Instance limits exceeded
Best Practices
For Builders
- Create templates with comprehensive baseline policies
- Use template IDs for public badges and documentation
- Monitor template status - suspension affects all instances
- Keep templates updated - changes propagate to instances
For Platforms
- Create instances for each tenant installation
- Use instance IDs for policy enforcement
- Set tenant-specific limits based on customer tier
- Register webhooks for real-time status updates
- Implement per-tenant suspend for incident response
For Policy Enforcement
- Always use instance IDs in middleware
- Check both template and instance status
- Respect tenant-specific limits and regions
- Log Verifiable Attestation with instance context
Migration from Legacy Passports
Legacy passports (without kind field) are treated as templates by default:
// Legacy passport
{
"agent_id": "ap_abc123", // No kind field
"name": "Legacy Agent",
// ... other fields
}
// Treated as:
{
"agent_id": "ap_abc123",
"kind": "template", // Default behavior
"name": "Legacy Agent",
// ... other fields
}
To create instances from legacy templates, use the same instance creation API with the legacy agent ID as the template ID.
Troubleshooting
Common Issues
Q: Why can't I suspend just one tenant?
A: You're using the template ID instead of the instance ID. Use the instance ID for tenant-specific suspension.
Q: Why did all my instances get suspended?
A: The template was suspended, which cascades to all instances. Check template status and resume if needed.
Q: Why are my limits not being enforced?
A: You're using the template ID for policy enforcement. Use the instance ID to get tenant-specific limits.
Q: Why can't I override capabilities in an instance?
A: Capabilities are inherited from the template and cannot be overridden. Update the template to change capabilities.
Q: Why is my webhook not firing?
A: Webhooks are instance-specific. Make sure you're using the instance ID and have registered webhooks for the instance.
API Reference
Template Operations
POST /api/admin/create- Create templateGET /api/verify/{template_id}- Get template infoPATCH /api/passports/{template_id}- Update templatePOST /api/passports/{template_id}/status- Suspend/revoke template
Instance Operations
POST /api/passports/{template_id}/instances- Create instanceGET /api/verify/{instance_id}- Get instance infoPATCH /api/passports/{instance_id}- Update instancePOST /api/passports/{instance_id}/status- Suspend instanceGET /api/passports/{template_id}/instances- List instances
Policy Verification
POST /api/verify/policy/{pack_id}- Verify policy complianceGET /api/verify/{agent_id}- Get passport data for verification