fal.ai Integration
Generate and edit images via fal.ai's queue-based API.
Setup
Add your API key to TOOLS.md:
### fal.ai
FAL_KEY: your-key-here
Get a key at: https://fal.ai/dashboard/keys
The script checks (in order): FAL_KEY env var โ TOOLS.md
Supported Models
fal-ai/nano-banana-pro (Text โ Image)
Google's Gemini 3 Pro for text-to-image generation.
input_data = {
"prompt": "A cat astronaut on the moon", # required
"aspect_ratio": "1:1", # auto|21:9|16:9|3:2|4:3|5:4|1:1|4:5|3:4|2:3|9:16
"resolution": "1K", # 1K|2K|4K
"output_format": "png", # jpeg|png|webp
"safety_tolerance": "4" # 1 (strict) to 6 (permissive)
}
fal-ai/nano-banana-pro/edit (Image โ Image)
Gemini 3 Pro for image editing. Slower (~20s) but handles complex edits well.
input_data = {
"prompt": "Transform into anime style", # required
"image_urls": [image_data_uri], # required - array of URLs or base64 data URIs
"aspect_ratio": "auto",
"resolution": "1K",
"output_format": "png"
}
fal-ai/flux/dev/image-to-image (Image โ Image)
FLUX.1 dev model. Faster (~2-3s) for style transfers.
input_data = {
"prompt": "Anime style portrait", # required
"image_url": image_data_uri, # required - single URL or base64 data URI
"strength": 0.85, # 0-1, higher = more change
"num_inference_steps": 40,
"guidance_scale": 7.5,
"output_format": "png"
}
fal-ai/kling-video/o3/pro/video-to-video/edit (Video โ Video)
Kling O3 Pro for video transformation with AI effects.
Limits:
- Formats: .mp4, .mov only
- Duration: 3-10 seconds
- Resolution: 720-2160px
- Max file size: 200MB
- Max elements: 4 total (elements + reference images combined)
input_data = {
# Required
"prompt": "Change environment to be fully snow as @Image1. Replace animal with @Element1",
"video_url": "https://example.com/video.mp4", # .mp4/.mov, 3-10s, 720-2160px, max 200MB
# Optional
"image_urls": [ # style/appearance references
"https://example.com/snow_ref.jpg" # use as @Image1, @Image2 in prompt
],
"keep_audio": True, # keep original audio (default: true)
"elements": [ # characters/objects to inject
{
"reference_image_urls": [ # reference images for the element
"https://example.com/element_ref1.png"
],
"frontal_image_url": "https://example.com/element_front.png" # frontal view (better results)
}
], # use as @Element1, @Element2 in prompt
"shot_type": "customize" # multi-shot type (default: customize)
}
Prompt references:
@Video1โ the input video@Image1,@Image2โ reference images for style/appearance@Element1,@Element2โ elements (characters/objects) to inject
Input Validation
The skill validates inputs before submission. For multi-input models, ensure all required fields are provided:
# Check what a model needs
python3 scripts/fal_client.py model-info "fal-ai/kling-video/o3/standard/video-to-video/edit"
# List all models with their requirements
python3 scripts/fal_client.py models
Before submitting, verify:
- โ
All
requiredfields are present and non-empty - โ
File fields (
image_url,video_url, etc.) are URLs or base64 data URIs - โ
Arrays (
image_urls) have at least one item - โ Video files are within limits (200MB, 720-2160p)
Example validation output:
โ ๏ธ Note: Reference video in prompt as @Video1
โ ๏ธ Note: Max 4 total elements (video + images combined)
โ Validation failed:
- Missing required field: video_url
Usage
CLI Commands
# Check API key
python3 scripts/fal_client.py check-key
# Submit a request
python3 scripts/fal_client.py submit "fal-ai/nano-banana-pro" '{"prompt": "A sunset over mountains"}'
# Check status
python3 scripts/fal_client.py status "fal-ai/nano-banana-pro" "<request_id>"
# Get result
python3 scripts/fal_client.py result "fal-ai/nano-banana-pro" "<request_id>"
# Poll all pending requests
python3 scripts/fal_client.py poll
# List pending requests
python3 scripts/fal_client.py list
# Convert local image to base64 data URI
python3 scripts/fal_client.py to-data-uri /path/to/image.jpg
# Convert local video to base64 data URI (with validation)
python3 scripts/fal_client.py video-to-uri /path/to/video.mp4
Python Usage
import sys
sys.path.insert(0, 'scripts')
from fal_client import submit, check_status, get_result, image_to_data_uri, poll_pending
# Text to image
result = submit('fal-ai/nano-banana-pro', {
'prompt': 'A futuristic city at night'
})
print(result['request_id'])
# Image to image (with local file)
img_uri = image_to_data_uri('/path/to/photo.jpg')
result = submit('fal-ai/nano-banana-pro/edit', {
'prompt': 'Transform into watercolor painting',
'image_urls': [img_uri]
})
# Poll until complete
completed = poll_pending()
for req in completed:
if 'result' in req:
print(req['result']['images'][0]['url'])
Queue System
fal.ai uses async queues. Requests go through stages:
IN_QUEUEโ waitingIN_PROGRESSโ generatingCOMPLETEDโ done, fetch resultFAILEDโ error occurred
Pending requests are saved to ~/. openclaw/workspace/fal-pending.json and survive restarts.
Polling Strategy
Manual: Run python3 scripts/fal_client.py poll periodically.
Heartbeat: Add to HEARTBEAT.md:
- Poll fal.ai pending requests if any exist
Cron: Schedule polling every few minutes for background jobs.
Adding New Models
- Find the model on fal.ai and check its
/apipage - Add entry to
references/models.jsonwith input/output schema - Test with a simple request
Note: Queue URLs use base model path (e.g., fal-ai/flux not fal-ai/flux/dev/image-to-image). The script handles this automatically.
Files
skills/fal-ai/
โโโ SKILL.md โ This file
โโโ scripts/
โ โโโ fal_client.py โ CLI + Python library
โโโ references/
โโโ models.json โ Model schemas
Troubleshooting
"No FAL_KEY found" โ Add key to TOOLS.md or set FAL_KEY env var
405 Method Not Allowed โ URL routing issue, ensure using base model path for status/result
Request stuck โ Check fal-pending.json, may need manual cleanup