STACK
MENU
DOCS / API REFERENCE / MISSIONS

Missions API

These routes require authentication. A worker can open and run Missions within its approved fleet policy. STACK returns 404 for another operator's Mission or a Mission the calling agent cannot access.

Missions are available on every plan. Every Passport is issued for exactly one Mission. Opening a Mission is free; issuing its Passport is metered.

Start a Mission

POST /v1/missions/start opens a Mission and issues its Passport in one call. It has two forms: the operator form for one of your agents, and the fleet form for fleet workers. The call counts once, as the Passport issue.

Operator form

Operator API keys, dashboard sessions, white-label tenant keys and partner Connect grants use this form. An agent can also use it for itself. A partner grant needs both missions:write and passports:write, and agent_id must name an agent the grant created. Agents in a fleet use the fleet form.

bash
curl -X POST https://api.getstack.run/v1/missions/start \
  -H "Authorization: Bearer $STACK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_7kx9m2nq4p",
    "mission": {
      "intent_summary": "Reconcile August invoices",
      "intent_services": ["stripe"],
      "max_actions": 200,
      "expires_in_seconds": 3600
    },
    "passport": { "ttl_seconds": 900 }
  }'
  • agent_id (string, required) - The agent the Mission is assigned to and the Passport is issued for, prefixed agt_.
  • mission (object, required) - The POST /v1/missions body without agent_id. intent_summary is required.
  • passport (object, optional) - POST /v1/passports/issue fields such as scopes, ttl_seconds, intent, session_id, checkpoint_interval_seconds, identity_claim_ids and authority_binding_ids. Do not pass agent_id or mission_ids. When intent is omitted, it defaults to the Mission's intent_summary and intent_services.

Response - 201 Created:

json
{
  "mission_id": "ms_4hT9pQ2xVn",
  "claim_id": "pc_...",
  "expires_at": "2026-10-01T11:30:00.000Z",
  "passport": {
    "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
    "jti": "ppt_9xm3kR7wL2",
    "expires_at": "2026-10-01T10:45:00.000Z"
  }
}

If issuance fails, STACK revokes the just-opened Mission and returns the error.

Fleet form

POST /v1/missions/start with fleet_policy_id accepts fleet_policy_id, idempotency_key, intent_summary, requested_access, requested_operations and limits. It checks the request against the live fleet policy and returns mission_id, policy_id, policy_revision and a Passport. Reuse the idempotency key only for the same job request.

Each requested_access entry names a connection_id and exact scopes. Named intents or constraints limit the action and its parameters, such as a Slack channel. requested_operations covers Skills, A2A tasks and Drop-offs with an exact target and action. These requests may narrow the fleet policy's permission.

Fleet start request fields

  • fleet_policy_id (string, required) - Approved fleet policy ID, prefixed flp_.
  • idempotency_key (string, required) - 8 to 128 characters. Reuse for the same job request.
  • intent_summary (string, required) - 1 to 500 characters describing the job.
  • requested_access (array, optional) - Up to 32 connection access entries. Each connection_id must be unique. Defaults to [].
  • requested_operations (array, optional) - Up to 32 operation access entries. Defaults to []. At least one requested access or operation entry is required.
  • limits (object, required) - Mission limits using the limits fields below.
  • expected_output_shape (object, optional) - JSON Schema for the output supplied when completing the Mission.
  • authority_binding_ids (string[], optional) - Up to 8 authority binding IDs, each prefixed abn_.

Open a Mission

POST /v1/missions

bash
curl -X POST https://api.getstack.run/v1/missions \
  -H "Authorization: Bearer $STACK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_7kx9m2nq4p",
    "intent_summary": "Reconcile August invoices",
    "intent_services": ["stripe", "quickbooks"],
    "expected_counterparties": ["acct_123"],
    "max_actions": 200,
    "coverage_cap_cents": 5000,
    "max_duration_seconds": 3600,
    "cap_behavior": { "max_actions": "auto_revoke" }
  }'

The response contains mission_id, the signed Mission claim_id, and expires_at.

A Mission bounds the job; it is not a mandate. An authority binding can pin the Mission ID, and a Passport can carry both mission_ids and opaque authority_refs. See Authority API.

agent_id (string, optional) assigns the Mission to one of your agents, prefixed agt_. A partner grant must pass the ID of an agent it created, and can then complete, revoke and read only those Missions. An agent caller is always assigned itself. If you pass passport_jti, it must belong to your account and to the assigned agent. Opening a Mission is free.

