Ir al contenido principal

Face Swap Plus es el intercambio de rostros de SpicyAPI para imágenes: ajusta automáticamente el tono de piel entre las dos fotos y decide si mezcla solo la cara o la cabeza entera. Salida en PNG, JPEG o WebP, con semilla opcional.

Desde $0.16/imagen

Playground

Enviar una solicitud

Inicio rápido

Los ejemplos usan las definiciones públicas de parámetros del endpoint seleccionado. Sustituye la clave de API y los medios de ejemplo, y envía la solicitud desde tu servidor.

SDK e integraciones
POSThttps://api.spicyapi.ai/api/v1/jobs/createTask

Autenticación de API

Guarda la clave de API en la variable de entorno del servidor SPICY_API_KEY. Usa autenticación Bearer y Content-Type: application/json en las solicitudes JSON.

Authorization: Bearer $SPICY_API_KEY
Face Swap Plus · Image Editing · Resultado de ejemplo
Resultado de ejemploUsar este ejemplo
# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
  -d '{
  "model": "spicyapi/face-swap-v1-plus/edit",
  "input": {
    "image_url": "https://example.com/reference.png",
    "output_format": "jpeg",
    "reference_image_url": "https://example.com/reference.png"
  }
}'

# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Generado a partir del esquema de entrada de este modelo: el mismo con el que la API valida cada solicitud.

Parámetros de entrada

Incluye estos campos en el objeto input del cuerpo de la solicitud. Los nombres y tipos coinciden con la API. No supongas un valor predeterminado si no está indicado.

reference_image_urlstringObligatorio

La imagen que aporta los rasgos faciales. El tono de piel se concilia por ti, pero la dirección de la luz no, así que una referencia iluminada desde el lado opuesto sigue dejando una costura visible en la mandíbula. Su propio encuadre, fondo y vestuario se ignoran —solo se lee el rostro— y un rostro más grande y nítido aquí es la mayor palanca de calidad.

Valor predeterminado
Sin especificar
Restricciones
minLength:1
contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
image_urlstringObligatorio

La imagen que cambia. La pose, el vestuario, la luz y el fondo de esta persona se conservan; lo que se reemplaza es la zona de la cabeza, y hasta dónde llega esa fusión —solo el rostro o la cabeza entera— se decide par a par y no con un ajuste. Un rostro claramente visible por imagen, más o menos de frente y lo bastante grande para que los rasgos se lean; recorta antes una foto de grupo al sujeto. JPEG, PNG o WebP en una URL que resuelva sin inicio de sesión y siga viva cuando corra la tarea.

Valor predeterminado
Sin especificar
Restricciones
minLength:1
contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
seedintegerOpcional

Reutiliza una semilla para comparar dos ejecuciones sobre el mismo par de imágenes contra un sorteo idéntico, de modo que lo único que se mueva sea lo que cambiaste. Es una herramienta de comparación, no una garantía de resultado idéntico. Déjala vacía para un sorteo nuevo, que suele ser lo que quieres en producción.

Valor predeterminado
Sin especificar
Restricciones
minimum:0
maximum:2147483647
output_qualityintegerOpcional

Calidad de imagen solicitada para el resultado, de 10 a 100 (por defecto 95). No cambia el costo.

Valor predeterminado
95
Restricciones
minimum:10
maximum:100
output_formatstringOpcional

El formato de archivo de la imagen devuelta. Si no ajustas nada se usa JPEG; elige PNG cuando necesites un archivo sin pérdida para seguir editando y WebP cuando el resultado va directo a la web. Los tres cuentan como una imagen generada, así que la elección nunca cambia el precio: toma el que tu tubería espera en lugar de convertir después y pagar una recodificación.

Valor predeterminado
"jpeg"
Valores permitidos
"png""jpeg""webp"
promptstringOpcional

Opcional, pero conviene construir como si no estuviera. El modelo acepta el campo, y aun así cinco llamadas reales del 20/09/2026 —dos pidiendo gafas de sol, una un peinado distinto y dos una expresión diferente— volvieron todas indistinguibles de la misma solicitud con el campo vacío. No falla nada ni avisa nada cuando eso ocurre, así que una llamada que se apoye en él parecerá haber funcionado. No lo envíe.

Valor predeterminado
Sin especificar
Restricciones
maxLength:200

Seguir la tarea

HTTP 202 significa que la tarea se aceptó, no que haya terminado. Guarda el taskId devuelto y consulta esa tarea. No crees otra mientras esperas el resultado.

Solicitud aceptada
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_create",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued",
    "estimatedCost": "0.750000"
  }
}

La respuesta de aceptación incluye la estimación para que tu aplicación pueda mostrar el mismo importe en el historial de tareas y en la facturación.

Consultar la tarea
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
  --data-urlencode "taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Empieza consultando cada 2 segundos aproximadamente y ve espaciando los intentos. Párate en un estado final. Si se cae la conexión, consulta el taskId original. Vuelve a crear la tarea solo con la clave de idempotencia y el cuerpo originales.

O recibe el resultado por callback
import { verifyWebhook } from "@spicyapi/sdk";

// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
  const { payload } = verifyWebhook({
    rawBody: req.body,
    timestamp: req.header("X-Webhook-Timestamp"),
    signature: req.header("X-Webhook-Signature"),
    payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
    secret: process.env.SPICY_WEBHOOK_SECRET,
  });
  res.status(200).end();
  void handleFinishedTask(payload);
});

Pasa callBackUrl al crear la tarea y recibirás el registro terminado por POST, sin un bucle de consultas de estado. Cada entrega lleva X-Webhook-Timestamp, X-Webhook-Signature y X-Webhook-Payload-Version. La firma es un HMAC-SHA256 en base64 sobre taskId.timestamp.sha256(body), así que debes verificarla con los bytes originales: si analizas el JSON y vuelves a serializarlo, los bytes cambian y la verificación falla. Las entregas fallidas se reintentan, de modo que el mismo taskId puede llegar dos veces; haz que tu manejador sea idempotente. Responde 2xx primero y haz el trabajo después: un manejador lento se trata como una entrega fallida.

Leer el resultado

Procesa output solo cuando state sea succeeded. Si falla, consulta errorCode, errorMessage y request_id. Los costos y estados de ejemplo no representan una factura real.

Ejemplo de respuesta completada
{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_record",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "spicyapi/face-swap-v1-plus/edit",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/3f7a1c9e5b2d48f0a6c1e3d5b7f9a1c3.png",
          "mime": "image/png",
          "url": "https://example.r2.cloudflarestorage.com/results/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.png?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
          "expiresAt": "2026-08-28T12:20:08.000Z"
        }
      ]
    },
    "cost": "0.750000",
    "settled": true,
    "createdAt": "2026-08-28T12:00:00Z",
    "completedAt": "2026-08-28T12:00:30Z"
  }
}

Para cada archivo disponible, abre o descarga assets[].url directamente, sin la cabecera Authorization de la API. El enlace firmado expira en expiresAt: vuelve a consultar la tarea para renovarlo mientras el archivo siga dentro del periodo de conservación. Un archivo pendiente o no disponible no trae URL. Trata los enlaces firmados como datos privados.

SDK e integraciones

Usa SpicyAPI en tu app, terminal, asistente de IA o flujo visual. Elige una guía de configuración.

Úsalo en ComfyUI

Instala los nodos de SpicyAPI desde ComfyUI Manager o con el comando de abajo y busca Face Swap Plus · Image Editing en el lienzo. El nodo tiene las mismas opciones que esta página y muestra su precio antes de ejecutarse.

cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi