Authentication
All API requests require authentication using an API key. For user-specific features like subscription-based content access, you can also include a Firebase ID token.
Getting Your API Key
- Sign in to app.fig1.ai
- Navigate to Settings → API Keys
- Click Create API Key
- Copy your key—it won't be shown again
Using Your API Key
Include your API key in the X-Fig1-API-Key header with every request:
POST /api/sdk/agent/chat HTTP/1.1
Host: app.fig1.ai
Content-Type: application/json
X-Fig1-API-Key: fig1_sdk_your_api_key
{
"message": "Hello!"
}
TypeScript Example
const response = await fetch('https://app.fig1.ai/api/sdk/agent/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Fig1-API-Key': process.env.FIG1_API_KEY!
},
body: JSON.stringify({ message: 'Hello!' })
});
cURL Example
curl -X POST https://app.fig1.ai/api/sdk/agent/chat \
-H "Content-Type: application/json" \
-H "X-Fig1-API-Key: fig1_sdk_your_api_key" \
-d '{"message": "Hello!"}'
API Key Format
API keys use the format fig1_sdk_ followed by a unique identifier. Each key is tied to a specific site in your account.
Firebase Authentication (Optional)
For user-specific features like membership tiers and subscription-based content, add a Firebase ID token.
When to Use Firebase Auth
- Accessing content with
accessLevel: 'authenticated','premium', or'subscription' - Tracking user-specific preferences
- Enforcing membership tier restrictions
- Checking user subscriptions
Setting Up Firebase
- In the Fig1 dashboard, go to Firebase & Subscriptions
- Enter your Firebase project configuration
- Upload your service account JSON for backend verification
- Click Verify Connection
See the Firebase Setup guide for detailed instructions.
Getting a Firebase Token
In your app, after Firebase authentication:
import { getAuth } from 'firebase/auth';
const auth = getAuth();
const user = auth.currentUser;
const token = await user.getIdToken();
Using Firebase Auth with SDK
Include both headers:
const response = await fetch('https://app.fig1.ai/api/sdk/content', {
headers: {
'X-Fig1-API-Key': process.env.FIG1_API_KEY!,
'Authorization': `Bearer ${firebaseToken}`
}
});
curl -X GET https://app.fig1.ai/api/sdk/content \
-H "X-Fig1-API-Key: fig1_sdk_your_api_key" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Authentication Modes
Mode 1: API Key Only (Server-to-Server)
For backend services and public content:
X-Fig1-API-Key: your-api-key
- Access to public content only
- No user context
- Full API access within rate limits
Mode 2: API Key + Firebase Token (User Context)
For user-facing applications with membership/subscription features:
X-Fig1-API-Key: your-api-key
Authorization: Bearer <firebase-id-token>
- Access to authenticated/premium/subscription content based on user's entitlements
- User-specific preferences and history
- Membership tier and subscription enforcement
Content Access Levels
| Level | API Key Only | With Firebase Token |
|-------|--------------|---------------------|
| public | Yes | Yes |
| authenticated | No | Yes (any user) |
| premium | No | Yes (premium/pro tier) |
| subscription | No | Yes (with required subscription) |
Membership Tiers
When using Firebase auth, the user's tier is read from custom claims:
free- Default tier, public content onlybasic- Authenticated content accesspremium- Premium content accesspro- Full content access
Subscription-Based Access
For granular content gating, use the subscription access level with specific subscription requirements.
How It Works
- Configure subscriptions in your Firebase & Subscriptions settings
- Assign subscriptions to users via Firebase custom claims
- Set content
accessLevel: 'subscription'withrequiredSubscriptions
Firebase Custom Claims Structure
{
"membershipTier": "premium",
"subscriptions": ["boxing_fundamentals", "premium_content"],
"membershipExpiry": "2025-12-31T00:00:00Z"
}
Checking User Subscriptions
const response = await fetch('https://app.fig1.ai/api/sdk/user/subscriptions', {
headers: {
'X-Fig1-API-Key': process.env.FIG1_API_KEY!,
'Authorization': `Bearer ${firebaseToken}`
}
});
const data = await response.json();
console.log(data.subscriptions); // ['boxing_fundamentals', 'premium_content']
See the Subscriptions guide for more details.
Security Best Practices
Never Expose Keys in Client-Side Code
// ❌ BAD - API key exposed in browser
const response = await fetch('/api/chat', {
headers: { 'X-Fig1-API-Key': 'fig1_sdk_xxx' }
});
// ✅ GOOD - Proxy through your backend
const response = await fetch('/api/my-backend/chat', {
method: 'POST',
body: JSON.stringify({ message })
});
Use Environment Variables
# .env.local
FIG1_API_KEY=fig1_sdk_your_api_key
// Access in server-side code only
const apiKey = process.env.FIG1_API_KEY;
Create a Backend Proxy
For web applications, always proxy API requests through your backend:
// app/api/chat/route.ts (Next.js)
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch('https://app.fig1.ai/api/sdk/agent/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Fig1-API-Key': process.env.FIG1_API_KEY!
},
body: JSON.stringify(body)
});
return Response.json(await response.json());
}
Error Responses
Invalid API Key (401)
{
"success": false,
"error": "Invalid API key"
}
Missing API Key (401)
{
"success": false,
"error": "API key required"
}
Authentication Required (401)
{
"success": false,
"error": "Firebase authentication required"
}
Premium Required (403)
{
"success": false,
"error": "Premium membership required"
}
Subscription Required (403)
{
"success": false,
"error": "Subscription required: boxing_fundamentals",
"accessLevel": "subscription",
"requiredSubscriptions": ["boxing_fundamentals"],
"userSubscriptions": [],
"isAuthenticated": true
}
Rate Limit Exceeded (429)
{
"success": false,
"error": "Rate limit exceeded. Try again in 30 seconds."
}
Rate Limits
Rate limits vary based on your subscription plan. Check your dashboard for your current limits.
Rotating Keys
To rotate your API key:
- Create a new key in the dashboard
- Update your application with the new key
- Test that everything works
- Delete the old key
This ensures zero downtime during rotation.