Envelope

Building a team (API)

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": "claude-3-5-sonnet-20241022",
      "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": { ... }
}

| Field | Required | Description | |---|---|---| | slug | Yes | URL-safe identifier. Must be globally unique. Min 2 chars. | | name | Yes | Display name shown in the Library. Min 2 chars. | | description | Yes | Short summary shown in search results. Min 10 chars. | | visibility | No | "private" (default), "team", or "public" | | category | No | Functional category, e.g. "support", "sales", "ops" | | targetPlatform | No | Platform the team is optimised for, e.g. "paperclip", "bedrock" | | definition | Yes | Full 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
}

| pricingModel | Description | |---|---| | "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.


8. Workspace document endpoints (deployer-scoped)

Workspace documents are scoped to installs, not templates. They are accessible to the install owner via these routes. All routes require authentication (Authorization: Bearer <api-key>).

List documents

GET /installs/:installId/documents

Returns all documents for the install with their lifecycle state and timestamps.

Read a document

GET /installs/:installId/documents/:name

Returns the full document including all rows, schema, and per-row metadata (notes, blocked-by, last-changed-by).

Create / ensure a document

POST /installs/:installId/documents/:name
{
  "schema": {
    "columns": [
      { "name": "company", "owner": "human", "id": true },
      { "name": "email",   "owner": "agent" },
      { "name": "email-status", "owner": "agent" }
    ],
    "statusValues": ["unverified", "verified", "sent"]
  }
}

Idempotent — returns the existing document ID if the document already exists. Documents declared in the team definition's workspace block are created automatically at install time.

Append rows

POST /installs/:installId/documents/:name/rows
{ "rows": [{ "company": "Acme", "email-status": "unverified" }] }

Edit a row (human)

PATCH /installs/:installId/documents/:name/rows/:rowId
{ "update": { "email": "[email protected]" }, "notes": "Confirmed via LinkedIn", "blockedBy": null }

Delete a row (hard delete for PII compliance)

DELETE /installs/:installId/documents/:name/rows/:rowId

Physically removes the row — no soft-delete flag. Required for GDPR erasure and any PII compliance obligation.

Export

GET /installs/:installId/documents/:name/export?format=csv
GET /installs/:installId/documents/:name/export?format=json

Returns the document as a file download. format defaults to json.

Lifecycle transition

POST /installs/:installId/documents/:name/lifecycle
{ "state": "archived" }

Valid states: new, active, complete, archived, deleted.

Version history

GET /installs/:installId/documents/:name/snapshots

Returns all named snapshots (one per agent write batch). Each snapshot has an id, label, agentRunId, and createdAt.

Revert to snapshot

POST /installs/:installId/documents/:name/snapshots/:snapshotId/revert

Restores the document to the state at that snapshot. The agent's last write is the most recent snapshot.


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.