Seedance 2.5 is live — 30-second cinematic video with native audio & real-person references
rreAPI Docs

Face Swap

Face Swap on reAPI — send a target photo and a source face, get one swapped image back with the target's pose, lighting and background kept. Seed control, flat price per image, playground and API.

Face Swap replaces the face in a target photo with the face from a source image, keeping the target's pose, lighting and background. Two public image URLs in, one image out; pin a seed to repeat a result. Submit returns a task_id; poll until ready. Try it in the playground on the model page, which also shows current pricing.

Content filtering

Content filtering is always off on this model, and there is no filter parameter: the request schema has no content_filter field, and a request that includes it is rejected with 400. Use it on people whose likeness you have the right to use; platform terms apply to everything you generate.

Generated images are stored in an isolated bucket and their URLs stay valid for 30 days. Mirror the files to your own storage if you need them longer.

Quick example

curl https://reapi.ai/api/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "face-swap",
    "image_url": "https://example.com/target-photo.jpg",
    "face_image_url": "https://example.com/source-face.jpg"
  }'
import requests

resp = requests.post(
    "https://reapi.ai/api/v1/images/generations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "face-swap",
        "image_url": "https://example.com/target-photo.jpg",
        "face_image_url": "https://example.com/source-face.jpg",
    },
    timeout=30,
)
print(resp.json())
const r = await fetch("https://reapi.ai/api/v1/images/generations", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "face-swap",
    image_url: "https://example.com/target-photo.jpg",
    face_image_url: "https://example.com/source-face.jpg",
  }),
});
console.log(await r.json());
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]any{
        "model":          "face-swap",
        "image_url":      "https://example.com/target-photo.jpg",
        "face_image_url": "https://example.com/source-face.jpg",
    })
    req, _ := http.NewRequest("POST",
        "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    out, _ := io.ReadAll(resp.Body)
    fmt.Println(string(out))
}

Submit response

{
  "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
  "model": "face-swap",
  "status": "processing",
  "created_at": 1735000000
}

Poll GET /api/v1/tasks/{id} (see the Tasks reference) until status === "completed". The completed payload's output.image_urls holds the swapped image URL.


Authentication

Every call needs a Bearer token. Generate keys at reapi.ai/settings/apikeys.

Authorization: Bearer YOUR_API_KEY

Endpoint

POST /api/v1/images/generations
GET  /api/v1/tasks/{id}

Submission is async. The POST returns immediately with a task_id; the task endpoint returns the same envelope until completion. Polling does not consume credits.

Face Swap is image-to-image only — there is no prompt and no size control; the output keeps the target photo's frame. Each request produces exactly one image (no n parameter) and handles one still image (no video).


Request body

model — string, required

Must be face-swap.

image_url — string, required

Public http(s) URL of the target photo: the image whose face will be replaced. Everything else in it — pose, framing, lighting, hair, background — is kept. Base64 and data: URIs are rejected.

face_image_url — string, required

Public http(s) URL of the source face: the face that is placed onto the target. A clear, front-facing shot in even light gives the strongest result. Base64 and data: URIs are rejected.

seed — integer or null, optional

Pin a seed to reproduce a result for the same two images. 0, null, or omitting the field all mean a random seed. No range is enforced beyond it being an integer.


Pricing

Face Swap bills a flat rate per generated image, independent of the input sizes and of seed. Each request produces one image:

credits = ceil(per_image_usd × 1000)

where 1 credit = $0.001 USD. Failed and rejected requests are not charged.

The exact per-image credit cost surfaces on the model page.


Response

The poll envelope returns the image URL in output.image_urls:

{
  "id": "task_019dfd44b7fd74168541552a3260a623",
  "model": "face-swap",
  "status": "completed",
  "output": {
    "image_urls": [
      "https://...png"
    ]
  }
}

Output URLs are valid for 30 days — mirror them to your own storage if you need long-term retention.


Errors

Failures return the standard reAPI envelope { error: { code, message, request_id } }. Common cases:

  • Invalid input (a missing or non-http(s) image_url / face_image_url, a non-integer seed, or an unknown field such as content_filter) → 400.
  • Insufficient credits → 402.
  • Rate limited → 429.
  • Upstream could not detect a usable face or failed to generate → the task ends failed and the reserved credits are refunded.

See the full catalog at /docs/api/errors.


Tips

  • Source face: front-facing, evenly lit, unobstructed (no sunglasses, no hand over the mouth). The larger and sharper the face, the better the transfer.
  • Target photo: the face should be clearly visible and not tiny in the frame. Strong side angles and heavy occlusion weaken the swap.
  • What stays: hair, head shape, skin tone of the body, pose and background all come from the target. If you need the whole head replaced, that is a head swap, a different operation.
  • Batches: submit many tasks in parallel and poll the ids; pin seed when you want to re-create a specific result later.
  • Output URLs expire after 30 days — copy the file into your own storage as part of the same job.

Table of Contents