One call, one video.
Send a photo to POST /v1/generations and receive the finished video by webhook. Test mode is free and works the moment you sign up.
- Signed webhooks
- Idempotent retries
- Free test mode
- Usage analytics
- Scoped keys with expiry
- Published error catalogue
POST/v1/generations
Status succeeded Queued Running Succeeded
{
"effect": "slow-dance",
"duration_s": 5,
"resolution": "640p",
"photo_url": "https://example.com/in.jpg"
} - Queued 14:02:11.204
- Running 14:02:12.006
- Succeeded 14:03:40.412
- Elapsed
- 89.2 s
- Video
- 5 s, 640p
- Price
- $0.152
waiting
output.mp4
Webhook generation.succeeded 200 OK41 ms Pending
Copy, paste, ship.
shell
curl https://api.moan.hot/v1/generations \
-H "Authorization: Bearer mh_test_..." \
-H "Idempotency-Key: ord_204918" \
-d effect=slow-dance \
-d duration_s=5 \
-d resolution=640p \
-d input[photo_url]=https://example.com/in.jpg Node.js
const res = await fetch("https://api.moan.hot/v1/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MOANHOT_KEY}`,
"Idempotency-Key": order.id,
},
body: JSON.stringify({
effect: "slow-dance",
duration_s: 5,
resolution: "640p",
input: { photo_url },
}),
});
const gen = await res.json(); // { id: "gen_01JBX4", status: "queued" } Python
import requests
gen = requests.post(
"https://api.moan.hot/v1/generations",
headers={"Authorization": f"Bearer {KEY}", "Idempotency-Key": order_id},
json={
"effect": "slow-dance",
"duration_s": 5,
"resolution": "640p",
"input": {"photo_url": photo_url},
},
).json()