Skip to main content
All EngageFabric API errors follow a consistent format:
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": [...],
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Authentication Errors

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key/token
TOKEN_EXPIRED401JWT token has expired
INVALID_API_KEY401API key is malformed or revoked
FORBIDDEN403Valid credentials but insufficient permissions
PROJECT_SUSPENDED403Project has been suspended

Example

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired API key",
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Validation Errors

CodeHTTP StatusDescription
VALIDATION_ERROR400Request body validation failed
INVALID_PARAMETER400Query parameter is invalid
MISSING_FIELD400Required field is missing
INVALID_FORMAT400Field format is incorrect

Example

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request parameters",
    "details": [
      {
        "field": "externalUserId",
        "message": "Must be a non-empty string"
      },
      {
        "field": "email",
        "message": "Must be a valid email address"
      }
    ],
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Resource Errors

CodeHTTP StatusDescription
NOT_FOUND404Requested resource does not exist
PLAYER_NOT_FOUND404Player with given ID not found
QUEST_NOT_FOUND404Quest with given ID not found
LEADERBOARD_NOT_FOUND404Leaderboard with given ID not found
LOBBY_NOT_FOUND404Lobby with given ID not found
ALREADY_EXISTS409Resource already exists
CONFLICT409Operation conflicts with current state

Example

{
  "error": {
    "code": "PLAYER_NOT_FOUND",
    "message": "Player with ID 'player-123' not found",
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Rate Limiting Errors

CodeHTTP StatusDescription
RATE_LIMITED429Too many requests
QUOTA_EXCEEDED429Monthly quota exceeded

Response Headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699900000
Retry-After: 60

Example

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry after 60 seconds.",
    "details": {
      "limit": 100,
      "window": "1 minute",
      "retryAfter": 60
    },
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Business Logic Errors

CodeHTTP StatusDescription
INSUFFICIENT_CURRENCY400Not enough currency for operation
INSUFFICIENT_LIVES400No lives remaining
QUEST_NOT_AVAILABLE400Quest is locked or expired
QUEST_ALREADY_COMPLETED400Quest already finished
LOBBY_FULL400Lobby has reached max players
LOBBY_STARTED400Cannot join started lobby
PLAYER_BANNED403Player is banned from action
PLAYER_MUTED403Player cannot send messages

Example

{
  "error": {
    "code": "INSUFFICIENT_CURRENCY",
    "message": "Not enough coins. Required: 100, Available: 50",
    "details": {
      "currencyId": "coins",
      "required": 100,
      "available": 50
    },
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}

Server Errors

CodeHTTP StatusDescription
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Service temporarily unavailable
TIMEOUT504Request timed out

Example

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An unexpected error occurred. Please try again.",
    "requestId": "req-abc123",
    "timestamp": "2025-01-21T10:00:00Z"
  }
}
If you receive a 500 error, please contact support with the requestId for investigation.

Handling Errors

JavaScript Example

try {
  const player = await client.players.get('player-123');
} catch (error) {
  switch (error.code) {
    case 'PLAYER_NOT_FOUND':
      // Create the player
      await client.players.identify({ externalUserId: 'player-123' });
      break;
    case 'RATE_LIMITED':
      // Wait and retry
      await sleep(error.details.retryAfter * 1000);
      return retry();
    case 'UNAUTHORIZED':
      // Refresh credentials
      await refreshApiKey();
      break;
    default:
      console.error('Unexpected error:', error);
  }
}

Retry Strategy

For transient errors (429, 503, 504), implement exponential backoff:
async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      if (!isRetryable(error)) throw error;

      const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
      await sleep(delay);
    }
  }
}

function isRetryable(error) {
  return ['RATE_LIMITED', 'SERVICE_UNAVAILABLE', 'TIMEOUT'].includes(error.code);
}