Skip to main content
The Project Provisioning API provides a set of flexible, modular endpoints to allow the programmatic creation of a project within . Each API endpoint handles a subset of the information required to provision a project, and executing all of these endpoints as detailed below will result in a functional project that can be accessed through the interface.
It is important to bear in mind that, until the intended users of the project are manually invited, the project will only be visible/accessible to users with the Super Admin role. To invite users, read Invite a user to an account.

Create project

This is the first endpoint to be called in the process, which initializes the project with minimal information. A successful request will produce a v4 UUID, which will be required for the subsequent endpoints. Currently, the supported data warehouses are SNOWFLAKE and REDSHIFT, with a deployment type of HYBRID or FULL_SAAS. Future updates will add support for other warehouses.

Example request

Base URL: POST /v1/projects Example request body:
{
  "name": "my-project-name",
  "description": "An optional description of the project.",
  "warehouse": "SNOWFLAKE",
  "agentDeploymentType": "HYBRID"
}
Example success response:
HTTP 201 Created
{
  "projectId": "678d39a9-98e2-45e7-80db-3e90d0942eaf"
}

Create Default Warehouse Connection

Adding a default warehouse connection sets up basic configuration for connecting to a data warehouse. Currently, the supported warehouse and authentication combinations are:
WarehouseAuthentication Type
Snowflakekey_pair
Amazon Redshiftpassword
This endpoint only defines basic metadata for the warehouse, not the actual credentials for connecting to the warehouse. These are provided in the Create Environment request below.

Example request

Base URL: POST /v1/projects/{projectId}/data-platform-connections Ensure that the {projectId} variable is replaced with the target project ID from the initial request to create the project. Example request body:
{
    "name": "my-warehouse-connection",
    "platformConnectionType": "dwh",
    "authProvider": "snowflake",
    "authType": "key_pair"
}
Example success response:
HTTP 201 Created

{}

Create Secret - Full SaaS only

If using a Full SaaS , you will need to create a secret containing the warehouse connection credentials for your chosen warehouse type. This request will securely store the provided credentials into the -hosted vault, and allow you to reference them when creating an environment.

Request Structure

There are a handful of fields to provide as part of the request: name: The name of the secret that is to be created. This is how you will refer to the secret in any subsequent requests. type: The type of secret to be created. For data warehouse credentials, this should be set to DWH_PASSWORD. key: The key which contains the data warehouse credential within the secret value itself. value: The secret to be stored, such as a password or private key.
When providing a private key, the value MUST include \n newline characters to ensure that it is properly formatted. See example below.

Example request

Note the differing URL path for this request. The agentId can be fetched from the agents API endpoints. Base URL: POST /v1/secrets/{agentId}/secret-value Ensure that the {agentId} variable is replaced with the target agent ID that belongs to the project created in the initial request. Example request body:
{
    "name": "snowflake-private-key",
    "type": "DWH_PASSWORD",
    "key": "password",
    "value": {
        "password": "-----BEGIN PRIVATE KEY-----\n.....\n-----END PRIVATE KEY-----"
    }
}
Example response:
HTTP 201 Created
{
    "vaultSecretName": "snowflake-private-key",
    "resolver_ref": "${srs-mhcv:1:DWH_PASSWORD/snowflake-private-key@password}"
}

Create cloud credential connection

If using a Full SaaS project, or connecting to cloud platform resources outside of the ‘s account, you need to provide credentials to connect to that cloud platform and then associate the new connection with the target environment. Currently, the supported cloud platform and authentication combinations are:
Cloud platformAuthentication type
AWSCLOUD_PROVIDER_SECRET
AzureCLOUD_PROVIDER_SECRET
Google CloudCLOUD_PROVIDER_SECRET
The secret containing the credentials must be created in the vault before you create a cloud platform connection.

Create a cloud credential secret in a Full SaaS vault

