Skip to content

Admin API

The Admin API provides endpoints for tenant management, user administration, and API key management. These endpoints require elevated permissions.


Overview

CalcBridge's admin system enables:

  • Tenant Management: Create and configure organizations
  • User Administration: Manage users, roles, and permissions
  • API Key Management: Create and revoke API keys for service integrations
  • System Configuration: Configure tenant-specific settings

Authorization

Admin endpoints require one of the following:

  • Owner role: Full access to tenant administration
  • Admin role: Limited access (cannot delete tenant or transfer ownership)
  • System API key: For automated tenant provisioning (Enterprise only)

Endpoints

Tenant Management

Get Current Tenant

Retrieve information about the current tenant.

GET /api/v1/admin/tenant
Example Request
curl -X GET https://api.calcbridge.io/api/v1/admin/tenant \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/admin/tenant",
    headers={"Authorization": f"Bearer {token}"}
)
tenant = response.json()
print(f"Tenant: {tenant['name']}")
print(f"Plan: {tenant['subscription_tier']}")
const response = await fetch('https://api.calcbridge.io/api/v1/admin/tenant', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const tenant = await response.json();
console.log('Tenant:', tenant.name);
console.log('Plan:', tenant.subscription_tier);
Response
{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "name": "Acme Capital",
  "slug": "acme-capital",
  "subscription_tier": "premium",
  "settings": {
    "default_currency": "USD",
    "timezone": "America/New_York",
    "date_format": "MM/DD/YYYY",
    "max_workbook_size_mb": 100,
    "max_users": 25
  },
  "usage": {
    "users": 12,
    "workbooks": 45,
    "api_calls_this_month": 15420,
    "storage_used_mb": 256
  },
  "created_at": "2025-06-15T10:00:00Z",
  "updated_at": "2026-01-20T15:30:00Z"
}

Update Tenant

Update tenant settings.

PATCH /api/v1/admin/tenant
Request Body
Field Type Description
name string Organization name
settings object Tenant settings
Settings Object
Field Type Description
default_currency string Default currency code (USD, EUR, GBP)
timezone string IANA timezone identifier
date_format string Date display format
number_format string Number format locale
Example Request
curl -X PATCH https://api.calcbridge.io/api/v1/admin/tenant \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Capital Partners",
    "settings": {
      "timezone": "Europe/London",
      "date_format": "DD/MM/YYYY"
    }
  }'
import requests

response = requests.patch(
    "https://api.calcbridge.io/api/v1/admin/tenant",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "name": "Acme Capital Partners",
        "settings": {
            "timezone": "Europe/London",
            "date_format": "DD/MM/YYYY"
        }
    }
)
tenant = response.json()
print(f"Updated: {tenant['name']}")
const response = await fetch('https://api.calcbridge.io/api/v1/admin/tenant', {
  method: 'PATCH',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Acme Capital Partners',
    settings: {
      timezone: 'Europe/London',
      date_format: 'DD/MM/YYYY'
    }
  })
});
const tenant = await response.json();
console.log('Updated:', tenant.name);
Response

Returns the updated tenant object.


User Management

List Users

Get all users in the current tenant.

GET /api/v1/admin/users
Query Parameters
Parameter Type Default Description
page integer 1 Page number
page_size integer 20 Items per page
role string - Filter by role
status string - Filter by status (active, inactive)
search string - Search by name or email
Example Request
curl -X GET "https://api.calcbridge.io/api/v1/admin/users?role=analyst&status=active" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/admin/users",
    headers={"Authorization": f"Bearer {token}"},
    params={"role": "analyst", "status": "active"}
)
users = response.json()
for user in users["items"]:
    print(f"{user['full_name']} ({user['email']}): {user['role']}")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/admin/users?role=analyst&status=active',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const users = await response.json();
users.items.forEach(user => {
  console.log(`${user.full_name} (${user.email}): ${user.role}`);
});
Response
{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "john@example.com",
      "full_name": "John Smith",
      "role": "analyst",
      "status": "active",
      "last_login": "2026-01-25T09:00:00Z",
      "created_at": "2025-08-10T10:00:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "email": "jane@example.com",
      "full_name": "Jane Doe",
      "role": "analyst",
      "status": "active",
      "last_login": "2026-01-24T16:30:00Z",
      "created_at": "2025-09-15T14:00:00Z"
    }
  ],
  "total": 8,
  "page": 1,
  "page_size": 20,
  "total_pages": 1
}

