AirCubeAirCube
API Reference

Face Swap API

Detect faces and swap them in images and videos using the AirCube API.

Face swap uses a two-step workflow: first detect faces in a source image (free), then swap the detected face into a target image or video (paid).

Step 1: Detect faces

POST https://aircube.ai/api/v3/aircube/face-swap/detect

Analyzes a source image and returns cropped face URLs. This endpoint is free — no credits are charged.

Request

{
  "source_image": "https://example.com/portrait.jpg"
}
FieldTypeRequiredDescription
source_imagestringYesURL of an image containing one or more faces

Response (200 OK)

Faces detected:

{
  "success": true,
  "data": {
    "faces": [
      "https://assets.aircube.dev/cropped-face-1.jpg",
      "https://assets.aircube.dev/cropped-face-2.jpg"
    ]
  }
}

No faces detected:

{
  "success": true,
  "data": {
    "faces": [],
    "message": "No faces detected in image"
  }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORMissing source_image field
500INTERNAL_ERRORFace detection failed

Step 2: Swap face

POST https://aircube.ai/api/v3/aircube/face-swap

Swaps a detected face into a target image or video. This endpoint charges credits based on the target media type and duration.

Request

{
  "source_face_url": "https://assets.aircube.dev/cropped-face-1.jpg",
  "target_media": "https://example.com/target-video.mp4"
}
FieldTypeRequiredDescription
source_face_urlstringYesA face URL returned from the detect endpoint
target_mediastringYesURL of the target image, video, or GIF

Response (202 Accepted)

{
  "success": true,
  "data": {
    "id": "gen_xyz789abc123",
    "status": "processing",
    "model": "Face Swap",
    "type": "image",
    "output_url": null,
    "created_at": "2025-01-15T13:45:00.000Z"
  }
}

The type field reflects the target media type (image or video).

Errors

StatusCodeWhen
400VALIDATION_ERRORMissing fields or invalid media URL
402PAYMENT_REQUIREDInsufficient credits
500INTERNAL_ERRORProcessing failed

Step 3: Poll for result

Use the Get Result endpoint to poll for the swap output:

GET https://aircube.ai/api/v3/status/{id}

Pricing

Face swap pricing depends on the target media type:

Target typePricing
ImageFixed price per swap
VideoPrice scales with video duration

Credits are charged when the swap request is submitted. If the swap fails, credits are automatically refunded.

Complete examples

cURL

# Step 1: Detect faces (free)
curl -X POST https://aircube.ai/api/v3/aircube/face-swap/detect \
  -H "Authorization: Bearer $AIRCUBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source_image": "https://example.com/portrait.jpg"}'

# Step 2: Swap face (paid)
curl -X POST https://aircube.ai/api/v3/aircube/face-swap \
  -H "Authorization: Bearer $AIRCUBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source_face_url": "https://assets.aircube.dev/cropped-face-1.jpg",
    "target_media": "https://example.com/target-video.mp4"
  }'

# Step 3: Poll for result
curl https://aircube.ai/api/v3/status/gen_xyz789abc123 \
  -H "Authorization: Bearer $AIRCUBE_API_KEY"

Python

import os
import time
import requests

API_KEY = os.environ["AIRCUBE_API_KEY"]
BASE_URL = "https://aircube.ai/api/v3"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Step 1: Detect faces
detect_res = requests.post(
    f"{BASE_URL}/aircube/face-swap/detect",
    headers=HEADERS,
    json={"source_image": "https://example.com/portrait.jpg"},
)
faces = detect_res.json()["data"]["faces"]

if not faces:
    print("No faces detected")
    exit()

print(f"Detected {len(faces)} face(s)")

# Step 2: Swap face
swap_res = requests.post(
    f"{BASE_URL}/aircube/face-swap",
    headers=HEADERS,
    json={
        "source_face_url": faces[0],
        "target_media": "https://example.com/target-video.mp4",
    },
)
generation_id = swap_res.json()["data"]["id"]

# Step 3: Poll for result
while True:
    result = requests.get(
        f"{BASE_URL}/status/{generation_id}",
        headers=HEADERS,
    ).json()

    status = result["data"]["status"]
    if status == "completed":
        print(f"Output: {result['data']['output_url']}")
        break
    elif status == "failed":
        print("Face swap failed")
        break

    time.sleep(5)

JavaScript

const API_KEY = process.env.AIRCUBE_API_KEY;
const BASE_URL = "https://aircube.ai/api/v3";
const headers = {
  Authorization: `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};

// Step 1: Detect faces
const detectRes = await fetch(`${BASE_URL}/aircube/face-swap/detect`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    source_image: "https://example.com/portrait.jpg",
  }),
});
const { data: detectData } = await detectRes.json();

if (detectData.faces.length === 0) {
  console.log("No faces detected");
  process.exit();
}

// Step 2: Swap face
const swapRes = await fetch(`${BASE_URL}/aircube/face-swap`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    source_face_url: detectData.faces[0],
    target_media: "https://example.com/target-video.mp4",
  }),
});
const { data: swapData } = await swapRes.json();

// Step 3: Poll for result
while (true) {
  const pollRes = await fetch(`${BASE_URL}/status/${swapData.id}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const result = await pollRes.json();

  if (result.data.status === "completed") {
    console.log(`Output: ${result.data.output_url}`);
    break;
  } else if (result.data.status === "failed") {
    throw new Error("Face swap failed");
  }

  await new Promise((r) => setTimeout(r, 5000));
}

On this page