Skip to content

Tenant Administration

Day-to-day management of tenants in Mantis.

Tenant administration covers ongoing management tasks:

Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants"

Response:

{
"data": [
{
"id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e",
"name": "Acme Corp",
"description": "Enterprise customer",
"contact_email": "ops@acme.com",
"created_at": "2024-01-15T10:30:00Z"
},
{
"id": "019b937d-4862-84ae-9c2a-6ac230cc4c80",
"name": "Globex Inc",
"description": "SMB customer",
"contact_email": "admin@globex.com",
"created_at": "2024-01-20T14:00:00Z"
}
],
"meta": {
"total": 2,
"page": 1,
"limit": 20
}
}
Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID"

Response includes relationships:

{
"id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e",
"name": "Acme Corp",
"description": "Enterprise customer",
"contact_email": "ops@acme.com",
"logo_url": "https://acme.com/logo.png",
"tags": [
{ "id": "tag_region", "key": "region", "value": "us-east" },
{ "id": "tag_tier", "key": "tier", "value": "enterprise" }
],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-02-01T09:15:00Z"
}
Terminal window
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corporation",
"description": "Updated enterprise customer description",
"contact_email": "newops@acme.com"
}' \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID"
FieldUpdate Behavior
nameMust remain unique
descriptionSet to null to clear
contact_emailSet to null to clear
logo_urlSet to null to clear
  1. Navigate to AdminTenants
  2. Click on the tenant name
  3. Click Edit
  4. Update fields
  5. Click Save
Terminal window
# List solutions
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"
# List targets
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets"
# List environments
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/environments"
Terminal window
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"solution_id": "sol_newfeature",
"environment_id": "env_staging"
}' \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"
Terminal window
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions/$SOLUTION_ID/environments/$ENV_ID"

Document tenant entitlements:

TenantSolutionProductionStagingDevelopment
Acme CorpWebApp
Acme CorpAPI
Globex IncWebApp
Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/variables"
Terminal window
# Update existing variable (POST upserts)
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"variable_type": "common",
"template_id_or_key": "api_url",
"value": "https://api-v2.acme.com",
"is_encrypted": false
}' \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/variables"
Terminal window
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/variables/$VARIABLE_ID?variable_type=common"

For security, rotate sensitive variables periodically:

Terminal window
# Update encrypted variable with new value
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"variable_type": "common",
"template_id_or_key": "database_password",
"value": "new_secure_password",
"is_encrypted": true
}' \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/variables"
Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/deployments"

Response:

{
"data": [
{
"id": "019b937d-4862-8de0-1111-222233334444",
"source_type": "solution",
"solution_name": "WebApp",
"state": "completed",
"progress": 1.0,
"tenant_name": "Acme Corp",
"environment_name": "Production",
"created_at": "2024-02-01T10:00:00Z",
"completed_at": "2024-02-01T10:05:32Z",
"duration_ms": 332000
}
],
"meta": {
"total": 150,
"page": 1,
"limit": 20
}
}
Terminal window
# Pagination
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID/deployments?page=2&limit=50"

State-based filtering is not currently supported on this endpoint. Use the SQL monitoring queries below for status-filtered analysis.

Track tenant health with deployment metrics:

SELECT
DATE_TRUNC('day', created_at) AS day,
COUNT(*) AS total_deployments,
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) AS successful,
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed,
AVG(EXTRACT(EPOCH FROM (completed_at - started_at))) AS avg_duration_secs
FROM deployment_history
WHERE tenant_id = $tenant_id
AND created_at >= NOW() - INTERVAL '30 days'
GROUP BY DATE_TRUNC('day', created_at)
ORDER BY day DESC;
Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/admin/users"

System admins see all users; tenant-scoped callers automatically see only users in their tenant, controlled by the caller’s JWT. There is no tenant_id query parameter — filtering is implicit based on the token used.

Terminal window
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "bob",
"email": "bob@acme.com",
"password": "secure_password",
"tenant_id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e",
"role_ids": ["role_viewer"]
}' \
"https://api.mantis.local/api/v1/admin/users"
Terminal window
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "ten_new_tenant"
}' \
"https://api.mantis.local/api/v1/admin/users/$USER_ID"

Disable rather than delete for audit retention:

Terminal window
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "inactive"}' \
"https://api.mantis.local/api/v1/admin/users/$USER_ID"

Audit logs are read from /api/v1/audit/logs. Results are automatically scoped to the caller’s tenant; an admin with no tenant sees logs across all tenants. There is no tenant_id query parameter.

Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/audit/logs"
Terminal window
# Authentication events
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/audit/logs?category=authentication"
# Deployment events
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/audit/logs?category=deployment"
# Security events
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/audit/logs?severity=security"
-- Export tenant audit logs for compliance
COPY (
SELECT
created_at,
event_type,
event_category,
severity,
actor_id,
action,
outcome,
metadata
FROM audit_log_entries
WHERE tenant_id = $tenant_id
AND created_at >= '2024-01-01'
AND created_at < '2024-02-01'
ORDER BY created_at
) TO '/tmp/audit_export.csv' WITH CSV HEADER;
□ Create tenant
□ Configure description and contact
□ Attach required solutions to environments
□ Assign targets
□ Set up variables (including encrypted secrets)
□ Add tags for organization
□ Create initial users
□ Configure SSO (if applicable)
□ Document tenant configuration
□ Notify tenant of access