To issue the Passport as a separate step, pass the Mission ID to POST /v1/passports/issue as mission_ids: ["ms_..."]. The Mission must be live and assigned to that agent or unassigned. POST /v1/missions also accepts the fleet request when opening and issuing are separate steps.

Read Missions

  • GET /v1/missions - list Missions. Filter with status, page, and limit.
  • GET /v1/missions/:id - return the Mission and current cap_usage.
  • GET /v1/missions/:id/replay - reconstruct its signed event timeline.
  • GET /v1/missions/:id/dossiers - list human dossier revisions in issue order.

GET /v1/missions/:id includes the approved connection access, operation targets and Mission usage under fleet. It also shows the fleet's current policy revision and shared limits.

Renew a Mission

POST /v1/missions/:id/renew returns a fresh Passport for the existing Mission. Renewal checks the current agent key, membership and policy. It keeps the Mission's original permissions, limits, deadline and usage.

Complete or revoke

bash
curl -X POST https://api.getstack.run/v1/missions/ms_123/complete \
  -H "Authorization: Bearer $STACK_TOKEN" -H "Content-Type: application/json" \
  -d '{"output":{"reconciled":42}}'

curl -X POST https://api.getstack.run/v1/missions/ms_123/revoke \
  -H "Authorization: Bearer $STACK_TOKEN" -H "Content-Type: application/json" \
  -d '{"reason":"adversarial","notes":"Unexpected recipient"}'

Repeating the same terminal transition is safe. An incompatible second transition returns 409. A revoke can use adversarial or operator_initiated_clean.

Completing or revoking a Mission, with either reason, revokes every Passport bound to it in the same transaction. Refresh and delegation of those Passports then fail.

When a Mission declares an output schema, successful completion requires matching output. STACK stores the output encrypted and signs a salted digest in the completion claim. Authorized callers can retrieve the output, salt and digest from GET /v1/missions/:id. Changing the encryption key leaves the signed claim intact.

Author a dossier

POST /v1/missions/:id/dossier

This route requires a same-operator member principal, such as a member OAuth session. Agent JWTs, Passports, partner grants, owner OAuth tokens and operator API keys cannot author it.

The body accepts narrative, optional decision-tree and alert detail, lessons_learned, and an incident classification. The Enterprise entitlement is enforced when STACK creates the signed claim.

Operator reviews use separate routes and a stricter dashboard-session rule. See Evidence API.

Fleet policies and enrollment

List routes accept page and limit and return items, page, limit, total and has_more. Without pagination parameters they return arrays.

GET /v1/fleets/:id

Read one fleet policy and its shared usage. The response includes policy, usage, window_started_at and window_seconds. Usage includes actions, concurrent_actions, reserved_spend_cents, dropoff_bytes and unknown_actions.

GET /v1/fleets/membership/:agentId

Read the fleet policy an agent belongs to. The response includes policy_id, policy_name, revision, membership_id, identity_expires_at, revoked_at, policy_status and policy_expires_at, or null when the agent has no fleet membership. Fleet reads require operator-admin access.

Membership response fields

  • policy_id (string) - Fleet policy ID.
  • policy_name (string) - Fleet policy name.
  • revision (integer) - Current policy revision.
  • membership_id (string) - Agent membership ID.
  • identity_expires_at (string) - Worker identity expiry timestamp.
  • revoked_at (string or null) - Membership revocation timestamp.
  • policy_status (string) - Current policy status.
  • policy_expires_at (string) - Policy expiry timestamp.

GET /v1/fleets

List fleet policies.

POST /v1/fleets

Request approval for a policy and activate it after approval. Supply Idempotency-Key. Retry the same body with X-Governance-Approval.

Policy request fields

  • name (string, required) - 1 to 128 characters.
  • rules (array, optional) - Up to 64 connection rules. Each contains id, effect and access. Defaults to [].
  • operation_rules (array, optional) - Up to 64 operation rules. Each contains id, effect and access. Defaults to [].
  • limits (object, required) - Shared fleet limits using the limits fields below.
  • window_seconds (integer, required) - Usage window from 60 to 2,678,400 seconds.
  • max_members (integer, required) - Membership limit from 1 to 100,000.
  • max_enrollments_per_hour (integer, required) - Enrollment limit from 1 to 100,000 per hour.
  • identity_lease_seconds (integer, required) - Worker identity lease from 60 to 86,400 seconds.
  • provisioner_agent_ids (string[], optional) - Up to 64 approved provisioner agent IDs, each prefixed agt_. Defaults to [].
  • workload_trust (array, optional) - Up to 16 workload trust entries. Defaults to []. At least one provisioner or workload trust entry is required.
  • allow_delegation (boolean, optional) - Whether fleet agents may delegate. Defaults to false.
  • expires_at (string, required) - Policy expiry as an ISO 8601 UTC timestamp.