Invite User

Invite a new user to the tenant.

POST /api/v1/admin/users/invite
Request Body
Field Type Required Description
email string Yes User email address
full_name string Yes User's full name
role string Yes Role: owner, admin, analyst, viewer
send_email boolean No Send invitation email (default: true)
Example Request
curl -X POST https://api.calcbridge.io/api/v1/admin/users/invite \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "newuser@example.com",
    "full_name": "New User",
    "role": "analyst",
    "send_email": true
  }'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/admin/users/invite",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "email": "newuser@example.com",
        "full_name": "New User",
        "role": "analyst",
        "send_email": True
    }
)
invitation = response.json()
print(f"Invited: {invitation['email']}")
print(f"Invitation expires: {invitation['expires_at']}")
const response = await fetch('https://api.calcbridge.io/api/v1/admin/users/invite', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: 'newuser@example.com',
    full_name: 'New User',
    role: 'analyst',
    send_email: true
  })
});
const invitation = await response.json();
console.log('Invited:', invitation.email);
Response
{
  "id": "770e8400-e29b-41d4-a716-446655440010",
  "email": "newuser@example.com",
  "full_name": "New User",
  "role": "analyst",
  "status": "pending",
  "invitation_token": "inv_abc123xyz...",
  "expires_at": "2026-02-01T10:30:00Z",
  "created_at": "2026-01-25T10:30:00Z"
}
Error Responses
Status Error Description
400 Invalid role Unknown role value
409 User already exists Email already registered
403 User limit exceeded Subscription user limit reached

Get User

Retrieve a specific user's details.

GET /api/v1/admin/users/{user_id}
Path Parameters
Parameter Type Description
user_id string (UUID) User identifier
Example Request
curl -X GET https://api.calcbridge.io/api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TOKEN"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "john@example.com",
  "full_name": "John Smith",
  "role": "analyst",
  "status": "active",
  "permissions": {
    "workbooks": ["read", "write", "delete"],
    "calculations": ["execute"],
    "compliance": ["read", "write"],
    "scenarios": ["read", "write"],
    "reports": ["read", "generate"],
    "admin": []
  },
  "last_login": "2026-01-25T09:00:00Z",
  "login_count": 145,
  "created_at": "2025-08-10T10:00:00Z",
  "updated_at": "2026-01-25T09:00:00Z"
}

Update User

Update a user's role or status.

PATCH /api/v1/admin/users/{user_id}
Path Parameters
Parameter Type Description
user_id string (UUID) User identifier
Request Body
Field Type Description
role string New role
status string Status: active, inactive
full_name string User's full name
Example Request
curl -X PATCH https://api.calcbridge.io/api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin",
    "status": "active"
  }'
import requests

response = requests.patch(
    f"https://api.calcbridge.io/api/v1/admin/users/{user_id}",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "role": "admin",
        "status": "active"
    }
)
user = response.json()
print(f"Updated {user['full_name']} to role: {user['role']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/admin/users/${userId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      role: 'admin',
      status: 'active'
    })
  }
);
const user = await response.json();
console.log(`Updated ${user.full_name} to role: ${user.role}`);
Response

Returns the updated user object.


Remove User

Remove a user from the tenant.

DELETE /api/v1/admin/users/{user_id}
Path Parameters
Parameter Type Description
user_id string (UUID) User identifier
Example Request
curl -X DELETE https://api.calcbridge.io/api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer $TOKEN"
Response

Returns 204 No Content on success.

Error Responses
Status Error Description
403 Cannot remove owner Tenant owner cannot be removed
403 Cannot remove self Cannot remove your own account
404 User not found Invalid user_id

API Key Management

List API Keys

Get all API keys for the current tenant.

GET /api/v1/admin/api-keys
Query Parameters
Parameter Type Default Description
page integer 1 Page number
page_size integer 20 Items per page
status string - Filter by status (active, revoked)
Example Request
curl -X GET "https://api.calcbridge.io/api/v1/admin/api-keys?status=active" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/admin/api-keys",
    headers={"Authorization": f"Bearer {token}"},
    params={"status": "active"}
)
api_keys = response.json()
for key in api_keys["items"]:
    print(f"{key['name']}: {key['key_prefix']}...")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/admin/api-keys?status=active',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const apiKeys = await response.json();
apiKeys.items.forEach(key => {
  console.log(`${key.name}: ${key.key_prefix}...`);
});
Response
{
  "items": [
    {
      "id": "880e8400-e29b-41d4-a716-446655440020",
      "name": "Production Integration",
      "key_prefix": "cb_live_a1b2c3",
      "permissions": ["workbooks:read", "calculations:execute", "compliance:read"],
      "status": "active",
      "last_used": "2026-01-25T10:15:00Z",
      "usage_count": 5420,
      "expires_at": null,
      "created_by": "admin@example.com",
      "created_at": "2025-10-01T10:00:00Z"
    },
    {
      "id": "880e8400-e29b-41d4-a716-446655440021",
      "name": "Development Testing",
      "key_prefix": "cb_test_x9y8z7",
      "permissions": ["workbooks:read", "workbooks:write", "calculations:execute"],
      "status": "active",
      "last_used": "2026-01-24T16:45:00Z",
      "usage_count": 892,
      "expires_at": "2026-06-01T00:00:00Z",
      "created_by": "admin@example.com",
      "created_at": "2025-12-01T14:00:00Z"
    }
  ],
  "total": 3,
  "page": 1,
  "page_size": 20,
  "total_pages": 1
}

Create API Key

Create a new API key.

POST /api/v1/admin/api-keys
Request Body
Field Type Required Description
name string Yes Key name (1-200 chars)
permissions array[string] Yes Permission scopes
expires_at string (ISO 8601) No Expiration date (null for no expiry)
environment string No Environment: live, test (default: live)
Available Permissions
Permission Description
workbooks:read List and view workbooks
workbooks:write Create, update, delete workbooks
calculations:execute Run formula evaluations
compliance:read View compliance results
compliance:write Run compliance tests, configure thresholds
scenarios:read View scenarios
scenarios:write Create and run scenarios
reports:read View reports
reports:generate Generate and export reports
alerts:read View alerts
alerts:write Configure alerts
mappings:read View mappings
mappings:write Create and update mappings
admin:users Manage users (admin only)
admin:api-keys Manage API keys (admin only)
Example Request
curl -X POST https://api.calcbridge.io/api/v1/admin/api-keys \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI/CD Pipeline",
    "permissions": [
      "workbooks:read",
      "workbooks:write",
      "calculations:execute",
      "compliance:read"
    ],
    "expires_at": "2027-01-01T00:00:00Z",
    "environment": "live"
  }'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/admin/api-keys",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "name": "CI/CD Pipeline",
        "permissions": [
            "workbooks:read",
            "workbooks:write",
            "calculations:execute",
            "compliance:read"
        ],
        "expires_at": "2027-01-01T00:00:00Z",
        "environment": "live"
    }
)
api_key = response.json()
# IMPORTANT: Save the full key now - it won't be shown again!
print(f"API Key: {api_key['key']}")
const response = await fetch('https://api.calcbridge.io/api/v1/admin/api-keys', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'CI/CD Pipeline',
    permissions: [
      'workbooks:read',
      'workbooks:write',
      'calculations:execute',
      'compliance:read'
    ],
    expires_at: '2027-01-01T00:00:00Z',
    environment: 'live'
  })
});
const apiKey = await response.json();
// IMPORTANT: Save the full key now - it won't be shown again!
console.log('API Key:', apiKey.key);
Response
{
  "id": "880e8400-e29b-41d4-a716-446655440022",
  "name": "CI/CD Pipeline",
  "key": "cb_live_abc123def456ghi789jkl012mno345pqr678stu901vwx234yz",
  "key_prefix": "cb_live_abc123",
  "permissions": [
    "workbooks:read",
    "workbooks:write",
    "calculations:execute",
    "compliance:read"
  ],
  "environment": "live",
  "status": "active",
  "expires_at": "2027-01-01T00:00:00Z",
  "created_by": "admin@example.com",
  "created_at": "2026-01-25T10:30:00Z"
}

Save your API key

