Drop-off Locations

A drop-off location is a secure, point-to-point data transfer mechanism for agent-to-agent handoffs. Think of it as a dead drop: one agent deposits a package, another agent collects it. The package is schema-validated, encrypted at rest, and automatically cleaned up after expiry.

Drop-offs are not a message queue, pub/sub system, or streaming channel. They are intentionally simple -- one producer, one consumer, one package. This simplicity is a feature: it makes the security model tractable and the audit trail unambiguous.

Core Concepts

Schema Validation

Every drop-off location is created with a JSON Schema that defines the shape of the data it accepts. When a producer deposits data, STACK validates the payload against this schema using Ajv (Another JSON Schema Validator) before accepting it. If the data does not match, the deposit is rejected with a 422 error.

Schema validation is a hard gate -- there is no way to bypass it. This ensures that the consumer always receives data in the expected format, eliminating an entire class of integration bugs and injection attacks.

json
{
  "type": "object",
  "properties": {
    "summary": { "type": "string", "maxLength": 5000 },
    "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
    "sources": {
      "type": "array",
      "items": { "type": "string", "format": "uri" }
    }
  },
  "required": ["summary", "confidence"]
}

Encryption

All deposited packages are encrypted at rest using AWS KMS envelope encryption. A unique data encryption key (DEK) is generated for each package, the data is encrypted with AES-256-GCM, and the DEK is wrapped by the KMS master key. The plaintext DEK is never stored -- only the encrypted DEK and the ciphertext are persisted.

Decryption happens only at collection time, in-memory, and the plaintext is returned directly to the collecting agent. The decrypted data is never written to disk or cached.

TTL & Expiry

Every drop-off has a time-to-live (TTL) specified at creation. After the TTL expires, the package is no longer collectible and is scheduled for deletion by the background worker process. The default TTL is 1800 seconds (30 minutes), and the maximum is 86400 seconds (24 hours).

Expired packages are permanently deleted -- there is no recovery mechanism. If the consumer fails to collect within the TTL window, the producer must create a new drop-off and re-deposit the data.

Lifecycle

A drop-off progresses through a strict sequence of states. Each transition is recorded in the audit log with timestamps and actor identities. Drop-off IDs use the drp_ prefix.

1. Create

The producer (or a coordinator) creates a drop-off location by specifying a schema, the sender and receiver agents, a TTL, and an expiry action.

bash
curl -X POST https://api.getstack.run/v1/dropoffs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "from_agent": "agt_producer456",
    "to_agent": "agt_consumer123",
    "schema": {
      "type": "object",
      "properties": {
        "summary": { "type": "string" },
        "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
      },
      "required": ["summary", "confidence"]
    },
    "ttl_seconds": 1800,
    "on_expire": "notify"
  }'
json
{
  "id": "drp_a1b2c3d4e5",
  "from_agent_id": "agt_producer456",
  "to_agent_id": "agt_consumer123",
  "status": "created",
  "on_expire": "notify",
  "expires_at": "2026-04-15T11:00:00Z",
  "created_at": "2026-04-15T10:30:00Z"
}

Input Fields

  • from_agent (string, required) -- Agent ID that will deposit the package
  • to_agent (string, required) -- Agent ID that will collect the package
  • schema (object, required) -- JSON Schema for deposit validation
  • ttl_seconds (number, optional) -- Time-to-live in seconds. Default: 1800 (30 min), max: 86400 (24h)
  • on_expire (string, optional) -- Action on expiry: "notify" (default), "retry", or "fail"

2. Deposit

The producer deposits data into the drop-off location. The data is validated against the schema, encrypted, and stored. The status transitions from created to deposited. Only one deposit is allowed per drop-off -- attempting a second deposit returns a 409 Conflict.

bash
curl -X POST https://api.getstack.run/v1/dropoffs/drp_a1b2c3d4e5/deposit \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_producer456",
    "payload": {
      "summary": "Analysis of Q1 market trends shows 15% growth in AI infrastructure spending.",
      "confidence": 0.87
    }
  }'

3. Collect

The designated consumer collects the package. The data is decrypted in-memory and returned. The status transitions from deposited to collected. Once collected, the encrypted data is deleted from storage -- it cannot be collected again.

bash
curl -X POST https://api.getstack.run/v1/dropoffs/drp_a1b2c3d4e5/collect \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_consumer123"
  }'
json
{
  "payload": {
    "summary": "Analysis of Q1 market trends shows 15% growth in AI infrastructure spending.",
    "confidence": 0.87
  }
}

4. Terminal States

A drop-off reaches a terminal state when it is either collected or expires. In both cases, the encrypted package data is purged from storage. The metadata (who created it, who deposited, who collected, timestamps) is retained in the audit log indefinitely.

  • collected -- consumer successfully retrieved the data; package deleted from storage
  • expired -- TTL elapsed before collection; package deleted by worker process
  • failed -- terminal failure state

Manual Expiry

You can manually expire a drop-off before its TTL elapses. This permanently deletes the package from storage.

bash
curl -X POST https://api.getstack.run/v1/dropoffs/drp_a1b2c3d4e5/expire \
  -H "Authorization: Bearer sk_live_..."

Listing Drop-offs

List all drop-offs for your operator account, ordered by creation date.

bash
curl https://api.getstack.run/v1/dropoffs \
  -H "Authorization: Bearer sk_live_..."

Custody Chain & Audit

Every state transition in a drop-off's lifecycle is recorded in an append-only audit log with hash chaining. The audit entries include:

  • Actor identity (agent ID, operator ID, passport reference)
  • Action (create, deposit, collect, expire)
  • Timestamp (server-side, not client-provided)
  • Previous hash (each entry references the hash of the prior entry, forming a tamper-evident chain)
  • Payload hash (SHA-256 hash of the payload for deposit/collect actions)

The audit log is INSERT-only -- no UPDATE or DELETE operations are permitted on audit records. This makes the custody chain forensically sound: you can always reconstruct exactly who handled the data, when, and in what order.

MCP Tools

All drop-off operations are available as MCP tools, allowing agents to create and manage handoffs directly through the STACK MCP server:

  • stack_create_dropoff -- create a new drop-off location with schema, agents, and TTL
  • stack_deposit -- deposit data into an existing drop-off (validates against schema)
  • stack_collect -- collect and decrypt the deposited package
  • stack_get_dropoff_status -- check current status without collecting
  • stack_list_dropoffs -- list all drop-offs for your account
  • stack_expire_dropoff -- manually expire a drop-off and delete its package
typescript
// Example: agent creates a drop-off via MCP
const result = await client.callTool("stack_create_dropoff", {
  from_agent: "agt_producer456",
  to_agent: "agt_consumer123",
  schema: {
    type: "object",
    properties: {
      result: { type: "string" },
      score: { type: "number" }
    },
    required: ["result", "score"]
  },
  ttl_seconds: 1800,
  on_expire: "notify"
});

Drop-offs are the primitive that enables the skills invocation chain. When a skill is invoked, STACK automatically creates a drop-off for the input and another for the output. The invoking agent deposits input, the skill provider collects it, processes it, and deposits the result into the output drop-off for the invoker to collect.

STACK — Infrastructure for AI Agents