Rule fields

  • id (string, required) - 1 to 128 letters, digits, underscores, periods or hyphens. IDs must be unique across rules and operation_rules. At least one rule is required.
  • effect (string, required) - allow, review or deny.
  • access (object, required) - Connection access for rules, or operation access for operation_rules.

Connection access fields

  • connection_id (string, required) - Exact connected account ID, prefixed scon_.
  • scopes (string[], required) - 1 to 64 exact scope names, each 1 to 128 characters. The value * is not allowed.
  • intents (array, optional) - Up to 32 entries containing name and params. Each name is 1 to 128 characters. params defaults to {}. Defaults to [].
  • constraints (array, optional) - Up to 32 constraints containing path, op and value. Defaults to [].
  • allow_data_from (string[], optional) - Up to 64 source names, each 1 to 128 characters. The value * is not allowed. Defaults to [].

Operation access fields

  • producer (string, required) - skill, a2a or dropoff.
  • action (string, required) - invoke for skill, tasks/send for a2a, or create, deposit or collect for dropoff.
  • target_id (string, required) - Exact target ID, 1 to 128 letters, digits, underscores, periods or hyphens.
  • constraints (array, optional) - Up to 32 constraints containing path, op and value. Defaults to [].

Workload trust fields

  • kind (string, required) - spiffe or wimse.
  • issuer (string, required) - Trusted issuer, 1 to 512 characters.
  • audience (string, required) - Exact expected audience, 1 to 512 characters.
  • subjects (string[], required) - 1 to 256 exact subjects, each 1 to 1,024 characters.

Limits fields

  • max_actions (integer, required) - 1 to 1,000,000 actions.
  • max_concurrent_actions (integer, required) - 1 to 10,000 concurrent actions.
  • max_duration_seconds (integer, required) - 1 to 86,400 seconds.
  • max_dropoff_bytes (integer, optional) - 0 to 9,007,199,254,740,991 bytes.
  • max_spend_cents (integer, optional) - 0 to 100,000,000 cents.

PUT /v1/fleets/:id

Revise an approved policy. Supply If-Match with its current revision, Idempotency-Key and the approval header.

POST /v1/fleets/:id/revoke

Revoke the fleet's permission to continue work.

GET /v1/fleets/:id/members

List enrolled agents and their identity expiry.

Member response fields

  • id (string) - Membership ID.
  • agent_id (string) - Enrolled agent ID.
  • agent_name (string) - Enrolled agent name.
  • identity_expires_at (string) - Worker identity expiry timestamp.
  • revoked_at (string or null) - Membership revocation timestamp.

POST /v1/fleets/:id/members/:agentId/revoke

Revoke one agent's fleet membership.

POST /v1/fleets/:id/enrollment-challenges

Request a challenge as an approved provisioner.

POST /v1/fleets/:id/enroll

Enroll or renew a worker using its public key, signed challenge and stable enrollment key. Key rotation also requires previous_key_proof from its old key.

POST /v1/fleets/:id/workload/enrollment-challenges

Request a challenge with a workload token from the policy's trusted issuer.

POST /v1/fleets/:id/workload/enroll

Enroll or renew a worker with that workload identity and its signed key proof.

POST /v1/fleets/session

Exchange a fresh agent proof for an MCP session lasting up to five minutes. Workers send an empty body. Provisioners include fleet_policy_id.

To replace a worker key, send the original name and enrollment idempotency key, the new public key and its signed challenge. Also supply previous_key_proof, signed by the old key. It covers canonical JSON containing domain=stack:fleet-key-rotation:v1, challenge_id, challenge, policy_id, idempotency_key and the new key's SHA-256 RFC 7638 public_key_thumbprint. Encode the signature as base64url. Local enrollment helpers retain the existing key. Use enroll or enrollWorkload when managing rotation yourself.

stack | Docs