API Reference
Integrate HappyHorse AI video and image generation into your applications via REST API.
Base URL
https://happy-horse.ai/api/v1Authentication
All API requests require an API key sent via the Authorization header. Get your key from the API Keys page.
curl https://happy-horse.ai/api/v1/credits \
-H "Authorization: Bearer sk-sd_your_api_key_here"Rate Limiting
Default: 60 requests per minute per API key. Rate limit info is returned in response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests per minute |
X-RateLimit-Remaining | Remaining requests in window |
X-RateLimit-Reset | Unix timestamp when window resets |
Response Format
Success
{
"data": { ... },
"error": null
}Error
{
"data": null,
"error": {
"message": "...",
"code": "..."
}
}Endpoints
/api/v1/generateStart a video generation task. Supports text-to-video and image-to-video modes.
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Text description of the video to generate |
model | string | No | Model ID. Default: seedance-1-5-pro |
generation_type | string | No | text_to_video (default) or image_to_video |
image_url | string | No | Reference image URL (required for image_to_video) |
aspect_ratio | string | No | Aspect ratio. Default: 16:9 |
duration | number | No | Video duration in seconds. Default: 5 |
resolution | string | No | Output resolution. Default: 720p |
curl -X POST https://happy-horse.ai/api/v1/generate \
-H "Authorization: Bearer sk-sd_your_key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A cat playing piano in a jazz club, cinematic lighting",
"duration": 5,
"aspect_ratio": "16:9"
}'/api/v1/generate-imageStart an image generation task using Nano Banana 2.0 model. Requires paid access.
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Text description of the image to generate |
model | string | No | Model ID. Default: nano-banana-2 |
resolution | string | No | Output resolution: 1k, 2k, or 4k |
aspect_ratio | string | No | Aspect ratio. Default: 1:1 |
output_format | string | No | png (default), jpg, or webp |
images | string[] | No | Reference image URLs for edit mode |
/api/v1/videosList your video generation history with pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | No | Page number. Default: 1 |
limit | number | No | Items per page (1-50). Default: 20 |
/api/v1/videos/:video_idGet the status of a specific video generation. If the video is still processing, this endpoint will poll the upstream API for the latest result.
status is completed or failed./api/v1/uploadUpload an image for use with image-to-video generation. Returns a hosted URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
image | File | Yes | Image file (JPG, PNG, WebP). Max 10MB. |
multipart/form-data/api/v1/creditsCheck your remaining credits, paid access, and subscription status.
Error Codes
| HTTP | Code | Description |
|---|---|---|
| 401 | unauthorized | Missing or invalid API key |
| 403 | insufficient_credits | Not enough credits |
| 403 | paid_access_required | Model requires paid access |
| 400 | validation_error | Missing or invalid parameters |
| 429 | rate_limit_exceeded | Too many requests |
| 500 | internal_error | Server-side failure |
| 502 | upstream_error | Upstream API failure |
Models & Credits
| Model | ID | Credits/sec | Subscription |
|---|---|---|---|
| HappyHorse Lite | doubao-seedance-1-5-pro | 5 | Not required |
| HappyHorse 1.0 | doubao-seedance-2-0 | 7.5 equivalent (rounded up per video) | Required |
| HappyHorse 1.0 Fast | doubao-seedance-2-0-fast | 5 | Required |
| Nano Banana 2.0 | nano-banana-2 | 5 per image | Required |
Full Example: Generate & Poll
import requests
import time
API_KEY = "sk-sd_your_key"
BASE = "https://happy-horse.ai/api/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}
# 1. Start generation
resp = requests.post(f"{BASE}/generate", headers=headers, json={
"prompt": "A golden retriever surfing a wave at sunset",
"duration": 5,
})
video_id = resp.json()["data"]["video_id"]
print(f"Started: {video_id}")
# 2. Poll for completion
while True:
status_resp = requests.get(f"{BASE}/videos/{video_id}", headers=headers)
result = status_resp.json()["data"]
print(f"Status: {result['status']}")
if result["status"] == "completed":
print(f"Video URL: {result['video_url']}")
break
elif result["status"] == "failed":
print(f"Error: {result.get('error')}")
break
time.sleep(5)