To create the secret in a Full SaaS vault, use the /v1/secrets/{agentId}/secret-value endpoint. Example request body (AWS):
{
    "secret": {
        "name": "aws-platform-credentials",
        "type": "CLOUD_PLATFORM_CREDENTIALS",
        "value": {
            "type": "aws",
            "accessKeyID": "<AWS access key ID>",
            "secretKey": "<AWS secret key>"
        }
    }
}
Replace the value block depending on the platform being configured, using the formats below. Azure CLOUD_PROVIDER_SECRET vault format:
{
    "type": "azure",
    "tenantID": "<Azure directory/tenant ID>",
    "clientID": "<Azure application (client) ID>",
    "secretKey": "<Azure client secret value>"
}
Google Cloud CLOUD_PROVIDER_SECRET vault format:
{
    "type": "gcp",
    "serviceAccount": "<Google Cloud service account key JSON, as an escaped string>"
}

Create a cloud credential secret in an external vault

When creating a secret in an external vault—such as AWS Secrets Manager, Azure Key Vault, or another supported platform—the format must match the value parameter in the examples above.

Example request

Base URL: POST /v1/projects/{projectId}/connections Ensure that the {projectId} variable is replaced with the target project ID from the initial request to create the project.

AWS via AWS Secrets Manager

Example request body:
{
  "name": "aws-connection",
  "platformConnectionType": "CLOUD_PLATFORM_CREDENTIALS",
  "authProvider": "aws",
  "authType": "CLOUD_PROVIDER_SECRET",
  "connectionDetails": {
    "description": "This is my AWS cloud credential",
    "secretsLocation": {
      "type": "AWS_SECRET_MANAGER",
      "region": "eu-west-1"
    },
    "connectionProperties": {
      "credentialSecretName": "aws-platform-credentials"
    }
  }
}
The region property is optional.
Example success response:
{
    "name": "aws-connection",
    "platformConnectionType": "CLOUD_PLATFORM_CREDENTIALS",
    "authProvider": "aws",
    "authType": "CLOUD_PROVIDER_SECRET",
    "createdBy": "34c003c5-909c-4efd-bb77-768eef731e77",
    "createdDate": "2026-04-23T14:05:30.858475",
    "projectId": "545b5a22-6490-4078-8e43-f9932c358b50",
    "connectionDetails": {
        "description": "This is my AWS cloud credential",
        "secretsLocation": {
            "type": "AWS_SECRET_MANAGER",
            "region": "eu-west-1"
        },
        "connectionProperties": {
            "credentialSecretName": "aws-platform-credentials"
        }
    }
}

AWS via Maia-hosted vault

Example request body:
{
  "name": "aws-connection",
  "platformConnectionType": "CLOUD_PLATFORM_CREDENTIALS",
  "authProvider": "aws",
  "authType": "CLOUD_PROVIDER_SECRET",
  "connectionDetails": {
    "description": "This is my AWS cloud credential",
    "secretsLocation": {
      "type": "MAIA_CUSTOMER_VAULT"
    },
    "connectionProperties": {
      "credentialSecretName": "aws-platform-credentials"
    }
  }
}

Azure via Azure Key Vault

Example request body:
{
    "name": "azure-connection",
    "platformConnectionType": "CLOUD_PLATFORM_CREDENTIALS",
    "authProvider": "azure",
    "authType": "CLOUD_PROVIDER_SECRET",
    "connectionDetails": {
        "description": "This is my Azure cloud credential",
        "secretsLocation": {
            "type": "AZURE_SECRET_MANAGER",
            "vaultName": "<your-azure-keyvault-name>"
        },
        "connectionProperties": {
            "credentialSecretName": "azure-platform-credentials"
        }
    }
}
The vaultName property is optional.

Google Cloud Secret Manager

Example request body:
{
    "name": "gcp-connection",
    "platformConnectionType": "CLOUD_PLATFORM_CREDENTIALS",
    "authProvider": "gcp",
    "authType": "CLOUD_PROVIDER_SECRET",
    "connectionDetails": {
        "description": "This is my Google Cloud credential",
        "secretsLocation": {
            "type": "GCP_SECRET_MANAGER"
        },
        "connectionProperties": {
            "credentialSecretName": "gcp-platform-credentials"
        }
    }
}
Listing cloud platform connections is performed through the general Connections API endpoint.

Create Environment

Request Structure

When creating an environment, there are a number of fields to provide: name: The name of the environment. This is an immutable identifier for the environment, and is used in other requests to refer to this specific environment. description (optional): An optional, text description for the environment. defaultAgentId: The UUID of the that will be used by default for this environment. defaultUserAccessLevel: The default access level that will be assigned to a user for the environment, when they are added to the project. The accepted values are one of:
  • default
  • admin
  • runner
  • readOnly
  • noAccess
defaultConnections: Specifies the following default connections for the environment:
  • Data warehouse.
  • Cloud platform (optional).
Ensure that the value provided here is identical to the name of the connection defined in the previous request (for example, my-warehouse-connection).
Currently, the connection details for the warehouse connection are provided via the connectionOverrides block as detailed below. These overrides correspond to the connections defined here in defaultConnections. Each environment expects a separate data warehouse connection. If the same data warehouse connection is used across multiple environments, adding or modifying details in one environment will affect the others.
connectionOverrides: Allows you to provide details for the data warehouse connection.
Within the connectionProperties, the passphrase is only required if the password itself is encrypted. For more information, see Storing the private key.

Example request

Base URL: POST /v1/projects/{projectId}/environments Ensure that the {projectId} variable is replaced with the target project ID from the initial request to create the project.

Snowflake

Example request body:
{
    "name": "development",
    "displayName": "Development Only",
    "description": "An optional description",
    "defaultAgentId": "28d7eae0-1ed5-42d1-b2d9-67decbdef2c3",
    "defaultUserAccessLevel": "admin",
    "defaultConnections": {
        "DWH": {
            "snowflake": "my-warehouse-connection"
        },
	    "CLOUD_PLATFORM": {
		    "aws": "aws-connection"
        }
    },
    "connectionOverrides": [
        {
            "connectionName": "my-warehouse-connection",
            "connectionProperties": {
                "account": {
                    "value": "snowflake.account-name"
                },
                "username": {
                    "value": "SNOWFLAKE_USERNAME"
                },
                "defaultRole": {
                    "value": "SNOWFLAKE_ROLE"
                },
                "defaultWarehouse": {
                    "value": "SNOWFLAKE_WAREHOUSE_NAME"
                },
                "defaultDatabase": {
                    "value": "SNOWFLAKE_DATABASE_NAME"
                },
                "defaultSchema": {
                    "value": "SNOWFLAKE_SCHEMA"
                },
                "privateKey": {
                    "secretName": "aws-secret-name-for-snowflake-private-key"
                },
                "passphrase": {
                    "secretName": "password-encryption-key-secret-name",
                    "secretKey": "snowflake-private-key-password"
                }
            }
        }
    ]
}
Example success response:
HTTP 201 Created

{}

Redshift

Example request body:
{
    "name": "development",
    "displayName": "Development Only",
    "description": "An optional description",
    "defaultAgentId": "28d7eae0-1ed5-42d1-b2d9-67decbdef2c3",
    "defaultUserAccessLevel": "admin",
    "defaultConnections": {
        "DWH": {
            "redshift": "my-redshift-connection"
        }
    },
    "connectionOverrides": [
        {
            "connectionName": "my-redshift-connection",
            "connectionProperties": {
                "url": {
                    "value": "cluster.name.eu-west-1.redshift.amazonaws.com"
                },
                "username": {
                    "value": "redshift-username"
                },
                "port": {
                    "value": "5439"
                },
                "defaultDatabase": {
                    "value": "devDatabase"
                },
                "useSsl": {
                    "value": "true"
                },
                "defaultSchema": {
                    "value": "public"
                },
                "defaultStorageLocation": {
                    "value": "optional-default-storage-location"
                },
                "password": {
                    "secretName": "my-redshift-credentials",
                    "secretKey": "my-redshift-key"
                }
            }
        }
    ]
}
Example success response:
HTTP 201 Created

{}

Snowflake with AWS cloud credentials

