Tenant Creation
Tenant Creation
Section titled “Tenant Creation”Create and configure tenants in Mantis for multi-tenant deployments.
Overview
Section titled “Overview”Tenants represent organizational units—customers, teams, or departments—that have isolated access to Mantis resources.
Creating a Tenant
Section titled “Creating a Tenant”Via API
Section titled “Via API”curl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Corp", "description": "Acme Corporation production tenant", "contact_email": "ops@acme.com", "logo_url": "https://acme.com/logo.png" }' \ "https://api.mantis.local/api/v1/tenants"Request Fields
Section titled “Request Fields”| Field | Required | Validation | Description |
|---|---|---|---|
name | Yes | 1-255 chars, unique | Tenant display name |
description | No | None | Tenant description |
contact_email | No | Valid email | Primary contact |
logo_url | No | None | Branding logo URL |
Response
Section titled “Response”{ "id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e", "name": "Acme Corp", "description": "Acme Corporation production tenant", "contact_email": "ops@acme.com", "logo_url": "https://acme.com/logo.png", "created_at": "2024-01-15T10:30:00Z", "updated_at": null}Via Lens UI
Section titled “Via Lens UI”- Navigate to Tenancy → Tenants
- Click New Tenant
- Fill in the tenant form:
- Name: Unique identifier for the tenant
- Description: Optional details about the tenant
- Contact Email: Primary contact for notifications
- Logo URL: Optional branding image
- Click Create Tenant
Attaching Solutions
Section titled “Attaching Solutions”After creating a tenant, grant access to solutions by attaching them with specific environments.
Via API
Section titled “Via API”# Attach solution to tenant for a specific environmentcurl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "solution_id": "019b937d-4862-8ccc-ddee-3344556677bb", "environment_id": "019b937d-fe4d-80c3-ac78-f9b11e725443" }' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"Solution-Environment Matrix
Section titled “Solution-Environment Matrix”A tenant can have different solution access per environment:
# Grant access to WebApp in Productioncurl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"solution_id": "019b937d-5c9d-819f-a89c-41c299a3872e", "environment_id": "019b937d-806c-8867-a7a0-24c41b64c969"}' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"
# Grant access to WebApp in Stagingcurl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"solution_id": "019b937d-5c9d-819f-a89c-41c299a3872e", "environment_id": "019b937d-739d-8cd8-a8af-636d98857494"}' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"Via Lens UI
Section titled “Via Lens UI”- Navigate to Admin → Tenants → select tenant
- Go to Solutions tab
- Click Attach Solution
- Select:
- Solution: Choose from available solutions
- Environment: Target environment for the entitlement
- Click Attach
List Tenant Solutions
Section titled “List Tenant Solutions”curl -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions"Response:
[ { "solution_id": "019b937d-5c9d-819f-a89c-41c299a3872e", "solution_name": "WebApp", "environment_id": "019b937d-806c-8867-a7a0-24c41b64c969", "environment_name": "Production", "created_at": "2026-01-15T09:12:03Z" }, { "solution_id": "019b937d-5c9d-819f-a89c-41c299a3872e", "solution_name": "WebApp", "environment_id": "019b937d-739d-8cd8-a8af-636d98857494", "environment_name": "Staging", "created_at": "2026-01-15T09:12:41Z" }]Detach Solution
Section titled “Detach Solution”curl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/solutions/$SOLUTION_ID/environments/$ENV_ID"Assigning Targets
Section titled “Assigning Targets”Bind targets to tenants for deployment scope.
Via API
Section titled “Via API”# Assign target to tenant (all environments)curl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "target_id": "019b937d-e1be-8b01-a285-68e757fa6139" }' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets"
# Assign target to tenant for specific environmentcurl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "target_id": "019b937d-a975-8f41-ac94-8b81b3f7c813", "environment_id": "019b937d-806c-8867-a7a0-24c41b64c969" }' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets"Target Scope
Section titled “Target Scope”| Scope | Configuration | Use Case |
|---|---|---|
| All environments | environment_id: null | Shared infrastructure |
| Single environment | environment_id: <env-uuid> | Dedicated production servers |
Via Lens UI
Section titled “Via Lens UI”- Navigate to Tenancy → Tenants → select tenant
- Go to Targets tab
- Click Attach Target
- Select:
- Target: Choose from available targets
- Environment: (Optional) Limit to specific environment
- Click Attach
List Tenant Targets
Section titled “List Tenant Targets”# All targetscurl -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets"
# Filter by environmentcurl -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets?environment_id=019b937d-806c-8867-a7a0-24c41b64c969"Remove Target Assignment
Section titled “Remove Target Assignment”# Remove from specific environmentcurl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets/$TARGET_ID?environment_id=019b937d-806c-8867-a7a0-24c41b64c969"
# Remove from all environmentscurl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/targets/$TARGET_ID"Setting Variables
Section titled “Setting Variables”Variables are not attached to the tenant record. They live in variable sets, and
it is the set that carries the tenant: give POST /variable-sets a
tenant_id and every variable in that set belongs to that tenant. A set created
without a tenant_id is global.
# Create a variable set owned by this tenantVARIABLE_SET_ID=$(curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "acme-defaults", "description": "Defaults for Acme deployments", "tenant_id": "'"$TENANT_ID"'" }' \ "https://api.mantis.local/api/v1/variable-sets" | jq -r '.id')
# Add a variable to itcurl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "api_endpoint", "value": "https://api.acme.local/v2", "variable_type": "string" }' \ "https://api.mantis.local/api/v1/variable-sets/$VARIABLE_SET_ID/variables"variable_type is one of string, sensitive, certificate or
execution_pool, and defaults to string. Use sensitive to store the value
encrypted at rest; reads of that variable return "********" in value and
"is_encrypted": true, so a set-but-withheld value is distinguishable from an
unset one.
Add "scope_environment_id" to narrow a variable to one environment. It is the
only scope this endpoint accepts, and the request body is declared
deny_unknown_fields, so key, is_encrypted, scope_tenant_id and
scope_solution_id are each rejected with 422 Unprocessable Entity rather
than being ignored.
Resolution across the ten scopes is described in Multi-Tenancy Overview. There is no resolved-variables endpoint — resolution happens during deployment planning.
Adding Tags
Section titled “Adding Tags”Organize tenants with tags for filtering and grouping.
Attach Tags
Section titled “Attach Tags”curl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tag_ids": ["019b937d-887b-86e6-ae7f-5aa6214f0833", "019b937d-946c-8d41-a642-2b58fe4e3ec2"] }' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/tags"List Tags
Section titled “List Tags”curl -H "Authorization: Bearer $TOKEN" \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/tags"Detach Tags
Section titled “Detach Tags”curl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tag_ids": ["019b937d-887b-86e6-ae7f-5aa6214f0833"] }' \ "https://api.mantis.local/api/v1/tenants/$TENANT_ID/tags"Creating Tenant Users
Section titled “Creating Tenant Users”After tenant creation, assign users to the tenant.
Via API
Section titled “Via API”curl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "username": "alice", "email": "alice@acme.com", "tenant_id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e", "role_ids": ["019b93a2-1f04-8c7e-b6d1-2a5f0c83e714"] }' \ "https://api.mantis.local/api/v1/admin/users"The body rejects any field it does not declare, and password is not one of them:
the account is created in an invited state with no usable password, and Mandible
emails an activation link the user completes themselves. role_ids are role UUIDs —
list them with GET /api/v1/admin/roles.
To set a password directly instead — for an account that will not go through the emailed invitation — post to the user returned above:
curl -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "new_password": "correct-horse-battery-staple" }' \ "https://api.mantis.local/api/v1/admin/users/$USER_ID/password"The password must meet the platform complexity rules, and the reset also revokes the user’s OAuth2 tokens, API keys and active sessions.
Via SSO
Section titled “Via SSO”Configure identity provider with tenant mapping:
- Set up OIDC provider for the tenant
- Configure role mappings
- Users created on first SSO login are automatically tenant-scoped
See Identity Providers for SSO configuration.
Complete Setup Example
Section titled “Complete Setup Example”Full tenant onboarding script:
#!/bin/bashset -e
API_URL="https://api.mantis.local/api/v1"TOKEN="your-admin-token"
# 1. Create tenantTENANT=$(curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Corp", "description": "Enterprise customer", "contact_email": "ops@acme.com" }' \ "$API_URL/tenants")
TENANT_ID=$(echo $TENANT | jq -r '.id')echo "Created tenant: $TENANT_ID"
# The solution, environments and targets to hand to the tenant, by UUIDSOLUTION_ID="019b937d-5c9d-819f-a89c-41c299a3872e"ENVIRONMENT_IDS=("019b937d-806c-8867-a7a0-24c41b64c969" "019b937d-739d-8cd8-a8af-636d98857494")TARGET_IDS=("019b937d-e1be-8b01-a285-68e757fa6139" "019b937d-a975-8f41-ac94-8b81b3f7c813")
# 2. Attach solutions to environmentsfor ENV in "${ENVIRONMENT_IDS[@]}"; do curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"solution_id\": \"$SOLUTION_ID\", \"environment_id\": \"$ENV\"}" \ "$API_URL/tenants/$TENANT_ID/solutions"doneecho "Attached solutions"
# 3. Assign targetsfor TARGET in "${TARGET_IDS[@]}"; do curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"target_id\": \"$TARGET\"}" \ "$API_URL/tenants/$TENANT_ID/targets"doneecho "Assigned targets"
# 4. Set variables — the set carries the tenant, the variables live inside itVARIABLE_SET_ID=$(curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"name\": \"acme-defaults\", \"tenant_id\": \"$TENANT_ID\" }" \ "$API_URL/variable-sets" | jq -r '.id')
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"name\": \"database_url\", \"value\": \"postgresql://db.acme.local:5432/webapp\", \"variable_type\": \"string\" }" \ "$API_URL/variable-sets/$VARIABLE_SET_ID/variables"echo "Set variables"
# 5. Add tagscurl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"tag_ids": ["019b937d-4d29-86bf-a4f8-f9a4bbf364e1", "019b937d-887b-86e6-ae7f-5aa6214f0833"]}' \ "$API_URL/tenants/$TENANT_ID/tags"echo "Added tags"
echo "Tenant setup complete: $TENANT_ID"Audit Trail
Section titled “Audit Trail”Tenant creation and modifications are logged:
{ "event_type": "tenant.created", "event_category": "tenant_management", "severity": "info", "actor_type": "user", "actor_id": "019b937d-4862-8e07-ac3a-1b8589d1b807", "actor_name": "admin", "resource_type": "tenant", "resource_id": "019b937d-4862-84ae-9c2a-6ac230cc4c7e", "resource_name": "Acme Corp", "tenant_id": null, "action": "create_tenant", "outcome": "success", "occurred_at": "2024-02-01T10:00:00Z"}The entry’s action is create_tenant (the operation label) and its tenant_id
is null — the builder does not stamp the tenant scope for this event, so the new
tenant is identified only by resource_id / resource_name.
Troubleshooting
Section titled “Troubleshooting”Tenant Name Conflict
Section titled “Tenant Name Conflict”Error: Tenant with name 'Acme Corp' already existsTenant names must be unique. Use a different name or include a suffix.
Solution Not Found
Section titled “Solution Not Found”Error: Solution 019b937d-4862-8ccc-ddee-3344556677bb not foundVerify the solution exists before attaching to tenant.
Permission Denied
Section titled “Permission Denied”Error: Insufficient permissionsThe response body contains error code INSUFFICIENT_PERMISSIONS. The required permission (tenants:create) appears in server-side audit logs. Assign the appropriate role to the user.
Next Steps
Section titled “Next Steps”- Data Isolation - Understand security model
- Tenant Administration - Day-to-day management
- Users - Create tenant users
