Swappr · API REST

API publique Swappr

Automatisez vos générations IA (image, vidéo, audio, Face Swap, Camera Roll, personas) depuis n'importe quel langage. REST JSON, auth Bearer, idempotency et rate-limit par clé.

Démarrage en 60 secondes

  1. Créez une clé API dans votre compte Swappr (choisissez les scopes read et generate).
  2. Stockez-la en variable d'environnement (SWAPPR_API_KEY). Elle commence par sk_swp_.
  3. Faites votre premier appel : GET /api/v1/mepour vérifier l'authentification.
  4. Lancez une génération : POST /api/v1/studio/image/generate, /studio/video/generate, /faceswap/generate ou /camera-roll/generate, puis poll GET /api/v1/jobs/{id} jusqu'à status: completed.
# 1. Test auth
curl -H "Authorization: Bearer $SWAPPR_API_KEY" https://swappr.fr/api/v1/me

# 2. Génération
curl -X POST https://swappr.fr/api/v1/studio/image/generate \
  -H "Authorization: Bearer $SWAPPR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"luxury café, golden hour","modelId":"seedream-45"}'

# 3. Récupère le résultat
curl -H "Authorization: Bearer $SWAPPR_API_KEY" https://swappr.fr/api/v1/jobs/JOB_ID

Authentification

