What are API Keys?
API keys are authentication credentials that grant programmatic access to the ActumX API. Each key:
Uniquely identifies your requests
Is associated with your user account
Can be named for easy identification
Can be revoked at any time
Tracks usage via lastUsedAt timestamp
API keys use bearer token authentication via the Authorization header.
API Key Structure
An API key has the following properties:
interface ApiKey {
id : string ; // Unique key ID (prefixed with "key_")
userId : string ; // Your user ID
name : string ; // Human-readable name (2-80 characters)
keyPrefix : string ; // First 14 chars of the key (for identification)
keyHash : string ; // Hashed key (for secure storage)
revokedAt : string | null ; // Revocation timestamp (null if active)
lastUsedAt : string | null ; // Last usage timestamp
createdAt : string ; // ISO 8601 creation timestamp
}
Database Schema
API keys are stored in the api_keys table:
CREATE TABLE api_keys (
id TEXT PRIMARY KEY ,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE ,
name TEXT NOT NULL ,
key_prefix TEXT NOT NULL ,
key_hash TEXT NOT NULL UNIQUE ,
revoked_at TEXT ,
last_used_at TEXT ,
created_at TEXT NOT NULL
);
CREATE INDEX idx_api_keys_user_id ON api_keys(user_id);
Source Reference : /home/daytona/workspace/source/api/src/db/schema.ts:5-16
How API Keys Work
Key Generation
When you create an API key:
A cryptographically secure random key is generated
The first 14 characters are stored as keyPrefix for identification
The full key is hashed using SHA-256 and stored as keyHash
The raw key is returned only once
import { hashSecret , newApiKey } from "../../lib/crypto" ;
// Generate new API key (source: service.ts:39-42)
const rawKey = newApiKey ();
const keyPrefix = rawKey . slice ( 0 , 14 );
const keyHash = hashSecret ( rawKey );
The raw API key is shown only once during creation. Store it securely - ActumX cannot recover lost keys.
API keys follow this format:
actumx_1234567890abcdefghijklmnopqrstuvwxyz
^^^^^^ ^^^^^^^^^
prefix random
Prefix : actumx_ + 14 random characters (stored for display)
Full Length : Approximately 40-50 characters
Encoding : Alphanumeric characters
Authentication Flow
Client Request : Include API key in the Authorization header
curl https://api.actumx.com/api/v1/agents \
-H "Authorization: Bearer actumx_abc123xyz..."
Server Validation : ActumX hashes the provided key and looks up the hash
// Validate API key (conceptual)
const providedHash = hashSecret ( providedKey );
const apiKey = await db . query . apiKeys . findFirst ({
where: eq ( apiKeys . keyHash , providedHash )
});
if ( ! apiKey || apiKey . revokedAt ) {
return 401 ; // Unauthorized
}
Request Processing : If valid and not revoked, the request proceeds
Usage Tracking : The lastUsedAt timestamp is updated
// Update last used timestamp (source: x402/service.ts:425-427)
await db
. update ( apiKeys )
. set ({ lastUsedAt: timestamp })
. where ( eq ( apiKeys . id , apiKey . id ));
API Key Lifecycle
1. Creation
Create an API key via the API or dashboard:
curl -X POST https://api.actumx.com/api/v1/api-keys \
-H "Cookie: your_session_cookie" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Key"
}'
Response:
{
"apiKeyId" : "key_abc123" ,
"apiKey" : "actumx_full_key_here" ,
"keyPrefix" : "actumx_abc123" ,
"warning" : "Store this key now. It is shown only once."
}
API key creation requires authentication via session cookie (web dashboard) or existing API key.
2. Usage
Use your API key to authenticate all requests:
# List agents
curl https://api.actumx.com/api/v1/agents \
-H "Authorization: Bearer actumx_your_key"
# Create x402 transaction
curl https://api.actumx.com/api/v1/x402/quote \
-H "Authorization: Bearer actumx_your_key"
# Top up credits
curl -X POST https://api.actumx.com/api/v1/billing/top-up \
-H "Cookie: your_session" \
-d '{"amountCents": 1000}'
3. Monitoring
List all your API keys to monitor usage:
curl https://api.actumx.com/api/v1/api-keys \
-H "Cookie: your_session_cookie"
Response:
{
"keys" : [
{
"id" : "key_abc123" ,
"name" : "Production Key" ,
"keyPrefix" : "actumx_abc123" ,
"revokedAt" : null ,
"lastUsedAt" : "2026-03-03T22:30:00Z" ,
"createdAt" : "2026-03-01T10:00:00Z"
},
{
"id" : "key_xyz789" ,
"name" : "Staging Key" ,
"keyPrefix" : "actumx_xyz789" ,
"revokedAt" : "2026-03-02T15:00:00Z" ,
"lastUsedAt" : "2026-03-02T14:30:00Z" ,
"createdAt" : "2026-02-15T09:00:00Z"
}
]
}
4. Revocation
Revoke a key if it’s compromised or no longer needed:
curl -X POST https://api.actumx.com/api/v1/api-keys/key_abc123/revoke \
-H "Cookie: your_session_cookie"
Response:
Revoked keys:
Cannot authenticate new requests
Remain visible in your key list (with revokedAt timestamp)
Cannot be un-revoked (create a new key instead)
Revoking a key immediately invalidates it. Any applications using that key will lose access.
Security Best Practices
Key Storage
DO:
Store keys in environment variables
Use secret management services (AWS Secrets Manager, HashiCorp Vault)
Encrypt keys at rest in your application
DON’T:
Commit keys to version control
Hardcode keys in source code
Share keys via email or chat
Log keys in application logs
Key Rotation
Create a new API key
Update your application to use the new key
Verify the new key works
Revoke the old key
# Step 1: Create new key
curl -X POST https://api.actumx.com/api/v1/api-keys \
-d '{"name": "Production Key v2"}'
# Step 2: Update app environment
export ACTUMX_API_KEY = "actumx_new_key"
# Step 3: Test
curl https://api.actumx.com/api/v1/agents \
-H "Authorization: Bearer $ACTUMX_API_KEY "
# Step 4: Revoke old key
curl -X POST https://api.actumx.com/api/v1/api-keys/key_old/revoke
Rotate API keys every 90 days or immediately if compromised.
Key Naming
Use descriptive names to track key usage:
Production Server
Staging Environment
CI/CD Pipeline
Local Development - John
Mobile App - iOS
This helps you identify which key to revoke if issues arise.
Least Privilege
Create separate keys for different environments:
# Production key (limited scope)
curl -X POST https://api.actumx.com/api/v1/api-keys \
-d '{"name": "Production - Read Only"}'
# Development key (full access)
curl -X POST https://api.actumx.com/api/v1/api-keys \
-d '{"name": "Development - Full Access"}'
ActumX currently doesn’t support key-level permissions, but using separate keys per environment aids in tracking and revocation.
Implementation Details
Service Layer
The API key service handles all key operations:
Key Functions:
list(request): Retrieve all API keys for authenticated user
create(request, payload): Generate new API key
revoke(request, id): Revoke an existing key
Source Reference : /home/daytona/workspace/source/api/src/modules/api-keys/service.ts
Validation
Key creation validates the name:
// Model validation (source: model.ts:4-6)
const createApiKeyBody = t . Object ({
name: t . String ({ minLength: 2 , maxLength: 80 }),
});
Cryptographic Functions
ActumX uses custom crypto utilities:
// Generate random API key
export function newApiKey () : string {
// Returns cryptographically secure random string
// Format: "actumx_" + random characters
}
// Hash key for storage
export function hashSecret ( secret : string ) : string {
// Returns SHA-256 hash of the key
}
Source Reference : /home/daytona/workspace/source/api/src/lib/crypto.ts
Context Service
The ApiKeyContextService extracts and validates keys from requests:
// Get authenticated API key from request
const apiKey = await ApiKeyContextService . getAuthenticatedApiKey ( request );
if ( ! apiKey ) {
return { statusCode: 401 , body: { error: "missing_or_invalid_api_key" } };
}
Source Reference : /home/daytona/workspace/source/api/src/services/api-key-context.service.ts
Usage Tracking
API keys track two timestamps:
createdAt : When the key was created (never changes)
lastUsedAt : Most recent API request using this key
// Track usage (source: x402/service.ts:425-427)
await db
. update ( apiKeys )
. set ({ lastUsedAt: timestamp })
. where ( eq ( apiKeys . id , apiKey . id ));
This helps you:
Identify unused keys (revoke them)
Detect unexpected usage patterns
Audit key activity
Error Handling
Common API key errors:
Error HTTP Status Cause Solution unauthorized401 Missing/invalid key Provide valid API key in Authorization header missing_or_invalid_api_key401 Key not found or revoked Check key prefix and revocation status Name validation error 400 Invalid name length Use 2-80 characters
Example Error Response
{
"error" : "unauthorized"
}
Integration Examples
Node.js
const axios = require ( 'axios' );
const actumx = axios . create ({
baseURL: 'https://api.actumx.com/api/v1' ,
headers: {
'Authorization' : `Bearer ${ process . env . ACTUMX_API_KEY } `
}
});
// List agents
const { data } = await actumx . get ( '/agents' );
console . log ( data . agents );
Python
import os
import requests
class ActumXClient :
def __init__ ( self ):
self .api_key = os.environ[ 'ACTUMX_API_KEY' ]
self .base_url = 'https://api.actumx.com/api/v1'
self .headers = { 'Authorization' : f 'Bearer { self .api_key } ' }
def list_agents ( self ):
response = requests.get(
f ' { self .base_url } /agents' ,
headers = self .headers
)
return response.json()[ 'agents' ]
client = ActumXClient()
agents = client.list_agents()
cURL
#!/bin/bash
API_KEY = "actumx_your_key_here"
BASE_URL = "https://api.actumx.com/api/v1"
# List agents
curl " $BASE_URL /agents" \
-H "Authorization: Bearer $API_KEY "
# Create agent
curl -X POST " $BASE_URL /agents" \
-H "Authorization: Bearer $API_KEY " \
-H "Content-Type: application/json" \
-d '{"name": "My Agent"}'
Best Practices Summary
Never commit keys to version control
Use environment variables for key storage
Name keys descriptively (e.g., “Production API”, “Staging Bot”)
Rotate keys every 90 days
Revoke compromised keys immediately
Create separate keys per environment
Monitor lastUsedAt to identify unused keys
Store keys in secret management systems
Next Steps
Managing API Keys Step-by-step guide to creating and managing keys
Dashboard - API Keys Manage keys in the web dashboard
API Reference View detailed API key endpoints
Authentication Learn about ActumX authentication methods