# Ultra Agent Exchange API

Base URL: https://ultra-dev.egomonk.com

Ultra is agent-first by design. Human browser UX exists as bootstrap/supervisor fallback.

## Protocol model (north star)

Core nouns:
- Agent
- Share
- Grant

Core verbs:
- upload -> `POST /api/upload`
- turbo multipart -> `/api/upload/multipart/*`
- tus resumable -> `/api/tus`
- import -> `POST /api/import-url`
- resolve -> `GET /api/share/{shareId}`
- grant -> `POST /api/agent/grants`
- fetch -> `GET /api/dl/{id}`

Everything else (inbox/outbox/channel/handoff) composes around these primitives.

## Transfer lanes

Ultra separates the control plane from byte movement:

- Live Pipe: default for small human-to-human transfers where both sides are present.
- Hybrid Live: live UX with durable backing for 1..10 GiB transfers.
- Turbo Multipart: native high-throughput path for 10..100 GiB transfers.
- TUS Compatibility: resumable-client adapter over multipart manifests.
- Import from URL: guarded server-side fetch for bytes already on HTTP(S).

Human docs:
- `https://ultra-dev.egomonk.com/docs/transfer-lanes.html`
- `https://ultra-dev.egomonk.com/docs/benchmarks.html`

## Auth model

- Root key: `agk_{keyId}.{secret}` (high-value)
- Short-lived access: `aat_{tokenId}.{secret}` via `POST /api/agent/auth`
- One-time data capability: `agrt_...` via `POST /api/agent/grants`

## TTL policy

- Anonymous uploads: fixed to 1800 seconds (30m)
- Authenticated uploads:
  - short agent window: 30..300 seconds
  - standard windows: 1800, 3600, 7200, 14400, 21600, 86400, 259200, 604800

## Agent-first canonical flow

```text
1) (bootstrap) human session creates agent key
2) agent exchanges agk_ -> aat_ (optional but recommended)
3) sender agent uploads with policy (open|agent + allow-list)
4) receiver agent resolves share
5) receiver agent requests one-time grant
6) receiver fetches transfer with X-Access-Grant
```

## Agent key + token endpoints

```
POST /api/agent/keys
Authorization: Bearer {sessionId}
Body: { agentId, scopes?, expiresAt? }
```
Returns: { keyId, agentId, scopes, createdAt, expiresAt?, token }

```
GET /api/agent/keys
Authorization: Bearer {sessionId}
```

```
DELETE /api/agent/keys/{keyId}
DELETE /api/agent/keys/{keyId}/purge
POST /api/agent/keys/revoke-all
Authorization: Bearer {sessionId}
```

```
POST /api/agent/auth
Authorization: Bearer agk_{keyId}.{secret}
Body: { ttlSeconds? }
```
Returns: { accessToken, tokenType, expiresAt, agentId, scopes }

```
GET /api/agent/inbox?limit=50
GET /api/agent/outbox?limit=50
Authorization: Bearer agk_{keyId}.{secret} OR aat_{tokenId}.{secret}
```

## Core transfer endpoints

```
POST /api/upload
Content-Type: multipart/form-data (or raw body + headers)
Body fields:
  file (required)
  ttl?                 (form/query/X-TTL)
  max_uses?            (positive integer, defaults to 1 for open links)
  auth_mode?           (open|agent)
  allowed_agent_ids?   (comma-separated)
  policy_metadata?     (JSON object)
```
Returns: { id, shareId, shareUrl, downloadUrl, expiresAt, deleteToken }
downloadUrl includes share_id so open-link maxUses is consumed when bytes are fetched.
Keep deleteToken private with the sender-side record; it is not embedded in share URLs.

```
POST /api/import-url
Content-Type: application/json
Body:
  url                 (required, http(s), SSRF-guarded)
  filename?           (override imported filename)
  mimeType?           (override imported content type)
  ttl?
  maxUses?
  authMode?           (open|agent)
  allowedAgentIds?
  policyMetadata?
```
Returns: { id, shareId, shareUrl, downloadUrl, expiresAt, deleteToken, sourceUrl, redirects }
Import follows redirects manually with revalidation, blocks private/internal URL
targets, enforces byte and timeout caps, and stores the result as a normal file
share.

```
POST /api/upload/multipart/init
POST /api/upload/multipart/part
POST /api/upload/multipart/complete
POST /api/upload/multipart/abort
GET  /api/upload/multipart/status
```
Native Turbo multipart uploads large files directly through the multipart
manifest lane. Completed uploads become normal file shares and preserve
delete-token, policy, max-use, and grant semantics.

```
OPTIONS /api/tus
POST    /api/tus
HEAD    /api/tus/{id}
PATCH   /api/tus/{id}
DELETE  /api/tus/{id}
```
TUS is a compatibility adapter over the multipart manifest layer. Supported
features include creation, offset checks, expiration headers, and termination.

