Character Swap API
Retrieve & List
Poll a swap for its status and finished video, or list your organization's swaps
Poll a swap
GET /v1/character-swap/{id}curl -s "https://api.goodtake.ai/v1/character-swap/$ID" \
-H "Authorization: Bearer $GOODTAKE_API_KEY" | jq .Response
{
"id": "1f7b2c40-8e55-4b21-9f03-77a1d0c4e902",
"character_id": "9d2f6a3e-4c11-4a90-b1d7-2f8e6a4c0b11",
"status": "completed",
"model": "dreamina-seedance-2-5-260628",
"source": {
"link": "https://www.instagram.com/reel/ABC123/",
"kind": "instagram",
"duration_seconds": 11.9,
"width": 1080,
"height": 1440,
"has_audio": true
},
"with_audio": true,
"background": "a neon-lit rooftop at night",
"resolution": "1080p",
"video": {
"url": "https://storage.googleapis.com/...signed...",
"content_type": "video/mp4",
"file_size_bytes": 8419201,
"expires_at": "2026-09-18T13:20:11Z"
},
"generation_id": "3ab2c400-e29b-41d4-a716-446655440022",
"estimated_cost": 542,
"cost_credits": 542,
"error": "",
"created_at": "2026-09-11T13:18:02Z",
"completed_at": "2026-09-11T13:22:47Z"
}Statuses
Status is derived at read time — there are four values and no others.
Downloading, probing and muxing are invisible sub-steps of pending and
generating.
status | Meaning |
|---|---|
pending | The source is being fetched, probed and mirrored; nothing has been dispatched yet. |
generating | The swap is in flight at the provider. |
completed | Done — video.url is a signed URL to the finished file. |
failed | Terminal. error carries a precise reason (bad link, duration out of range, content-safety rejection). |
Poll every 4–8 seconds. A swap typically takes 2–6 minutes depending on source duration and resolution.
Video URLs expire
video.url is a signed URL with an expires_at. It is re-signed on every
read, so simply re-fetching the swap gives you a fresh one. Do not cache the
URL; cache the id.
List swaps
GET /v1/character-swap?limit=20&offset=0Paginated, newest first. Summary rows carry an honest derived status but no video URL — fetch the detail for that.
curl -s "https://api.goodtake.ai/v1/character-swap?limit=10" \
-H "Authorization: Bearer $GOODTAKE_API_KEY" | jq .| Param | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 20 | 100 | Max items to return |
offset | integer | 0 | — | Pagination offset |
Full polling example
KEY="gt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE="https://api.goodtake.ai/v1"
ID=$(curl -s -X POST "$BASE/character-swap" \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"character_id":"9d2f6a3e-...","video_url":"https://www.instagram.com/reel/ABC123/","resolution":"720p"}' \
| jq -r .id)
while :; do
BODY=$(curl -s "$BASE/character-swap/$ID" -H "Authorization: Bearer $KEY")
STATUS=$(echo "$BODY" | jq -r .status)
echo "status: $STATUS"
[ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] && break
sleep 6
done
echo "$BODY" | jq -r '.video.url // .error'Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
404 | Unknown swap id, or one belonging to another organization |