ResourcesError Handling

Error Handling

Understanding and handling Flameup API errors

Error Response Format

Most errors are flat. Write your handler against this shape first — it is what the great majority of endpoints return, including everything on the ingestion, people and device surfaces:

{
  "error": "Person not found"
}

Some responses add a message alongside it with more detail, and the ingestion routes (/track, /identify) add "success": false and a details string to their flat errors.

A minority of endpoints — mainly workspace and campaign management — return a typed envelope instead:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Human-readable error message",
    "details": "field: what was wrong with it"
  }
}
Read error defensively: it is a string on most responses and an object on some. typeof err.error === 'string' ? err.error : err.error.message covers both. (The typed envelope is itself not perfectly uniform — some variants omit success — which is one more reason to key on error rather than on success.)

HTTP Status Codes

Flameup uses standard HTTP status codes:

CodeMeaningDescription
200OKRequest succeeded
201CreatedResource created successfully
204No ContentRequest succeeded (no response body)
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
409ConflictResource already exists, or a delete is blocked by references (e.g. deleting a segment still used by campaigns returns 409 naming them)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error
501Not ImplementedThe route exists but is not built yet (e.g. push delivery-history reads). Returns {"error": "not implemented"} — not worth retrying
503Service UnavailableTemporary unavailability

Common Error Codes

Authentication Errors

Authentication and rate-limit failures use the flat response shape ({"error": ..., "message": ...}), not the typed error.code envelope.

HTTP Status: 401

API key is missing or invalid. Any authentication failure returns this generic 401 response.

{
  "error": "Unauthorized",
  "message": "Invalid or expired API key",
  "details": "Please provide a valid API key in the Authorization header: Bearer <your_api_key>"
}

Solutions:

  • Verify the API key is correct
  • Check the Authorization header is set with Bearer prefix
  • Ensure the key hasn't been revoked

Resource Errors

HTTP Status: 404

The requested resource doesn't exist. On the people, events, device and push surfaces this is flat, with a surface-specific string — the push surface says "Person not found", the people surface says:

{ "error": "person with id 'user_12345' not found" }

Match on the status code, not the string.

Workspace and campaign management endpoints return the typed form instead:

{ "success": false, "error": { "code": "NOT_FOUND", "message": "..." } }

Solutions:

  • Verify the resource ID is correct
  • Check you're using the right workspace

Validation Errors

HTTP Status: 400

Request body or parameters failed validation. details is a string in the form field: message.

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": "email: Invalid email format"
  }
}

Solutions:

  • Check the request body matches the API spec
  • Validate data before sending

Rate Limiting Errors

HTTP Status: 429

Too many requests in a time window. This response uses the flat shape and includes X-RateLimit-* headers.

{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Please try again later."
}

Solutions:

  • Check the X-RateLimit-Reset header for when to retry
  • Implement exponential backoff
  • Contact support if you need a higher limit

Error Handling Best Practices

Retry Strategy

Implement exponential backoff for transient errors:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.ok) {
        return response.json();
      }

      const error = await response.json();

      // Don't retry client errors (except rate limits)
      if (response.status >= 400 && response.status < 500) {
        if (response.status === 429) {
          // Rate limited - wait and retry using header
          const resetTime = parseInt(response.headers.get('X-RateLimit-Reset') || '0') * 1000;
          const waitTime = resetTime > Date.now() ? resetTime - Date.now() : 60000;
          await sleep(waitTime);
          continue;
        }
        throw new FlameupError(error);
      }

      // Server error - retry with backoff
      if (attempt < maxRetries - 1) {
        await sleep(Math.pow(2, attempt) * 1000);
        continue;
      }

      throw new FlameupError(error);

    } catch (networkError) {
      if (attempt < maxRetries - 1) {
        await sleep(Math.pow(2, attempt) * 1000);
        continue;
      }
      throw networkError;
    }
  }
}

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

Error Logging

Log errors with context for debugging:

// `error` is the response body's `error` field, which is a string on most
// surfaces and an object on the workspace and campaign endpoints.
function logError(error, context) {
  const e = typeof error === 'string' ? { message: error } : (error || {});
  console.error('Flameup API Error', {
    code: e.code,
    message: e.message,
    details: e.details,
    context: {
      endpoint: context.endpoint,
      method: context.method,
      userId: context.userId,
      timestamp: new Date().toISOString()
    }
  });
}

User-Friendly Messages

Map error codes to user-friendly messages:

const ERROR_MESSAGES = {
  UNAUTHORIZED: 'Please check your API credentials',
  FORBIDDEN: 'You don\'t have permission for this action',
  NOT_FOUND: 'The requested item was not found',
  VALIDATION_ERROR: 'Please check your input and try again',
  RATE_LIMIT: 'Too many requests. Please wait a moment.',
  default: 'Something went wrong. Please try again.'
};

function getUserMessage(errorCode) {
  return ERROR_MESSAGES[errorCode] || ERROR_MESSAGES.default;
}

Debugging Tips

Use these tips to debug API issues:
  1. Check the response body - Error details are always in the response
  2. Verify API key permissions - Most 403 errors are permission issues
  3. Validate request format - Use the API reference for correct schemas
  4. Check rate limit headers - Monitor X-RateLimit-* headers (returned on 429 responses)
  5. Include the full response - Paste the status code and body when contacting support