API Reference
Reference for the Envelope core API. Manage templates and deployments programmatically.
Authentication
Most Envelope endpoints require an API key. Authenticate your requests by providing the key in the Authorization header.
Personal keys
Tied to your account. Can create and manage templates you personally own. Generated from Account → API Keys.
Org keys
Tied to an organisation, not any individual. Can manage all templates owned by that org. Generated from Org dashboard → API Keys. Use these for CI/CD and shared automation so access doesn't break when people leave.
Copy your key for use in examples
Set it in your shell: export ENVELOPE_KEY=<paste here>
Errors
Envelope uses conventional HTTP response codes to indicate the success or failure of an API request.
The request was successfully received, understood, and accepted.
The request contains bad syntax or cannot be fulfilled (e.g. missing auth).
The server failed to fulfill a valid request.
All error responses return a JSON body with a single error field:
// 4xx / 5xx error body
{ "error": "Install not found" }Rate Limits
All API endpoints are rate-limited per IP address. Requests that exceed the limit receive a 429 Too Many Requests response. The Retry-After header indicates how many seconds to wait before retrying.
All endpoints (global)300 requests15 minutesAuth routes (/api/auth/*)20 requests15 minutesPublic template generate (/api/templates/generate/public)5 requests1 hour per IPLimits apply per IP. If you need higher throughput for production automation, contact us.
List Templates
Returns a list of published templates available in the registry. No authentication required — the registry is public.
curl -X GET https://openenvelope.org/api/templates
Response
{
"templates": [
{
"id": "tmpl_xyz",
"slug": "sales-team-v1",
"name": "Outbound Sales Team",
"description": "Standard B2B SDR configuration",
"ownerTeam": "acme-corp",
"visibility": "public",
"status": "published",
...
}
]
}Create Template
Creates a new template in draft mode.
curl -X POST https://openenvelope.org/api/templates \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "support-squad",
"name": "L1 Support Squad",
"description": "Handles inbound tickets",
"ownerTeam": "customer-success",
"visibility": "team",
"definition": {
"requiredVariables": ["companyName"],
"requiredSecrets": ["ZENDESK_API_KEY"],
"agents": [
{
"key": "triage",
"name": "Triage Agent",
"title": "L1 Triage Agent",
"role": "support",
"capabilities": "Handles inbound ticket classification and initial response.",
"model": "anthropic:claude-haiku-3-5",
"prompt": "You are a triage agent for {{companyName}}..."
}
]
}
}'Variables and secrets
requiredVariables — non-sensitive config values interpolated into agent prompts at install time via {{varName}} syntax (e.g. "companyName", "supportEmail"). They are baked into the prompt before deployment — not injected at runtime.
requiredSecrets — API keys or tokens the deployer must supply (e.g. "ZENDESK_API_KEY", "SLACK_BOT_TOKEN"). Stored in Paperclip's encrypted secrets store. For local adapters they are injected as env vars into agent processes. For http managed agents they are injected as ${SECRET_NAME} substitution in any URL or header the managed runtime sends.
Both arrays are optional — omit them if your team needs no external configuration. Envelope's AI scaffolding automatically populates these when you describe a team that references specific tools.
Model selection — one team, any platform
Each agent declares a model in provider:model format — the same field works across every platform. Envelope translates it automatically: Paperclip picks the right local runtime (claude_local, codex_local, gemini_local), Relevance AI sets its llm_config — future platforms do their own translation.
Supported values: anthropic:claude-opus-4-5, anthropic:claude-sonnet-4-5, anthropic:claude-haiku-3-5, openai:gpt-4o, openai:o4-mini, openai:codex-mini-latest, google:gemini-2.5-pro, google:gemini-2.0-flash.
For Paperclip only: agents can also declare "adapterType": "http" to use a webhook runtime instead of a local CLI — this is the only case where adapterType needs to be set explicitly. In all other cases it is auto-derived from the model field.
Distribution settings
Three optional top-level fields control how a public team is distributed. They are only meaningful when visibility is "public":
pricingModelstring"free", "per_run", or "per_k_tokens". Defaults to "free".priceUsdCentsintegerPrice in US cents per run or per 1K tokens. Required when pricingModel is not "free".forkablebooleanWhether other builders can fork this team into their own workspace. Defaults to true. Owners can always fork their own teams regardless.Access Policy Schema
The accessPolicy field on any agent definition controls which outbound HTTP requests that agent is allowed to make. It travels with the team definition to every platform — part of Envelope's portable standard for agent access controls.
Enforcement scope
Access policies are enforced by Envelope's managed runtime (agents using adapterType: "http"). For self-hosted Paperclip deployments the policy travels in the team config and can be enforced at the operator's network layer. The field is ignored by platforms that don't yet support it — it never breaks existing deployments.
{
"key": "support-agent",
"name": "Support Agent",
"model": "anthropic:claude-haiku-3-5",
"prompt": "...",
"accessPolicy": {
"accessPolicyVersion": "1",
"defaultAction": "allow",
"rules": [
{
"match": { "host": "api.zendesk.com", "methods": ["GET"] },
"action": "allow"
},
{
"match": { "host": "api.zendesk.com", "methods": ["DELETE"] },
"action": "deny",
"reason": "Ticket deletion is irreversible — disabled for all agents."
},
{
"match": { "host": "*.internal.co" },
"action": "deny",
"reason": "Internal endpoints must never be reachable from agents."
}
]
}
}accessPolicyVersionstringAlways "1". Required when the field is present.defaultActionstringWhat to do when no rule matches. "allow" (default) or "deny".rulesRule[]Ordered list of rules. Evaluated top-to-bottom. First matching rule wins.Rule object
match.hoststringHostname to match. Supports leading wildcard: *.zendesk.com matches api.zendesk.com. Omit to match all hosts.match.methodsstring[]HTTP methods to match, e.g. ["DELETE", "PATCH"]. Omit to match all methods.match.pathPrefixstringURL path prefix to match, e.g. /api/v2/tickets. Omit to match all paths.actionstring"allow" proceeds immediately. "deny" blocks with an error. "require_approval" routes the request to the LLM security judge — allowed or blocked based on the agent's declared role and the request context.reasonstringHuman-readable explanation. Shown in block messages and activity logs. Optional but recommended for deny rules.Common patterns
Read-only access to an API: Set defaultAction: "allow", add a deny rule for methods: ["POST","PUT","PATCH","DELETE"].
Allowlist only specific domains: Set defaultAction: "deny", add allow rules for each permitted host.
Block a specific endpoint: Add a deny rule with match.host + match.pathPrefix targeting the sensitive path. Leave everything else on defaultAction: "allow".
Publish Template
Transitions a draft to published status. If the draft has a parentTemplateId (i.e. it's a version draft), the content is merged into the parent template, the parent's version is incremented, and the draft row is deleted — the parent's id and slug never change.
curl -X POST https://openenvelope.org/api/templates/tmpl_abc123/publish \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response
{
"id": "tmpl_abc123",
"slug": "support-squad",
"name": "L1 Support Squad",
"status": "published",
"publishedAt": "2025-04-03T12:00:00.000Z"
}New Version
Creates a version draft linked to an existing published template. Edit the draft freely — it has no impact on live installs until you publish it.
curl -X POST https://openenvelope.org/api/templates/tmpl_abc123/new-version \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response
{
"id": "tmpl_draft_v2",
"parentTemplateId": "tmpl_abc123",
"slug": "support-squad-v2",
"status": "draft",
"version": 2,
...
}Publishing a version draft
When you call POST /api/templates/:draftId/publish on a version draft, Envelope detects the parentTemplateId and merges the draft into the parent — copying the updated definition, bumping the version, and deleting the draft row. The parent template's id and slug never change.
Delete Template
Permanently deletes a team. Allowed for drafts (any kind) and published templates with no active installs. Returns 409 if the team has active installs — archive it instead.
curl -X DELETE https://openenvelope.org/api/templates/tmpl_abc123 \ -H "Authorization: Bearer $ENVELOPE_KEY"
Empty response — the template has been permanently removed.
Returns canArchive: true. Use the archive endpoint to delist instead.
Archive Template
Delists a published team from the marketplace and blocks new installs. Existing installs are unaffected — they continue running. Once all installs are removed, the team can be hard deleted.
curl -X POST https://openenvelope.org/api/templates/tmpl_abc123/archive \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response
{
"id": "tmpl_abc123",
"slug": "support-squad",
"status": "archived",
"installCount": 4,
...
}published templates can be archived. Drafts should be deleted directly.Rollback Template
Creates a new version draft pre-loaded with the definition from a specific past version. Non-destructive — the live published version continues running while you review and publish the restored draft.
curl -X POST https://openenvelope.org/api/templates/tmpl_abc123/rollback \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "version": 2 }'Body
versionintegerThe version number to restore from (must have a stored snapshot)Response — 201 Created
{
"id": "tmpl_def456",
"slug": "support-squad",
"status": "draft",
"version": 4,
"parentId": "tmpl_abc123",
...
}Returns 422 if the requested version has no stored snapshot. Snapshots are only available for versions published after the rollback feature was introduced.
Returns 409 if the team already has an active version draft — publish or delete the existing draft first.
Fork Template
Creates a new private draft in your workspace that is a copy of the specified published team — including all agents, prompts, and settings. Use this to start from a known-good community design and customise from there. Returns 403 if the source team has forkable: false and you are not the owner.
curl -X POST https://openenvelope.org/api/templates/tmpl_abc123/fork \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response — 201 Created
{
"id": "tmpl_fork789",
"slug": "support-squad-fork",
"name": "L1 Support Squad (fork)",
"status": "draft",
"visibility": "team",
"forkedFromId": "tmpl_abc123",
...
}Returns 403 if the source team's forkable flag is false and the caller is not the owner.
Returns 404 if the source template does not exist or is not published.
Test Chat
Streams a chat response from the root agent of a team definition. Accepts the full definition object and a conversation history array — useful for testing prompts interactively without publishing. Returns a streaming SSE response; no install required.
curl -X POST https://openenvelope.org/api/templates/test-chat \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"definition": { ... },
"messages": [
{ "role": "user", "content": "I need help resetting my password" }
]
}'Body
definitionobject requiredThe full team definition object. The root agent's model and prompt are used for the chat response.messagesarray requiredConversation history as [{ role: "user" | "assistant", content: string }]. Must contain at least one message. The last message is sent to the agent; prior messages are passed as context.Response — SSE stream
Returns a streaming SSE response identical in format to the generate and assist endpoints. Text chunks are streamed as they are produced; the final event carries done: true.
data: {"chunk": "Hi! I can help you reset your password."}
data: {"chunk": " Could you confirm the email address on your account?"}
data: {"done": true}Model: Test Chat uses the root agent's model field from the supplied definition, defaulting to anthropic:claude-haiku-4-5 if none is set.
Secrets: No deployer secrets are injected during test runs — secret references in the prompt are passed as-is. If your prompt requires live credential substitution, test via a real Paperclip install instead.
Generate from Description
Generates a complete team definition from a plain-English description. Returns a streaming SSE response — each event is a JSON chunk of the definition as it is produced. The final event contains the complete definition and a done: true flag. The authenticated endpoint accepts a model parameter; the public /api/templates/generate/public endpoint hardcodes anthropic:claude-haiku-4-5.
curl -X POST https://openenvelope.org/api/templates/generate \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "A sales development team with an SDR manager, two outbound SDRs who work leads in HubSpot, and a RevOps analyst who tracks pipeline metrics.",
"model": "anthropic:claude-sonnet-4-6"
}'Body
descriptionstring requiredPlain-English description of the team to generate.modelstringModel to use for generation. Default: openai:gpt-5-mini. Also accepts anthropic:claude-sonnet-4-6, anthropic:claude-haiku-4-5, openai:gpt-4o, openai:gpt-4o-mini.Response — SSE stream
Each event carries a partial or complete JSON object. The final event has done: true and the full definition.
data: {"chunk": "{\n \"version\": \"v1\""}
data: {"chunk": ",\n \"description\": \"Sales Development Team\""}
...
data: {
"done": true,
"definition": {
"version": "v1",
"description": "Sales Development Team ...",
"requiredVariables": ["companyName"],
"requiredSecrets": ["HUBSPOT_API_KEY"],
"agents": [
{
"key": "sdr-manager",
"name": "SDR Manager",
"title": "Head of Sales Development",
"role": "manager",
"capabilities": "Manages outbound SDRs and reviews pipeline metrics.",
"model": "anthropic:claude-sonnet-4-5",
"prompt": "You are the SDR Manager at {{companyName}}..."
},
...
]
}
}Rate limit — public endpoint
The unauthenticated POST /api/templates/generate/public endpoint (used by the /try page) is limited to 5 requests per hour per IP and always uses anthropic:claude-haiku-4-5. Authenticated requests via /api/templates/generate are not rate-limited.
AI Assist
Applies a natural language instruction to an existing team definition and returns an updated definition. Used by the AI Assist panel in the team editor. Like the generate endpoint, the response is a streaming SSE event stream — the final event contains the updated definition and a diff summary.
curl -X POST https://openenvelope.org/api/templates/assist \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"currentDefinition": { ... },
"instruction": "Add a Slack notification agent that pings #ops whenever a deal is stalled.",
"model": "anthropic:claude-sonnet-4-6"
}'Body
currentDefinitionobject requiredThe team definition to modify. Must be a valid Envelope team definition object.instructionstring requiredPlain-English instruction describing the change to apply.modelstringModel to use. Default: anthropic:claude-sonnet-4-6. Also accepts anthropic:claude-haiku-4-5, openai:gpt-4o, openai:gpt-4o-mini.conversationHistoryarrayOptional prior turns as [{ role: "user" | "assistant", content: string }]. Pass the previous exchanges to give the model context for follow-up instructions.Response — SSE stream
The endpoint has two modes depending on whether the model interpreted the instruction as an apply or a discuss request. In APPLY mode the final event carries definition. In DISCUSS mode it carries text. Always check which key is present before processing.
data: {"chunk": "{\n \"teamName\": \"Sales Dev Team\""}
...
// APPLY MODE — model returned JSON: final event carries the updated definition
data: {"done": true, "definition": { ... }}
// DISCUSS MODE — model responded in text: final event carries plain text
data: {"done": true, "text": "I'd suggest adding a Slack notification agent ..."}Non-destructive by design
Assist returns an updated definition but does not save or publish it automatically. The editor's AI Assist panel shows the diff and lets the builder apply or discard the change before committing. If you call this endpoint directly, you are responsible for saving the result via Create Template or a form save action.
List Platforms
Returns the list of orchestration platforms Envelope currently supports, along with the credential fields required to deploy to each one. Use this to dynamically build your deployment UI without hardcoding platform details.
curl https://openenvelope.org/api/platforms
Response
{
"platforms": [
{
"id": "paperclip",
"label": "Paperclip",
"credentialFields": [
{ "key": "paperclipBaseUrl", "label": "Base URL", "type": "text", "required": true },
{ "key": "paperclipApiKey", "label": "API Key", "type": "password", "required": true }
],
"capabilities": {
"maxHierarchyDepth": null,
"supportedModels": null,
"billingCompleteness": "full",
"provisioningModel": "rest"
}
},
{
"id": "relevance_ai",
"label": "Relevance AI",
"credentialFields": [
{ "key": "projectId", "label": "Project ID", "type": "text", "required": true },
{ "key": "apiKey", "label": "API Key", "type": "password", "required": true },
{ "key": "region", "label": "Region", "type": "text", "required": true }
],
"capabilities": {
"maxHierarchyDepth": null,
"supportedModels": null,
"billingCompleteness": "none",
"provisioningModel": "rest"
}
},
{
"id": "bedrock",
"label": "Amazon Bedrock",
"credentialFields": [
{ "key": "accessKeyId", "label": "Access Key ID", "type": "text", "required": true },
{ "key": "secretAccessKey", "label": "Secret Access Key", "type": "password", "required": true },
{ "key": "region", "label": "Region", "type": "text", "required": true },
{ "key": "agentResourceRoleArn", "label": "Agent IAM Role ARN", "type": "text", "required": true }
],
"capabilities": {
"maxHierarchyDepth": 1,
"supportedModels": ["claude", "anthropic", "titan", "nova", "llama", "mistral", "cohere", "ai21", "jamba", "deepseek"],
"billingCompleteness": "full",
"provisioningModel": "rest"
}
}
]
}Create Install
Deploys a template to a target orchestration platform. Specify the platform field and the matching credentials — Envelope provisions all agents according to the template definition. Defaults to paperclip if omitted.
# Envelope Managed — no external platform needed
curl -X POST https://openenvelope.org/api/installs \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"platform": "envelope",
"variables": { "companyName": "Acme Corp" }
}'
# Secrets are NOT required here — add them afterwards:
# PATCH /api/installs/{installId}/secrets
# Relevance AI
curl -X POST https://openenvelope.org/api/installs \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"platform": "relevance_ai",
"credentials": {
"projectId": "proj_...",
"apiKey": "sk-...",
"region": "f1db6c"
},
"variables": { "companyName": "Acme Corp" }
}'
# Paperclip (self-hosted)
curl -X POST https://openenvelope.org/api/installs \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"platform": "paperclip",
"companyId": "org_789",
"credentials": {
"paperclipBaseUrl": "https://paperclip.ing/api",
"paperclipApiKey": "pc_admin_key_..."
},
"variables": { "companyName": "Acme Corp" }
}'Envelope Managed — how it differs
When platform: "envelope" is used, Envelope itself is the runtime — no external infrastructure is provisioned. This has several important differences from other platforms:
- ·No credentials required. There is no external platform to authenticate against — omit the
credentialsfield entirely. - ·Secrets are added post-install. Required secrets are not validated at install time. Add them after creation via PATCH /installs/:id/secrets.
- ·API key is automatically scoped. The API key used to create the install is immediately linked to the new
installId— so GET /installs/whoami returns it right away, no extra setup needed. - ·Billing is native to Envelope. Usage (runs, tokens) is tracked and billed directly through Envelope's billing cycle — no external platform billing. Attach
stripeCustomerIdandstripePaymentMethodIdat install time (or via the Card Setup Intent flow) so Envelope can charge at end of cycle.
Creating a company on install
Instead of companyId, pass companyName to have Envelope create a new Paperclip company and deploy into it in a single call. The created company's ID is returned in the response.
{
"templateId": "tmpl_abc123",
"companyName": "New Client Co", // creates the company
"paperclipBaseUrl": "https://paperclip.ing/api",
"paperclipApiKey": "pc_admin_key_...",
"variables": { "companyName": "New Client Co" }
}Useful for provisioning pipelines that spin up a new Paperclip company per customer and immediately bootstrap it with an AI team.
Response
{
"installId": "inst_xyz",
"platform": "relevance_ai",
"deployedAgents": [
{ "key": "sdr", "externalId": "agent_abc", "name": "SDR Agent" },
{ "key": "ae-lead", "externalId": "agent_def", "name": "AE Lead" }
],
"platformData": {
"dashboardUrl": "https://app.relevanceai.com/agents/f1db6c/proj_...",
"agentUrls": [
{ "name": "SDR Agent", "url": "https://app.relevanceai.com/agents/..." }
]
},
"warnings": [
"analyst reports to sdr which reports to ae-lead — platform supports depth 1 only; hierarchy was flattened"
]
}warnings is omitted when empty. It appears when the deploy succeeded but the platform required a silent adaptation — the most common case is hierarchy flattening on platforms that only support a single reporting level (agents can only report directly to the top-level manager, not to other agents). Treat warnings as informational: the team is live, but review them to confirm the deployed structure matches your intent.
Platform-specific parameters
Some request fields are only valid for specific platforms. Sending an unsupported field returns a 400 with a message explaining which platform requires it.
| Field | Envelope | Paperclip | Relevance AI | Bedrock |
|---|---|---|---|---|
| credentials | — | ✓ | ✓ | ✓ |
| variables | ✓ | ✓ | ✓ | ✓ |
| secrets | post-install | ✓ | — | — |
| model | — | ✓ | ✓ | ✓ |
| companyId / companyName | — | ✓ | — | — |
| adapterType | — | ✓ | — | — |
| webhookUrl | — | ✓ | — | — |
| cwd | — | ✓ | — | — |
For http agents — managed vs. custom
Omit webhookUrl (recommended) and Envelope automatically configures its own managed runtime — no extra work required:
// webhookUrl omitted → Envelope uses its built-in runtime automatically
Or provide webhookUrl to route heartbeats to your own server instead — see the Runtime API for the wire format. Local adapter agents (claude_local, gemini_local, etc.) need no webhookUrl at all.
Billing — Envelope Managed vs. other platforms
Billing works differently depending on the platform:
stripeCustomerId + stripePaymentMethodId at install time so Envelope can charge automatically.{
"templateId": "tmpl_abc123",
"platform": "envelope", // or "paperclip", etc.
// Billing — card-on-file collected via the Card Setup Intent flow
"deployerEmail": "[email protected]",
"stripeCustomerId": "cus_...",
"stripePaymentMethodId": "pm_..."
}These fields are optional. Omit them for free teams or when billing is handled out of band. Collect them via the Card Setup Intent flow first.
Check Known Secrets
Returns which of a given list of secret keys Envelope already has stored in its credential vault for a specific company. Use this before re-installing to determine which secrets the deployer still needs to supply versus which Envelope can fill in automatically from a prior install.
curl "https://openenvelope.org/api/secrets/known?companyId=org_789&keys=SLACK_TOKEN,ZENDESK_KEY" \ -H "Authorization: Bearer $ENVELOPE_KEY"
Query Parameters
companyIdThe Paperclip company ID to check secrets for. Required.keysComma-separated list of secret key names to check (e.g. SLACK_TOKEN,ZENDESK_KEY). Required.Response
{
"known": ["SLACK_TOKEN"]
}
// ZENDESK_KEY was not in the list — deployer must provide it at install time
// SLACK_TOKEN was found in the vault — will be filled in automaticallyHow the credential vault works
When a deployer supplies secrets at install time, Envelope pushes them to Paperclip's secrets store and saves an encrypted copy in its own vault (keyed by companyId + secretKey). On re-install, Envelope checks the vault and pre-fills any secrets it already knows — the deployer only needs to enter secrets that are genuinely new or have changed.
Trigger a Run
Trigger an Envelope team run from any external caller — Zapier, HubSpot, a webhook, or any HTTP client. Runs the full team against the provided task and returns the result. This is the core endpoint for all marketplace and automation integrations.
curl -X POST https://openenvelope.org/api/installs/ins_abc123/run \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"task": "Summarise the open Zendesk tickets from the last 24 hours and draft a handoff note."
}'Request body
taskrequiredThe task description passed to the team as its input. Plain text. Can be a question, an instruction, or a structured prompt — whatever the team was built to handle.Response
{
"runId": "a3f8c1d2-...",
"status": "completed",
"response": "Here is the handoff note for the last 24 hours...",
"agent": "supervisor",
"inputTokens": 1842,
"outputTokens": 412
}How it works
The endpoint runs the full team. The supervisor agent receives the task and can delegate to sub-agents using its built-in delegate tools — one per agent in the team. Each sub-agent runs its own loop with its own prompt, model, and access policy. The supervisor synthesises the final response once all delegated work is complete. Secrets and variables are loaded from the install and substituted into every agent's prompt automatically. The run is recorded in observability.
Runs are synchronous — the connection stays open until the team finishes. For long-running or complex teams, consider triggering via a background job and polling the runs API for the result.
One endpoint, every integration
Every marketplace wrapper calls this same endpoint — Zapier actions, HubSpot workflow actions, Slack commands, Make modules, Power Automate connector actions. The platform-specific wrapper is just packaging around POST /api/installs/:installId/run.
Invoke Agent
Sends a message to your deployed Bedrock supervisor agent and returns the response. Envelope proxies the call using the AWS credentials stored at install time — no Bedrock SDK required in your application. Token counts are captured from the response stream and automatically recorded as an observability run.
curl -X POST "https://openenvelope.org/api/installs/{installId}/invoke" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputText": "Summarise the support queue from the last 24 hours",
"sessionId": "session-abc-123"
}'Request body
inputTextrequired
sessionIdoptional
Response
{
"ok": true,
"runId": "f7a3c2d1-...", // Envelope run record ID
"sessionId": "session-abc-123", // Echo or Bedrock-assigned session
"agentName": "Support Supervisor",
"text": "Here's a summary of the last 24 hours...",
"inputTokens": 1847,
"outputTokens": 312
}Data flow note
Because Envelope proxies the call, your input text and the agent's response transit Envelope's servers. Envelope does not persist the content — only the run count, token totals, and success/failure status are recorded. See the security guide for the full Bedrock data flow.
Your AWS CloudTrail will show InvokeAgent calls originating from Envelope's infrastructure IP — this is expected.
Self-report a Run
If you invoke Bedrock directly from your own code (rather than through the Envelope proxy), use this endpoint to report the run back for observability and billing. This is the zero-proxy option — your LLM traffic stays entirely within AWS, and only the token count and status reach Envelope.
curl -X POST "https://openenvelope.org/api/installs/{installId}/runs" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentKey": "supervisor",
"status": "completed",
"inputTokens": 1847,
"outputTokens": 312,
"runId": "bedrock-request-id"
}'Request body
agentKeyrequired
supervisor).statusrequired
"completed" or "failed"inputTokensoptional
per_k_tokens billing.outputTokensoptional
runIdoptional
errorMessageoptional
status is "failed".Response
{ "ok": true, "runId": "f7a3c2d1-..." }Delete Install
Cancels a deployment and tears down all platform-side resources. For Bedrock installs, Envelope deletes every provisioned agent and its aliases from your AWS account, then removes the stored credentials from the Envelope vault. For other platforms the install is marked cancelled without touching platform resources (use each platform's own console to clean up).
Irreversible for Bedrock
Bedrock agents and aliases deleted by this endpoint cannot be recovered. Deleted agents stop incurring AWS charges immediately. If you need to redeploy later, create a new install.
curl -X DELETE "https://openenvelope.org/api/installs/{installId}" \
-H "Authorization: Bearer $ENVELOPE_KEY"Response
// Bedrock install with 3 agents cleaned up:
{
"ok": true,
"installId": "uuid",
"platform": "bedrock",
"deletedAgents": 3
}
// Bedrock with a partial failure (one agent already gone):
{
"ok": true,
"installId": "uuid",
"platform": "bedrock",
"deletedAgents": 2,
"warnings": ["Failed to delete alias for agent \"SDR\": ..."]
}
// Non-Bedrock install:
{
"ok": true,
"installId": "uuid",
"platform": "relevance_ai",
"deletedAgents": 0
}IAM permissions required for Bedrock teardown
The stored caller credentials must have bedrock:DeleteAgent and bedrock:DeleteAgentAlias in addition to the deploy-time permissions. If the credentials lack these permissions, the endpoint returns a 502 with the AWS error detail.
Runtime API
For teams using the http adapter in managed mode, Envelope includes a built-in webhook handler. It receives Paperclip heartbeats, fetches the agent config, calls the LLM configured for that agent, and responds — no server required on your end.
Most teams use local adapters (claude_local, gemini_local, etc.) and don't need this section. The Runtime API documents Envelope's managed webhook endpoint and a test utility for verifying the LLM integration.
Managed by Envelope
Envelope auto-configures its own runtime URL at install time. Paperclip calls it; you don't set anything. Envelope runs the full agentic loop on your behalf.
Custom webhook
The deployer supplies their own URL. Paperclip calls that URL on every trigger. Your server receives the heartbeat payload below and must respond with the wire format shown.
Managed Webhook Handler
Used automatically for http agents installed in managed mode. Envelope configures this URL on the agent at install time — you never set it manually. Paperclip calls it on every trigger; Envelope runs a full agentic loop and responds.
# Envelope sets the agent's Runtime URL to this automatically at install time:
https://your-envelope-domain/api/runtime/webhook?paperclipApiKey=pc_xxx
# Paperclip then POSTs this payload on each trigger:
{
"runId": "run_abc",
"agentId": "agent_xyz",
"companyId": "org_123",
"context": { "taskId": "...", "wakeReason": "..." }
}What Envelope's managed runtime does
Runs a full agentic loop powered by gpt-4o-mini, up to 10 iterations per run. Supports:
- ✓External API calls via a built-in http_request tool (Slack, Zendesk, GitHub, email, etc.)
- ✓Deployer secrets injected as ${SECRET_NAME} in any URL or header field
- ✓Multi-step agentic loops — tool call → result → next LLM call, up to 10 iterations
Cannot access the local file system. For that, use a *_local adapter or bring a custom webhook.
Custom Webhook — Wire Format
When the deployer supplies their own webhook URL, Paperclip calls your server directly using the same heartbeat payload. Your endpoint must receive it, run whatever inference or logic you want, and return a response in the format below.
{
"runId": "run_abc",
"agentId": "agent_xyz",
"companyId": "org_123",
"context": { "taskId": "...", "wakeReason": "..." }
}Response your server must return
{
"runId": "run_abc",
"agentId": "agent_xyz",
"companyId": "org_123",
"agentName": "Head of Sales", // optional but useful for logs
"response": "..." // the agent's text output
}Your server is fully responsible for fetching the agent config, calling the LLM, running any agentic loop, and returning the result. Use any model or framework you like — Envelope only sees the final response.
Test Endpoint
Test the LLM integration directly without a live Paperclip instance. Provide a system prompt and task — returns the OpenAI response immediately.
curl -X POST https://your-envelope-domain/api/runtime/webhook/test \
-H "Content-Type: application/json" \
-d '{
"systemPrompt": "You are the head of sales at Acme Corp.",
"task": "Draft a follow-up email for a prospect who went quiet."
}'Response
{
"response": "Subject: Checking in..."
}Observability API
Envelope automatically collects run data from deployed teams. Each platform has its own reporting mechanism — the ingest endpoint is the common receiver. You never call this directly; you query your data via GET /api/runs.
Ingest Run Report
Called by platform integrations on each completed run. Authenticated via the install token provisioned at deploy time — not your app API key.
POST /api/runs/ingest
Authorization: Bearer env_install_xxxxxxxx
{
"platformAgentId": "agent_abc", // platform's native agent ID
"platform": "paperclip", // "paperclip" | "crewai" | "relevance" | ...
"runId": "run_xyz",
"status": "completed", // "completed" | "failed"
"inputTokens": 1840,
"outputTokens": 920,
"errorMessage": null
}How it works per platform
Paperclip — At install time, Envelope provisions the @envelope/paperclip-plugin with ENVELOPE_URL and ENVELOPE_API_KEY set automatically. The plugin fires on every task.completed event and posts to this endpoint with platformAgentId set to the Paperclip agent's native ID and platform: "paperclip".
Amazon Bedrock — Two options. (1) Use the proxy invoke endpoint — Envelope calls Bedrock on your behalf, extracts token counts from the response stream, and records the run automatically. No action required from the deployer. (2) Invoke Bedrock directly in your own code, then self-report via POST /api/installs/:installId/runs — your LLM traffic stays entirely within AWS.
Relevance AI — No push mechanism; Envelope polls the conversation list every 5 minutes. Token data is not available from the Relevance AI API, so only run counts are reported — per_k_tokens billing is not supported for Relevance AI installs.
CrewAI Enterprise (upcoming) — Envelope registers a crewWebhookUrl at deploy time. CrewAI fires crew_kickoff_completed with exact token counts; the receiver posts to ingest using platformAgentId + platform: "crewai".
Query Run Stats
Returns summary stats and a per-agent breakdown of all recorded runs for a deployed team. This powers the Observability dashboard — you can also query it directly.
curl "https://openenvelope.org/api/runs?templateSlug=startup-ops-team" \ -H "Authorization: Bearer $ENVELOPE_KEY"
Query Parameters
templateIdrequired* — Template UUID. Use either this or templateSlug.templateSlugrequired* — Human-readable slug (e.g. startup-ops-team). Resolved to ID server-side.limitMax recent runs to return in the runs array (default: 100, max: 500). Does not affect summary, byAgent, or byPlatform — those are always computed across all runs.* At least one of templateId or templateSlug is required. Returns 400 if neither is provided.
Response
{
"summary": {
"totalRuns": 592,
"failedRuns": 35,
"successRate": 94, // number (0-100), or null if totalRuns is 0
"totalInputTokens": 770491,
"totalOutputTokens": 339135,
"totalToolCalls": 0,
"failedToolCalls": 0
},
"byPlatform": [
{
"platform": "paperclip",
"totalRuns": 521,
"failedRuns": 30,
"inputTokens": 770491,
"outputTokens": 339135,
"hasTokens": true
},
{
"platform": "relevance_ai",
"totalRuns": 71,
"failedRuns": 5,
"inputTokens": 0,
"outputTokens": 0,
"hasTokens": false
}
],
"byAgent": [
{
"agentKey": "ops-analyst",
"runs": 128,
"failed": 7,
"inputTokens": 49403,
"outputTokens": 24697
},
...
],
"runs": [
{
"id": "019250ab-...",
"installId": "019250ab-...",
"platform": "paperclip",
"agentKey": "chief-of-staff",
"status": "completed",
"inputTokens": 1840,
"outputTokens": 920,
"errorMessage": null,
"createdAt": "2025-04-05T09:12:00.000Z"
},
...
]
}Billing API
Envelope tracks every agent run and computes cost based on the pricing model you set on your team. Builders earn their share; Envelope retains a fixed 10% platform fee. Payouts are handled via Stripe Connect.
Pricing guidance for builders
A good starting point is to charge 3–5× your underlying model API cost. This covers infrastructure margin while staying cheap enough that deployers don't think twice. Envelope takes its cut on top — you keep the rest.
Light teams
1–2 agents, short tasks
$0.01 – $0.05 / run
Mid-complexity
3–5 agents, tool use
$0.05 – $0.25 / run
Heavy teams
Long-context, many agents
$0.25 – $1.00+ / run
For variable-length tasks, consider per-1K-token pricing at $0.002–$0.01. At 400 runs/month, a $0.05/run team earns ~$18/month after Envelope's cut — real passive income at scale.
Read the full pricing guide →Query Billing Estimate
Returns a cost breakdown for a team over a rolling period — what deployers were charged, what builders earned, and Envelope's cut. Useful for invoicing dashboards and revenue reporting.
curl "https://openenvelope.org/api/billing?templateSlug=startup-ops-team&periodDays=30" \ -H "Authorization: Bearer $ENVELOPE_KEY"
Query Parameters
templateIdTemplate UUID. Use either this or templateSlug.templateSlugHuman-readable slug (e.g. startup-ops-team).installIdOptional. Scope the estimate to a single deployer's install.periodDaysRolling window in days (default: 30, max: 365).Response
{
"templateId": "01925000-0000-7000-8000-000000000001",
"templateSlug": "startup-ops-team",
"pricing": {
"model": "per_run", // "free" | "per_run" | "per_k_tokens"
"priceUsdCents": 5, // cents per run (or per 1K tokens)
"envelopeFeePercent": 10,
"priceDisplay": "$0.0500/run"
},
"period": {
"days": 30,
"start": "2026-03-06T00:00:00.000Z",
"end": "2026-04-05T00:00:00.000Z"
},
"usage": {
"totalRuns": 408, // all runs in period (including failed)
"completedRuns": 388, // only these are billed
"totalTokens": 762702, // all tokens in period
"billedTokens": 724681 // tokens from completed runs only
},
"billing": {
"totalAmountCents": 1940, // deployer pays this (388 × $0.05)
"builderAmountCents": 1746, // builder receives this (90%)
"envelopeFeeCents": 194, // Envelope retains this (10%)
"projectedMonthlyAmountCents": 1940,
"totalAmountDisplay": "$19.40",
"projectedMonthlyDisplay": "$19.40"
},
"byInstall": [
{ "installId": "inst_abc", "runs": 208, "tokens": 390000, "amountCents": 1040 },
...
]
}Update Pricing
Set or update the pricing model for one of your templates. You must own the template (i.e. it was created with your API key). Works on both draft and published templates.
curl -X PATCH https://openenvelope.org/api/billing/pricing \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "01925000-0000-7000-8000-000000000001",
"pricingModel": "per_run", // "free" | "per_run" | "per_k_tokens"
"priceUsdCents": 5 // cents per run (or per 1K tokens)
}'Pricing Models
freeNo charge. Deployers pay nothing. Set priceUsdCents to null.per_runCharged per agent run. E.g. priceUsdCents: 5 = $0.05 per run.per_k_tokensCharged per 1,000 tokens consumed. E.g. priceUsdCents: 2 = $0.02 per 1K tokens. Platform-limited — supported on Paperclip only. Relevance AI deployments do not report token counts; runs will not be billed under this model.Revenue split
Deployers are charged totalAmountCents per period. Envelope retains a fixed 10% platform fee and routes the remaining 90% to your Stripe Connect account automatically.
Response
{
"id": "01925000-0000-7000-8000-000000000001",
"pricingModel": "per_run",
"priceUsdCents": 5,
"envelopeFeePercent": 10
}Payments & Payouts
Envelope uses Stripe for all payment flows. Deployers attach a card-on-file at deploy time; builders connect a Stripe Express account to receive their 90% share automatically.
Authentication — two patterns
Most /api/stripe/* endpoints require a valid session cookie (envelope_session) and are designed to be called from the Envelope frontend on behalf of a logged-in user. Two endpoints use an App API Key instead: POST /api/stripe/setup-intent (called during the deploy wizard before a session exists) and POST /api/stripe/charge-cycle (admin/scheduler trigger).
Card Setup Intent
Creates a Stripe SetupIntent and Stripe Customer for a deployer. The returned clientSecret is used to render the Stripe PaymentElement and collect card details. Once confirmed, the resulting paymentMethodId is attached to the install record.
curl -X POST https://openenvelope.org/api/stripe/setup-intent \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]" }'Response
{
"clientSecret": "seti_..._secret_...",
"customerId": "cus_..."
}Builder Payout Onboarding
Creates (or resumes) a Stripe Express account for the authenticated builder and returns a one-time onboarding URL. Redirect the user to this URL to complete identity verification. On return, Envelope polls Connect status to update the builder's payout state.
curl -X POST https://openenvelope.org/api/stripe/connect/onboard \
-H "Content-Type: application/json" \
--cookie "envelope_session=<token>" \
-d '{ "returnUrl": "https://yourapp.com/account?stripe_connect=return" }'Response
{ "url": "https://connect.stripe.com/setup/e/..." }Platform requirement
Your Stripe platform account must have Connect enabled. If not, this endpoint returns a 422 with code: "connect_enrollment_required" and a direct link to the Stripe Connect dashboard.
Connect Status
Returns the current Stripe Connect status for the authenticated builder. Use this to determine whether a builder can receive payouts.
curl https://openenvelope.org/api/stripe/connect/status \ --cookie "envelope_session=<token>"
Response
// Not connected
{ "status": "not_connected" }
// Onboarding incomplete
{ "status": "pending_onboarding" }
// Active — payouts enabled
{
"status": "active",
"dashboardUrl": "https://connect.stripe.com/express/..."
}not_connectedBuilder has not started Connect onboarding. Call the onboard endpoint to begin.pending_onboardingAccount created but identity verification is incomplete. Re-call onboard to resume.activeAccount is fully verified. Payouts will be triggered automatically each billing cycle.restrictedAccount has restrictions. Builder must complete additional verification in their Stripe Express dashboard.Charge Billing Cycle
Charges a deployer's card-on-file for a specific amount. The billing scheduler calls this automatically at the start of each month for all active paid installs — but you can also call it manually for custom billing intervals or ad-hoc charges. Requires an App API Key (not a session cookie).
Automated by default
Envelope's billing scheduler runs on the 1st of each month (UTC) and handles this automatically for all installs with a saved payment method. Use this endpoint only for custom or ad-hoc billing. Override the schedule with the BILLING_CRON_SCHEDULE environment variable (standard cron syntax).
curl -X POST https://openenvelope.org/api/stripe/charge-cycle \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"installId": "inst_xyz",
"amountCents": 500
}'installIdstringThe install ID to charge.amountCentsintegerAmount in USD cents to charge (e.g. 500 = $5.00). Must be ≥ 50 (Stripe minimum).periodStartstringISO-8601 timestamp. Start of the billing window recorded on the invoice. Defaults to the start of the previous calendar month.periodEndstringISO-8601 timestamp. End of the billing window recorded on the invoice. Defaults to the end of the previous calendar month.Response
// Charge succeeded
{
"invoiceId": "01925000-...",
"paymentIntentId": "pi_...",
"status": "succeeded",
"amountCents": 500
}
// Period was already billed (idempotent)
{
"status": "already_paid",
"invoiceId": "01925000-..."
}List Installs
Returns all installs associated with your API key, ordered newest-first. Use this to query the state of your deployed teams programmatically.
curl https://openenvelope.org/api/installs \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response
{
"installs": [
{
"id": "inst_abc123",
"templateId": "tmpl_xyz",
"templateName": "Outbound Sales Team",
"templateSlug": "sales-team-v1",
"templateVersion": 3,
"platform": "paperclip",
"companyId": "org_789",
"paperclipBaseUrl": "https://paperclip.ing/api",
"status": "completed",
"createdAt": "2026-04-01T12:00:00.000Z"
},
...
]
}My Managed Installs
Returns all Envelope Managed installs belonging to the authenticated session user — either directly deployed by them or accessible via their org membership. Includes config completeness signals so the operator UI can immediately surface which installs still need secrets or variables configured.
curl https://openenvelope.org/api/installs/mine \ --cookie "envelope_session=<token>"
[
{
"id": "inst_abc123",
"name": "Acme Corp", // org name, or template name if no org
"pipelineName": "Acme Corp", // pipeline display name from definition
"orgSlug": "acme-corp", // null if not linked to an org
"status": "completed",
"platform": "envelope",
"lastRunAt": "2026-05-03T09:00:04.000Z", // null if never run
"nextRunAt": "2026-05-04T09:00:00.000Z", // null if no schedule
"webhookToken": "wh_abc123xyz", // null if not enabled
"requiredVariables": ["COMPANY_NAME", "TIMEZONE"],
"currentVariables": { "COMPANY_NAME": "Acme Corp", "TIMEZONE": "UTC" },
"missingSecrets": ["SLACK_BOT_TOKEN"], // required secrets not yet configured
"missingVariables": [] // required variables not yet configured
},
...
]missingSecrets / missingVariables
These arrays are computed at query time by comparing the template's requiredSecrets and requiredVariables against what's currently stored. Non-empty arrays indicate the install is not yet fully configured and the pipeline will likely fail if triggered.
lastRunAt / nextRunAt
lastRunAt is the timestamp of the most recent pipeline execution for this install. nextRunAt is derived from the configured cron schedule and timezone — it is null when no schedule is set or the schedule is disabled.
Resolve Install (whoami)
Resolves which install ID the current API key is scoped to. The Pipelines frontend calls this once after key entry to establish its pipeline context. Returns 400 if the key has no install scope — either not yet linked or not an Envelope Managed key.
When is a key automatically scoped?
When you create an Envelope Managed install (platform: "envelope"), the API key used to make that call is automatically linked to the new installId. Subsequent calls to this endpoint with that same key return immediately without any additional setup.
Keys can also be scoped via the APP_API_KEYS environment variable using the installId:key format — useful for self-hosted or development environments.
curl https://openenvelope.org/api/installs/whoami \ -H "Authorization: Bearer $ENVELOPE_KEY"
// Key is scoped — returns install ID
{ "installId": "inst_abc123" }
// Key has no install scope
// 400 Bad Request
{
"error": "This API key is not linked to a pipeline install.",
"hint": "For APP_API_KEYS, use the format 'installId:key'. For user API keys, set install_id via the key management API."
}Update Variables
Merges the supplied key-value pairs into an install's variable set. Existing keys are overwritten; keys not included are left unchanged. Accepts both a flat object and a { variables: { ... } } wrapper.
curl -X PATCH "https://openenvelope.org/api/installs/{installId}/variables" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"companyName": "Acme Corp v2",
"supportEmail": "[email protected]"
}'Response
{
"ok": true,
"installId": "inst_abc123",
"updatedKeys": ["companyName", "supportEmail"]
}Rotate Secrets
Merges new secret values into an install's secret store without requiring a full redeploy. Useful for key rotation. Accepts both a flat object and a { secrets: { ... } } wrapper.
Encrypted at rest
All secret values are encrypted before storage. The plaintext value you send is never logged or persisted anywhere other than the encrypted vault record.
curl -X PATCH "https://openenvelope.org/api/installs/{installId}/secrets" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"SLACK_BOT_TOKEN": "xoxb-new-token-...",
"ZENDESK_API_KEY": "zdapi_new_..."
}'Response
{
"ok": true,
"installId": "inst_abc123",
"updatedKeys": ["SLACK_BOT_TOKEN", "ZENDESK_API_KEY"]
}Pipelines API
Programmatic access to the Pipelines operator console — monitor run health, cancel active runs, resume after human gates, manage schedules, review gate queues, and read the activity feed. All endpoints accept both a session cookie and an API key (Authorization: Bearer).
Run Health Log
Returns a day-by-day breakdown of completed and failed pipeline steps for the last N days (default 7, max 30). Use this to monitor pipeline health over time, build dashboards, or trigger alerts when error counts spike.
curl "https://openenvelope.org/api/installs/{id}/run-log?days=7" \
-H "Authorization: Bearer $ENVELOPE_KEY"Query parameters
daysNumber of days to include (1–30). Defaults to 7.Response
{
"days": [
{ "date": "2026-04-27", "ok": 0, "error": 0 }, // no steps ran
{ "date": "2026-04-28", "ok": 14, "error": 1 },
{ "date": "2026-04-29", "ok": 18, "error": 0 },
{ "date": "2026-04-30", "ok": 9, "error": 3 },
{ "date": "2026-05-01", "ok": 21, "error": 0 },
{ "date": "2026-05-02", "ok": 17, "error": 0 },
{ "date": "2026-05-03", "ok": 22, "error": 0 }
]
}step_completed / step_failed), not full pipeline runs. A single pipeline execution with three agents increments ok by three when all succeed. Days are returned oldest-first in the caller's requested range.Agent Run History
Returns recent individual agent executions for an install, newest-first. Each record represents one agent invocation — use this to audit token usage, track per-agent failure rates, and correlate Envelope run IDs with your own logs.
curl "https://openenvelope.org/api/installs/{id}/agent-runs?limit=20" \
-H "Authorization: Bearer $ENVELOPE_KEY"Query parameters
limitNumber of records to return (1–200). Defaults to 50.Response
{
"runs": [
{
"id": "ar_abc123",
"agentKey": "supervisor",
"runId": "a3f8c1d2-...", // parent pipeline run ID
"status": "completed", // "completed" | "failed"
"inputTokens": 1842,
"outputTokens": 412,
"errorMessage": null, // set on failure
"createdAt": "2026-05-03T09:00:03.000Z"
},
{
"id": "ar_def456",
"agentKey": "writer",
"runId": "a3f8c1d2-...",
"status": "failed",
"inputTokens": 924,
"outputTokens": 0,
"errorMessage": "Rate limit exceeded from upstream",
"createdAt": "2026-05-03T09:00:01.000Z"
}
]
}Cancel Run
Cancels the currently active pipeline run for an install. The running agent's proxy token is revoked — the agent errors out on its next outbound request, stopping execution cleanly. A step_cancelled event is emitted in the activity feed. Returns 404 if no run is currently active.
curl -X POST "https://openenvelope.org/api/installs/{id}/cancel-run" \
-H "Authorization: Bearer $ENVELOPE_KEY"Response
{
"ok": true,
"runId": "a3f8c1d2-...",
"cancelledStep": "writer" // key of the step that was active when cancelled
}Resume after Gate
Resumes a pipeline that is paused at a human gate checkpoint. The server recovers the gated step's output and continues execution from the next agent in the sequence. Returns 409 if no pending gate is found for this install.
curl -X POST "https://openenvelope.org/api/installs/{id}/continue" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "bypassGates": false }'Request body
bypassGatesoptional · boolean
true, all subsequent gate checkpoints in this run are skipped automatically. Defaults to false.Response
{ "ok": true }
// No pending gate:
// 409 { "error": "No pending gate found for this install" }
// No agents remaining after the gate:
// 409 { "error": "No agents remaining after gate" }Human gate flow
When a pipeline step reaches a gate checkpoint, execution pauses and a gate_triggered event is emitted. The operator reviews items in the gate queue (see Human gate queue) and calls this endpoint to resume. The pipeline picks up from where it left off, passing the gated step's output into the next agent.
Get Schedule
Returns the cron schedule configured for an install, along with the last and next run timestamps. Also returns the list of available IANA timezone strings for schedule setup UIs.
curl https://openenvelope.org/api/installs/{id}/schedule \
-H "Authorization: Bearer $ENVELOPE_KEY"{
"schedule": {
"cronExpression": "0 9 * * 1-5",
"label": "Weekdays at 9am",
"enabled": true,
"onBacklog": "skip", // "skip" | "queue" — what to do if prior run is still active
"timezone": "America/New_York",
"bypassGates": false, // if true, runs skip all human gate checkpoints
"lastRunAt": "2026-04-22T09:00:00.000Z",
"nextRunAt": "2026-04-23T09:00:00.000Z"
},
"timezones": ["America/New_York", "Europe/London", "Asia/Tokyo", ...]
}
// No schedule configured:
{ "schedule": null, "timezones": [...] }Update Schedule
Creates or replaces the cron schedule for an install. Pass cronExpression: null to delete the schedule entirely.
# Set a schedule
curl -X PATCH "https://openenvelope.org/api/installs/{id}/schedule" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"cronExpression": "0 9 * * 1-5",
"label": "Weekdays at 9am",
"enabled": true,
"onBacklog": "skip",
"timezone": "America/New_York",
"bypassGates": false
}'
# Delete the schedule
curl -X PATCH "https://openenvelope.org/api/installs/{id}/schedule" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "cronExpression": null }'cronExpressionrequired
labeloptional
enabledoptional
onBacklogoptional
timezoneoptional
bypassGatesoptional
{
"ok": true,
"schedule": {
"cronExpression": "0 9 * * 1-5",
"label": "Weekdays at 9am",
"enabled": true,
"onBacklog": "skip",
"timezone": "America/New_York",
"bypassGates": false,
"lastRunAt": null,
"nextRunAt": "2026-04-23T09:00:00.000Z"
}
}Toggle Schedule
Pause or resume a schedule without changing any other settings. Equivalent to toggling the switch in the Pipelines UI.
curl -X PATCH "https://openenvelope.org/api/installs/{id}/schedule/toggle" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'{ "ok": true, "enabled": false }Human gate queue
Returns the pending-review records for a named human gate checkpoint. The name path parameter must match a gate declared in the team definition. Built-in gate names are target-review and draft-approval. Unknown gate names return an empty queue gracefully.
What is a human gate?
Human gates are declared checkpoints in a team definition where agent output pauses for human review before the pipeline continues. They are defined in the template's gates field. See the Human gates guide for the full spec.
curl https://openenvelope.org/api/installs/{id}/gates/draft-approval/queue \
-H "Authorization: Bearer $ENVELOPE_KEY"// gate: draft-approval
{
"records": [
{
"id": 42,
"status": "pending_approval",
"subject": "Quick question about your open source work",
"body": "Hi Sarah, I came across your work on...",
"recipientEmail": "[email protected]",
"targetHandle": "sarahdev"
}
],
"total": 1
}
// gate: target-review
{
"records": [
{
"id": 7,
"githubHandle": "sarahdev",
"email": "[email protected]",
"priorityScore": 92,
"status": "pending",
"categoryFit": "strong match — active OSS contributor",
"bio": "Senior engineer at Stripe, focused on developer tooling..."
}
],
"total": 1
}List Drafts
Returns all outreach drafts for an install, joined with their target contact. Ordered newest-first. Drafts are created by the agent pipeline and queued for human review before sending.
curl https://openenvelope.org/api/installs/{id}/drafts \
-H "Authorization: Bearer $ENVELOPE_KEY"{
"drafts": [
{
"draft": {
"id": 42,
"installId": "inst_abc",
"targetId": 7,
"status": "pending_approval", // pending_approval | approved | rejected | sent | archived
"subject": "Quick question about your open source work",
"body": "Hi Sarah, ...",
"rejectionNote": null,
"editedAt": null,
"createdAt": "2026-04-22T10:00:00.000Z"
},
"target": {
"id": 7,
"installId": "inst_abc",
"githubHandle": "sarahdev",
"email": "[email protected]",
"priorityScore": 92,
"status": "approved"
}
}
]
}Approve Draft
Marks a draft as approved. The pipeline's Sender step picks up approved drafts on its next run and dispatches them. Triggers an auto-advance check so the pipeline resumes immediately if all gate conditions are satisfied.
curl -X POST "https://openenvelope.org/api/installs/{id}/drafts/42/approve" \
-H "Authorization: Bearer $ENVELOPE_KEY"{ "ok": true }Optional — edit before approving
Use PATCH /installs/:id/drafts/:draftId to update subject and/or body before calling approve. editedAt is stamped automatically.
Reject Draft
Marks a draft as rejected. Supply an optional note to give the Writer agent context for re-running — this note becomes part of the feedback loop and can meaningfully improve the next iteration.
curl -X POST "https://openenvelope.org/api/installs/{id}/drafts/42/reject" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "note": "Too generic — reference their specific project next time" }'{ "ok": true }POST /installs/:id/drafts/:draftId/recall — this moves the draft back to pending_approval. Returns 409 if the draft has already been sent.Bulk Draft Action
Apply an action to multiple drafts at once. Target drafts by explicit ID list or by status filter. Returns the count of records updated.
# Approve specific drafts by ID
curl -X POST "https://openenvelope.org/api/installs/{id}/drafts/bulk" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "approve", "ids": [42, 43, 44] }'
# Reject all pending_approval drafts
curl -X POST "https://openenvelope.org/api/installs/{id}/drafts/bulk" \
-H "Authorization: Bearer $ENVELOPE_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "reject", "filter": { "status": "pending_approval" } }'actionrequired
idsoptional
filter.statusoptional
{ "ok": true, "count": 3 }Events Feed
Returns the last 100 pipeline events for an install, ordered newest-first. Events include gate approvals, rejections, step completions, and scheduling actions. Powers the Activity panel in the Pipelines console.
curl https://openenvelope.org/api/installs/{id}/events \
-H "Authorization: Bearer $ENVELOPE_KEY"{
"events": [
{
"id": "evt_abc",
"eventType": "gate_approved", // gate_approved | gate_rejected | step_complete | scheduler_run | ...
"stepKey": "writer",
"gateName": "draft-approval",
"actorId": "usr_xyz",
"actorEmail": "[email protected]",
"meta": { "draftId": 42 },
"createdAt": "2026-04-22T11:05:00.000Z"
},
...
]
}Security Policies
Returns each agent in the install together with its declared accessPolicy. Use this to audit which agents are allowed to call which external hosts, and what the fallback behaviour is for unmatched requests.
curl https://openenvelope.org/api/installs/{id}/policies \
-H "Authorization: Bearer $ENVELOPE_KEY"{
"agents": [
{
"key": "sdr",
"name": "SDR Agent",
"policy": {
"defaultAction": "BLOCK",
"rules": [
{ "hosts": ["api.sendgrid.com"], "action": "ALLOW" },
{ "hosts": ["*.internal.acme.com"], "action": "JUDGE" }
]
}
},
{
"key": "analyst",
"name": "Analyst",
"policy": null // no policy declared — all requests pass through
}
]
}accessPolicy schema is defined in the Access Policy Schema section. See the Security guide for enforcement details.Security Request Log
Returns the last 200 outbound HTTP requests made by agents in this install, with their policy decision and reasoning. Powers the Security dashboard in the Pipelines console. Use this to audit which requests were allowed, blocked, or sent to the judge.
curl https://openenvelope.org/api/installs/{id}/security/requests \
-H "Authorization: Bearer $ENVELOPE_KEY"{
"requests": [
{
"id": "req_001",
"agentKey": "sdr",
"agentName": "SDR Agent",
"runId": "run_xyz",
"method": "POST",
"url": "https://api.sendgrid.com/v3/mail/send",
"hostname": "api.sendgrid.com",
"path": "/v3/mail/send",
"decision": "ALLOW", // ALLOW | BLOCK | JUDGE | PASSTHROUGH
"decisionSource": "rule", // rule | default | judge
"reason": "matched allow rule for api.sendgrid.com",
"judgeReasoning": null, // LLM explanation when decision is JUDGE
"judgeConfidence": null, // 0–1 confidence score from judge
"statusCode": 202,
"latencyMs": 341,
"createdAt": "2026-04-22T11:05:00.000Z"
},
{
"id": "req_002",
"agentKey": "sdr",
"agentName": "SDR Agent",
"runId": "run_xyz",
"method": "GET",
"url": "https://unknown-api.io/endpoint",
"hostname": "unknown-api.io",
"path": "/endpoint",
"decision": "BLOCK",
"decisionSource": "default",
"reason": "no matching rule — defaultAction is BLOCK",
"judgeReasoning": null,
"judgeConfidence": null,
"statusCode": null,
"latencyMs": 0,
"createdAt": "2026-04-22T11:05:01.000Z"
}
]
}ALLOWRequest matched an ALLOW rule and was forwarded to the destination.BLOCKRequest was blocked — either matched a BLOCK rule or hit the defaultAction.JUDGERequest was sent to the LLM judge. The judge's decision is in judgeReasoning / judgeConfidence.PASSTHROUGHAgent has no access policy — request was forwarded without any check.Orgs API
Create and manage organisations, their members, API keys, and deployment governance. All org endpoints require a session cookie (envelope_session) — they are not accessible via API key. Use them from your own web dashboard or authenticated backend service.
Create Org
Creates a new organisation. The authenticated user automatically becomes the owner. Envelope derives a URL-safe slug from the name — it must be unique across all orgs.
curl -X POST https://openenvelope.org/api/orgs \
--cookie "envelope_session=<token>" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Corp" }'{
"org": {
"id": "org_abc",
"name": "Acme Corp",
"slug": "acme-corp",
"plan": "free",
"createdAt": "2026-04-24T00:00:00.000Z"
}
}List My Orgs
Returns all organisations the authenticated user belongs to, along with their role in each.
curl https://openenvelope.org/api/orgs/mine \ --cookie "envelope_session=<token>"
{
"orgs": [
{
"role": "owner",
"org": { "id": "org_abc", "name": "Acme Corp", "slug": "acme-corp", "plan": "pro", ... }
},
{
"role": "member",
"org": { "id": "org_def", "name": "Partner Inc", "slug": "partner-inc", "plan": "free", ... }
}
]
}Get Org
Returns full details for a single org including member count, recent templates, and the caller's role. Requires membership.
curl https://openenvelope.org/api/orgs/acme-corp \ --cookie "envelope_session=<token>"
{
"org": {
"id": "org_abc",
"name": "Acme Corp",
"slug": "acme-corp",
"plan": "pro",
"billingEmail": "[email protected]",
"avatarUrl": null,
"governanceEnabled": true,
"currentPeriodEnd": "2026-05-01T00:00:00.000Z",
"cancelAtPeriodEnd": false
},
"memberCount": 4,
"recentTemplates": [ ... ],
"myRole": "owner" // "owner" | "admin" | "member"
}Update Org
Updates the org's name, billing email, or avatar URL. Requires owner or admin role. All fields are optional — only supplied fields are updated.
curl -X PATCH https://openenvelope.org/api/orgs/acme-corp \
--cookie "envelope_session=<token>" \
-H "Content-Type: application/json" \
-d '{ "billingEmail": "[email protected]" }'{ "org": { ... } } // Updated org objectDelete Org
Permanently deletes the organisation. Templates owned by the org revert to personal ownership rather than being deleted. Requires owner role.
Irreversible
All members are removed, all invitations are cancelled, and all org-level API keys are revoked. Templates are not deleted — they revert to personal ownership.
curl -X DELETE https://openenvelope.org/api/orgs/acme-corp \ --cookie "envelope_session=<token>"
{ "ok": true }Members
List, update, and remove org members. Roles are owner, admin, and member. Owners cannot be removed via the remove-member endpoint — use the transfer endpoint first.
/api/orgs/:slug/membersList all members with their user details and role.
Requires: all members
/api/orgs/:slug/members/:userId/roleChange a member's role to admin or member. Cannot change the owner's role.
Requires: owner / admin
/api/orgs/:slug/members/:userIdRemove a member, or self-remove as a member.
Requires: owner / admin (or self)
/api/orgs/:slug/transferTransfer ownership to an existing admin. Body: { newOwnerId, confirmation (must equal org name) }.
Requires: owner
// GET /api/orgs/:slug/members
{
"members": [
{
"memberId": "mem_abc",
"role": "owner",
"joinedAt": "2026-01-01T00:00:00.000Z",
"userId": "usr_xyz",
"name": "Alice",
"handle": "alice",
"email": "[email protected]",
"avatarUrl": null
}
]
}Invitations
Send, list, and cancel pending org invitations. Invitations expire after 7 days. Sending to an already-pending email replaces the existing invite token.
/api/orgs/:slug/invitationsSend an email invitation to join the org. Body: { email, role (admin|member) }. Sends an invitation email immediately.
Requires: owner / admin
/api/orgs/:slug/invitationsList pending (not yet accepted, not expired) invitations.
Requires: owner / admin
/api/orgs/:slug/invitations/:idCancel a pending invitation by its ID.
Requires: owner / admin
Org API Keys
Org-level API keys are tied to the organisation rather than any individual user. Use these for CI/CD and shared automation so access doesn't break when people leave. The raw key is only returned once at creation — store it securely.
/api/orgs/:slug/keysList all org API keys (id, label, createdAt only — key value is never returned after creation).
Requires: all members
/api/orgs/:slug/keysCreate a new org API key. Body: { label? }. Returns the raw key — save it immediately.
Requires: owner / admin
/api/orgs/:slug/keys/:idRevoke an org API key. Immediate effect — any requests using this key will fail with 401.
Requires: owner / admin
// POST /api/orgs/:slug/keys response — save this key, it's only shown once
{
"id": "key_abc",
"key": "env_live_...",
"label": "CI deploy key",
"createdAt": "2026-04-24T00:00:00.000Z"
}Deployment Governance
When governance is enabled on an org, all new deployments require approval from an owner or admin before going live. This is a Pro-plan feature. Approval requests notify all org admins by email.
Pro plan required
These endpoints return 402 if the org is not on a Pro plan. Upgrade via Pricing or the org billing settings.
/api/orgs/:slug/settings/governanceEnable or disable deployment governance. Body: { enabled: boolean }.
Requires: owner / admin
/api/orgs/:slug/approvalsList approval requests. Filter by status: ?status=pending|approved|rejected.
Requires: all members
/api/orgs/:slug/approvalsSubmit a deployment for review. Body: { installId, templateId, templateName }. Notifies all org admins.
Requires: all members
/api/orgs/:slug/approvals/:idApprove or reject a request. Body: { status: 'approved'|'rejected', note? }. Notifies the requestor.
Requires: owner / admin
// GET /api/orgs/:slug/approvals?status=pending
{
"approvals": [
{
"id": "appr_uuid",
"orgId": "org_abc",
"installId": "inst_xyz",
"templateId": "tmpl_abc",
"templateName": "Outbound Sales Team",
"requestedBy": "usr_alice",
"requestedByEmail": "[email protected]",
"status": "pending", // pending | approved | rejected
"note": null,
"reviewedBy": null,
"reviewedByEmail": null,
"reviewedAt": null,
"createdAt": "2026-04-24T10:00:00.000Z"
}
]
}Credentials Vault
Store shared secrets (API keys, tokens, credentials) at the org level so every install in the org can use them without each operator configuring them individually. Values are encrypted at rest with AES-256-GCM. Secret values are never returned after creation.
Pro plan required
These endpoints return 402 if the org is not on a Pro plan.
/api/orgs/:slug/secretsList all secrets (keys, ids, timestamps only — values never returned).
Requires: all members
/api/orgs/:slug/secretsCreate or update a secret. Body: { key, value }. Key is normalised to UPPER_SNAKE_CASE. Upserts if the key already exists.
Requires: owner / admin
/api/orgs/:slug/secrets/:keyDelete a secret by key. Returns 204 No Content.
Requires: owner / admin
// GET /api/orgs/:slug/secrets
{
"secrets": [
{ "id": "sec_abc", "key": "OPENAI_API_KEY", "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-22T00:00:00.000Z" },
{ "id": "sec_def", "key": "SLACK_BOT_TOKEN", "createdAt": "2026-04-10T00:00:00.000Z", "updatedAt": "2026-04-10T00:00:00.000Z" }
]
}
// POST /api/orgs/:slug/secrets — create or update
{ "ok": true, "key": "OPENAI_API_KEY" }Org Billing
Manage an org's Pro subscription. The checkout endpoint creates a Stripe Checkout session (14-day free trial, card required). The portal endpoint returns a Stripe Billing Portal URL for plan changes and invoice history. All billing endpoints require owner or admin role except billing status, which is readable by all members.
/api/orgs/:slug/billing/statusReturns current plan, subscription status, trial expiry, and Pro flag. Readable by all members.
Requires: all members
/api/orgs/:slug/billing/checkoutCreates a Stripe Checkout session for upgrading to Pro. Returns { url } — redirect the user to this URL.
Requires: owner / admin
/api/orgs/:slug/billing/portalReturns a Stripe Billing Portal URL for managing payment method, cancelling, or viewing invoices.
Requires: owner / admin
/api/orgs/:slug/billing/cancelSchedules subscription cancellation at period end (no immediate effect). Returns { ok, message }.
Requires: owner only
// GET /api/orgs/:slug/billing/status
{
"plan": "pro",
"subscriptionStatus": "trialing", // "active" | "trialing" | "past_due" | "cancelled" | null
"trialEndsAt": "2026-05-18T00:00:00.000Z",
"trialDaysLeft": 14,
"hasCustomer": true,
"planUpdatedAt": "2026-05-04T00:00:00.000Z",
"isPro": true,
"isTrialing": true
}
// POST /api/orgs/:slug/billing/checkout
{ "url": "https://checkout.stripe.com/c/pay/..." }
// GET /api/orgs/:slug/billing/portal
{ "url": "https://billing.stripe.com/p/session/..." }Audit Log
Paginated audit trail of all actions taken within the org — member changes, secret creates/deletes, billing changes, governance decisions, and deployment approvals. Supports date range filtering. Returns newest events first.
Pro plan required
Returns 402 on free orgs.
curl "https://openenvelope.org/api/orgs/acme-corp/audit-log?page=1&limit=50&from=2026-05-01" \ --cookie "envelope_session=<token>"
Query parameters
pagePage number (1-based). Defaults to 1.limitRecords per page (1–100). Defaults to 50.fromISO 8601 date — only return events on or after this timestamp.toISO 8601 date — only return events on or before this timestamp.{
"events": [
{
"id": "evt_abc",
"actorId": "usr_alice",
"actorEmail": "[email protected]",
"action": "secret.created", // e.g. secret.created | member.role_changed | billing.cancel_requested
"meta": { "key": "OPENAI_API_KEY" },
"createdAt": "2026-05-03T14:22:00.000Z"
}
],
"page": 1,
"limit": 50
}Analytics
Aggregate run statistics for all templates and pipeline installs owned by the org. Returns daily totals and a per-template breakdown. Free orgs are limited to a 30-day window; Pro orgs can query up to 365 days.
curl "https://openenvelope.org/api/orgs/acme-corp/analytics?from=2026-04-01&to=2026-05-04" \ --cookie "envelope_session=<token>"
Query parameters
fromISO 8601 start date. Defaults to 30 days ago.toISO 8601 end date. Defaults to now.{
"fromDate": "2026-04-01T00:00:00.000Z",
"toDate": "2026-05-04T00:00:00.000Z",
"isPro": true,
"maxDays": 365,
"totalRuns": 1284,
"successRate": 97, // null if no runs in range
"byDay": [
{ "date": "2026-04-01", "total": 42, "success": 41 },
{ "date": "2026-04-02", "total": 38, "success": 38 },
...
],
"byTemplate": [
{ "templateId": "tmpl_abc", "name": "Outbound Sales Team", "total": 820, "success": 798 },
{ "templateId": "pipeline:inst_xyz:daily_report", "name": "daily_report › daily report", "total": 464, "success": 464 }
]
}Transfer Ownership
Transfers org ownership to another existing member. The current owner is downgraded to member. Requires a confirmation string equal to the org name to prevent accidental transfers. Only the current owner can call this.
curl -X PATCH "https://openenvelope.org/api/orgs/acme-corp/transfer" \
--cookie "envelope_session=<token>" \
-H "Content-Type: application/json" \
-d '{
"newOwnerId": "usr_bob123",
"confirmation": "Acme Corp"
}'Request body
newOwnerIdrequired
confirmationrequired
400 if it doesn't match.{ "ok": true }
// Errors:
// 400 { "error": "Confirmation must match the org name exactly" }
// 404 { "error": "Target user is not a member" }Cancel Deployment
Cancels an active install. Before marking the install as cancelled, Envelope automatically bills any unbilled usage since the last paid invoice — so the deployer is charged for work already done and the builder receives their share. Requires a session cookie.
Bill-to-date on cancel: The endpoint finds the last paid invoice's period end, counts completed runs since then, and charges the deployer if the amount is ≥ $0.50 (Stripe minimum). If there is no billable usage, the install is cancelled immediately with no charge.
A receipt email is sent to the deployer regardless of whether a charge was made.
curl -X PATCH https://openenvelope.org/api/stripe/installs/inst_xyz/cancel \ --cookie "envelope_session=<token>"
Response
// Cancelled with bill-to-date charge
{
"status": "cancelled",
"charged": true,
"amountCents": 320
}
// Cancelled — no billable usage
{
"status": "cancelled",
"charged": false,
"amountCents": 0
}Team JSON Schema
Returns the canonical JSON Schema (draft-07) for Envelope team definitions. Use this to validate team.json files locally or configure IDE tooling (VS Code, JetBrains, etc.) for autocomplete. The schema is served with a 24-hour cache header and CORS open to all origins.
curl https://openenvelope.org/api/schema/team/v1.json
VS Code tip: Add a $schema key to your team.json to get inline validation and autocomplete:
{
"$schema": "https://openenvelope.org/api/schema/team/v1.json",
"name": "My Pipeline",
"agents": [ ... ]
}Response
// Content-Type: application/schema+json
// Cache-Control: public, max-age=86400, immutable
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Envelope Team Definition",
"type": "object",
"properties": { ... }
}Webhook Trigger (no-auth)
Triggers a managed pipeline run using only the install's webhookToken — no Authorization header needed. The token IS the credential, designed for safe storage in external systems like Zapier, HubSpot workflows, Make, or n8n that need to fire a pipeline without managing API keys. The response is immediate; the run executes asynchronously. If callbackUrl is provided, Envelope POSTs the full result there when the run completes.
Finding your token: The webhookToken is returned in the My Managed Installs response. Treat it like a password — rotate it by re-deploying the install if compromised.
# Minimal — fire and forget
curl -X POST https://openenvelope.org/api/webhook/wh_abc123def456
# With context seeded into the first agent
curl -X POST https://openenvelope.org/api/webhook/wh_abc123def456 \
-H "Content-Type: application/json" \
-d '{ "inputText": "Focus on enterprise accounts in Q3" }'
# With callback — Envelope will POST the result here when done
curl -X POST https://openenvelope.org/api/webhook/wh_abc123def456 \
-H "Content-Type: application/json" \
-d '{
"inputText": "Weekly digest run",
"callbackUrl": "https://your-server.com/envelope-callback"
}'Request Body
inputTextoptional
callbackUrloptional
Immediate Response (200)
{
"runId": "e3f1a2b4-...",
"status": "queued"
}
// Errors:
// 404 { "error": "Webhook token not found" }
// 409 { "error": "Install is not ready (status: pending)" }Callback Body (POSTed to callbackUrl on completion)
{
"runId": "e3f1a2b4-...",
"installId": "inst_abc",
"status": "completed", // "completed" | "paused" | "failed"
"response": "Here is your weekly digest…",
"inputTokens": 1240,
"outputTokens": 480
}
// If the run paused at a human gate:
{
"runId": "e3f1a2b4-...",
"installId": "inst_abc",
"status": "paused",
"pausedAtGate": "review-gate",
"response": null
}Builder Earnings
Returns a breakdown of revenue earned by the authenticated builder across all their published templates. Only counts paid invoices. Requires a session cookie (available to template authors only).
curl https://openenvelope.org/api/stripe/my-earnings \ --cookie "envelope_session=<token>"
Response
{
"totalBuilderAmountCents": 4850,
"byTemplate": [
{
"templateId": "tmpl_abc",
"name": "Outreach Sequencer",
"slug": "outreach-sequencer",
"paidCount": 12,
"builderAmountCents": 3600,
"lastPaidAt": "2025-04-01T00:00:00.000Z"
},
{
"templateId": "tmpl_def",
"name": "Lead Enricher",
"slug": "lead-enricher",
"paidCount": 4,
"builderAmountCents": 1250,
"lastPaidAt": "2025-03-01T00:00:00.000Z"
}
]
}totalBuilderAmountCentsSum of all builder payouts across all templates, in cents.byTemplate[].paidCountNumber of paid invoices for this template.byTemplate[].builderAmountCentsTotal builder payout for this template, in cents. Divide by 100 for dollars.byTemplate[].lastPaidAtISO-8601 timestamp of the most recent paid invoice period start.Current User
Returns the profile of the currently authenticated session user. Useful for confirming the identity behind a session cookie or building account pages. Returns 401 if no valid session exists.
curl https://openenvelope.org/api/auth/me \ --cookie "envelope_session=<token>"
Response
{
"id": "a1b2c3d4",
"email": "[email protected]",
"name": "Alice Chen",
"avatarUrl": "https://avatars.githubusercontent.com/u/...",
"githubConnected": true,
"handle": "alice",
"handleLocked": false
}
// Errors:
// 401 { "error": "Not authenticated" }
// 401 { "error": "Session expired" }handleURL-safe username (e.g. alice). null if not yet set.handleLockedtrue once the handle has been changed once — it cannot be changed again via the API.githubConnectedWhether a GitHub OAuth identity is linked to this account.Set Handle
Sets the authenticated user's public handle (URL-safe username). Handles are one-time changes — once set, they cannot be updated again via the API. The handle is lowercased, stripped of invalid characters, and truncated to 24 characters. Returns 409 if already taken by another account, and 403 if the handle has already been changed once.
curl -X PATCH https://openenvelope.org/api/auth/me \
--cookie "envelope_session=<token>" \
-H "Content-Type: application/json" \
-d '{ "handle": "alice-chen" }'{ "ok": true, "handle": "alice-chen" }
// Errors:
// 400 { "error": "Handle is required" }
// 400 { "error": "Handle must be at least 2 characters" }
// 403 { "error": "Handle can only be changed once" }
// 409 { "error": "That handle is already taken" }List API Keys
Returns all personal API keys belonging to the authenticated session user, newest first. Key values are included in full — treat the response as sensitive.
curl https://openenvelope.org/api/auth/keys \ --cookie "envelope_session=<token>"
{
"keys": [
{
"id": "k1a2b3c4",
"key": "env_live_a1b2c3d4e5f6...",
"label": "Production key",
"createdAt": "2025-03-15T10:22:00.000Z"
}
]
}Create API Key
Creates a new personal API key for the authenticated session user. The raw key value is returned only on creation — it cannot be retrieved again. Keys follow the format env_live_<32 hex chars>.
curl -X POST https://openenvelope.org/api/auth/keys \
--cookie "envelope_session=<token>" \
-H "Content-Type: application/json" \
-d '{ "label": "CI/CD pipeline key" }'Request Body
labeloptional
installIdoptional
// 201 Created
{
"id": "k1a2b3c4",
"key": "env_live_a1b2c3d4e5f6...",
"label": "CI/CD pipeline key",
"installId": null,
"createdAt": "2025-05-01T12:00:00.000Z",
"note": "Store this key securely — it will not be shown again."
}Delete API Key
Permanently revokes an API key. Any integrations using the deleted key will immediately lose access. Returns 204 No Content on success.
curl -X DELETE https://openenvelope.org/api/auth/keys/k1a2b3c4 \ --cookie "envelope_session=<token>"
// 204 No Content (empty body on success)
// Errors:
// 404 { "error": "Key not found" }
// 403 { "error": "Forbidden" }Resolve Key Identity
Resolves an API key to the name of its owner and their primary organization. Useful in deploy wizards, CLI tools, or onboarding flows where you want to confirm the key belongs to the expected user before proceeding. Requires a valid API key in the Authorization header.
curl https://openenvelope.org/api/auth/key-identity \ -H "Authorization: Bearer $ENVELOPE_KEY"
Response
{
"userName": "Alice Chen",
"orgName": "Acme Corp",
"orgSlug": "acme-corp"
}
// Key with no org membership:
{
"userName": "Alice Chen",
"orgName": null,
"orgSlug": null
}
// Errors:
// 401 { "error": "Invalid API key" }