GoodTake AI Docs
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.

statusMeaning
pendingThe source is being fetched, probed and mirrored; nothing has been dispatched yet.
generatingThe swap is in flight at the provider.
completedDone — video.url is a signed URL to the finished file.
failedTerminal. 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=0

Paginated, 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 .
ParamTypeDefaultMaxDescription
limitinteger20100Max items to return
offsetinteger0Pagination 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

StatusMeaning
401Missing or invalid API key
404Unknown swap id, or one belonging to another organization