# iwasthere Public API — LLM Quick Reference

## What is iwasthere?
iwasthere is a service for collecting event photos in one shared album. A host creates
an event and shares a QR/link; anyone can upload to and download from the album — no
login required. This public API exposes the **organizer** side: create events, upload
photos/videos, get share links, read plan limits.

## Authentication
All requests require: `Authorization: Bearer iwt_<32bytes base64url>`.
Issue keys at https://iwasthere.pics/dashboard/developer. Scopes: `events:read`, `events:write` (choose read-only or read+write per key).

## Plan gating (how to handle 403)
When a plan limit is exceeded the API returns HTTP 403 with a body like:
```json
{ "error": "ACTIVE_EVENT_LIMIT_EXCEEDED", "upgrade": { "message": "...", "url": "https://iwasthere.pics/dashboard/plan" } }
```
Relay `upgrade.message` to the user as-is and point them to `upgrade.url`.
Gating codes: ACTIVE_EVENT_LIMIT_EXCEEDED, PHOTO_LIMIT_EXCEEDED, FILE_SIZE_EXCEEDED,
VIDEO_NOT_ALLOWED, VIDEO_SIZE_EXCEEDED, VIDEO_LIMIT_EXCEEDED.

## Rate limiting
Per API key: free = 60/hour, pro = 600/hour. On exceed → HTTP 429 `RATE_LIMITED` + `Retry-After`.

## End-to-end workflow (photo album) — copy/paste curl
```bash
KEY="iwt_YOUR_KEY"
BASE="https://iwasthere.pics/api/public/v1"

# 1) Create an event → capture id + shareLink
EV=$(curl -s -X POST "$BASE/events" -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" -d '{"name":"Summer Workshop"}')
EVENT_ID=$(echo "$EV" | jq -r .id)          # e.g. 3fa85f64-...
echo "$EV" | jq .shareLink                    # → https://iwasthere.pics/e/abc123  (give this to participants)

# 2) Get a presigned upload URL for each file
PRE=$(curl -s -X POST "$BASE/events/$EVENT_ID/photos/presign" -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"files":[{"name":"IMG_0001.jpg","size":3145728,"type":"image/jpeg"}]}')
URL=$(echo "$PRE" | jq -r '.uploads[0].url')
PHOTO_ID=$(echo "$PRE" | jq -r '.uploads[0].photoId')
S3KEY=$(echo "$PRE" | jq -r '.uploads[0].s3Key')

# 3) PUT the raw image directly to S3 (no auth header; match Content-Type)
curl -s -X PUT "$URL" -H "Content-Type: image/jpeg" --data-binary @IMG_0001.jpg

# 4) Complete → thumbnail + add to album
curl -s -X POST "$BASE/events/$EVENT_ID/photos/complete" -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d "{\"uploaded\":[{\"photoId\":\"$PHOTO_ID\",\"s3Key\":\"$S3KEY\",\"fileSize\":3145728}]}"

# 5) List the album's photos
curl -s "$BASE/events/$EVENT_ID/photos" -H "Authorization: Bearer $KEY" | jq '.photos[].id'

# 6) Share the shareLink from step 1 with participants.
```

### Video (Pro only): 3-step multipart
`POST /events/{id}/videos` (→ uploadId + partUrls) → `PUT` each part (collect ETags) → `POST /events/{id}/videos/{videoId}/complete` with parts[].

### Handling a gating error mid-workflow
```json
// HTTP 403 from step 2 when the free photo limit is hit:
{ "error": "PHOTO_LIMIT_EXCEEDED", "current": 50, "limit": 50,
  "upgrade": { "message": "The free plan allows up to 50 photos per event. Pro allows up to 500.", "url": "https://iwasthere.pics/dashboard/plan" } }
```
→ Relay `upgrade.message` to the user and stop uploading, or call `GET /plan` first to check limits proactively.

## Endpoints
| Method | Path | Summary |
|---|---|---|
| GET | `https://iwasthere.pics/api/public/v1/events` | List my events |
| POST | `https://iwasthere.pics/api/public/v1/events` | Create an event |
| GET | `https://iwasthere.pics/api/public/v1/events/{eventId}` | Get a single event |
| PATCH | `https://iwasthere.pics/api/public/v1/events/{eventId}` | Update an event (name/date) |
| DELETE | `https://iwasthere.pics/api/public/v1/events/{eventId}` | Delete or purge an event |
| GET | `https://iwasthere.pics/api/public/v1/events/{eventId}/photos` | List photos |
| POST | `https://iwasthere.pics/api/public/v1/events/{eventId}/photos/presign` | Get photo upload URLs (step 1/2) |
| POST | `https://iwasthere.pics/api/public/v1/events/{eventId}/photos/complete` | Complete photo upload (step 2/2) |
| DELETE | `https://iwasthere.pics/api/public/v1/photos/{photoId}` | Delete a single photo |
| GET | `https://iwasthere.pics/api/public/v1/events/{eventId}/videos` | List videos |
| POST | `https://iwasthere.pics/api/public/v1/events/{eventId}/videos` | Create video multipart upload session (Pro only, step 1/3) |
| POST | `https://iwasthere.pics/api/public/v1/events/{eventId}/videos/{videoId}/complete` | Complete video multipart upload (step 3/3) |
| GET | `https://iwasthere.pics/api/public/v1/plan` | Get plan/limits |

## MCP server (for AI agents)
An MCP server wraps this API so agents (Claude, Cursor, etc.) can call it via tools.
- **Endpoint (Streamable HTTP, stateless):** `https://7y62bns2zdo3xfpm6azyelalxq0gbelo.lambda-url.ap-northeast-2.on.aws/`
- **Transport:** JSON-RPC over HTTP POST (methods: `initialize`, `tools/list`, `tools/call`). No session state.
- **Auth:** send the same `Authorization: Bearer iwt_<...>` header; the server forwards it to this API. Doc tools need no auth.
- **Tools (12):** `search_docs`, `get_page` (docs, no auth) · `create_event`, `list_events`, `get_event`, `get_event_status`, `patch_event`, `delete_event`, `upload_photo`, `complete_upload`, `get_share_link`, `get_plan_and_limits` (actions).
- **Tool annotations:** each tool carries MCP hints (`readOnlyHint`/`destructiveHint`/`idempotentHint`/`openWorldHint`) so clients can gate approvals. `delete_event` is `destructiveHint:true`.
- **Photo upload (chained, out-of-band PUT):** `upload_photo` returns presigned URLs + a `contentType` per file; do the actual `PUT` yourself (set the `Content-Type` header to that `contentType`, or S3 returns 403), then call `complete_upload` to register the photos.
- **Status:** prefer `get_event_status` — it merges event detail + photo count into a single call instead of `get_event` + a separate photos list.
- Setup guide: https://iwasthere.pics/docs/mcp

```bash
# List available MCP tools
curl -s -X POST "https://7y62bns2zdo3xfpm6azyelalxq0gbelo.lambda-url.ap-northeast-2.on.aws/" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# Call an action tool (forward your API key)
curl -s -X POST "https://7y62bns2zdo3xfpm6azyelalxq0gbelo.lambda-url.ap-northeast-2.on.aws/" -H "Content-Type: application/json" \
  -H "Authorization: Bearer iwt_YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_event","arguments":{"name":"Summer Workshop"}}}'
```

Full contract with per-endpoint examples: https://iwasthere.pics/openapi.json
Per-tag markdown: https://iwasthere.pics/docs/api/events.md · /photos.md · /videos.md · /plan.md
