Creating Service Providers
Codesphere allows you to publish existing Codesphere landscapes as Managed Service Providers. This enables other developers to discover and deploy your custom solutions.
Landscape-based Service Providers
A landscape-based service provider enables others to instantiate your Codesphere landscape as a pre-configured managed service that they can deploy and manage through the service catalog.
info
Publishing providers requires cluster admin permissions. Team admins can request providers to be scoped to specific teams.
Prerequisites
Before creating a landscape-based service provider, you need:
- A Git repository containing a valid Codesphere landscape with a
ci.ymlfile. - A provider definition, either as a
provider.ymlfile at the repository root or provided directly in the API request. - Git access to the landscape repository. Codesphere pulls the repository through your Git connection, so the account you use to create the provider must have permission to access it. You can manage your Git connections in your user settings.
Git access is tied to a user
The Git connection of the user who created (or last updated) a provider is used for pulling the landscape repository. If that user loses access to the repository, deployments of the provider will fail. To transfer the provider to another user's Git connection, that user sends a PUT or PATCH request for the provider — their connection is then used for pulling. For long-lived providers, consider publishing with a technical user.
Provider Definition
The provider.yml file defines all metadata and configuration schemas for your service provider.
name: mattermost
schemaVersion: v1
author: Your Team
displayName: Mattermost
iconUrl: https://example.com/mattermost-icon.png
category: collaboration
description: |
Open-source team messaging and collaboration platform.
Supports channels, direct messaging, and file sharing.
backend:
landscape:
gitUrl: https://github.com/your-org/mattermost-landscape
configSchema:
type: object
properties:
SITE_NAME:
type: string
description: Display name for your Mattermost instance
default: mattermost
readOnly: false
MAX_USERS:
type: integer
description: Maximum number of users allowed
x-update-constraint: increase-only
required: ['MAX_USERS']
secretsSchema:
type: object
properties:
ADMIN_PASSWORD:
type: string
format: password
detailsSchema:
type: object
properties:
hostname:
type: string
port:
type: integer
plans:
# The plan has no influence on the resource usage, so you should only define one.
# You can also set plans to an empty array to disable the plan selection UI.
- id: 0
name: Default Plan
description: Resource usage depends on the ci-profile of the landscape.
parameters: {}
versions:
0.0.1:
ciProfile: debug
# gitRef can be a commit-hash, branch or tag
gitRef: 1a410efbd13591db07496601ebc7a059dd55cfe9
description: Initial release
1.0.0-rc:
appVersion: Nextcloud v33
ciProfile: prod
gitRef: release-branches/1-0-0-rc
description: |
Release Candidate.
Changelog:
- Feature X
- Feature Y
- Fix Z
1.0.0:
appVersion: Nextcloud v33
ciProfile: prod
gitRef: release-tags/1-0-0
description: Long Term Support Release
scope:
type: team
teamIds: [4008]
Provider Fields
| Field | Description |
|---|---|
name | Unique identifier for the provider. Must match ^[-a-z0-9_]+$. |
version | Version string in the format v[0-9]+ (e.g., v1, v2). |
displayName | Human-readable name shown in the Marketplace UI. |
iconUrl | URL to the provider icon (absolute or relative path). |
category | Grouping category (e.g., databases, messaging, monitoring). |
author | Organization or individual responsible for the provider. |
description | Markdown-formatted description of the service. |
backend.landscape.gitUrl | Git repository URL containing the landscape configuration. |
configSchema | JSON Schema defining user-configurable options. These values are passed to the landscape as environment variables. |
secretsSchema | JSON Schema defining secret values (e.g., passwords). These values are set in the landscape's secrets vault. |
detailsSchema | JSON Schema defining runtime details exposed after provisioning. |
versions | Versions of the service that users can deploy. At least one version is required. See Provider Versions. |
scope | Visibility of the provider: global makes it available to everyone, team restricts it to the listed teamIds. See Provider Scopes. |
The configSchema, secretsSchema, and detailsSchema serve different purposes but share the same format: each must be a valid OpenAPI schema object, which is how Codesphere parses them. As in OpenAPI, properties can be marked as required or given sensible default values.
Below you can see where each schema type appears in the Codesphere UI:
- ConfigSchema
- SecretsSchema
- DetailsSchema
The configSchema defines the configuration properties the user sets when creating a service — for example, the PostgreSQL version to deploy. Once the service is created, the configuration can be inspected in the service settings. Properties that are not marked as readOnly can be updated later (see Update Constraints).

caution
Updating configuration parameters may cause a short downtime of the service.
Secrets defined in the secretsSchema appear as form inputs in the create service dialog and must be filled in by the user — for example, the PostgreSQL superuser password. The values are injected into the service during creation.

Properties defined in the detailsSchema are provided by the service at runtime — for example, the PostgreSQL hostname. They are read-only and can be inspected in the details section of the service settings.

Provider Versions
Every provider must define at least one entry in versions. Each version pins the exact state of the landscape that gets deployed:
gitRef: A commit hash, branch, or tag of the landscape repository.ciProfile: The CI profile from the landscape'sci.ymlto use for deployment.appVersion(optional): A human-readable label for the deployed application version.description(optional): Markdown-formatted release notes shown to the user.
When creating a service, users choose which version to deploy.
Deprecated fields
backend.landscape.ciProfile and backend.landscape.gitRef used to define these values once for the whole provider. They are deprecated — ciProfile and gitRef are now defined per version — but remain available for backward compatibility.
Publishing and Updating a Landscape-based Provider
The recommended way to publish and update a provider is the idempotent upsert endpoint of the Codesphere Public API. Send a PUT request to /managed-services/providers:
- If no provider with the same
nameandschemaVersionexists yet, it is created. - If one already exists, all mutable fields are updated in place.
This means you can use the same request to create a provider and to roll out later changes — you don't need to track whether the provider already exists. This is useful in CI/CD pipelines, for example.
You can either provide a Git URL that includes the provider.yml file or the full provider specification in the payload.
tip
Dedicated create (POST) and update (PATCH) endpoints still exist for partial updates and more explicit workflows, but for most cases the upsert endpoint is the simplest choice.
Versions are append-only
You can add new entries to versions, but existing version records cannot be modified or removed through an upsert. All other provider fields are updated in place.
- Fetch provider.yml from Git
- Provide full specification
The simplest approach is to provide the Git repository URL. Codesphere will fetch and validate the provider.yml file from your repository automatically.
note
If you omit gitRef, the default branch of the repository is used to fetch the provider.yml file.
curl -X PUT "https://<your-codesphere-url>/api/managed-services/providers" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"gitUrl": "https://github.com/your-org/mattermost-landscape",
"gitRef": "my-branch",
"scope": {
"type": "global"
}
}'
For more control, or if you don't want to include a provider.yml in your repository, you can provide the complete provider specification directly in the API request:
curl -X PUT "https://<your-codesphere-instance-url>/api/managed-services/providers" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "mattermost",
"schemaVersion": "v1",
"author": "Your Team",
"displayName": "Mattermost",
"iconUrl": "https://example.com/mattermost-icon.png",
"category": "collaboration",
"description": "Open-source team messaging platform.",
"backend": {
"landscape": {
"gitUrl": "https://github.com/your-org/mattermost-landscape",
"ciProfile": "production"
}
},
"configSchema": {
"type": "object",
"properties": {
"SITE_NAME": {
"type": "string",
"description": "Display name for your Mattermost instance"
},
"MAX_USERS": {
"type": "integer",
"description": "Maximum number of users allowed"
}
}
},
"secretsSchema": {
"type": "object",
"properties": {
"ADMIN_PASSWORD": {
"type": "string",
"format": "password"
}
}
},
"detailsSchema": {
"type": "object",
"properties": {
"hostname": { "type": "string" },
"port": { "type": "integer" }
}
},
"plans": [],
"scope": {
"type": "team",
"teamIds": [42, 43]
},
"versions": {
"0.0.1": {
"ciProfile": "debug",
"gitRef": "1a410efbd13591db07496601ebc7a059dd55cfe9",
"description": "Initial release"
},
"1.0.0-rc": {
"appVersion": "Nextcloud v33",
"ciProfile": "prod",
"gitRef": "release-branches/1-0-0-rc",
"description": "Release Candidate.\nChangelog:\n - Feature X\n - Feature Y\n - Fix Z\n"
},
"1.0.0": {
"appVersion": "Nextcloud v33",
"ciProfile": "prod",
"gitRef": "release-tags/1-0-0",
"description": "Long Term Support Release"
}
}
}'
Provider Scopes
When creating a provider, you can define its visibility scope:
| Scope Type | Description |
|---|---|
global | Available to all teams in the Codesphere instance. Requires cluster admin permissions. |
team | Available only to specified teams. Provide an array of teamIds. |
Passing Configuration to Landscapes
When a service is created from a landscape-based provider, the user's input is passed down to the landscape: properties from the configSchema are set as environment variables, and secrets from the secretsSchema are injected into the landscape's vault. Both can be referenced in the landscape's ci.yml:
schemaVersion: v0.2
run:
my-service:
steps:
- command: ./start.sh
env:
APP_VERSION: ${{ workspace.env['APP_VERSION'] }}
ADMIN_PASSWORD: ${{ vault.ADMIN_PASSWORD }}
In this example, APP_VERSION is a property of the provider's configSchema and ADMIN_PASSWORD is a property of the provider's secretsSchema.
Update Constraints with x-update-constraint
The configSchema supports a custom extension x-update-constraint that lets you restrict how individual properties can be changed
after a service has been created. This is useful for enforcing operational rules — for example, preventing storage from being
decreased or locking down a database engine version after initial setup.
Add the x-update-constraint keyword to any property in your configSchema:
configSchema:
type: object
properties:
storage:
type: integer
description: Storage allocation in GB
x-update-constraint: increase-only
version:
type: string,
description: Version of the Postgres DB.
enum: ['17.6', '16.10', '15.14', '14.19', '13.22']
x-update-constraint: immutable,
Available Constraints
| Constraint | Behavior |
|---|---|
increase-only | The new value must be greater than or equal to the current value. Only applies to numeric fields. |
immutable | The property cannot be changed once it has been set. |
info
Update constraints are only enforced when updating an existing service. During initial creation, all values are accepted as long as they pass the standard schema validation.
Supported Formats
Provider schemas use JSON Schema validation. The following format values are supported in schema properties:
int32, int64, float, double, byte, binary, date, date-time, password, uri, hostname
Dynamic Details with x-endpoint
The detailsSchema supports a custom OpenAPI extension x-endpoint that allows you to fetch runtime details dynamically from your service. This is useful for retrieving live status information, metrics, or other data that changes after provisioning.
When x-endpoint is set on a property, Codesphere will fetch the value from the specified endpoint. The endpoint URL supports interpolation using other details fields.
detailsSchema:
type: object
properties:
hostname:
type: string
port:
type: integer
status:
type: object
properties:
state:
type: string
uptime:
type: number
x-endpoint: "https://{{hostname}}:{{port}}/status"
In this example, the status property is fetched dynamically from the service's /status endpoint using the hostname and port values.
info
Only GET requests are supported for x-endpoint. The endpoint must return JSON matching the property's schema definition.
Custom REST Backends
Codesphere's Managed Services architecture is designed to be extensible. If landscape-based providers don't meet your specific requirements you can implement your own custom REST backend.
tip
For a complete guide on implementing the Managed Service Adapter API specification, see Create a Custom REST Backend.