The full API key is only shown once at creation time. Store it securely - you won't be able to retrieve it later.


Revoke API Key

Revoke an API key.

DELETE /api/v1/admin/api-keys/{key_id}
Path Parameters
Parameter Type Description
key_id string (UUID) API key identifier
Example Request
curl -X DELETE https://api.calcbridge.io/api/v1/admin/api-keys/880e8400-e29b-41d4-a716-446655440020 \
  -H "Authorization: Bearer $TOKEN"
Response

Returns 204 No Content on success.


Rotate API Key

Create a new key and revoke the old one atomically.

POST /api/v1/admin/api-keys/{key_id}/rotate
Path Parameters
Parameter Type Description
key_id string (UUID) API key identifier
Request Body
Field Type Required Description
grace_period_hours integer No Hours to keep old key active (default: 0)
Example Request
curl -X POST https://api.calcbridge.io/api/v1/admin/api-keys/880e8400-e29b-41d4-a716-446655440020/rotate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "grace_period_hours": 24
  }'
Response
{
  "new_key": {
    "id": "880e8400-e29b-41d4-a716-446655440023",
    "name": "Production Integration",
    "key": "cb_live_new123key456here789...",
    "key_prefix": "cb_live_new123",
    "permissions": ["workbooks:read", "calculations:execute", "compliance:read"],
    "status": "active",
    "created_at": "2026-01-25T10:30:00Z"
  },
  "old_key": {
    "id": "880e8400-e29b-41d4-a716-446655440020",
    "status": "deprecated",
    "expires_at": "2026-01-26T10:30:00Z"
  }
}

Audit Logs

List Audit Logs

Get audit logs for the tenant (Enterprise tier only).

GET /api/v1/admin/audit-logs
Query Parameters
Parameter Type Default Description
page integer 1 Page number
page_size integer 50 Items per page (max 100)
user_id string (UUID) - Filter by user
action string - Filter by action type
resource_type string - Filter by resource type
start_date string (ISO 8601) - Logs after this date
end_date string (ISO 8601) - Logs before this date
Example Request
curl -X GET "https://api.calcbridge.io/api/v1/admin/audit-logs?action=delete&resource_type=workbook&page_size=50" \
  -H "Authorization: Bearer $TOKEN"
Response
{
  "items": [
    {
      "id": "990e8400-e29b-41d4-a716-446655440030",
      "timestamp": "2026-01-25T10:30:00Z",
      "user_id": "550e8400-e29b-41d4-a716-446655440000",
      "user_email": "john@example.com",
      "action": "delete",
      "resource_type": "workbook",
      "resource_id": "550e8400-e29b-41d4-a716-446655440099",
      "resource_name": "Old Portfolio Q4 2025",
      "ip_address": "192.168.1.100",
      "user_agent": "Mozilla/5.0...",
      "details": {
        "reason": "Replaced with updated version"
      }
    }
  ],
  "total": 150,
  "page": 1,
  "page_size": 50,
  "total_pages": 3
}

User Roles

Role Description Permissions
owner Tenant owner Full access, can delete tenant
admin Administrator Manage users, API keys, settings
analyst Power user Full workbook and analysis access
viewer Read-only View workbooks and reports only

Role Permissions Matrix

Permission Owner Admin Analyst Viewer
View workbooks Yes Yes Yes Yes
Upload workbooks Yes Yes Yes No
Delete workbooks Yes Yes Yes No
Run calculations Yes Yes Yes No
Run compliance tests Yes Yes Yes No
Create scenarios Yes Yes Yes No
Generate reports Yes Yes Yes No
Configure alerts Yes Yes Yes No
Manage mappings Yes Yes Yes No
Manage users Yes Yes No No
Manage API keys Yes Yes No No
Update tenant settings Yes Yes No No
Delete tenant Yes No No No

Best Practices

  1. Use least privilege: Assign minimum necessary permissions to API keys
  2. Rotate keys regularly: Set expiration dates and rotate production keys periodically
  3. Monitor audit logs: Review access patterns and investigate anomalies
  4. Separate environments: Use different API keys for development/staging/production
  5. Document API key purposes: Use descriptive names for easy identification
  6. Review user access: Regularly audit user roles and remove inactive accounts