API Documentation

Integrate LeakifyHub's generation capabilities into your applications.

Authentication

All API requests require authentication using your Secret Key. The API uses Bearer token authentication.

Header
Authorization: Bearer sk_live_your_secret_key

Base URL

All API endpoints are accessed through our base URL with /api/v1 prefix.

Base URL
https://api.leakifyhub.fun/api/v1

Pricing

Pay-as-you-go pricing. Credits deducted on submission, refunded if job fails.

Video Generation

$0.20 - $0.30

per request (varies by style)

Photo Generation

$0.10

per request

Faceswap & Custom generation

$0.10

each per request (same rate as catalog photo)

Sandbox Mode

Sandbox mode allows you to test the API without consuming real credits. Sandbox keys return example videos after a simulated 10-second processing delay, making it perfect for development, testing, and integration workflows.

Key Features

  • No credits charged - completely free for testing
  • Fixed 10-second processing delay to simulate real workflow
  • Returns example videos/photos for each style
  • Separate statistics tracking for sandbox usage
  • Same authentication and response shape as production; includes POST /faceswap/jobs and POST /custom-generation/jobs

Creating Sandbox Keys

To create a sandbox key, check the "Sandbox Key" option when creating a new API key in your dashboard. Sandbox keys use the sk_test_ prefix instead of sk_live_.

Example
Authorization: Bearer sk_test_your_sandbox_secret_key

Differences from Production

FeatureProductionSandbox
Credits ChargedYes (real cost)No (free)
Processing Time1-3 minutes (real)~10 seconds (simulated)
ResultsGenerated from your imageExample videos/photos
Rate Limit100 req/min (job generation), 300-600 req/min (other endpoints)300 req/min (job generation), 500-1000 req/min (other endpoints)

💡 Use Cases

  • Testing API integration before going live
  • Development and debugging workflows
  • Demonstrating API capabilities to clients
  • Building and testing webhook handlers
  • Validating error handling and edge cases

Available Styles

Styles define the generation type. Video styles generate animated content, photo styles produce static images.

Video Styles (type: "video")

Style IDNameCostOptions
Loading styles...

Photo Styles (type: "photo")

The Images column shows how many input URLs you send on POST /jobs/generate: Two means you must pass image_url and image_url_2 (same flag as requires_dual_image: true in GET /jobs/styles).

Style IDNameCostImagesOptions
Loading styles...

Dual-input catalog styles vs faceswap

Only rows with Images: 2 in the table above need a second URL on POST /jobs/generate. In JSON from GET /jobs/styles, those are the photo entries with requires_dual_image: true.

There are no dual-input photo styles in the live catalog right now. Always rely on the Images column or requires_dual_image in GET /jobs/styles — do not guess from the style name alone.

Faceswap is separate: swap a face onto a target body via POST /faceswap/jobs (image_url + face_image_url). Do not use image_url_2 for faceswap.

Style Options Reference

Styles with options require either options.suboption (classic) or options.boolean_selections (boolean-mode). Valid values:

Loading options...

Faceswap

Replace the face on a target image with a face from a second image. Priced at $0.10 per job (same as catalog photo). Poll GET /jobs/{job_id} or use webhook_url like catalog jobs.

Custom generation

Image-to-image generation with a text prompt. The API appends the same face-and-body preservation suffix as the web product. $0.10 per job (same as catalog photo). Use GET /jobs/{job_id} for status and results.

Endpoints

RESTful endpoints for managing generation jobs. Jobs are processed asynchronously.

Usage & Statistics

Monitor your API usage, credits balance, and generation statistics. These endpoints use the same authentication as job endpoints (API keys or Bearer tokens).

API Keys Management

Create and manage your API keys. Important: These endpoints require website JWT authentication (not API key authentication). You must be logged into your account on the website to manage keys.

Authentication: API key management endpoints use website JWT tokens (from your website login), not API keys. Use your website session token with Authorization: Bearer <website_jwt_token>.

File Encryption & Decryption

All generated files are encrypted at rest before being stored on Supabase. Each user's files are encrypted with a unique key derived from their API secret, ensuring privacy and security.

How It Works

  1. You submit a job with your API_SECRET
  2. GPU worker derives a unique encryption key from your API secret using PBKDF2
  3. Generated file is encrypted with this derived key
  4. Encrypted file is uploaded to storage
  5. Job response includes encryption_metadata for decryption
  6. You derive the same key from your API secret and decrypt the file

Key Derivation

Your encryption key is derived from your API_SECRET using PBKDF2:

  • Algorithm: SHA-256
  • Salt: b'leakify_api_secret_salt_v1' (fixed)
  • Iterations: 100,000
  • Key Length: 32 bytes (256 bits)

Important: The same API secret always produces the same encryption key. You only need your API_SECRET to decrypt your files—no master key required!

Encryption Metadata

The job response includes encryption_metadata:

JSON
{
  "encrypted_key": "base64_encoded_encrypted_file_key",
  "iv": "base64_encoded_initialization_vector",
  "algorithm": "AES-256-GCM",
  "key_version": 1
}

encrypted_key: The file's encryption key, encrypted with your derived user key

iv: Initialization vector for file key encryption (fixed: b'file_key_iv_16b')

algorithm: Always "AES-256-GCM"

key_version: Version identifier (currently 1)