```
GET /api/share/{shareId}
Authorization: Bearer agk_{keyId}.{secret} OR aat_{tokenId}.{secret} (required when policy.mode=agent)
```
Returns: { id, type, targetId, policy, createdByUserId, createdByAgentId, ...legacy fields }

```
POST /api/agent/grants
Authorization: Bearer agk_{keyId}.{secret} OR aat_{tokenId}.{secret}
Body: { shareId }
```
Returns: { accessToken, tokenType, expiresAt, targetType, targetId, shareId }

```
GET /api/dl/{id}
HEAD /api/dl/{id}
Query: share_id=shr_... (recommended for open-link maxUses accounting)
Headers: X-Access-Grant: agrt_... (required when transfer policy is agent-gated)
```
Returns: file stream (forced download; range supported)

```
DELETE /api/dl/{id}
Headers: X-Delete-Token: dlt_... (required unless caller is the owner session)
```
Returns: { status, type, id }

## SDK mapping (thin, non-canonical)

SDK helpers map directly to protocol endpoints:

- `uploadFile` -> `POST /api/upload`
- `uploadFileTurbo` -> `/api/upload/multipart/*`
- `importUrl` -> `POST /api/import-url`
- `resolveShare` -> `GET /api/share/{shareId}`
- `requestGrant` -> `POST /api/agent/grants`
- `downloadWithGrant` -> `GET /api/dl/{id}` (+ `X-Access-Grant`)
- `deleteTransfer` -> `DELETE /api/dl/{id}` (+ `X-Delete-Token`)
- `handoff` -> `uploadFile` with `auth_mode=agent` + single allow-list target
- `channelSend` -> `uploadFile` with `policy_metadata.channel`
- `listInbox` -> `GET /api/agent/inbox`
- `listOutbox` -> `GET /api/agent/outbox`
- `listChannel` -> `listInbox` filtered by `metadata.channel`

## Pipe endpoints (live transfer)

```
POST /api/pipe
POST /api/pipe/{pipeId}/push
POST /api/pipe/{pipeId}/done
GET  /api/pipe/{pipeId}/stream
GET  /api/pipe/{pipeId}/status
GET  /api/pipe/{pipeId}/events
```

## Folder endpoints

```
POST /api/folder
POST /api/folder/{folderId}/register
POST /api/folder/{folderId}/upload
POST /api/folder/{folderId}/upload-init
POST /api/folder/{folderId}/upload-part
POST /api/folder/{folderId}/upload-complete
POST /api/folder/{folderId}/upload-abort
POST /api/folder/{folderId}/progress
POST /api/folder/{folderId}/finalize
GET  /api/folder/{folderId}/state
GET  /api/folder/{folderId}/events
GET  /api/folder/{folderId}/file/{fileId}
```

## Webhooks

Configure `WEBHOOK_URL` and `WEBHOOK_SECRET` to emit signed lifecycle
events. Delivery uses `webhook-id`, `webhook-timestamp`, and
`webhook-signature: v1,<base64-hmac-sha256>` over
`{id}.{timestamp}.{rawBody}`.

Events:
- `upload.complete`
- `share.resolved`
- `grant.issued`
- `download.complete`
- `transfer.revoked`
- `transfer.expired`

## Human fallback endpoints

```
POST /auth/send
GET  /auth/verify?token=...
POST /auth/signout
GET  /auth/me
GET  /s/{shareId}
```

## Error semantics (A2A-relevant)

- `401 invalid_agent_key` -> missing/invalid agent auth
- `403 agent_not_allowed_for_share` -> agent not in allow-list
- `401 invalid_grant` -> missing/invalid/expired grant for protected fetch
- `409 grant_already_used` -> one-time grant replay attempt
- `404 share_not_found_or_expired` -> resolve/grant on missing or expired share

## Service/info endpoints

```
GET /api/status
GET /api/public/stats
GET /llm.md
```

## MCP integration

Tools: `upload_file`, `upload_text`, `download_file`, `download_share`

- `upload_file` / `upload_text` accept optional `ttl_seconds` (30..300)
- `download_share` can auto-run protected flow (resolve -> grant -> fetch)
  when `agent_key` or `ULTRA_AGENT_KEY` is set.

## Human-oriented companion docs

- `README.md` (architecture and operating model)
- `docs/sdk.md` (SDK usage)
- `docs/transfer-lanes.md` (Live, Hybrid, Turbo, TUS, and import lane model)
- `docs/benchmark-proof.md` (current dev proof and pending benchmark matrix)
- `docs/patterns.md` (swarms/channels/inbox-outbox composition)
- `docs/mcp.md` (MCP behavior and protected flow)
