STACK
MENU
DOCS / GUIDES / MULTI-AGENT HANDOFF

Guide: Multi-Agent Handoff

Use a drop-off to pass one schema-validated payload between two agents that belong to the same operator. The producer deposits it. The named consumer collects it once.

Fleet authorization

For fleet agents, include the required dropoff operations in each Mission’s requested_operations. Specify create, deposit or collect and the exact participating agent permitted by policy. Send the Mission Passport and a stable operation ID on each call. Producer and consumer authentication, payload validation and one-time collection still apply.

1. Start a Mission for each agent

bash
curl -X POST "https://api.getstack.run/v1/missions/start" \
  -H "Authorization: Bearer $STACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_researcher",
    "mission": { "intent_summary": "Hand supplier findings to the writer" }
  }'

Repeat for agt_writer. Each response carries the agent's Passport in passport.token. Every drop-off call made for an agent sends that agent's Passport. An agent without one is refused with 403.

2. Create the drop-off

bash
curl -X POST "https://api.getstack.run/v1/dropoffs" \
  -H "Authorization: Bearer $STACK_API_KEY" \
  -H "X-Passport-Token: $RESEARCHER_PASSPORT" \
  -H "Content-Type: application/json" \
  -d '{
    "from_agent": "agt_researcher",
    "to_agent": "agt_writer",
    "schema": {
      "type": "object",
      "required": ["topic", "findings"],
      "properties": {
        "topic": { "type": "string" },
        "findings": { "type": "array", "items": { "type": "string" } }
      }
    },
    "ttl_seconds": 1800,
    "on_expire": "notify"
  }'

The default TTL is 30 minutes. The accepted range is 60 seconds to 24 hours. Both agent IDs must belong to the authenticated operator.

3. Deposit as the producer

bash
curl -X POST "https://api.getstack.run/v1/dropoffs/dof_abc/deposit" \
  -H "Authorization: Bearer $STACK_API_KEY" \
  -H "X-Passport-Token: $RESEARCHER_PASSPORT" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_researcher",
    "payload": {
      "topic": "Q2 supplier audit",
      "findings": [
        "Vendor A invoices are 12% above the comparison set.",
        "Vendor B delivered 94% of orders on time."
      ]
    }
  }'

STACK checks that agent_id is the declared producer. It validates the payload, stores an encrypted copy, and records its SHA-256 hash in the audit entry.

4. Collect as the consumer

bash
curl -X POST "https://api.getstack.run/v1/dropoffs/dof_abc/collect" \
  -H "Authorization: Bearer $STACK_API_KEY" \
  -H "X-Passport-Token: $WRITER_PASSPORT" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "agt_writer" }'
json
{
  "payload": {
    "topic": "Q2 supplier audit",
    "findings": [
      "Vendor A invoices are 12% above the comparison set.",
      "Vendor B delivered 94% of orders on time."
    ]
  }
}

A successful collection deletes the encrypted payload from the drop-off row. The row keeps its status, hash, and timestamps for the audit trail. Complete each agent's Mission when its part is done.

5. Handle terminal states

  • SCHEMA_VALIDATION_FAILED: correct the payload before the drop-off expires.
  • FORBIDDEN: use the declared producer for deposit or the declared consumer for collect, with that agent’s live Mission Passport.
  • DROPOFF_ALREADY_COLLECTED: do not reuse the drop-off.
  • DROPOFF_EXPIRED: create a new drop-off and deposit again.

The expiry worker marks overdue drop-offs as expired and removes any stored payload.

6. Build a longer handoff

Create one drop-off per hop. Give each hop its own producer, consumer, schema, and TTL. This keeps each transfer independently scoped and auditable.

stack | Docs