Decryption Process

  1. Download the encrypted file from result_url
  2. Derive your encryption key from your API_SECRET using PBKDF2
  3. Decrypt the file key from encryption_metadata.encrypted_key using your derived key
  4. Extract the IV (first 12 bytes) from the encrypted file
  5. Decrypt the file content using the decrypted file key and IV
  6. Save the decrypted file

⚠️ Security Best Practices

  • Never share your API secret—anyone with your secret can decrypt your files
  • Store your API secret securely (environment variables, secrets manager)
  • Never commit secrets to version control
  • If you lose your API secret, you cannot decrypt old files—generate a new key pair for future jobs

Complete Decryption Example

See the Code Examples section above for complete Python and JavaScript implementations that include decryption.

Webhooks

Receive real-time notifications when jobs complete. Include webhook_url in your request.

Webhook Payload

JSON
{
  "job_id": 12345,
  "status": "completed",
  "job_type": "video",
    "style": "cumshot-facial",
  "credits_cost": 0.4,
  "result_url": "https://storage.../signed-url",
  "result_expires_at": "2026-01-11T12:00:00Z",
  "encryption_metadata": {
    "encrypted_key": "base64_encoded_encrypted_file_key",
    "iv": "base64_encoded_iv",
    "algorithm": "AES-256-GCM",
    "key_version": 1
  }
}

Note: The webhook payload includes encryption_metadata for decrypting the file. The result_url is a signed URL that expires in 24 hours.

Code Examples

Complete examples in popular programming languages.

python
import requests
import base64
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

API_SECRET = "sk_live_your_secret_key"
BASE_URL = "https://api.leakifyhub.fun/api/v1"

def derive_user_key(api_secret: str) -> bytes:
    """Derive encryption key from API secret"""
    salt = b'leakify_api_secret_salt_v1'
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )
    return kdf.derive(api_secret.encode('utf-8'))

def decrypt_file(encrypted_path: str, output_path: str, 
                 encryption_metadata: dict, api_secret: str):
    """Decrypt a file using API secret"""
    # Derive user key
    user_key = derive_user_key(api_secret)
    
    # Decrypt file key from metadata
    encrypted_file_key = base64.b64decode(encryption_metadata['encrypted_key'])
    aesgcm = AESGCM(user_key)
    file_key = aesgcm.decrypt(
        nonce=b'file_key_iv_16b',
        data=encrypted_file_key,
        associated_data=None
    )
    
    # Read and decrypt file
    with open(encrypted_path, 'rb') as f:
        file_data = f.read()
    
    file_iv = file_data[:12]
    ciphertext = file_data[12:]
    
    file_aesgcm = AESGCM(file_key)
    plaintext = file_aesgcm.decrypt(
        nonce=file_iv,
        data=ciphertext,
        associated_data=None
    )
    
    with open(output_path, 'wb') as f:
        f.write(plaintext)

# Submit a job
response = requests.post(
    f"{BASE_URL}/jobs/generate",
    headers={"Authorization": f"Bearer {API_SECRET}"},
    json={
        "image_url": "https://example.com/image.jpg",
        "style": "cumshot-facial",
        "type": "video"
    }
)
job = response.json()
print(f"Job ID: {job['job_id']}")

# Poll for completion
import time
while True:
    status = requests.get(
        f"{BASE_URL}/jobs/{job['job_id']}",
        headers={"Authorization": f"Bearer {API_SECRET}"}
    ).json()
    
    if status['status'] == 'completed':
        # Download encrypted file
        encrypted_data = requests.get(status['result_url']).content
        with open('encrypted.mp4.encrypted', 'wb') as f:
            f.write(encrypted_data)
        
        # Decrypt file
        decrypt_file(
            'encrypted.mp4.encrypted',
            'decrypted.mp4',
            status['encryption_metadata'],
            API_SECRET
        )
        print("File decrypted successfully!")
        break
    elif status['status'] == 'failed':
        print(f"Error: {status['error_message']}")
        break
    
    time.sleep(5)

Error Codes

Standard HTTP status codes with JSON error responses.

CodeDescription
401Invalid or missing API key
402Insufficient credits
403API access not approved
404Job not found
429Rate limit exceeded
500Internal server error

API Access Application

Before using the API, you need to apply for API access through the website. These endpoints help you check your application status. Note: These endpoints use website JWT authentication, not API keys.

Getting Started: If you don't have API access yet, visit the API Application page on the website to submit your application. Once approved, you can create API keys and start using the API.

Rate Limits

Rate limiting protects our infrastructure. Limits vary by endpoint and API key type (production vs sandbox).

Production Keys (pk_live_/sk_live_)

EndpointRate Limit
POST /jobs/generate100 requests/minute
POST /faceswap/jobs100 requests/minute
POST /custom-generation/jobs100 requests/minute
GET /jobs/{id}600 requests/minute
GET /jobs300 requests/minute
GET /usage/*300 requests/minute
Other endpoints300 requests/minute

Sandbox Keys (pk_test_/sk_test_)

EndpointRate Limit
POST /jobs/generate300 requests/minute
POST /faceswap/jobs300 requests/minute
POST /custom-generation/jobs300 requests/minute
GET /jobs/{id}1000 requests/minute
GET /jobs600 requests/minute
GET /usage/*500 requests/minute
Other endpoints1000 requests/minute

Rate limit headers included in all responses:

  • X-RateLimit-Limit - Max requests per minute for this endpoint
  • X-RateLimit-Remaining - Remaining requests in current window
  • X-RateLimit-Reset - Unix timestamp when the limit resets
  • Retry-After - Seconds to wait before retrying (only on 429 responses)