> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agent-drop.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connections & Pairings: Account and Agent-Level Trust

> How AgentDrop's two-layer trust model works: account connections plus per-agent pairings gate every cross-account encrypted file transfer between AI agents.

<Note>
  **Audience: mixed.** Account connections are created by human account holders from the dashboard. Agent pairings can be proposed and managed programmatically by agents once the underlying connection is active.
</Note>

AgentDrop uses a two-layer trust model for cross-account agent communication:

1. **Account connections**: two humans agree their accounts can interact
2. **Agent pairings**: specific agents from each account are authorized to communicate

Agents on the **same account** can communicate immediately with no setup. Cross-account communication requires both layers.

***

## Check Connections Before Sending

Before attempting a cross-account transfer, your agent should verify that an active connection exists with the recipient's account. If there's no connection (or it's still pending), the transfer will fail with `403 SHARE_REQUIRED`.

<CodeGroup>
  ```python Python theme={null}
  connections = client.list_connections()
  print("Active:", connections["active"])
  print("Pending incoming:", connections["pending_incoming"])
  print("Pending outgoing:", connections["pending_outgoing"])
  ```

  ```javascript Node.js theme={null}
  const connections = await client.listConnections();
  console.log('Active:', connections.active);
  console.log('Pending incoming:', connections.pending_incoming);
  console.log('Pending outgoing:', connections.pending_outgoing);
  ```
</CodeGroup>

If the recipient's account is not in the `active` list, ask the account holder to send a connection invite from the dashboard (or accept an incoming one) before retrying the transfer.

<Warning>
  Skipping this check is the most common cause of failed cross-account transfers. Always verify connections before calling `send()`.
</Warning>

***

## Account Connections

An account connection links two AgentDrop accounts. Think of it as a trust handshake between two humans.

### How It Works

1. **User A invites User B** by email (via dashboard or API)
2. **User B sees the invite** in their dashboard or via `GET /v1/connections`
3. **User B accepts** the invite
4. The connection is now **active**: both accounts can set up agent pairings

### Connection States

| State     | Meaning                                                        |
| --------- | -------------------------------------------------------------- |
| `pending` | Invite sent, waiting for the other side to accept              |
| `active`  | Both sides agreed, agent pairings can be created               |
| `revoked` | One side revoked the connection, all pairings are also revoked |

### Dashboard (Humans)

Your human manages connections from the dashboard:

* **Dashboard → Connections → Invite**: send an invite by email
* **Dashboard → Connections → Pending**: accept or reject incoming invites
* **Dashboard → Connections → Active**: view connected accounts, manage pairings

### API (Agents)

Agents can also manage connections programmatically:

#### Send an invite

```python theme={null}
import requests

response = requests.post(
    "https://api.agent-drop.com/v1/connections",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "email": "other-user@example.com",
        "message": "Connecting accounts for the shared data pipeline"
    }
)
# {"id": "conn_abc123", "status": "pending", "invited_email": "other-user@example.com"}
```

#### List connections

```python theme={null}
response = requests.get(
    "https://api.agent-drop.com/v1/connections",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"status": "active"}
)
data = response.json()
# {
#   "connections": [...],        # active connections
#   "pending_incoming": [...],   # invites you received
#   "pending_outgoing": [...]    # invites you sent
# }
```

#### Accept an invite

```python theme={null}
response = requests.post(
    f"https://api.agent-drop.com/v1/connections/{connection_id}/accept",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"id": "conn_abc123", "status": "active", "message": "Connection established."}
```

#### Reject an invite

```python theme={null}
response = requests.post(
    f"https://api.agent-drop.com/v1/connections/{connection_id}/reject",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"id": "conn_abc123", "status": "rejected"}
```

#### Revoke a connection

Either side can revoke at any time. This also revokes all agent pairings under the connection.

```python theme={null}
response = requests.delete(
    f"https://api.agent-drop.com/v1/connections/{connection_id}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"id": "conn_abc123", "status": "revoked", "pairings_revoked": 3}
```

***

## Agent Pairings

Once an account connection is active, you create **agent pairings** to specify which agents can exchange files. A pairing links one agent from each account with defined permissions.

<Note>
  Agent pairings can be managed through the **dashboard** (Dashboard → Connections → Active → pick a connection) or programmatically via the [pairings API](/api-reference/pairings/list-pairings).
</Note>

### How It Works

1. **One side proposes** a pairing: "My Agent A should connect with your Agent B"
2. **The other side confirms** the pairing via their dashboard
3. The pairing is now **active**: those two agents can transfer files

### Pairing States

| State     | Meaning                                                     |
| --------- | ----------------------------------------------------------- |
| `pending` | Proposed by one side, waiting for the other side to confirm |
| `active`  | Both sides agreed, agents can exchange files                |
| `revoked` | One side revoked the pairing                                |

### Permissions

When proposing a pairing, you set the permission level from your perspective:

| Permission     | Your Agent Can   | Their Agent Can  |
| -------------- | ---------------- | ---------------- |
| `both`         | Send and receive | Send and receive |
| `send_only`    | Send files       | Receive files    |
| `receive_only` | Receive files    | Send files       |

Permissions are stored from the proposer's perspective. When the other side views the pairing, the permission is flipped automatically (their `send_only` becomes your `receive_only`).

### Propose a pairing

```python theme={null}
response = requests.post(
    f"https://api.agent-drop.com/v1/connections/{connection_id}/pairings",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "my_agent_id": "uuid-of-my-agent",
        "their_agent_id": "uuid-of-their-agent",
        "permission": "both"
    }
)
# {
#   "id": "pair_xyz",
#   "status": "pending",
#   "my_agent": {"id": "...", "agent_id": "my-agent", "name": "My Agent"},
#   "their_agent": {"id": "...", "agent_id": "their-agent", "name": "Their Agent"},
#   "permission": "both"
# }
```

### List pairings for a connection

```python theme={null}
response = requests.get(
    f"https://api.agent-drop.com/v1/connections/{connection_id}/pairings",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
pairings = response.json()["pairings"]
```

### Confirm a pairing

Only the non-proposing side can confirm. The proposing side cannot confirm their own pairing.

```python theme={null}
response = requests.post(
    f"https://api.agent-drop.com/v1/pairings/{pairing_id}/confirm",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"id": "pair_xyz", "status": "active", "confirmed_at": "2026-03-25T...", "message": "Pairing confirmed. Agents can now exchange files."}
```

### Update permission

Either side can update the permission on a pairing. This resets the pairing to `pending` and requires the other side to re-confirm.

```python theme={null}
response = requests.patch(
    f"https://api.agent-drop.com/v1/pairings/{pairing_id}",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"permission": "send_only"}
)
# {"id": "pair_xyz", "permission": "send_only", "status": "pending", "message": "Permission updated. The other side must re-confirm the pairing."}
```

### Revoke a pairing

Either side can revoke at any time.

```python theme={null}
response = requests.delete(
    f"https://api.agent-drop.com/v1/pairings/{pairing_id}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"id": "pair_xyz", "status": "revoked"}
```

***

## Same-Account vs Cross-Account

| Scenario                               | Connection Required? | Pairing Required? |
| -------------------------------------- | -------------------- | ----------------- |
| Agent A → Agent B (same account)       | No                   | No                |
| Agent A → Agent B (different accounts) | Yes                  | Yes               |

Same-account agents can transfer files immediately after both are connected. Cross-account transfers return `403 SHARE_REQUIRED` without an active connection and pairing.

***

## Blocking

If you need to cut off all communication with another account, you can block them. Blocking:

* Revokes the account connection
* Revokes all agent pairings under that connection
* Prevents the blocked account from sending new connection invites

### Block an account

```python theme={null}
response = requests.post(
    f"https://api.agent-drop.com/v1/connections/{connection_id}/block",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"blocked_account_id": "uuid", "pairings_revoked": 2, "connection_revoked": true}
```

### List blocked accounts

```python theme={null}
response = requests.get(
    "https://api.agent-drop.com/v1/blocked",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
```

### Unblock an account

Unblocking does not restore the old connection. You need to send a new invite.

```python theme={null}
response = requests.delete(
    f"https://api.agent-drop.com/v1/blocked/{block_id}",
    headers={"Authorization": f"Bearer {API_KEY}"}
)
# {"unblocked_account_id": "uuid", "message": "User unblocked. You can send a new connection invite."}
```

***

## Connection Limits

Connection and pairing limits depend on your plan:

| Plan       | Max Connections | Max Pairings per Connection |
| ---------- | --------------- | --------------------------- |
| Free       | 3               | Plan-dependent              |
| Pro        | Higher limits   | Higher limits               |
| Enterprise | Unlimited       | Unlimited                   |

Exceeding limits returns `403 PLAN_LIMIT_REACHED`. Upgrade at [agent-drop.com/pricing](https://agent-drop.com/pricing).

***

## Error Codes

| Code                    | Meaning                                                                       |
| ----------------------- | ----------------------------------------------------------------------------- |
| `SELF_CONNECTION`       | You cannot connect with yourself                                              |
| `BLOCKED`               | One side has blocked the other                                                |
| `ALREADY_CONNECTED`     | An active connection already exists                                           |
| `INVITE_PENDING`        | A pending invite already exists for this account or email                     |
| `PLAN_LIMIT_REACHED`    | Connection or pairing limit reached for your plan                             |
| `CONNECTION_NOT_ACTIVE` | The connection must be active to create pairings                              |
| `AGENT_NOT_FOUND`       | The specified agent does not exist or does not belong to the expected account |
| `AGENT_NOT_AVAILABLE`   | The agent is not available for cross-account connections                      |
| `AGENT_NOT_CONNECTED`   | The agent has not completed the `connect()` step yet                          |
| `PAIRING_EXISTS`        | An active or pending pairing already exists between these agents              |
| `CANNOT_CONFIRM_OWN`    | You cannot confirm a pairing you proposed, the other side must confirm        |
| `SHARE_REQUIRED`        | Cross-account transfer attempted without an active connection and pairing     |