Toutes les requêtes /api/v1/* doivent inclure le header Authorization: Bearer sk_swp_…. Les clés sont liées à un utilisateur, limitées par scopes et soumises à un rate-limit (60 req/min, 5 000 req/jour par défaut). Format : sk_swp_ suivi de 24 caractères base62. Le préfixe (6 premiers chars du suffixe) est visible côté dashboard pour identification.

read

Lecture profil, crédits, jobs, modèles, pricing, bibliothèque

generate

Lance Studio image/vidéo/audio, Face Swap et Camera Roll

publish

Publication Instagram via Social Manager

Endpoints

GET/api/v1/mescope: read

Profil + solde crédits + abonnement + métadonnées de la clé API courante.

Response

{
  "user": { "id": "user_…", "email": "…", "createdAt": "…" },
  "credits": { "balance": 4750, "monthlyQuota": 5300, "usedThisMonth": 550 },
  "subscription": { "planId": "pro", "status": "active", "currentPeriodEnd": "…" },
  "apiKey": { "id": "…", "scopes": ["read","generate"], "rateLimit": { "perMinute": 60, "perDay": 5000 } }
}

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/me

JavaScript

const res = await fetch("https://swappr.fr/api/v1/me", {
  headers: { Authorization: `Bearer ${SWAPPR_KEY}` },
});
const data = await res.json();

Python

import requests
r = requests.get("https://swappr.fr/api/v1/me",
  headers={"Authorization": f"Bearer {SWAPPR_KEY}"})
print(r.json())
GET/api/v1/credits/balancescope: read

Solde crédits courant.

Response

{ "balance": 4750, "monthlyQuota": 5300, "usedThisMonth": 550, "welcomeTrialRemaining": 0 }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/credits/balance

JavaScript

await fetch("https://swappr.fr/api/v1/credits/balance", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/credits/balance", headers={"Authorization": f"Bearer {k}"})
GET/api/v1/jobsscope: read

Liste les jobs actifs et récemment terminés. `?include=active,recent&limit=40`.

Response

{
  "jobs": [{ "id": "…", "status": "processing", "workflow": "studio_image", "createdAt": "…" }],
  "hasMore": false
}

cURL

curl -H "Authorization: Bearer sk_swp_xxx" "https://swappr.fr/api/v1/jobs?include=active,recent&limit=40"

JavaScript

await fetch("https://swappr.fr/api/v1/jobs?include=active,recent", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/jobs?include=active,recent", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/studio/image/generatescope: generate

Lance une génération image. Retourne un jobId à poller. Modèles : gpt-image-2, nano-banana-2, seedream-45, wan-27-image, qwen-image, grok-imagine. Avec nsfw=true : défaut seedream-45, 3 guards API (plan, consentement dashboard, modèle compatible).

Request body

{
  "prompt": "luxury café interior, golden hour, cinematic",
  "modelId": "seedream-45",
  "imageCount": 1,
  "aspectRatio": "4:5",
  "nsfw": false,
  "referenceImageUrls": []
}

Response

{ "jobId": "…", "batchId": "…", "status": "queued", "creditsCharged": 10 }

cURL

curl -X POST https://swappr.fr/api/v1/studio/image/generate \
  -H "Authorization: Bearer sk_swp_xxx" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"café interior","modelId":"seedream-45","aspectRatio":"4:5"}'

JavaScript

const res = await fetch("https://swappr.fr/api/v1/studio/image/generate", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "café interior", modelId: "seedream-45" }),
});

Python

requests.post("https://swappr.fr/api/v1/studio/image/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"prompt": "café interior", "modelId": "seedream-45"})
GET/api/v1/studio/modelsscope: read

Catalogue des modèles Studio image/vidéo : tarifs, qualités, ratios, support NSFW.

Response

{
  "imageModels": [{ "id": "seedream-45", "label": "Seedream 4.5", "nsfwCapable": true }],
  "videoModels": [{ "id": "kling-3", "label": "Kling", "durations": [5, 10] }]
}

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/studio/models

JavaScript

await fetch("https://swappr.fr/api/v1/studio/models", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/studio/models", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/studio/video/generatescope: generate

Lance une génération vidéo asynchrone. Supporte références image/vidéo, audio selon modèle, ratios et durées.

Request body

{
  "prompt": "cinematic rooftop reel",
  "modelId": "kling-3",
  "aspectRatio": "9:16",
  "duration": 5,
  "referenceImageUrls": ["https://…"],
  "generateAudio": false
}

Response

{ "jobId": "…", "status": "queued", "creditsCharged": 120 }

cURL

curl -X POST https://swappr.fr/api/v1/studio/video/generate \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"prompt":"rooftop reel","modelId":"kling-3","aspectRatio":"9:16","duration":5}'

JavaScript

await fetch("https://swappr.fr/api/v1/studio/video/generate", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "rooftop reel", modelId: "kling-3", duration: 5 }),
});

Python

requests.post("https://swappr.fr/api/v1/studio/video/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"prompt": "rooftop reel", "modelId": "kling-3", "duration": 5})
POST/api/v1/studio/audio/ttsscope: generate

Synthèse vocale ElevenLabs synchrone. Retourne un média audio et débite les crédits au tarif Studio Son.

Request body

{
  "text": "Bienvenue sur Swappr.",
  "voiceId": "VOICE_ID",
  "modelId": "eleven_multilingual_v2",
  "languageCode": "fr"
}

Response

{ "url": "https://…/audio.mp3", "mediaType": "audio", "creditsCharged": 4 }

cURL

curl -X POST https://swappr.fr/api/v1/studio/audio/tts \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"text":"Bienvenue sur Swappr.","voiceId":"VOICE_ID"}'

JavaScript

await fetch("https://swappr.fr/api/v1/studio/audio/tts", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ text: "Bienvenue sur Swappr.", voiceId: "VOICE_ID" }),
});

Python

requests.post("https://swappr.fr/api/v1/studio/audio/tts",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"text": "Bienvenue sur Swappr.", "voiceId": "VOICE_ID"})
POST/api/v1/studio/audio/dialoguescope: generate

Dialogue multi-voix ElevenLabs synchrone, jusqu'à 10 répliques.

Request body

{
  "inputs": [
    { "text": "Salut !", "voiceId": "VOICE_A" },
    { "text": "On tourne maintenant ?", "voiceId": "VOICE_B" }
  ],
  "languageCode": "fr"
}

Response

{ "url": "https://…/dialogue.mp3", "mediaType": "audio", "creditsCharged": 8 }

cURL

curl -X POST https://swappr.fr/api/v1/studio/audio/dialogue \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"inputs":[{"text":"Salut !","voiceId":"VOICE_A"}]}'

JavaScript

await fetch("https://swappr.fr/api/v1/studio/audio/dialogue", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ inputs: [{ text: "Salut !", voiceId: "VOICE_A" }] }),
});

Python

requests.post("https://swappr.fr/api/v1/studio/audio/dialogue",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"inputs": [{"text": "Salut !", "voiceId": "VOICE_A"}]})
GET/api/v1/jobs/{id}scope: read

Statut + outputs d'un job. Poll toutes les 3 s recommandé.

Response

{
  "id": "…", "status": "completed", "outputs": ["https://…"],
  "creditsCharged": 10, "createdAt": "…", "updatedAt": "…"
}

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/jobs/JOB_ID

JavaScript

await fetch(`https://swappr.fr/api/v1/jobs/${jobId}`, { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get(f"https://swappr.fr/api/v1/jobs/{job_id}", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/uploadsscope: generate

Upload multipart d'un fichier de référence image, vidéo ou audio. Utilisez ensuite `storagePath` ou `url` dans les endpoints génératifs.

Request body

multipart/form-data
[email protected]

Response

{ "url": "https://…", "storagePath": "api-uploads/user/…", "mimeType": "image/jpeg", "size": 123456 }

cURL

curl -X POST https://swappr.fr/api/v1/uploads \
  -H "Authorization: Bearer sk_swp_xxx" \
  -F "[email protected]"

JavaScript

const form = new FormData();
form.append("file", file);
await fetch("https://swappr.fr/api/v1/uploads", { method: "POST", headers: { Authorization: `Bearer ${k}` }, body: form });

Python

requests.post("https://swappr.fr/api/v1/uploads",
  headers={"Authorization": f"Bearer {k}"},
  files={"file": open("reference.jpg", "rb")})
GET/api/v1/nsfw/statusscope: read

État d'accès NSFW : plan compatible, consentement signé, mode disponible.

Response

{ "eligible": true, "consentRequired": false, "planId": "pro", "surchargeMultiplier": 1.25 }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/nsfw/status

JavaScript

await fetch("https://swappr.fr/api/v1/nsfw/status", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/nsfw/status", headers={"Authorization": f"Bearer {k}"})
GET/api/v1/library/itemsscope: read

Liste paginée des médias de la bibliothèque. `?kind=saved|temporary&limit=20&cursor=<iso>`.

Response

{
  "items": [{ "id": "…", "url": "…", "mediaType": "image", "retention": "saved", "createdAt": "…", "jobId": "…" }],
  "nextCursor": "2026-06-12T12:00:00Z",
  "hasMore": true
}

cURL

curl -H "Authorization: Bearer sk_swp_xxx" "https://swappr.fr/api/v1/library/items?limit=20&kind=saved"

JavaScript

await fetch("https://swappr.fr/api/v1/library/items?limit=20", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/library/items?limit=20", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/library/items/{id}/savescope: generate

Sauvegarde permanente d'un média temporaire de la bibliothèque.

Request body

{ "mediaType": "image", "modelId": "seedream-45" }

Response

{ "id": "…", "retention": "saved", "url": "https://…" }

cURL

curl -X POST https://swappr.fr/api/v1/library/items/ITEM_ID/save \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" -d '{}'

JavaScript

await fetch("https://swappr.fr/api/v1/library/items/ITEM_ID/save", { method: "POST", headers: { Authorization: `Bearer ${k}` }})

Python

requests.post("https://swappr.fr/api/v1/library/items/ITEM_ID/save", headers={"Authorization": f"Bearer {k}"})
DELETE/api/v1/library/items/{id}scope: generate

Supprime un média de la bibliothèque appartenant à l'utilisateur.

Response

{ "ok": true }

cURL

curl -X DELETE -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/library/items/ITEM_ID

JavaScript

await fetch("https://swappr.fr/api/v1/library/items/ITEM_ID", { method: "DELETE", headers: { Authorization: `Bearer ${k}` }})

Python

requests.delete("https://swappr.fr/api/v1/library/items/ITEM_ID", headers={"Authorization": f"Bearer {k}"})
GET/api/v1/modelsscope: read

Liste des personas/modèles IA enregistrés par l'utilisateur, utilisables comme référence d'identité.

Response

{ "models": [{ "id": "…", "name": "Maya", "imageUrl": "https://…", "createdAt": "…" }] }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/models

JavaScript

await fetch("https://swappr.fr/api/v1/models", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/models", headers={"Authorization": f"Bearer {k}"})
GET/api/v1/faceswap/pricingscope: read

Tarifs Face Swap HD et refinement selon moteur, NSFW et options.

Response

{ "baseCredits": 15, "refineCredits": 9, "nsfwMultiplier": 1.25 }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/faceswap/pricing

JavaScript

await fetch("https://swappr.fr/api/v1/faceswap/pricing", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/faceswap/pricing", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/faceswap/generatescope: generate

Face Swap HD asynchrone : source + cible via URL publique ou `storagePath` d'upload.

Request body

{
  "sourceImageUrl": "https://…/face.jpg",
  "targetImageUrl": "https://…/scene.jpg",
  "engine": "gpt",
  "nsfw": false
}

Response

{ "jobId": "…", "status": "queued", "creditsCharged": 15 }

cURL

curl -X POST https://swappr.fr/api/v1/faceswap/generate \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"sourceImageUrl":"https://…/face.jpg","targetImageUrl":"https://…/scene.jpg"}'

JavaScript

await fetch("https://swappr.fr/api/v1/faceswap/generate", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ sourceImageUrl: "https://…/face.jpg", targetImageUrl: "https://…/scene.jpg" }),
});

Python

requests.post("https://swappr.fr/api/v1/faceswap/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"sourceImageUrl": "https://…/face.jpg", "targetImageUrl": "https://…/scene.jpg"})
POST/api/v1/faceswap/refinescope: generate

Finition/réalisme post Face Swap. Utile après un swap validé pour améliorer lumière, peau et blending.

Request body

{ "imageUrl": "https://…/swap.jpg", "engine": "gpt", "nsfw": false }

Response

{ "jobId": "…", "status": "queued", "creditsCharged": 9 }

cURL

curl -X POST https://swappr.fr/api/v1/faceswap/refine \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"imageUrl":"https://…/swap.jpg"}'

JavaScript

await fetch("https://swappr.fr/api/v1/faceswap/refine", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ imageUrl: "https://…/swap.jpg" }),
});

Python

requests.post("https://swappr.fr/api/v1/faceswap/refine",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"imageUrl": "https://…/swap.jpg"})
GET/api/v1/camera-roll/pricingscope: read

Tarifs Camera Roll safe-only selon moteur, résolution et nombre de photos.

Response

{ "engines": ["gpt", "nano"], "qualities": ["1k", "2k", "4k"], "photoCounts": [4, 8, 12, 20] }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/camera-roll/pricing

JavaScript

await fetch("https://swappr.fr/api/v1/camera-roll/pricing", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/camera-roll/pricing", headers={"Authorization": f"Bearer {k}"})
GET/api/v1/camera-roll/scenesscope: read

Catalogue des scènes Camera Roll iPhone-style, filtrable par vibe/catégorie.

Response

{ "scenes": [{ "id": "parking-selfie", "title": "Parking selfie", "category": "lifestyle" }] }

cURL

curl -H "Authorization: Bearer sk_swp_xxx" https://swappr.fr/api/v1/camera-roll/scenes

JavaScript

await fetch("https://swappr.fr/api/v1/camera-roll/scenes", { headers: { Authorization: `Bearer ${k}` }})

Python

requests.get("https://swappr.fr/api/v1/camera-roll/scenes", headers={"Authorization": f"Bearer {k}"})
POST/api/v1/camera-roll/generatescope: generate

Génère une galerie Camera Roll cohérente depuis une identité ou une référence. `subjectGender` accepte `feminine`, `masculine`, `neutral`, `auto`.

Request body

{
  "prompt": "night parking, casual selfie",
  "sceneIds": ["parking-selfie"],
  "photoCount": 5,
  "engine": "gpt",
  "aspectRatio": "3:4",
  "subjectGender": "feminine"
}

Response

{ "batchId": "…", "jobIds": ["…"], "status": "queued", "creditsCharged": 75 }

cURL

curl -X POST https://swappr.fr/api/v1/camera-roll/generate \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"prompt":"night parking","sceneIds":["parking-selfie"],"photoCount":5,"subjectGender":"feminine"}'

JavaScript

await fetch("https://swappr.fr/api/v1/camera-roll/generate", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "night parking", sceneIds: ["parking-selfie"], photoCount: 5, subjectGender: "feminine" }),
});

Python

requests.post("https://swappr.fr/api/v1/camera-roll/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={"prompt": "night parking", "sceneIds": ["parking-selfie"], "photoCount": 5, "subjectGender": "feminine"})

Mode NSFW via API

Le paramètre nsfw: true dans POST /api/v1/studio/image/generate active le mode adulte (filtrage Kie désactivé + surcoût ×1,25). 3 conditions doivent être réunies :

  1. Droit NSFW : Pro/Studio inclus ou option NSFW active. Sinon 403 nsfw_plan_required.
  2. Consentement légal signé une seule fois sur le dashboard (modale au premier toggle NSFW). Sinon 403 nsfw_consent_required.
  3. Modèle compatible : seedream-45, wan-27-image, qwen-image, grok-imagine, nano-banana-2. Le modèle gpt-image-2 n'est pas compatible NSFW. Sinon 400 model_not_nsfw_capable.

Modèle par défaut : sans modelId, l'API utilise gpt-image-2 (safe) ou wan-27-image si nsfw: true.

Exemption surcoût: les utilisateurs avec 3+ filleuls actifs (programme d'affiliation) ou flag admin nsfw_surcharge_exempt sont automatiquement détectés — pas de ×1,25.

Interdit en toute circonstance : contenus impliquant des mineurs, ou des personnes réelles sans consentement (deepfake — sanctionné par la loi française du 21 mai 2024). Toute violation entraîne révocation immédiate des clés et signalement.

Codes d'erreur

Toutes les erreurs renvoient un body JSON : { "error": { "code": "…", "message": "…", "details"?: { … } } }

StatusCodeCause
400invalid_bodyBody JSON manquant ou invalide
400missing_prompt`prompt` requis pour generate
400invalid_aspect_ratioRatio non supporté par le modèle ou le workflow
400model_not_supportedModèle inconnu ou indisponible sur cet endpoint
401missing_or_invalid_keyHeader Authorization absent ou mal formé
401invalid_keyClé inconnue ou révoquée
401key_expiredClé expirée (champ expires_at)
402insufficient_creditsSolde insuffisant pour la génération
403scope_missingLa clé n'a pas le scope requis
403nsfw_plan_requiredNSFW non inclus — option NSFW ou upgrade Pro/Studio
403nsfw_consent_requiredConsentement NSFW non signé — à valider une fois côté dashboard
403FRAUD_BLOCKEDCompte suspendu : repasser par le dashboard et la réactivation Pro
404job_not_foundJob introuvable ou n'appartient pas à l'utilisateur
404library_item_not_foundMédia introuvable ou n'appartient pas à l'utilisateur
409idempotency_conflictMême Idempotency-Key réutilisée avec un body différent
413file_too_largeUpload trop volumineux
415unsupported_media_typeMIME non supporté pour l'upload
400model_not_nsfw_capableModèle ne supporte pas NSFW (utiliser seedream-45/wan-27-image/qwen-image/grok-imagine/nano-banana-2)
429rate_limit_minutePlus de 60 req/min
429rate_limit_dayPlus de 5 000 req/jour
500internal_errorErreur serveur — ouvrez un ticket si récurrent

Intégrations prêtes

Skill Claude

Copiez skills/swappr-api/ dans ~/.claude/skills/. Claude (Code ou Desktop) appelle directement l'API.

Voir le skill

Serveur MCP

npx -y @swappr/mcp— connecte Claude Desktop, Cursor, Continue, tout client MCP à l'API Swappr.

Voir le serveur MCP

Spec OpenAPI 3.1

Le fichier YAML est servi à /openapi.yaml. Importable dans Postman, Insomnia, Stoplight ou pour générer des clients (openapi-generator).