Overview
SO1 APIs use Bearer token authentication with API keys. All requests must include a valid API key in the Authorization header.
API keys provide full access to your account. Treat them like passwords and never commit them to version control.
Authentication Methods
Bearer Token (Recommended)
Include your API key in the Authorization header with the Bearer scheme:
Authorization: Bearer YOUR_API_KEY
Example Request:
curl https://control-plane.so1.io/api/v1/workflows \
-H "Authorization: Bearer cp_live_sk_1234567890abcdef"
Query Parameter (Not Recommended)
For testing only, you can include the API key as a query parameter:
https://control-plane.so1.io/api/v1/workflows?api_key=YOUR_API_KEY
Query parameter authentication is not recommended for production use as API keys may be logged in server logs, browser history, and proxy logs.
API Key Types
SO1 provides different API key types for different use cases:
Control Plane API Keys
Format: cp_live_sk_... (production) or cp_test_sk_... (test mode)
Permissions:
- Agent execution
- Workflow orchestration
- FORGE gate validation
- System metrics access
Generate in: Console → Settings → API Keys
Veritas API Keys
Format: ver_live_... (production) or ver_test_... (test mode)
Permissions:
- Prompt retrieval
- Chain execution
- Fragment management
- A/B testing
Generate in: Veritas Dashboard → Settings
n8n API Keys
Format: n8n_...
Permissions:
- Workflow creation/modification
- Workflow execution
- Webhook management
- Credential access
Generate in: n8n Settings → API
Generating API Keys
Via SO1 Console
Create New Key
Click “Create API Key” and select the key type
Configure Permissions
Select specific permissions (optional):
- Read-only access
- Agent execution only
- Workflow management
- Full access (default)
Save Key Securely
Copy the key immediately - it will only be shown onceexport CONTROL_PLANE_API_KEY="cp_live_sk_..."
Via API
You can also generate API keys programmatically:
curl -X POST https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline Key",
"permissions": ["agent:execute", "workflow:read"],
"expires_at": "2027-03-10T00:00:00Z"
}'
Response:
{
"api_key_id": "key_abc123",
"api_key": "cp_live_sk_1234567890abcdef",
"name": "CI/CD Pipeline Key",
"permissions": ["agent:execute", "workflow:read"],
"created_at": "2026-03-10T15:30:00Z",
"expires_at": "2027-03-10T00:00:00Z"
}
Store the api_key value securely. It cannot be retrieved again after creation.
Environment-Specific Keys
Use different API keys for each environment:
export CONTROL_PLANE_API_KEY="cp_test_sk_dev123..."
export VERITAS_API_KEY="ver_test_dev123..."
export N8N_API_KEY="n8n_dev123..."
Authentication Errors
401 Unauthorized
Cause: Missing, invalid, or expired API key
{
"error": {
"code": "unauthorized",
"message": "Invalid API key",
"details": {
"reason": "The provided API key is not valid"
}
}
}
Solutions:
- Verify the API key is correct
- Check the key hasn’t been revoked
- Ensure the key hasn’t expired
- Verify you’re using the correct environment key
403 Forbidden
Cause: API key doesn’t have required permissions
{
"error": {
"code": "forbidden",
"message": "Insufficient permissions",
"details": {
"required_permission": "agent:execute",
"key_permissions": ["workflow:read"]
}
}
}
Solutions:
- Use an API key with appropriate permissions
- Request permission upgrade from account admin
- Generate a new key with required permissions
Security Best Practices
1. Use Environment Variables
Never hardcode API keys in your application code:
// ✅ Good: Use environment variables
const apiKey = process.env.CONTROL_PLANE_API_KEY;
// ❌ Bad: Hardcoded API key
const apiKey = "cp_live_sk_1234567890abcdef";
2. Rotate Keys Regularly
Rotate API keys every 90 days:
# List existing keys
curl https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
# Create new key
curl -X POST https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-d '{"name": "Production Key - Q2 2026"}'
# Update application with new key
# ...
# Revoke old key
curl -X DELETE https://control-plane.so1.io/api/v1/auth/api-keys/key_old123 \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
3. Use Least Privilege
Create keys with minimum required permissions:
# Read-only key for monitoring
curl -X POST https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-d '{
"name": "Monitoring Dashboard",
"permissions": ["metrics:read", "workflow:read"]
}'
# Agent execution only (no workflow modification)
curl -X POST https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-d '{
"name": "CI/CD Agent Runner",
"permissions": ["agent:execute"]
}'
4. Set Expiration Dates
Always set expiration dates on API keys:
curl -X POST https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-d '{
"name": "Temporary Integration Test Key",
"expires_at": "2026-06-10T00:00:00Z"
}'
5. Monitor Key Usage
Track API key usage and set up alerts:
# Get key usage statistics
curl https://control-plane.so1.io/api/v1/auth/api-keys/key_abc123/usage \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
Response:
{
"key_id": "key_abc123",
"usage": {
"requests_today": 1247,
"requests_this_month": 38492,
"last_used_at": "2026-03-10T15:25:00Z",
"last_used_ip": "203.0.113.45"
}
}
6. Revoke Compromised Keys
If a key is compromised, revoke it immediately:
# Revoke key
curl -X DELETE https://control-plane.so1.io/api/v1/auth/api-keys/key_abc123 \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
# Verify revocation
curl https://control-plane.so1.io/api/v1/workflows \
-H "Authorization: Bearer cp_live_sk_revoked_key"
# Should return 401 Unauthorized
Managing API Keys
List All API Keys
curl https://control-plane.so1.io/api/v1/auth/api-keys \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
Response:
{
"api_keys": [
{
"id": "key_abc123",
"name": "Production API Key",
"permissions": ["*"],
"created_at": "2026-01-15T10:00:00Z",
"expires_at": "2027-01-15T00:00:00Z",
"last_used_at": "2026-03-10T15:25:00Z"
},
{
"id": "key_def456",
"name": "CI/CD Pipeline",
"permissions": ["agent:execute", "workflow:read"],
"created_at": "2026-02-01T14:30:00Z",
"expires_at": "2026-08-01T00:00:00Z",
"last_used_at": "2026-03-10T14:50:00Z"
}
]
}
Update API Key
curl -X PATCH https://control-plane.so1.io/api/v1/auth/api-keys/key_abc123 \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key - Updated",
"expires_at": "2027-03-10T00:00:00Z"
}'
Delete API Key
curl -X DELETE https://control-plane.so1.io/api/v1/auth/api-keys/key_abc123 \
-H "Authorization: Bearer ${CONTROL_PLANE_API_KEY}"
Webhook Authentication
For webhook endpoints, SO1 uses HMAC signature verification:
Verifying Webhook Signatures
import { createHmac } from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const hmac = createHmac('sha256', secret);
hmac.update(payload);
const expectedSignature = `sha256=${hmac.digest('hex')}`;
return signature === expectedSignature;
}
// Express.js example
app.post('/webhooks/so1', (req, res) => {
const signature = req.headers['x-so1-signature'];
const payload = JSON.stringify(req.body);
const secret = process.env.WEBHOOK_SECRET;
if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
res.json({ status: 'received' });
});
OAuth 2.0 (Coming Soon)
OAuth 2.0 support for third-party integrations will be available soon:
- Authorization Code Flow: For web applications
- Client Credentials Flow: For server-to-server
- Scoped Permissions: Fine-grained access control
Join OAuth Beta
Contact us to participate in the OAuth 2.0 beta program