Skip to main content
The shortkit API uses conventional HTTP response codes and returns structured error responses to help you handle failures gracefully.

HTTP status codes

CodeMeaning
200Success
201Created - Resource successfully created
204No Content - Success with no response body
400Bad Request - Invalid request parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Key lacks required permissions
404Not Found - Resource doesn’t exist
409Conflict - Resource state conflict
422Unprocessable Entity - Validation failed
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server-side issue
503Service Unavailable - Temporary outage

Error response format

All errors follow a consistent structure:
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Title is required",
    "details": {
      "field": "title",
      "reason": "required"
    }
  },
  "meta": {
    "requestId": "req_xyz789"
  }
}

Error fields

error.code
string
required
Machine-readable error code for programmatic handling.
error.message
string
required
Human-readable error description.
error.details
object
Additional context about the error. Structure varies by error type.
meta.requestId
string
required
Unique request identifier for support inquiries.

Error codes reference

Authentication errors

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key
KEY_REVOKED401API key has been revoked
KEY_EXPIRED401API key has expired
FORBIDDEN403Insufficient permissions
ENVIRONMENT_MISMATCH403Wrong environment key

Validation errors

CodeHTTP StatusDescription
VALIDATION_ERROR400Request validation failed
INVALID_REQUEST400Malformed request body
MISSING_PARAMETER400Required parameter missing
INVALID_PARAMETER400Parameter value invalid

Resource errors

CodeHTTP StatusDescription
NOT_FOUND404Resource doesn’t exist
ALREADY_EXISTS409Resource already exists
CONFLICT409Resource state conflict
GONE410Resource has been deleted

Content errors

CodeHTTP StatusDescription
CONTENT_NOT_READY409Content still processing
CONTENT_FAILED422Content processing failed
INVALID_MEDIA_TYPE422Unsupported file format
FILE_TOO_LARGE422File exceeds size limit
DURATION_EXCEEDED422Video exceeds max duration

Rate limiting errors

CodeHTTP StatusDescription
RATE_LIMITED429Too many requests
QUOTA_EXCEEDED429Monthly quota exceeded

Server errors

CodeHTTP StatusDescription
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Temporary service outage
UPSTREAM_ERROR502Third-party service failure

Handling errors

Basic error handling

async function createContent(data) {
  try {
    const response = await fetch('https://api.shortkit.dev/v1/content', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    });

    if (!response.ok) {
      const error = await response.json();
      throw new ShortkitError(error);
    }

    return response.json();
  } catch (error) {
    handleError(error);
  }
}

function handleError(error) {
  switch (error.code) {
    case 'VALIDATION_ERROR':
      console.error(`Validation failed: ${error.message}`);
      break;
    case 'RATE_LIMITED':
      // Implement retry with backoff
      break;
    case 'UNAUTHORIZED':
      // Refresh credentials or redirect to login
      break;
    default:
      console.error(`API error: ${error.message}`);
  }
}

Retry with exponential backoff

For transient errors (429, 503), implement retry logic:
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429 || response.status === 503) {
        if (attempt === maxRetries) throw new Error('Max retries exceeded');

        // Get retry delay from header or use exponential backoff
        const retryAfter = response.headers.get('Retry-After');
        const delay = retryAfter
          ? parseInt(retryAfter) * 1000
          : Math.pow(2, attempt) * 1000;

        await sleep(delay);
        continue;
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Validation error details

Validation errors include field-level details:
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {
      "errors": [
        {
          "field": "title",
          "reason": "required",
          "message": "Title is required"
        },
        {
          "field": "duration",
          "reason": "max",
          "message": "Duration cannot exceed 180 seconds",
          "max": 180
        }
      ]
    }
  }
}
Handle multiple validation errors:
function displayValidationErrors(error) {
  if (error.code !== 'VALIDATION_ERROR') return;

  const errors = error.details?.errors || [];
  errors.forEach(err => {
    const field = document.querySelector(`[name="${err.field}"]`);
    if (field) {
      field.classList.add('error');
      showFieldError(field, err.message);
    }
  });
}

SDK error handling

The SDKs provide typed error classes:
shortKit.fetchFeed { result in
    switch result {
    case .success(let feed):
        self.displayFeed(feed)
    case .failure(let error):
        switch error {
        case .networkError(let underlying):
            self.showNetworkError()
        case .authenticationError:
            self.refreshCredentials()
        case .rateLimited(let retryAfter):
            self.scheduleRetry(after: retryAfter)
        case .serverError(let code, let message):
            self.showError(message)
        }
    }
}

Debugging errors

Using request IDs

Every response includes a requestId. Include this when contacting support:
curl -i https://api.shortkit.dev/v1/content/cnt_abc123 \
  -H "Authorization: Bearer sk_live_..."

# Response headers include:
# X-Request-Id: req_xyz789

Verbose logging

Enable verbose logging in SDKs for debugging:
shortkit.setLogLevel('verbose');

Common issues

  • Check for extra whitespace in the key
  • Verify key hasn’t been revoked
  • Confirm environment matches (live vs test)
  • Ensure domain is in your allowlist
  • Check that you’re using a publishable key
  • Verify request origin matches configuration
  • Check shortkit status page
  • Implement retry logic
  • Contact support with request IDs
  • Check for API version changes
  • Review changelog for breaking changes
  • Verify request body structure

Next steps