---
name: shortodella
description: Use the Shortodella API to generate images and videos, do image-to-image / editing with reference images, take website screenshots, search and upload assets, manage projects, and drive browser-based site tools (trim/crop a single asset, or ask the user to list/pick/swipe through a set of assets). TRIGGER when the user asks to generate images or videos, screenshot a website, search stock assets, work with Shortodella, or get the user to choose / filter assets in their browser.
allowed-tools: Bash(curl*), Read
---

# Shortodella API skill

Public skill for using the Shortodella REST API from any Claude Code installation.

- **Base URL:** `https://api.shortodella.com/api/v1`
- **Auth:** `Authorization: Bearer sk_...`
- **Pricing:** energy-based (see [Energy Costs](#energy-costs))
- **Sign-up / billing:** https://shortodella.com

---

## 1. Get an API key (one-time, browser flow)

If no API key is in the env yet, run the device-auth flow once. The user clicks "Connect" in the browser and the key is returned.

```bash
# 1. Request device code
RESP=$(curl -s -X POST https://api.shortodella.com/api/v1/auth/device \
  -H "Content-Type: application/json" \
  -d '{"client_name": "Claude Code"}')

# 2. Show the activation URL to the user
echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Open and click Connect:', d['verification_url'])"

# 3. After the user confirms, poll for the key
DEVICE_CODE=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['device_code'])")
curl -s -X POST https://api.shortodella.com/api/v1/auth/device/token \
  -H "Content-Type: application/json" \
  -d "{\"device_code\": \"$DEVICE_CODE\"}"
# → { "status": "authorized", "api_key": "sk_..." }
```

The key does not expire. Save it once (e.g. `export SK=sk_...`) and reuse it.

Quick sanity check:

```bash
curl -s https://api.shortodella.com/api/v1/energy -H "Authorization: Bearer $SK"
# → { "total": 75.1, "permanent": 75.1, ... }
```

---

## 2. Generate an image (sync)

```bash
curl -s -X POST https://api.shortodella.com/api/v1/generate/image \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "anthropomorphic cat in a designer outfit at a rooftop cafe",
    "model": "nanobanana",
    "size": "1024x1024"
  }'
```

| Field    | Values |
|----------|--------|
| `model`  | `nanobanana` (fast, 1 energy) · `grok` (creative, 1 energy) · `gpt-image-2` (best quality, 4 energy) · `gpt-image-1.5` (transparent backgrounds, 3 energy) |
| `size`   | `1024x1024` · `1248x832` · `832x1248` |

**Returns:** `{ asset_uid, status, r2_path, url, width, height }`. The `url` is a presigned download link (expires in 7 days). The `asset_uid` is permanent and lives in your account.

### Image-to-image / editing (reference images)

Pass up to 3 existing asset uids — the model uses them as visual reference (img-to-img, character/scene consistency, editing text on a photo, restyling, etc). Supported by all four image models.

```bash
# 1. Upload a starter image (or use an asset uid you already have)
UPLOAD=$(curl -s -X POST https://api.shortodella.com/api/v1/assets/upload \
  -H "Authorization: Bearer $SK" \
  -F "file=@/path/to/base.png")
REF_UID=$(echo "$UPLOAD" | python3 -c "import sys,json; print(json.load(sys.stdin)['asset_uid'])")

# 2. Generate using it as reference
curl -s -X POST https://api.shortodella.com/api/v1/generate/image \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d "{
    \"prompt\": \"Use the reference image. Keep the cat, pose, and scene identical. Only change the wooden sign text to 'NEKO COFFEE'.\",
    \"model\": \"nanobanana\",
    \"size\": \"832x1248\",
    \"reference_images\": [\"$REF_UID\"]
  }"
```

**Allowed:** your own assets and public-library assets (`is_public=true`). Up to 3 uids. Order matters — the first uid is the primary reference for most models.

**Errors:**
- `404 Reference asset not found: <uid>` — uid is missing or not yours / not public
- `500 Failed to load reference asset: <uid>` — R2 fetch failed

---

## 3. Generate a video (async)

```bash
# Start
TASK=$(curl -s -X POST https://api.shortodella.com/api/v1/generate/video \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "cat walking on a beach at sunset",
    "model": "grok",
    "duration": 5,
    "aspect_ratio": "16:9"
  }')
TASK_ID=$(echo "$TASK" | python3 -c "import sys,json; print(json.load(sys.stdin)['task_id'])")

# Poll every ~5s
curl -s "https://api.shortodella.com/api/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer $SK"
# → { status: "completed", result: { asset_uid, url, ... } }
```

| Field          | Values |
|----------------|--------|
| `model`        | `grok` (1/sec, fastest) · `kling` (2/sec text, 4/sec image) · `veo` (3/sec, cinematic) · `seedance` (3/sec, native audio + smooth motion) |
| `duration`     | 3–15 seconds (`seedance`: 4–15) |
| `aspect_ratio` | `16:9` · `9:16` · `1:1` · `4:3` · `3:4` |
| `source_image` | optional asset uid — start frame for image-to-video. Same allow-list as `reference_images` (own assets or public-library assets). |
| `end_image`    | optional asset uid — end frame, used with `source_image` for a start→end transition. Supported by `kling` and `seedance`; with `grok`/`veo` it auto-forces `kling`. |

```bash
# Image-to-video example: animate the latte-art still into a 5s vertical clip
curl -s -X POST https://api.shortodella.com/api/v1/generate/video \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d "{
    \"prompt\": \"slow zoom in on the cup, gentle steam, cinematic\",
    \"model\": \"seedance\",
    \"duration\": 5,
    \"aspect_ratio\": \"9:16\",
    \"source_image\": \"$REF_UID\"
  }"
```

---

## 4. Assets

```bash
# Upload (free)
curl -s -X POST https://api.shortodella.com/api/v1/assets/upload \
  -H "Authorization: Bearer $SK" \
  -F "file=@/path/to/image.png" \
  -F "name=my image"

# List your assets
curl -s "https://api.shortodella.com/api/v1/assets?type=all&limit=20&sort=newest" \
  -H "Authorization: Bearer $SK"

# Search public library
curl -s "https://api.shortodella.com/api/v1/assets/search?q=minimalist+logo&limit=12" \
  -H "Authorization: Bearer $SK"

# Detail
curl -s "https://api.shortodella.com/api/v1/assets/$UID" \
  -H "Authorization: Bearer $SK"

# Download
curl -sL "https://api.shortodella.com/api/v1/assets/$UID/download" \
  -H "Authorization: Bearer $SK" \
  -o output.png
```

---

## 5. Other endpoints

```bash
# Screenshot a website (async → poll /tasks/{id})
curl -s -X POST https://api.shortodella.com/api/v1/screenshot/website \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "viewport": "desktop", "count": 1}'

# Extract brand (logo/colors/fonts) from a site (async)
curl -s -X POST https://api.shortodella.com/api/v1/extract/brand \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

# Merge videos (async, free)
curl -s -X POST https://api.shortodella.com/api/v1/merge/videos \
  -H "Authorization: Bearer $SK" \
  -H "Content-Type: application/json" \
  -d '{"asset_uids": ["video_abc123", "video_def456"]}'

# Available models (no auth)
curl -s https://api.shortodella.com/api/v1/models

# Energy balance
curl -s https://api.shortodella.com/api/v1/energy \
  -H "Authorization: Bearer $SK"
```

### Site Tools (browser interfaces)

These endpoints return a `tool_url` the user opens in their logged-in browser.
Two flavors:

- **Edit tools** (`trim`, `crop`) — single asset → new asset with
  `parent_asset_uid` set to the original.
- **Choice tools** (`list`, `pick`, `swipe`) — pass multiple `asset_uids`,
  poll `GET /site-tools/sessions/{id}` for the user's submission.

```bash
# Edit: trim a video
curl -s -X POST https://api.shortodella.com/api/v1/site-tools/trim \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"asset_uid": "video_abc123"}'
# → { "tool_url": "https://shortodella.com/site-tools/trim?asset=video_abc123", ... }

# Edit: crop an image (png/jpg/webp/gif)
curl -s -X POST https://api.shortodella.com/api/v1/site-tools/crop \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"asset_uid": "png_abc123"}'

# Choice: show user a grid of N assets (no result collected)
curl -s -X POST https://api.shortodella.com/api/v1/site-tools/list \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"asset_uids": ["png_a","png_b","video_c"], "title": "Mood board"}'

# Choice: ask user to pick 2 of 4
curl -s -X POST https://api.shortodella.com/api/v1/site-tools/pick \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"asset_uids": ["png_a","png_b","png_c","png_d"], "min": 2, "max": 2, "title": "Pick 2 covers"}'
# → { "tool_url": "...", "session_id": "sess_...", "poll_url": "/api/v1/site-tools/sessions/sess_..." }

# Choice: tinder-style swipe through a batch
curl -s -X POST https://api.shortodella.com/api/v1/site-tools/swipe \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"asset_uids": ["png_a","png_b","png_c"], "title": "Quick filter"}'

# Poll a session (any choice tool) — status pending → done, then read result
curl -s "https://api.shortodella.com/api/v1/site-tools/sessions/sess_xxx" \
  -H "Authorization: Bearer $SK"
# → { "status": "done", "result": { "picked_uids": [...] } }     # pick
# → { "status": "done", "result": { "kept_uids": [...], "discarded_uids": [...] } }  # swipe
```

Pattern: send `tool_url` to the user, poll `poll_url` every 2s, react to
`status: "done"`. Sessions live for 24h.

For `trim`/`crop`: poll the user's assets list (or look up by
`parent_asset_uid` once the new asset appears) — there's no session for those.

Energy: free.

### Projects (canvas / video editor)

```bash
# List
curl -s https://api.shortodella.com/api/v1/projects -H "Authorization: Bearer $SK"

# Create
curl -s -X POST https://api.shortodella.com/api/v1/projects \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"name": "My Project"}'

# Get with layers
curl -s "https://api.shortodella.com/api/v1/projects/$ID" -H "Authorization: Bearer $SK"

# Add a layer
curl -s -X POST "https://api.shortodella.com/api/v1/projects/$ID/layers" \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{"layer": {"type": "png", "x": 100, "y": 100, "r2_path": "user-assets/png_abc/main.png"}}'
```

---

## Energy Costs

| Operation | Cost |
|-----------|------|
| Image (`nanobanana` / `grok`) | 1 |
| Image (`gpt-image-1.5`) | 3 |
| Image (`gpt-image-2`) | 4 |
| Video (`grok`) | 1 / sec |
| Video (`kling`, text-to-video) | 2 / sec |
| Video (`kling`, image-to-video) | 4 / sec |
| Video (`veo`) | 3 / sec |
| Video (`seedance`) | 3 / sec |
| Screenshot | 1 |
| Brand extract | 1 |
| Upload / describe / merge | 0 |

---

## Tips

- Default image model: `nanobanana` (fast, photoreal-friendly, supports text editing on images).
- For img-to-img / consistency, prefer `nanobanana` with `reference_images`.
- Always check `/energy` before expensive ops (`veo` video, big batches).
- Video is always async — poll `/tasks/{task_id}` every ~5 seconds.
- `url` in responses is a presigned R2 link (7-day expiry). `asset_uid` is permanent — store it.
- Download with `curl -o` from `url`, or use `/assets/{uid}/download`.
- Full API reference: https://shortodella.com/api · Skill docs: https://shortodella.com/docs
