Skip to main content
Organizations in Zitadel provide multi-tenancy and isolation for users and resources. This guide covers how to create and manage organizations, configure domains, and handle organization settings.

Prerequisites

  • Zitadel Ruby SDK installed and configured
  • Authentication configured with appropriate permissions
  • Required permissions: org.read, org.write, org.create, org.delete

Creating Organizations

Create a New Organization

Organizations are created with at least one administrative user who receives the ORG_OWNER role.
require 'zitadel-client'

client = Zitadel::Client::Zitadel.with_access_token(
  "https://example.zitadel.cloud",
  "your_access_token"
)

request = Zitadel::Client::OrganizationServiceAddOrganizationRequest.new(
  name: "Acme Corporation",
  admins: [
    {
      user_id: "admin_user_id_here",
      roles: ["ORG_OWNER"]
    }
  ]
)

begin
  response = client.organizations.add_organization(request)
  puts "Organization created with ID: #{response.organization_id}"
  puts "Details: #{response.details}"
rescue Zitadel::Client::ApiError => e
  puts "Error creating organization: #{e.message}"
end
If no roles are specified for the admin users, they will automatically be granted the ORG_OWNER role.

Create Organization with Multiple Admins

request = Zitadel::Client::OrganizationServiceAddOrganizationRequest.new(
  name: "Enterprise Inc",
  admins: [
    {
      user_id: "user_1_id",
      roles: ["ORG_OWNER"]
    },
    {
      user_id: "user_2_id",
      roles: ["ORG_OWNER_VIEWER"]
    },
    {
      user_id: "user_3_id",
      roles: ["ORG_USER_MANAGER"]
    }
  ]
)

response = client.organizations.add_organization(request)
puts "Organization created: #{response.organization_id}"

Retrieving Organization Information

List Organizations

request = Zitadel::Client::OrganizationServiceListOrganizationsRequest.new(
  queries: [],
  sorting_column: "FIELD_NAME_CREATION_DATE",
  asc: false
)

response = client.organizations.list_organizations(request)

response.result.each do |org|
  puts "Organization: #{org.name}"
  puts "  ID: #{org.id}"
  puts "  State: #{org.state}"
  puts "  Created: #{org.details.creation_date}"
end

Search Organizations by Name

request = Zitadel::Client::OrganizationServiceListOrganizationsRequest.new(
  queries: [
    {
      name_query: {
        name: "Acme",
        method: "TEXT_QUERY_METHOD_CONTAINS"
      }
    }
  ]
)

response = client.organizations.list_organizations(request)
puts "Found #{response.result.length} organizations"

Updating Organizations

Update Organization Name

request = Zitadel::Client::OrganizationServiceUpdateOrganizationRequest.new(
  organization_id: "org_id_here",
  name: "Acme Corporation - Updated"
)

response = client.organizations.update_organization(request)
puts "Organization updated"

Managing Organization Domains

Domains are used to identify which organization a user belongs to based on their email address.

Add a Domain

request = Zitadel::Client::OrganizationServiceAddOrganizationDomainRequest.new(
  organization_id: "org_id_here",
  domain: "acme.com"
)

response = client.organizations.add_organization_domain(request)
puts "Domain added: #{response.domain}"

Generate Domain Validation

After adding a domain, you need to verify ownership using DNS or HTTP validation.
request = Zitadel::Client::OrganizationServiceGenerateOrganizationDomainValidationRequest.new(
  organization_id: "org_id_here",
  domain: "acme.com",
  type: "DOMAIN_VALIDATION_TYPE_DNS" # or DOMAIN_VALIDATION_TYPE_HTTP
)

response = client.organizations.generate_organization_domain_validation(request)

if response.validation_type == "DOMAIN_VALIDATION_TYPE_DNS"
  puts "Add this DNS TXT record:"
  puts "  Token: #{response.token}"
  puts "  URL: #{response.url}"
elsif response.validation_type == "DOMAIN_VALIDATION_TYPE_HTTP"
  puts "Place this file at the URL:"
  puts "  URL: #{response.url}"
  puts "  Token: #{response.token}"
end
1
Add the domain
2
Use add_organization_domain to register the domain with your organization.
3
Generate validation token
4
Call generate_organization_domain_validation to get DNS or HTTP validation details.
5
Add DNS record or HTTP file
6
For DNS: Add a TXT record with the provided token. For HTTP: Host a file at the provided URL containing the token.
7
Verify the domain
8
Call verify_organization_domain to complete the verification process.

Verify Domain

request = Zitadel::Client::OrganizationServiceVerifyOrganizationDomainRequest.new(
  organization_id: "org_id_here",
  domain: "acme.com"
)

begin
  response = client.organizations.verify_organization_domain(request)
  puts "Domain verified successfully"
rescue Zitadel::Client::ApiError => e
  puts "Verification failed: #{e.message}"
end

List Organization Domains

request = Zitadel::Client::OrganizationServiceListOrganizationDomainsRequest.new(
  organization_id: "org_id_here"
)

response = client.organizations.list_organization_domains(request)