To attach a cloud platform connection to the environment, add a CLOUD_PLATFORM entry to defaultConnections alongside the DWH entry. The value must match the name of the cloud credential connection created in Create cloud credential connection. Example request body:
{
    "name": "development",
    "displayName": "Development Only",
    "description": "An optional description",
    "defaultAgentId": "28d7eae0-1ed5-42d1-b2d9-67decbdef2c3",
    "defaultUserAccessLevel": "admin",
    "defaultConnections": {
        "DWH": {
            "snowflake": "my-warehouse-connection"
        },
        "CLOUD_PLATFORM": {
            "aws": "aws-connection"
        }
    },
    "connectionOverrides": [
        {
            "connectionName": "my-warehouse-connection",
            "connectionProperties": {
                "account": {
                    "value": "snowflake.account-name"
                },
                "username": {
                    "value": "SNOWFLAKE_USERNAME"
                },
                "defaultRole": {
                    "value": "SNOWFLAKE_ROLE"
                },
                "defaultWarehouse": {
                    "value": "SNOWFLAKE_WAREHOUSE_NAME"
                },
                "defaultDatabase": {
                    "value": "SNOWFLAKE_DATABASE_NAME"
                },
                "defaultSchema": {
                    "value": "SNOWFLAKE_SCHEMA"
                },
                "privateKey": {
                    "secretName": "aws-secret-name-for-snowflake-private-key",
                    "secretKey": "password"
                },
                "passphrase": {
                    "secretName": "password-encryption-key-secret-name",
                    "secretKey": "snowflake-private-key-password"
                }
            }
        }
    ]
}
Example success response:
HTTP 201 Created

{}

Initialize Repository

After creating the project, this endpoint allows a Git repository to be associated with the project. The Project Provisioning API supports three Git providers: GitHub, Azure DevOps and GitLab. Full SaaS repositories are not supported.

Authentication

To associate a GitHub or Azure DevOps repository with the project, uses a -managed identity to connect to your repository. When calling these endpoints, authentication is handled automatically by . To associate a GitLab repository with the project, you need the personal access token for a GitLab service account. For more information on how to acquire the personal access token, see Acquire a service account personal access token. Base URL: POST /v1/projects/{projectId}/repositories Ensure that the {projectId} variable is replaced with the target project ID from the initial request to create the project.

GitHub

uses GitHub App authentication. No additional setup is required in your GitHub organization beyond installing the GitHub App once per organization.

Example request

Request Headers
{
  "Authorization": "Bearer ey.abc.jwt"
}

Request Body
{
  "provider": "github",
  "providerParameters": {
    "ownerName": "github-organization-name"
  },
  "repositoryName": "my-github-repository"
}
Example success response:
HTTP 201 Created

{}

Azure DevOps

uses a -owned Microsoft Entra service principal to connect to your Azure DevOps repository. Before calling this endpoint with "provider": "azure-devops", you must:
  1. Install the service principal in your Azure tenant.
  2. Grant the service principal access to your Azure DevOps organization and the target repository.
If either prerequisite is missing, subsequent Git operations performed by —such as committing or pushing pipeline changes—will fail with an authentication error.

Install the Maia service principal

If you (or another user in your Azure tenant) have previously connected an Azure DevOps repository to through the UI, the service principal is already installed in your tenant and you can skip this step. Otherwise, follow Installing the Maia app in Azure to install the service principal in your Azure tenant. To verify, visit the Enterprise Applications blade in the Azure portal and confirm that the service principal is listed.

Grant the Maia service principal access

This is a one-time setup per Azure DevOps organization. Once the service principal has been granted access, it can be reused for any project and repository in that organization that has been granted the same permissions.
  1. In your Azure DevOps organization, go to Organization settings → Users → Add user.
  2. In the Users field, search for and select the service principal as it appears in your tenant.
  3. Set Access level to Basic.
  4. Add the service principal to the project that contains your target repository.
  5. Set the Azure DevOps group membership to Project Contributors, or a custom group with at least Read and Contribute permissions on the target repository.
  6. Click Add.
