Envelope

Building a team

How to write a team definition file, publish it to the Library, and manage it entirely via the API — no editor required.

Authenticate every request with your API key:

Authorization: Bearer <your-api-key>

All endpoints are prefixed with /api. The base URL is your Envelope instance origin (e.g. https://openenvelope.org/api).


1. Write the definition

A team definition is a JSON object describing the team's name, agents, required secrets, required variables, access policy, and pricing. The full schema is published at:

https://schema.openenvelope.org/team/v1.json

Add a $schema reference to your file and your editor validates against it automatically.

Minimal valid definition:

{
  "$schema": "https://schema.openenvelope.org/team/v1.json",
  "name": "Support Triage",
  "description": "Routes inbound support tickets to the correct queue based on urgency and topic.",
  "agents": [
    {
      "key": "coordinator",
      "name": "Triage Coordinator",
      "title": "Coordinator",
      "role": "Receives incoming ticket text and routes it to the correct specialist.",
      "model": "anthropic:claude-sonnet-4-5",
      "systemPrompt": "You are a support triage coordinator. Analyse the ticket and output a routing decision."
    }
  ],
  "requiredSecrets": ["ZENDESK_API_KEY"],
  "requiredVariables": ["QUEUE_EMAIL"]
}

Agent hierarchy

Connect agents with reportsToKey. The agent with no reportsToKey is the coordinator — all others report up through the hierarchy.

{
  "agents": [
    { "key": "coordinator", "name": "Coordinator" },
    { "key": "specialist-a", "name": "Tier 1 Specialist", "reportsToKey": "coordinator" },
    { "key": "specialist-b", "name": "Escalation Specialist", "reportsToKey": "coordinator" }
  ]
}

Keep hierarchies shallow. One coordinator with 2–4 specialists is the most common pattern. Deep hierarchies add latency and complicate debugging.

Access policy

Declare which outbound hosts each agent may call. Deployers and their security teams can review this in the Library before installing. An explicit policy — even a permissive one — builds more trust than no policy.

{
  "agents": [
    {
      "key": "coordinator",
      "accessPolicy": {
        "default": "deny",
        "rules": [
          { "host": "api.zendesk.com", "methods": ["GET", "POST"], "effect": "allow" }
        ]
      }
    }
  ]
}

Adapter types

By default Envelope chooses the adapter. Override per-agent with adapterType:

{
  "agents": [
    { "key": "coordinator", "adapterType": "claude_local" }
  ]
}

Supported values: claude_local, codex_local, gemini_local, opencode_local, cursor_local, openclaw, process, http.


2. Create a draft

POST /templates
{
  "slug": "support-triage",
  "name": "Support Triage",
  "description": "Routes inbound support tickets to the correct queue based on urgency and topic.",
  "visibility": "private",
  "category": "support",
  "definition": { ... }
}
FieldRequiredDescription
slugYesURL-safe identifier. Must be globally unique. Min 2 chars.
nameYesDisplay name shown in the Library. Min 2 chars.
descriptionYesShort summary shown in search results. Min 10 chars.
visibilityNo"private" (default), "team", or "public"
categoryNoFunctional category, e.g. "support", "sales", "ops"
targetPlatformNoPlatform the team is optimised for, e.g. "paperclip", "bedrock"
definitionYesFull team definition object (see above)

Response: 201 Created — returns the full template object including the assigned id. Store this id — you'll use it in every subsequent call for this team.

A slug collision returns 409 Conflict. Choose a different slug.


3. Update the draft

PATCH /templates/:id
{
  "description": "Routes tickets and escalates P1s automatically.",
  "definition": { ... }
}

Only draft status templates can be patched. Attempting to patch a published template returns 409. Create a version draft first — see Versioning your team.

Updatable fields: name, description, visibility, pricingModel, priceUsdCents, forkable, changeLog, definition.


4. Set pricing

Update via PATCH /templates/:id:

{
  "pricingModel": "per_run",
  "priceUsdCents": 50
}
pricingModelDescription
"free"No charge to deployers
"per_run"Fixed charge per run trigger
"per_k_tokens"Charge per 1,000 tokens consumed across the run

priceUsdCents is the amount in US cents charged to deployers. Envelope's platform fee is deducted automatically before payout. See Pricing your team for fee details and payout mechanics.


5. Publish

POST /templates/:id/publish
{
  "changeLog": "Initial release. Routes tickets by urgency using keyword detection."
}

Always supply a changeLog string. It is shown to deployers in the Library and in their install's version history — a blank changelog makes upgrade decisions harder for everyone who installs your team.

Response: Returns the updated template with status: "published" and a version number. The team is now visible in the Library and installable by ID or slug.

Envelope validates your definition against the JSON Schema on publish. A 400 error includes specific field-level messages. Fix those and re-publish.


6. List your teams

GET /templates/all

Returns all templates owned by your API key — drafts, published, and archived — ordered newest first.


7. Get a team

GET /templates/:id

Returns the full template including definition and system prompts. Other callers receive a stripped version without prompts.


Model routing

Envelope assigns a model to each agent automatically based on its role. Builders can pin a specific model in the definition, and deployers can override any agent's model at the install level — without touching the team definition.

Setting a default model in the definition

Set model on any agent in provider:model format. This becomes the default for all installs of this team, but deployers can override it:

{
  "agents": [
    { "key": "triage", "model": "openai:gpt-5-mini", "role": "classify incoming tickets" },
    { "key": "responder", "model": "anthropic:claude-sonnet-4-5", "role": "draft replies" }
  ]
}

How the resolution order works

For each agent, Envelope resolves in this order:

  1. Deployer override — set via API or workspace UI — wins over everything
  2. Definition model — the model field you set above
  3. Auto-routing — Envelope assigns a tier based on role keywords (orchestrators get frontier models, classifiers get efficient ones, etc.)

If you want Envelope's model router to decide for an agent, omit the model field entirely.

Deployer model override API

Deployers can inspect and change model assignments per-agent without forking or re-installing:

GET  /api/installs/:installId/agents          — list all agents with effective models
PATCH /api/installs/:installId/agents/:key/model  — pin a model override
DELETE /api/installs/:installId/agents/:key/model — reset back to auto-routing

See Installing a team for details.


Common mistakes

Not validating the definition before publishing — run the JSON Schema validator locally first. Envelope validates on publish and returns specific field errors, but catching them locally is faster.

No access policy — teams with no policy look opaque to deployers who need to justify network access to their security teams. Even a permissive "default": "allow" policy is better than nothing.

Blank changelog — every release your deployers track needs context to decide when to upgrade. Write something meaningful even for small changes.

Wrong version bump for breaking changes — removing a field, renaming an agent key, or making an optional input required are all breaking changes. When in doubt, bump MAJOR. See Versioning your team.