Basestack Docs
Backend

API Reference

The Basestack Feature Flags REST API provides a simple, HTTP-based interface for retrieving feature flags. This API is used by all Basestack SDKs under the hood and can also be used directly in any application that can make HTTP requests.

The API uses standard HTTP methods and returns JSON responses, making it easy to integrate with any programming language or framework. All requests require authentication via custom headers containing your project and environment keys.

Base URL

All API requests should be made to your Basestack instance:

https://flags-api.basestack.co/v1

If you're using a self-hosted instance, replace the base URL with your own domain. The API version (/v1) is required for all requests.

Authentication

All API requests require two custom headers for authentication:

HeaderDescriptionRequired
x-project-keyYour project identifierYes
x-environment-keyYour environment identifier (e.g., development, staging, production)Yes

You can find these values in your Basestack Feature Flags Dashboard under your project settings.

Getting Started

Get Your API Credentials

Before making API requests, you'll need your project and environment keys:

  1. Log in to your Basestack Feature Flags Dashboard
  2. Navigate to your project settings
  3. Copy your Project Key and Environment Key

These keys identify which project and environment you're querying flags from.

Make Your First Request

Test the API by fetching a single flag. Replace the placeholders with your actual values:

curl "https://flags-api.basestack.co/v1/flags/header" \
     -H "x-project-key: your-project-key" \
     -H "x-environment-key: your-environment-key"

If successful, you'll receive a JSON response with the flag details.

Endpoints

Get a Flag by Slug

Retrieve a specific feature flag by its slug (name). This endpoint returns a single flag object with all its properties.

Endpoint: GET /flags/:slug

Path Parameters:

ParameterTypeDescriptionRequired
slugstringThe unique identifier (slug) of the flagYes

Headers:

HeaderTypeDescriptionRequired
x-project-keystringYour project identifierYes
x-environment-keystringYour environment identifierYes

Example Request:

curl "https://flags-api.basestack.co/v1/flags/header" \
     -H "x-project-key: your-project-key" \
     -H "x-environment-key: your-environment-key"
const response = await fetch('https://flags-api.basestack.co/v1/flags/header', {
  headers: {
    'x-project-key': 'your-project-key',
    'x-environment-key': 'your-environment-key',
  },
});

const flag = await response.json();
console.log(flag);
import requests

headers = {
    'x-project-key': 'your-project-key',
    'x-environment-key': 'your-environment-key',
}

response = requests.get(
    'https://flags-api.basestack.co/v1/flags/header',
    headers=headers
)

flag = response.json()
print(flag)
<?php

$headers = [
    'x-project-key: your-project-key',
    'x-environment-key: your-environment-key',
];

$ch = curl_init('https://flags-api.basestack.co/v1/flags/header');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$flag = json_decode($response, true);

curl_close($ch);

Response Codes:

Status CodeDescription
200Success - Flag found and returned
404Flag not found
400Bad request - Server error or invalid request

Success Response (200):

The flag object is returned directly (not wrapped in an object). Note that createdAt and updatedAt are not included in this endpoint:

response.json
{
  "slug": "header",
  "enabled": true,
  "payload": {
    "variant": "dark",
    "showLogo": true
  },
  "expiredAt": null,
  "description": "Controls the header visibility and styling"
}

Response Headers:

The response includes cache headers for optimal performance:

Cache-Control: public, s-maxage=60, max-age=30, stale-while-revalidate=60, stale-if-error=300

Error Response (404):

When a flag with the specified slug doesn't exist:

error-404.json
{
  "enabled": false,
  "error": true,
  "message": "Flag with slug header does not exist"
}

Error Response (400):

When a server error occurs or the request is invalid:

error-400.json
{
  "error": true,
  "message": "Something went wrong, please try again later."
}

Even when a flag doesn't exist, the API returns a response with enabled: false and error: true. This allows your application to handle missing flags gracefully without throwing exceptions.

Get All Flags

Retrieve all feature flags for a specific project and environment. This endpoint returns an array of all flags, useful for preloading or displaying a list of available flags.

Endpoint: GET /flags

Headers:

HeaderTypeDescriptionRequired
x-project-keystringYour project identifierYes
x-environment-keystringYour environment identifierYes

Example Request:

curl "https://flags-api.basestack.co/v1/flags" \
     -H "x-project-key: your-project-key" \
     -H "x-environment-key: your-environment-key"
const response = await fetch('https://flags-api.basestack.co/v1/flags', {
  headers: {
    'x-project-key': 'your-project-key',
    'x-environment-key': 'your-environment-key',
  },
});

const { flags } = await response.json();
console.log(`Found ${flags.length} flags`);
flags.forEach(flag => {
  console.log(`${flag.slug}: ${flag.enabled}`);
});
import requests

headers = {
    'x-project-key': 'your-project-key',
    'x-environment-key': 'your-environment-key',
}

response = requests.get(
    'https://flags-api.basestack.co/v1/flags',
    headers=headers
)

data = response.json()
flags = data['flags']
print(f"Found {len(flags)} flags")
for flag in flags:
    print(f"{flag['slug']}: {flag['enabled']}")
<?php

$headers = [
    'x-project-key: your-project-key',
    'x-environment-key: your-environment-key',
];

$ch = curl_init('https://flags-api.basestack.co/v1/flags');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
$flags = $data['flags'];

echo "Found " . count($flags) . " flags\n";
foreach ($flags as $flag) {
    echo $flag['slug'] . ": " . ($flag['enabled'] ? 'enabled' : 'disabled') . "\n";
}

curl_close($ch);

Response Codes:

Status CodeDescription
200Success - Flags retrieved successfully (may be empty array)
400Bad request - Server error or invalid request

Success Response (200):

Flags are returned in an array, ordered by creation date (newest first). Each flag includes all fields including createdAt and updatedAt:

response.json
{
  "flags": [
    {
      "slug": "footer",
      "enabled": true,
      "payload": {
        "theme": "light"
      },
      "expiredAt": null,
      "description": "Controls footer visibility",
      "createdAt": "2023-07-20T14:08:27.284Z",
      "updatedAt": "2023-07-20T14:08:27.284Z"
    },
    {
      "slug": "header",
      "enabled": true,
      "payload": {
        "variant": "dark",
        "showLogo": true
      },
      "expiredAt": null,
      "description": "Controls the header visibility and styling",
      "createdAt": "2023-07-20T14:08:16.433Z",
      "updatedAt": "2023-07-20T14:08:16.433Z"
    }
  ]
}

Response Headers:

The response includes cache headers for optimal performance:

Cache-Control: public, s-maxage=60, max-age=30, stale-while-revalidate=60, stale-if-error=300

Empty Response (200):

If no flags exist for the environment, an empty array is returned (still a 200 status):

empty-response.json
{
  "flags": []
}

Error Response (400):

When a server error occurs or the request is invalid:

error-400.json
{
  "error": true,
  "message": "Something went wrong, please try again later."
}

Error Handling

Common Error Responses

Server Error (400)

When a server error occurs or the request is invalid:

error-400.json
{
  "error": true,
  "message": "Something went wrong, please try again later."
}

Common causes:

  • Database connection issues
  • Invalid request format
  • Internal server errors

Solution: Retry the request after a short delay. If the issue persists, check your request format and authentication headers.

Flag Not Found (404)

When requesting a specific flag that doesn't exist:

error-404.json
{
  "enabled": false,
  "error": true,
  "message": "Flag with slug header does not exist"
}

Solution: Verify the flag slug exists in your environment. Check your Basestack dashboard to see available flags.

The 404 response includes enabled: false to allow your application to handle missing flags gracefully. You can treat this as a disabled flag rather than an error condition.

Best Practices for Error Handling

  1. Always check response status codes before processing the response body
  2. Handle missing flags gracefully - Use the enabled: false response as a fallback
  3. Implement retry logic for network errors (5xx status codes)
  4. Cache responses to reduce API calls and handle temporary failures
  5. Log errors for debugging and monitoring

Example Error Handling:

