# API -- Getting Started

{% hint style="info" %}
The FLORA API is currently in **beta**. Endpoints and behavior may change as we iterate.
{% endhint %}

The FLORA API lets you run techniques (reusable AI workflows) programmatically. Look up a technique to see its inputs, submit a run, and poll for results.

**Base URL:** `https://app.flora.ai`

***

## Step 1: Create your API key

1. Sign in to [FLORA](https://app.flora.ai)
2. Open **Settings** > **API Keys** (or go to `https://app.flora.ai/projects?openSettings=true&initialTab=apiKeys`)
3. Click **Create API Key**, give it a name, and copy the secret immediately -- it's shown only once
4. You can only have one active key at a time. To rotate, revoke the old key first.

Use the key in every request:

```
Authorization: Bearer sk_live_XXXX
```

***

## Step 2: Find your technique slug

Every technique has a **slug** -- a short, URL-safe identifier. You can find it in the URL when you open a technique in the FLORA app:

```
https://app.flora.ai/techniques/portrait-enhancer
                                ^^^^^^^^^^^^^^^^^^
                                this is the slug
```

Any technique you've built with the technique builder or that's available in your techniques dashboard can be used via the API.

### Available techniques

| Slug                                 | Name                               | Description                                         |
| ------------------------------------ | ---------------------------------- | --------------------------------------------------- |
| `art-directors-critique`             | Art Director's Critique            | Analyze, critique, and redesign any creative asset. |
| `auto-translate`                     | Auto Translate                     | Translate text in images instantly                  |
| `book-drop`                          | Book Drop                          | Mocks up front and back book covers                 |
| `cctv-cam`                           | CCTV Cam                           | Any face, CCTV style                                |
| `character-lock`                     | Character Lock                     | One character, 6 different angles                   |
| `cinematic-movie-generator`          | Cinematic Movie Stills             | Generate film-quality scene stills                  |
| `color-mapping`                      | Segment Mapper                     | Color-codes every element in your image             |
| `color-transfer`                     | Color Transfer                     | Apply color grading from any reference              |
| `earth-zoom-out`                     | Earth Zoom Out                     | Zoom out to space from any scene                    |
| `facade-swap`                        | Facade Swap                        | Reskin buildings with new materials                 |
| `fit-checks`                         | Fit Check                          | Extract outfits & swap onto new looks               |
| `glam-shots`                         | Glam Shots                         | Create polished makeup ads instantly                |
| `icon-pack`                          | Icon Pack                          | Generate matched icon sets from a prompt            |
| `live-like-an-amsterdammer`          | Live like an Amsterdammer          | Places you into everyday Amsterdam scenes           |
| `location-scouter`                   | Location Scout                     | Scouts five views from a single location            |
| `logo-stylist`                       | Logo Stylist                       | Stylize any logo with a new visual twist            |
| `memoji-me`                          | Memoji Me                          | Turn any face into a custom memoji                  |
| `moodboard-maker`                    | Mood Board Maker                   | Eclectic mood board from a photo                    |
| `mugshot`                            | Mugshot                            | Turn any portrait into a mugshot                    |
| `palette-pull`                       | Palette Pull                       | Extract color palettes from any image               |
| `product-animator`                   | Product Animator                   | Animate your product                                |
| `product-lookbook-grid`              | Product Lookbook Grid              | Turn products into styled grid layouts              |
| `product-motion`                     | Product Motion                     | Animate product shots in one click                  |
| `quick-reframe`                      | Layout Resizer                     | Resize layouts for any aspect ratio                 |
| `relight-technique`                  | Relighting                         | Relights your photo                                 |
| `room-render`                        | Room Render                        | Turn floor plans into realistic rooms               |
| `seamless-transition`                | Seamless Transition                | Animate between any two frames                      |
| `sigil`                              | Sigil                              | Turns any image into an animated glyph              |
| `sketch-to-garment`                  | Garment Sketch                     | One sketch, one final garment.                      |
| `studio-blur`                        | Studio Blur                        | Add pro depth-of-field blur to photos               |
| `studio-shot`                        | Studio Shot                        | Turns any product into a studio-lit shoot           |
| `tarot-pull`                         | Tarot Pull                         | Custom illustrated tarot card readings              |
| `texture-matchers`                   | Texture Match                      | Replicate textures & colors across assets           |
| `turn-any-product-into-4-ad-visuals` | Turn any product into 4 ad visuals | Make a full ad campaign from 1 product              |
| `ugc-creation`                       | UGC Creator                        | Casual, phone-shot clips of your product            |
| `video-scene-builder`                | Video Scene Builder                | Compose video scenes from still assets              |
| `wireframe`                          | Photo Wireframe                    | Turn any photo into a clean wireframe               |
| `wonder-fy`                          | Wonder(fy)                         | Apply Wonder's cinematic style to images            |

***

## Step 3: Look up a technique's inputs

Before running a technique, fetch its details to see the required inputs, expected outputs, and credit cost:

```bash
curl https://app.flora.ai/api/v1/techniques/{slug} \
  -H "Authorization: Bearer sk_live_XXXX"
```

**Response:**

```json
{
  "techniqueId": "abc123...",
  "name": "Portrait Enhancer",
  "description": "Enhance portrait photos with AI",
  "runCost": 5,
  "inputs": [
    { "id": "input_image", "name": "Input Image", "type": "imageUrl" }
  ],
  "outputs": [
    { "id": "output_image", "name": "Output Image", "type": "imageUrl" }
  ]
}
```

Use the `inputs` array to build your run request -- match the `id` and `type` exactly.

***

## Step 4: Create a run

```bash
curl -X POST https://app.flora.ai/api/v1/techniques/{slug}/runs \
  -H "Authorization: Bearer sk_live_XXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [
      { "id": "input_image", "type": "imageUrl", "value": "https://example.com/photo.jpg" }
    ],
    "mode": "async"
  }'
```

**Response (201 Created):**

```json
{
  "runId": "j57abc...",
  "createdAt": 1710000000000,
  "status": "pending",
  "progress": 0,
  "pollUrl": "https://app.flora.ai/api/v1/techniques/{slug}/runs/j57abc..."
}
```

***

## Step 5: Poll for results

```bash
curl https://app.flora.ai/api/v1/techniques/{slug}/runs/{runId} \
  -H "Authorization: Bearer sk_live_XXXX"
```

Poll every 2-5 seconds until `status` is `completed` or `failed`.

```json
{
  "runId": "j57abc...",
  "status": "completed",
  "progress": 100,
  "createdAt": 1710000000000,
  "startedAt": 1710000001000,
  "completedAt": 1710000030000,
  "chargedCost": 5,
  "outputs": [
    { "outputId": "output_image", "type": "imageUrl", "url": "https://ik.imagekit.io/flora/..." }
  ]
}
```

***

## Full Python example

```python
import requests, time

API_KEY = "sk_live_XXXX"
BASE = "https://app.flora.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# Find your slug from the technique URL in the FLORA app:
# e.g., app.flora.ai/techniques/portrait-enhancer -> slug is "portrait-enhancer"
SLUG = "portrait-enhancer"

# 1. Look up the technique to confirm inputs and cost
technique = requests.get(f"{BASE}/api/v1/techniques/{SLUG}", headers=HEADERS).json()
print(f"Technique: {technique['name']} (cost: {technique['runCost']} credits)")
print(f"Expected inputs: {[i['id'] + ' (' + i['type'] + ')' for i in technique['inputs']]}")

# 2. Create a run (match inputs to the technique's schema)
resp = requests.post(f"{BASE}/api/v1/techniques/{SLUG}/runs", headers=HEADERS, json={
    "inputs": [{"id": "input_image", "type": "imageUrl", "value": "https://example.com/photo.jpg"}],
    "mode": "async",
})
run = resp.json()
print(f"Run created: {run['runId']}")

# 3. Poll until done (pollUrl is an absolute URL)
while True:
    poll = requests.get(run["pollUrl"], headers=HEADERS).json()
    print(f"Status: {poll['status']} ({poll.get('progress', 0)}%)")
    if poll["status"] in ("completed", "failed"):
        break
    time.sleep(3)

# 4. Handle result
if poll["status"] == "completed":
    for output in poll["outputs"]:
        print(f"Output: {output['url']}")
else:
    print(f"Failed: {poll.get('errorCode')} - {poll.get('errorMessage', '')}")
```

***

## Endpoints

| Method | Path                                     | Description                                   |
| ------ | ---------------------------------------- | --------------------------------------------- |
| GET    | `/api/v1/techniques/{slug}`              | Get technique details (inputs, outputs, cost) |
| POST   | `/api/v1/techniques/{slug}/runs`         | Create and start a run                        |
| GET    | `/api/v1/techniques/{slug}/runs/{runId}` | Poll run status and results                   |

***

## Create run request fields

| Field             | Required | Notes                                                             |
| ----------------- | -------- | ----------------------------------------------------------------- |
| `inputs`          | Yes      | Must match the technique's expected inputs (count, IDs, types)    |
| `inputs[].id`     | Yes      | Input identifier from the technique's `inputs` array              |
| `inputs[].type`   | Yes      | `imageUrl`, `videoUrl`, or `text`                                 |
| `inputs[].value`  | Yes      | URL for images/videos, or text content                            |
| `mode`            | Yes      | Use `"async"`                                                     |
| `idempotency_key` | No       | Prevents duplicate runs on retry -- same key returns existing run |

***

## Input media URL restrictions

Only **HTTPS** URLs are accepted (`https://` -- not `http://`).

**Supported hosts:**

| Host                                  | URL pattern                                                                                                                                                                                                                                                                       |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Flora media                           | `https://media.flora.ai/...`                                                                                                                                                                                                                                                      |
| Google Cloud Storage (path-style)     | `https://storage.googleapis.com/...`                                                                                                                                                                                                                                              |
| Google Cloud Storage (virtual-hosted) | `https://<bucket>.storage.googleapis.com/...`                                                                                                                                                                                                                                     |
| Amazon S3                             | Standard S3 object URL hostnames, including virtual-hosted (`https://<bucket>.s3.<region>.amazonaws.com/...`), path-style (`https://s3.<region>.amazonaws.com/<bucket>/...`), dual-stack, and S3 Transfer Acceleration (`https://<bucket>.s3-accelerate.amazonaws.com/...`) forms |
| ImageKit                              | `https://ik.imagekit.io/...`                                                                                                                                                                                                                                                      |

***

## Run statuses

| Status      | Meaning                                         |
| ----------- | ----------------------------------------------- |
| `pending`   | Queued                                          |
| `running`   | In progress (`progress` field shows 0-100%)     |
| `completed` | Done -- check `outputs` array and `chargedCost` |
| `failed`    | Check `errorCode` and `errorMessage`            |

***

## Errors

All errors return `{ "error": { "code": "...", "message": "..." } }`.

| Code                     | HTTP | Meaning                           |
| ------------------------ | ---- | --------------------------------- |
| `unauthorized`           | 401  | Missing auth header               |
| `invalid_api_key`        | 401  | Bad or revoked key                |
| `invalid_json`           | 400  | Malformed request body            |
| `input_validation_error` | 400  | Wrong inputs for this technique   |
| `not_found`              | 404  | Bad technique slug or run ID      |
| `insufficient_credits`   | 402  | Out of credits -- ask us for more |

***

## Known limitations (beta)

* **Async polling only** -- no streaming, no webhooks yet
* **No list-techniques endpoint** -- find technique slugs from the URL bar in the FLORA app (e.g., `app.flora.ai/techniques/portrait-enhancer` means the slug is `portrait-enhancer`)
* **Output URLs** are long-lived but not permanent -- download what you need to keep
* **One API key at a time** -- revoke the old one before creating a new one
* **Technique builder is in beta** -- build techniques using FLORA's visual workflow editor, then call them via the API using their slug

***

## Problems?

Message us in the shared Slack channel with your `runId`, technique slug, and the error response.