response.result.each do |domain|
  puts "Domain: #{domain.domain_name}"
  puts "  Verified: #{domain.is_verified}"
  puts "  Primary: #{domain.is_primary}"
end

Remove a Domain

request = Zitadel::Client::OrganizationServiceDeleteOrganizationDomainRequest.new(
  organization_id: "org_id_here",
  domain: "acme.com"
)

response = client.organizations.delete_organization_domain(request)
puts "Domain removed"
Removing a domain will prevent users with email addresses from that domain from logging in using the domain-based login.

Managing Organization Metadata

Metadata allows you to store custom key-value data associated with an organization.

Set Metadata

require 'base64'

metadata_value = {
  subscription_tier: "enterprise",
  max_users: 1000,
  features: ["sso", "audit_logs", "custom_branding"]
}.to_json

request = Zitadel::Client::OrganizationServiceSetOrganizationMetadataRequest.new(
  organization_id: "org_id_here",
  key: "subscription",
  value: Base64.strict_encode64(metadata_value)
)

response = client.organizations.set_organization_metadata(request)
puts "Metadata updated"
Metadata values must be base64 encoded before sending to the API.

List Metadata

request = Zitadel::Client::OrganizationServiceListOrganizationMetadataRequest.new(
  organization_id: "org_id_here",
  queries: []
)

response = client.organizations.list_organization_metadata(request)

response.result.each do |metadata|
  decoded_value = Base64.strict_decode64(metadata.value)
  puts "Key: #{metadata.key}"
  puts "Value: #{decoded_value}"
end

Delete Metadata

request = Zitadel::Client::OrganizationServiceDeleteOrganizationMetadataRequest.new(
  organization_id: "org_id_here",
  key: "subscription"
)

response = client.organizations.delete_organization_metadata(request)
puts "Metadata deleted"

Organization Lifecycle

Deactivate Organization

Deactivating an organization prevents all users in that organization from logging in.
request = Zitadel::Client::OrganizationServiceDeactivateOrganizationRequest.new(
  organization_id: "org_id_here"
)

response = client.organizations.deactivate_organization(request)
puts "Organization deactivated"

Activate Organization

request = Zitadel::Client::OrganizationServiceActivateOrganizationRequest.new(
  organization_id: "org_id_here"
)

response = client.organizations.activate_organization(request)
puts "Organization activated"

Delete Organization

Deleting an organization removes it and all associated resources (users, projects, grants).
request = Zitadel::Client::OrganizationServiceDeleteOrganizationRequest.new(
  organization_id: "org_id_here"
)

response = client.organizations.delete_organization(request)
puts "Organization deleted"
Deleting an organization is permanent and will remove all resources including users, projects, and grants. Users will not be able to log in.

Complete Workflow Example

Here’s a complete example of creating and configuring an organization:
require 'zitadel-client'
require 'base64'

client = Zitadel::Client::Zitadel.with_private_key(
  "https://example.zitadel.cloud",
  "path/to/service-account.json"
)

begin
  # 1. Create organization
  org_request = Zitadel::Client::OrganizationServiceAddOrganizationRequest.new(
    name: "Tech Startup Inc",
    admins: [
      { user_id: "admin_user_id" }
    ]
  )
  org_response = client.organizations.add_organization(org_request)
  org_id = org_response.organization_id
  puts "Created organization: #{org_id}"

  # 2. Add domain
  domain_request = Zitadel::Client::OrganizationServiceAddOrganizationDomainRequest.new(
    organization_id: org_id,
    domain: "techstartup.com"
  )
  client.organizations.add_organization_domain(domain_request)
  puts "Added domain: techstartup.com"

  # 3. Generate DNS validation
  validation_request = Zitadel::Client::OrganizationServiceGenerateOrganizationDomainValidationRequest.new(
    organization_id: org_id,
    domain: "techstartup.com",
    type: "DOMAIN_VALIDATION_TYPE_DNS"
  )
  validation_response = client.organizations.generate_organization_domain_validation(validation_request)
  puts "DNS Token: #{validation_response.token}"

  # 4. Set metadata
  metadata = { tier: "starter", created_by: "api" }.to_json
  metadata_request = Zitadel::Client::OrganizationServiceSetOrganizationMetadataRequest.new(
    organization_id: org_id,
    key: "config",
    value: Base64.strict_encode64(metadata)
  )
  client.organizations.set_organization_metadata(metadata_request)
  puts "Metadata configured"

  puts "Organization setup complete!"
rescue Zitadel::Client::ApiError => e
  puts "Error: #{e.message}"
end

Best Practices

1
Use verified domains
2
Always verify organization domains to ensure secure user identification and prevent domain spoofing.
3
Implement proper access control
4
Assign appropriate organization roles (ORG_OWNER, ORG_USER_MANAGER, etc.) based on user responsibilities.
5
Store configuration in metadata
6
Use organization metadata to store application-specific configuration and settings.
7
Handle deactivation gracefully
8
Before deactivating an organization, notify users and provide alternatives if needed.
9
Monitor organization lifecycle
10
Track organization creation, modification, and deletion events for audit purposes.

Next Steps

Build docs developers (and LLMs) love