Skip to content

Instantly share code, notes, and snippets.

@geekodour
Created June 27, 2025 01:59
Show Gist options
  • Save geekodour/a37f061af0801c842040d93b59c17c2a to your computer and use it in GitHub Desktop.
Save geekodour/a37f061af0801c842040d93b59c17c2a to your computer and use it in GitHub Desktop.
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "click",
# ]
# ///
# NOTE: This script creates a new virtual instance in ZITADEL.
# NOTE: Virtual instances are separated at the network level; there is no central UI to view them.
# See for more details:
# https://zitadel.com/docs/guides/integrate/zitadel-apis/access-zitadel-system-api
# https://zitadel.com/docs/apis/resources/system/system-service-create-instance
import http.client
import json
import os
import sys
import click
def create_zitadel_instance(
jwt_token, zitadel_url, instance_name, org_name, custom_domain, username, email
):
conn = http.client.HTTPSConnection(zitadel_url)
payload = json.dumps(
{
"instanceName": instance_name,
"firstOrgName": org_name,
"customDomain": custom_domain,
"human": {
"userName": username,
"email": {
"email": email,
"isEmailVerified": True,
},
"profile": {
"firstName": "Admin",
"lastName": "G",
},
"password": {
"password": "dummyPASS0!",
"passwordChangeRequired": False,
},
},
}
)
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": f"Bearer {jwt_token}",
}
try:
conn.request("POST", "/system/v1/instances/_create", payload, headers)
res = conn.getresponse()
data = res.read()
print(f"Status: {res.status} {res.reason}")
try:
print(json.dumps(json.loads(data.decode("utf-8")), indent=2))
except json.JSONDecodeError:
print(data.decode("utf-8"))
except Exception as e:
print(f"An error occurred: {e}", file=sys.stderr)
finally:
conn.close()
@click.command(help="Create a new ZITADEL instance via the System API.")
@click.option(
"--instance-name",
required=True,
help="The name for the new ZITADEL instance (e.g., 'my-company').",
)
@click.option(
"--first-org-name",
required=True,
help="The name of the first organization within the new instance.",
)
@click.option(
"--custom-domain",
required=True,
help="The custom domain for the instance (e.g., 'auth.my-company.com').",
)
@click.option(
"--username",
required=True,
help="The username for the first instance administrator.",
)
@click.option(
"--email", required=True, help="The email for the first instance administrator."
)
def main(instance_name, first_org_name, custom_domain, username, email):
# Get sensitive data from environment variables
jwt_token = os.environ["NEW_INSTANCE_ZITADEL_JWT_TOKEN"]
zitadel_instance_url = os.environ["MAIN_ZITADEL_INSTANCE_URL"]
create_zitadel_instance(
jwt_token,
zitadel_instance_url,
instance_name,
first_org_name,
custom_domain,
username,
email,
)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment