Ssemble API

Errors

Error codes and response format for the Ssemble API.

Error response format

All API errors follow a consistent JSON structure:

{
  "error": {
    "code": "error_code",
    "message": "Human-readable error description",
    "details": null
  }
}
FieldTypeDescription
codestringMachine-readable error code for programmatic handling
messagestringHuman-readable description explaining what went wrong
detailsobject | nullAdditional context about the error (e.g., invalid field values)

Error codes reference

Client errors (4xx)

HTTP StatusCodeDescription
400invalid_requestMissing or invalid parameters in the request body
400invalid_youtube_urlThe YouTube URL is invalid, unreachable, or is a Shorts URL
400video_too_longVideo duration exceeds the 5-hour (18,000 second) limit
400url_validation_failedFailed to validate or fetch the provided URL
401missing_api_keyNo API key header was provided in the request
401invalid_api_keyAPI key format is wrong, key not found, or key has been revoked
403subscription_requiredAn active subscription is required to use the API
403insufficient_creditsAccount has no remaining credits to create shorts
404resource_not_foundThe requested resource (request ID) does not exist
429rate_limit_exceededToo many requests — slow down and check rate limit headers

Server errors (5xx)

HTTP StatusCodeDescription
500internal_errorAn unexpected server error occurred — safe to retry

Handling errors in code

JavaScript

async function createShort(params) {
  const response = await fetch('https://aiclipping.ssemble.com/api/v1/shorts/create', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.SSEMBLE_API_KEY
    },
    body: JSON.stringify(params)
  });
 
  const result = await response.json();
 
  if (!response.ok) {
    const { code, message, details } = result.error;
 
    switch (code) {
      case 'invalid_request':
        console.error(`Validation error: ${message}`, details);
        break;
      case 'insufficient_credits':
        console.error('No credits remaining — purchase more at app.ssemble.com');
        break;
      case 'rate_limit_exceeded':
        const resetAt = response.headers.get('X-RateLimit-Reset');
        const waitMs = new Date(resetAt).getTime() - Date.now();
        console.error(`Rate limited. Retry in ${Math.ceil(waitMs / 1000)}s`);
        break;
      case 'internal_error':
        console.error('Server error — retrying in 5 seconds...');
        await new Promise(r => setTimeout(r, 5000));
        return createShort(params); // Retry once
      default:
        console.error(`API error [${code}]: ${message}`);
    }
 
    throw new Error(`API error: ${code}`);
  }
 
  return result.data;
}

Python

import requests
import time
 
def create_short(params):
    response = requests.post(
        'https://aiclipping.ssemble.com/api/v1/shorts/create',
        json=params,
        headers={'X-API-Key': os.environ['SSEMBLE_API_KEY']}
    )
 
    if not response.ok:
        error = response.json().get('error', {})
        code = error.get('code', 'unknown')
        message = error.get('message', 'Unknown error')
 
        if code == 'rate_limit_exceeded':
            reset_at = response.headers.get('X-RateLimit-Reset', '')
            from datetime import datetime
            reset_time = datetime.fromisoformat(reset_at.replace('Z', '+00:00'))
            wait = max(int((reset_time - datetime.now(reset_time.tzinfo)).total_seconds()), 1)
            raise Exception(f'Rate limited. Retry in {wait}s')
        elif code == 'insufficient_credits':
            raise Exception('No credits remaining')
        elif code == 'internal_error':
            time.sleep(5)
            return create_short(params)  # Retry once
        else:
            raise Exception(f'API error [{code}]: {message}')
 
    return response.json()['data']

Common error scenarios

Invalid request parameters

Returned when required fields are missing or parameter values are invalid.

{
  "error": {
    "code": "invalid_request",
    "message": "Start time must be less than end time",
    "details": { "start": 600, "end": 100 }
  }
}

Common triggers:

  • Missing url or fileUrl
  • Both url and fileUrl provided (must provide exactly one)
  • Missing start or end
  • start is negative
  • end is less than or equal to start
  • Time window (end - start) exceeds 1,200 seconds (20 minutes)
  • Time window (end - start) is less than 1 second
  • Invalid templateId format (must be 24-character hex)
  • Non-existent templateId (valid format but not found in template library)
  • Invalid musicName (track not found in music library)
  • Invalid gameVideoName (video not found in game video library)
  • Invalid memeHookName (clip not found in meme hook library)
  • Invalid preferredLength value
  • Invalid language or captionLanguage code
  • Invalid layout value
  • ctaEnabled is true but ctaText is missing
  • ctaText exceeds 200 characters
  • fileUrl doesn't start with http:// or https://
  • Invalid JSON in request body

Invalid YouTube URL

{
  "error": {
    "code": "invalid_youtube_url",
    "message": "YouTube Shorts URLs are not supported. Please provide the full video URL.",
    "details": { "url": "https://youtube.com/shorts/abc123" }
  }
}

Common triggers:

  • YouTube Shorts URL (youtube.com/shorts/...) — use the full video URL instead
  • Private or deleted video
  • URL is not a valid YouTube video link
  • Region-restricted video that can't be accessed

Rate limit exceeded

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Hourly rate limit exceeded",
    "details": {
      "limit": 100,
      "reset": "2024-06-01T13:00:00.000Z"
    }
  }
}

The details object includes retryAfter (for per-endpoint limits) or limit + reset (for account-level limits). You can also check the response headers:

const resetAt = response.headers.get('X-RateLimit-Reset');
const waitSeconds = Math.ceil((new Date(resetAt).getTime() - Date.now()) / 1000);
console.log(`Retry in ${waitSeconds} seconds`);

See Rate Limits for detailed limits per endpoint and best practices.

Insufficient credits

{
  "error": {
    "code": "insufficient_credits",
    "message": "No credits available",
    "details": {
      "required": 1,
      "available": 0
    }
  }
}

Each short creation consumes 1 credit. Purchase additional credits or upgrade your plan at app.ssemble.com.

Authentication failure

When no API key is provided:

{
  "error": {
    "code": "missing_api_key",
    "message": "API key is required. Please provide it in X-API-Key header or as Bearer token.",
    "details": null
  }
}

When the API key is invalid or revoked:

{
  "error": {
    "code": "invalid_api_key",
    "message": "Invalid or inactive API key",
    "details": null
  }
}

Verify your API key is correct and included in the X-API-Key or Authorization: Bearer header. See Authentication for details.

Resource not found

{
  "error": {
    "code": "resource_not_found",
    "message": "Request not found",
    "details": null
  }
}

The request ID doesn't exist or belongs to a different account. Verify the ID is correct and was created with the same API key.

Internal server error

{
  "error": {
    "code": "internal_error",
    "message": "An internal error occurred. Please try again.",
    "details": null
  }
}

Server errors are typically transient. Wait a few seconds and retry the request. If the error persists, contact support.


Best practices for error handling

  • Always check response.ok (or the HTTP status code) before parsing the response body as success data.
  • Use the code field for programmatic error handling, not the message — messages may change over time.
  • Retry on 500 errors with exponential backoff. A simple strategy: wait 1s, 2s, 4s, then give up.
  • Don't retry 4xx errors (except 429) — they indicate a problem with your request that needs to be fixed.
  • Log the full error response including details for debugging. The details field often contains the specific field or value that caused the error.
  • Handle 429 gracefully — read the X-RateLimit-Reset header and schedule retries accordingly.
Ssemble Logo
Copyright © 2026 Ssemble Inc.
All rights reserved