error-handling.js
async function getFlagSafely(slug, projectKey, environmentKey) {
  try {
    const response = await fetch(
      `https://flags-api.basestack.co/v1/flags/${slug}`,
      {
        headers: {
          'x-project-key': projectKey,
          'x-environment-key': environmentKey,
        },
      }
    );

    const data = await response.json();

    // Handle 404 - flag doesn't exist
    if (response.status === 404) {
      // API returns { enabled: false, error: true, message: "..." }
      return { enabled: false, error: true };
    }

    // Handle 400 - server error
    if (response.status === 400) {
      console.error('API error:', data.message);
      return { enabled: false, error: true };
    }

    // Success - return flag object
    if (response.ok) {
      return data; // Flag object directly
    }

    throw new Error(`Unexpected status: ${response.status}`);
  } catch (error) {
    console.error('Failed to fetch flag:', error);
    // Return safe default
    return { enabled: false, error: true };
  }
}

Response Schema

Flag Object

The flag object structure varies slightly depending on the endpoint:

GET /flags/:slug returns:

PropertyTypeDescription
slugstringUnique identifier for the flag
enabledbooleanWhether the flag is currently enabled
payloadobject | nullOptional JSON data associated with the flag
expiredAtstring | nullISO 8601 date string when the flag expires (if applicable)
descriptionstringHuman-readable description of the flag

GET /flags returns flags with additional fields:

PropertyTypeDescription
slugstringUnique identifier for the flag
enabledbooleanWhether the flag is currently enabled
payloadobject | nullOptional JSON data associated with the flag
expiredAtstring | nullISO 8601 date string when the flag expires (if applicable)
descriptionstringHuman-readable description of the flag
createdAtstringISO 8601 date string when the flag was created
updatedAtstringISO 8601 date string when the flag was last updated

Error Response Fields:

PropertyTypeDescription
errorbooleanWhether an error occurred (always true in error responses)
messagestringError message describing what went wrong
enabledbooleanAlways false in 404 responses (flag not found)

TypeScript Type Definition

For TypeScript projects, use these type definitions:

flag.ts
// Flag object returned by GET /flags/:slug
export interface Flag {
  slug: string;
  enabled: boolean;
  payload?: unknown | null;
  expiredAt?: string | null;
  description: string;
}

// Flag object returned by GET /flags (includes timestamps)
export interface FlagWithTimestamps extends Flag {
  createdAt: string;
  updatedAt: string;
}

// Response from GET /flags
export interface FlagsResponse {
  flags: FlagWithTimestamps[];
}

// Error response
export interface ErrorResponse {
  error: true;
  message: string;
  enabled?: boolean; // Present in 404 responses
}

Caching

All endpoints include cache headers to optimize performance:

Cache-Control: public, s-maxage=60, max-age=30, stale-while-revalidate=60, stale-if-error=300

This means:

  • CDN/Edge Cache: 60 seconds (s-maxage)
  • Browser Cache: 30 seconds (max-age)
  • Stale While Revalidate: Serve stale content for up to 60 seconds while fetching fresh data
  • Stale If Error: Serve stale content for up to 5 minutes if the origin server errors

The API uses aggressive caching to reduce load and improve response times. If you need fresh flag data immediately, you may need to bypass the cache or wait for the cache to expire.

Rate Limiting

API rate limits may apply depending on your plan. Check your dashboard for current rate limit information. If you exceed rate limits, you'll receive a 429 Too Many Requests response.

Common Use Cases

Preloading Flags on Application Start

Fetch all flags when your application initializes:

preload-flags.js
async function preloadFlags(projectKey, environmentKey) {
  const response = await fetch('https://flags-api.basestack.co/v1/flags', {
    headers: {
      'x-project-key': projectKey,
      'x-environment-key': environmentKey,
    },
  });

  const { flags } = await response.json();
  
  // Cache flags for use throughout your application
  return flags.reduce((cache, flag) => {
    cache[flag.slug] = flag;
    return cache;
  }, {});
}

Checking a Flag Before Rendering

Check a flag before rendering a feature:

check-flag.js
async function shouldShowFeature(featureSlug, projectKey, environmentKey) {
  const response = await fetch(
    `https://flags-api.basestack.co/v1/flags/${featureSlug}`,
    {
      headers: {
        'x-project-key': projectKey,
        'x-environment-key': environmentKey,
      },
    }
  );

  const flag = await response.json();
  return flag.enabled && !flag.error;
}