Swappr · API REST

Swappr public API

Automate your AI generations (image, video, audio, Face Swap, Camera Roll, personas) from any language. REST JSON, Bearer auth, idempotency and per-key rate limit.

Get started in 60 seconds

  1. Create an API key in your Swappr account (choose the read and generate scopes).
  2. Store it as an environment variable (SWAPPR_API_KEY). It starts with sk_swp_.
  3. Make your first call: GET /api/v1/me to verify authentication.
  4. Launch a generation: POST /api/v1/studio/image/generate, /studio/video/generate, /faceswap/generate or /camera-roll/generate, then poll GET /api/v1/jobs/{id} until 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-5"}'

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

Authentication

Every /api/v1/* request must include the Authorization: Bearer sk_swp_… header. Keys are tied to a user, scoped and rate-limited (60 req/min, 5,000 req/day by default). Format: sk_swp_ followed by 24 base62 characters. The prefix (first 6 chars of the suffix) is visible in the dashboard for identification.

read

Read profile, credits, jobs, models, pricing, library

generate

Starts Studio image/video/audio, Face Swap and Camera Roll

Endpoints

GET/api/v1/mescope: read

Profile + credit balance + subscription + metadata for the current API key.

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

Current credit balance.

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

Lists active and recently completed jobs. `?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

Starts an image generation. Returns a jobId to poll. Models: gpt-image-2, nano-banana-2, seedream-5, wan-27-image, grok-imagine. With nsfw=true: default seedream-5, 3 API guards (plan, dashboard consent, compatible model).

Request body

{
  "prompt": "luxury café interior, golden hour, cinematic",
  "modelId": "seedream-5",
  "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-5","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-5" }),
});

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-5"})
GET/api/v1/studio/modelsscope: read

Studio image/video model catalogue: pricing, qualities, ratios, NSFW support.

Response

{
  "imageModels": [{ "id": "seedream-5", "label": "Seedream 5 Pro", "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

Starts an async video generation. Supports image/video references, audio depending on the model, ratios and durations.

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

Synchronous ElevenLabs text-to-speech. Returns an audio media file and charges credits at Studio Son rates.

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

Synchronous ElevenLabs multi-voice dialogue, up to 10 lines.

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

Status + outputs for a job. Polling every 3 s is recommended.

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

Multipart upload of an image, video or audio reference. Then use `storagePath` or `url` in generative endpoints.

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

NSFW access state: compatible plan, signed consent, mode available.

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

Paginated library media list. `?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

Permanently save a temporary library media item.

Request body

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

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

Deletes a library media item owned by the user.

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

List of AI personas/models saved by the user, usable as identity references.

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

HD Face Swap and refine pricing by engine, NSFW and options.

Response

{ "refineCredits": { "safe": 18, "nsfw": 23 }, "matrix": { "gpt": { "2k": 18 } } }

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

Async HD Face Swap: source + target via public URL or upload `storagePath`.

Request body

{
  "baseImage": { "url": "https://example.com/scene.jpg" },
  "identity": { "modelId": "persona-uuid" },
  "engine": "gpt",
  "quality": "2k",
  "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 '{"baseImage":{"url":"https://example.com/scene.jpg"},"identity":{"modelId":"persona-uuid"},"engine":"gpt"}'

JavaScript

await fetch("https://swappr.fr/api/v1/faceswap/generate", {
  method: "POST",
  headers: { Authorization: `Bearer ${k}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    baseImage: { url: "https://example.com/scene.jpg" },
    identity: { modelId: "persona-uuid" },
    engine: "gpt",
  }),
});

Python

requests.post("https://swappr.fr/api/v1/faceswap/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={
    "baseImage": {"url": "https://example.com/scene.jpg"},
    "identity": {"modelId": "persona-uuid"},
    "engine": "gpt",
  })
POST/api/v1/faceswap/refinescope: generate

Post Face Swap refinement/realism. Useful after a validated swap to improve light, skin and blending.

Request body

{ "faceSwapResultImageUrl": "https://example.com/swap-result.jpg", "engine": "gpt", "nsfw": false }

Response

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

cURL

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

JavaScript

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

Python

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

Camera Roll safe-only pricing by engine, resolution and photo count.

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

iPhone-style Camera Roll scene catalogue, filterable by vibe/category.

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

Generates a coherent Camera Roll gallery from an identity or reference. `subjectGender` accepts `feminine`, `masculine`, `neutral`, `auto`.

Request body

{
  "referenceImage": { "url": "https://example.com/portrait.jpg" },
  "sceneId": "car_passenger_bad_selfie",
  "photoIndex": 0,
  "totalPhotos": 4,
  "engine": "gpt",
  "quality": "2k",
  "subjectGender": "feminine"
}

Response

{ "jobId": "…", "batchParentId": "…", "status": "queued", "creditsCharged": 18 }

cURL

curl -X POST https://swappr.fr/api/v1/camera-roll/generate \
  -H "Authorization: Bearer sk_swp_xxx" -H "Content-Type: application/json" \
  -d '{"referenceImage":{"url":"https://example.com/portrait.jpg"},"sceneId":"car_passenger_bad_selfie","photoIndex":0,"totalPhotos":4,"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({
    referenceImage: { url: "https://example.com/portrait.jpg" },
    sceneId: "car_passenger_bad_selfie",
    photoIndex: 0,
    totalPhotos: 4,
    subjectGender: "feminine",
  }),
});

Python

requests.post("https://swappr.fr/api/v1/camera-roll/generate",
  headers={"Authorization": f"Bearer {k}", "Content-Type": "application/json"},
  json={
    "referenceImage": {"url": "https://example.com/portrait.jpg"},
    "sceneId": "car_passenger_bad_selfie",
    "photoIndex": 0,
    "totalPhotos": 4,
    "subjectGender": "feminine",
  })

NSFW mode via API

The nsfw: true parameter in POST /api/v1/studio/image/generate enables adult mode (Kie filtering off + ×1.25 surcharge). 3 conditions must be met:

  1. NSFW entitlement : Pro/Studio included or NSFW add-on active. Otherwise 403 nsfw_plan_required.
  2. Signed legal consent once on the dashboard (modal on the first NSFW toggle). Otherwise 403 nsfw_consent_required.
  3. Compatible model : seedream-5, wan-27-image, nano-banana-2. gpt-image-2 is not NSFW capable. Otherwise 400 model_not_nsfw_capable.

Default model : without modelId, the API uses gpt-image-2 (safe) or wan-27-image if nsfw: true.

Surcharge exemption : users with 3+ active referrals (affiliate program) or admin flag nsfw_surcharge_exempt are detected automatically, no ×1.25.

Forbidden in all cases : content involving minors, or real people without consent (deepfake, sanctioned by the French law of 21 May 2024). Any violation triggers immediate key revocation and reporting.

Error codes

All errors return a JSON body: { "error": { "code": "…", "message": "…", "details"?: { … } } }

StatusCodeCause
400invalid_bodyMissing or invalid JSON body
400missing_prompt`prompt` required for generate
400invalid_aspect_ratioRatio not supported by the model or workflow
400model_not_supportedUnknown model or unavailable on this endpoint
401missing_or_invalid_keyAuthorization header missing or malformed
401invalid_keyUnknown or revoked key
401key_expiredExpired key (expires_at field)
402insufficient_creditsInsufficient balance for the generation
403scope_missingThe key is missing the required scope
403nsfw_plan_requiredNSFW not included, NSFW add-on or Pro/Studio upgrade
403nsfw_consent_requiredNSFW consent not signed, confirm once on the dashboard
403FRAUD_BLOCKEDAccount suspended: go back to the dashboard and Pro reactivation
404job_not_foundJob not found or not owned by the user
404library_item_not_foundMedia not found or not owned by the user
409idempotency_conflictSame Idempotency-Key reused with a different body
413file_too_largeUpload too large
415unsupported_media_typeMIME not supported for upload
400model_not_nsfw_capableModel does not support NSFW (use seedream-5/wan-27-image/nano-banana-2)
429rate_limit_minuteMore than 60 req/min
429rate_limit_dayMore than 5,000 req/day
500internal_errorServer error, open a ticket if it keeps happening

Ready-made integrations

Skill Claude

Download the ZIP from Account & credits → API or copy docs/agents/skills/swappr-api/ dans ~/.claude/skills/.

View the skill

MCP server

npx -y @swappr/[email protected], connects Claude Desktop, Cursor, Continue, any MCP client to the Swappr API.

View the MCP server

Spec OpenAPI 3.1

The YAML file is served at /openapi.yaml. Importable in Postman, Insomnia, Stoplight or to generate clients (openapi-generator).