Authentication
Learn how to authenticate with the Workflows API
Authentication
The Workflows API uses API keys for authentication. All API requests must include your API key in the x-api-key header.
API Key Format
API keys follow this format:
wfk_[32 character random string]Example: wfk_abc123def456ghi789jkl012mno345pq
Using Your API Key
Include your API key in the x-api-key header with every request:
curl http://localhost:3000/api/v1/workflows \
-H "x-api-key: wfk_your_api_key_here"const API_KEY = process.env.WORKFLOWS_API_KEY;
const response = await fetch('http://localhost:3000/api/v1/workflows', {
headers: {
'x-api-key': API_KEY
}
});const API_KEY = process.env.WORKFLOWS_API_KEY as string;
const response = await fetch('http://localhost:3000/api/v1/workflows', {
headers: {
'x-api-key': API_KEY
}
});import os
import requests
API_KEY = os.environ.get('WORKFLOWS_API_KEY')
response = requests.get(
'http://localhost:3000/api/v1/workflows',
headers={'x-api-key': API_KEY}
)API Key Scopes
API keys can be configured with different permission scopes:
| Scope | Description | Endpoints |
|---|---|---|
workflows:read | Read workflow definitions | GET /workflows, GET /workflows/:id |
workflows:write | Create and modify workflows | POST /workflows, PUT /workflows/:id |
workflows:execute | Run workflows | POST /workflows/:id/run |
runs:read | Read workflow run history | GET /runs, GET /runs/:id |
connections:read | View connections | GET /connections |
connections:write | Manage connections | POST /connections, DELETE /connections/:id |
Security Best Practices
Never expose your API key in client-side code, public repositories, or logs.
Do's
- Store API keys in environment variables
- Use different keys for development and production
- Rotate keys periodically (every 90 days recommended)
- Use the minimum required scopes
- Revoke compromised keys immediately
Don'ts
- Don't commit API keys to version control
- Don't share keys via email or chat
- Don't use production keys in development
- Don't log API keys in application logs
Environment Variables
We recommend storing your API key in an environment variable:
# .env (add to .gitignore!)
WORKFLOWS_API_KEY=wfk_your_api_key_hereThen access it in your code:
const apiKey = process.env.WORKFLOWS_API_KEY;import os
api_key = os.environ.get('WORKFLOWS_API_KEY')export WORKFLOWS_API_KEY=wfk_your_api_key_here
curl -H "x-api-key: $WORKFLOWS_API_KEY" ...Rate Limits
API requests are rate limited per API key using a sliding window algorithm:
| Category | Limit | Endpoints |
|---|---|---|
| Read | 1000/min | GET requests |
| Write | 100/min | POST, PUT, DELETE requests |
| Execute | 500/min | Workflow run, cancel, retry |
| Webhooks | 10000/min | Webhook ingestion (by IP) |
Rate Limit Headers
Every authenticated response includes rate limit headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1702531200| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when window resets |
Handling Rate Limits
When you exceed the rate limit, you'll receive a 429 Too Many Requests response:
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Limit: 100 requests per minute."
}
}Best practices for handling rate limits:
- Check rate limit headers proactively
- Implement exponential backoff on 429 errors
- Queue non-urgent requests
- Cache responses where appropriate
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const resetTime = response.headers.get('X-RateLimit-Reset');
const waitMs = resetTime
? (parseInt(resetTime) * 1000) - Date.now()
: Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, waitMs));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Error Responses
401 Unauthorized
Missing or invalid API key:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}403 Forbidden
API key lacks required permissions:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions for this operation"
}
}Managing API Keys
List API Keys
curl http://localhost:3000/api/v1/auth/api-keys \
-H "x-api-key: YOUR_API_KEY"Create API Key
curl -X POST http://localhost:3000/api/v1/auth/api-keys \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"scopes": ["workflows:read", "workflows:write", "workflows:execute"]
}'Revoke API Key
curl -X DELETE http://localhost:3000/api/v1/auth/api-keys/{KEY_ID} \
-H "x-api-key: YOUR_API_KEY"