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/v1If 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:
| Header | Description | Required |
|---|---|---|
x-project-key | Your project identifier | Yes |
x-environment-key | Your 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:
- Log in to your Basestack Feature Flags Dashboard
- Navigate to your project settings
- 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:
| Parameter | Type | Description | Required |
|---|---|---|---|
slug | string | The unique identifier (slug) of the flag | Yes |
Headers:
| Header | Type | Description | Required |
|---|---|---|---|
x-project-key | string | Your project identifier | Yes |
x-environment-key | string | Your environment identifier | Yes |
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 Code | Description |
|---|---|
200 | Success - Flag found and returned |
404 | Flag not found |
400 | Bad 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:
{
"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=300Error Response (404):
When a flag with the specified slug doesn't exist:
{
"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": 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:
| Header | Type | Description | Required |
|---|---|---|---|
x-project-key | string | Your project identifier | Yes |
x-environment-key | string | Your environment identifier | Yes |
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 Code | Description |
|---|---|
200 | Success - Flags retrieved successfully (may be empty array) |
400 | Bad 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:
{
"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=300Empty Response (200):
If no flags exist for the environment, an empty array is returned (still a 200 status):
{
"flags": []
}Error Response (400):
When a server error occurs or the request is invalid:
{
"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": 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:
{
"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
- Always check response status codes before processing the response body
- Handle missing flags gracefully - Use the
enabled: falseresponse as a fallback - Implement retry logic for network errors (5xx status codes)
- Cache responses to reduce API calls and handle temporary failures
- Log errors for debugging and monitoring
Example Error Handling:
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:
| Property | Type | Description |
|---|---|---|
slug | string | Unique identifier for the flag |
enabled | boolean | Whether the flag is currently enabled |
payload | object | null | Optional JSON data associated with the flag |
expiredAt | string | null | ISO 8601 date string when the flag expires (if applicable) |
description | string | Human-readable description of the flag |
GET /flags returns flags with additional fields:
| Property | Type | Description |
|---|---|---|
slug | string | Unique identifier for the flag |
enabled | boolean | Whether the flag is currently enabled |
payload | object | null | Optional JSON data associated with the flag |
expiredAt | string | null | ISO 8601 date string when the flag expires (if applicable) |
description | string | Human-readable description of the flag |
createdAt | string | ISO 8601 date string when the flag was created |
updatedAt | string | ISO 8601 date string when the flag was last updated |
Error Response Fields:
| Property | Type | Description |
|---|---|---|
error | boolean | Whether an error occurred (always true in error responses) |
message | string | Error message describing what went wrong |
enabled | boolean | Always false in 404 responses (flag not found) |
TypeScript Type Definition
For TypeScript projects, use these type definitions:
// 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=300This 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:
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:
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;
}