When a tenant needs to be temporarily disabled:

Terminal window
# Remove all solution entitlements
for SOL_ENV in $(get_tenant_solutions); do
curl -X DELETE "$API_URL/tenants/$TENANT_ID/solutions/$SOL_ENV"
done
# Disable all tenant users (valid statuses: active, inactive, locked, pending)
for USER_ID in $(get_tenant_users); do
curl -X PUT -d '{"status": "inactive"}' \
"https://api.mantis.local/api/v1/admin/users/$USER_ID"
done
Terminal window
# Re-enable users
for USER_ID in $(get_tenant_users); do
curl -X PUT -d '{"status": "active"}' \
"https://api.mantis.local/api/v1/admin/users/$USER_ID"
done
# Restore entitlements
curl -X POST -d '{"solution_id": "sol_...", "environment_id": "env_..."}' \
"$API_URL/tenants/$TENANT_ID/solutions"

Before deletion:

  1. Export data - Audit logs, deployment history
  2. Notify stakeholders - Confirm deletion is authorized
  3. Disable users first - Prevent new activity
  4. Document decision - For compliance
ResourceOn Tenant Delete
Solution-Environment linksCascade deleted
Target assignmentsCascade deleted
Tenant variablesDeletion blocked (must be removed first)
Common variablesDeletion blocked (must be removed first)
Tenant tagsCascade deleted
UsersNot deleted - orphaned
Audit logsPreserved
Deployment historyPreserved
Terminal window
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
"https://api.mantis.local/api/v1/tenants/$TENANT_ID"

No manual user cleanup is needed. The users.tenant_id foreign key is ON DELETE SET NULL, so PostgreSQL automatically clears it when a tenant is deleted — there are no orphaned users to find afterward. (If you need the list of affected users, query them BEFORE deleting the tenant.)

Monitor key metrics per tenant:

MetricAlert ThresholdAction
Failed deployments>3 in 1 hourInvestigate failures
Inactive users>30 daysReview user access
Variable changesUnexpectedReview audit logs
Target disconnections>1 targetCheck target health

Failed Deployments by Tenant:

SELECT
t.name AS tenant,
COUNT(*) AS failed_count
FROM deployment_history dh
JOIN tenants t ON t.id = dh.tenant_id
WHERE dh.status = 'failed'
AND dh.created_at >= NOW() - INTERVAL '24 hours'
GROUP BY t.name
ORDER BY failed_count DESC;

Active Users per Tenant:

SELECT
t.name AS tenant,
COUNT(*) AS active_users,
MAX(u.last_login_at) AS latest_login
FROM users u
JOIN tenants t ON t.id = u.tenant_id
WHERE u.status = 'active'
GROUP BY t.name;
#!/bin/bash
# Update variable across all tenants
VARIABLE_KEY="api_version"
NEW_VALUE="v2"
for TENANT_ID in $(curl -s "$API_URL/tenants" | jq -r '.data[].id'); do
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"variable_type\": \"common\",
\"template_id_or_key\": \"$VARIABLE_KEY\",
\"value\": \"$NEW_VALUE\",
\"is_encrypted\": false
}" \
"$API_URL/tenants/$TENANT_ID/variables"
echo "Updated $TENANT_ID"
done
#!/bin/bash
# Grant new solution to all enterprise tenants
SOLUTION_ID="sol_new_feature"
ENVIRONMENT_ID="env_production"
# Get tenants with enterprise tag
ENTERPRISE_TENANTS=$(curl -s "$API_URL/tenants" | \
jq -r '.data[] | select(.tags[] | .value == "enterprise") | .id')
for TENANT_ID in $ENTERPRISE_TENANTS; do
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"solution_id\": \"$SOLUTION_ID\",
\"environment_id\": \"$ENVIRONMENT_ID\"
}" \
"$API_URL/tenants/$TENANT_ID/solutions"
echo "Granted to $TENANT_ID"
done
  1. Check solution entitlement:

    Terminal window
    curl "$API_URL/tenants/$TENANT_ID/solutions"
  2. Check target assignment:

    Terminal window
    curl "$API_URL/tenants/$TENANT_ID/targets"
  3. Verify variables:

    Terminal window
    curl "$API_URL/tenants/$TENANT_ID/variables/resolved?solution_id=$SOL&environment_id=$ENV"
  1. Verify user’s tenant_id:

    SELECT tenant_id FROM users WHERE id = $user_id;
  2. Check user status:

    SELECT status FROM users WHERE id = $user_id;
  3. Verify tenant exists:

    SELECT id, name FROM tenants WHERE id = $tenant_id;