If successful, the service principal will appear in the Users list of your Azure DevOps organization with the Basic access level. For details on Azure DevOps access controls, refer to the Microsoft documentation on permissions and access.

Example request

Request Headers
{
  "Authorization": "Bearer ey.abc.jwt"
}

Request Body
{
  "provider": "azure-devops",
  "providerParameters": {
    "organization": "{azure-devops-organization-name}",
    "repositoryId": "{azure-devops-repository-id}",
    "tenantId": "{your-azure-entra-tenant-id}"
  },
  "repositoryName": "my-azure-devops-repository"
}
Replace the variables as follows:
  • {azure-devops-organization-name}: The name of your Azure DevOps organization (the segment immediately after dev.azure.com/ in the URL).
  • {azure-devops-repository-id}: The UUID of the target Azure DevOps repository. Find this via the Repositories - List API.
  • {your-azure-entra-tenant-id}: The UUID of the Microsoft Entra tenant backing your Azure DevOps organization. Find this in the Azure portal under Microsoft Entra ID → Overview.
Example success response:
HTTP 201 Created

{}

GitLab

When you associate a GitLab repository with a project, receives the service account personal access token you provide via the API and immediately rotates it for security. This means that never stores the personal access token you supply—a new personal access token is generated and held securely in the vault. When rotates the personal access token, the original lifetime is honored. For example, if you create a personal access token with a one-week lifetime and rotation occurs two days later, the newly rotated personal access token will also have a one-week lifetime from the point of rotation. In the GitLab UI, you can see each previous personal access token revoked and each new personal access token created in the service account’s personal access token list, but you can’t see the value of any personal access tokens. If necessary, you can manually rotate an expired personal access token. For more information on personal access token rotation, read the GitLab Self-rotate documentation.
Because immediately rotates the personal access token when you provide it, you can’t use the same personal access token across multiple projects. Each project must be associated with its own dedicated service account token, ensuring separation of concerns and keeping projects isolated from one another.

Acquire a service account personal access token

You can set up an account at project or group level. The steps to acquire a service account token are the same, but you must add the service account to your group or project with the Developer role or higher.
  1. If you do not already have a service account, follow the steps in the GitLab Create a service account guide to create a new service account.
  2. If you do already have a service account, or after creating a new service account, follow the steps in the GitLab Create a personal access token for a service account guide to create a personal access token for the account with the self_rotate scope.
    • The self_rotate scope allows to automatically rotate the token so it stays secure. will rotate the token three days before it expires, so that the connection to GitLab remains uninterrupted.
    • We recommend setting a personal access token lifetime of at least one week to avoid the token expiring too soon. When rotates the token, the original lifetime is honored.
  3. Copy the service account personal access token.
  4. If you created a new service account, follow the steps in the GitLab Add users to a group or Add users to a project guide to add the service account to your group or project with the Developer role or higher.

Example request

Request Headers
{
  "Authorization": "Bearer ey.abc.jwt",
  "Git-Provider-Access-Token": "<service-account-personal-access-token>"
}

Request Body
{
  "provider": "gitlab",
  "providerParameters": {
    "repositoryId": "<gitlab-repository-id>"
  },
  "repositoryName": "<gitlab-repository-name>"
}
Replace the variables as follows:
  • <service-account-personal-access-token>: The service account personal access token
  • <gitlab-repository-id>: The ID of your GitLab repository
  • <gitlab-repository-id>: The name of your GitLab repository
Example success response:
HTTP 201 Created

{}

Manually rotate an expired personal access token

If your personal access token has expired and was unable to rotate it automatically, you can manually provide a new token using the endpoint below
  1. Follow the steps in the GitLab Rotate a personal access token guide to rotate the expired personal access token or create a new personal access token.
  2. Copy the new personal access token, and use it as the value of the Git-Provider-Access-Token header in the following request:
Base URL: POST /v1/projects/{projectId}/repositories/token
Request Headers
{
  "Authorization": "Bearer ey.abc.jwt",
  "Git-Provider-Access-Token": "<new-service-account-personal-access-token>"
}
Example success response:
HTTP 201 Created

{}