Additionally, there are some conventions that are specific to the ZITADEL API.
These conventions are described in the following sections.
### Versioning
The services and messages are versioned using major version numbers. This means that any change within a major version number is backward compatible.
Any breaking change requires a new major version number.
Each service is versioned independently. This means that a service can have a different version number than another service.
When creating a new service, start with version `2`, as version `1` is reserved for the old context based API and services.
Please check out the structure Buf style guide for more information about the folder and package structure: https://buf.build/docs/best-practices/style-guide/
### Explicitness
Make the handling of the API as explicit as possible. Do not make assumptions about the client's knowledge of the system or the API.
Provide clear and concise documentation for the API.
Do not rely on implicit fallbacks or defaults if the client does not provide certain parameters.
Only use defaults if they are explicitly documented, such as returning a result set for the whole instance if no filter is provided.
### Naming Conventions
Names of resources, fields and methods MUST be descriptive and consistent.
Use domain-specific terminology and avoid abbreviations.
For example, use `organization_id` instead of **org_id** or **resource_owner** for the creation of a new user or when returning one.
> [!NOTE]
> We'll update the resources in the [concepts section](https://zitadel.com/docs/concepts/structure/instance) to describe
> common resources and their meaning.
> Until then, please refer to the following issue: https://github.com/zitadel/zitadel/issues/5888
#### Resources and Fields
When a context is required for creating a resource, the context is added as a field to the resource.
For example, when creating a new user, the organization's id is required. The `organization_id` is added as a field to the `CreateUserRequest`.
Only allow providing a context where it is required. The context MUST not be provided if not required.
For example, when retrieving or updating a user, the `organization_id` is not required, since the user can be determined by the user's id.
However, it is possible to provide the `organization_id` as a filter to retrieve a list of users of a specific organization.
Prevent the creation of global messages that are used in multiple resources unless they always follow the same pattern.
Use dedicated fields as described above or create a separate message for the specific context, that is only used in the boundary of the same resource.
For example, settings might be set as a default on the instance level, but might be overridden on the organization level.
In this case, the settings could share the same `SettingsContext` message to determine the context of the settings.
But do not create a global `Context` message that is used across the whole API if there are different scenarios and different fields required for the context.
The same applies to messages that are returned by multiple resources.
For example, information about the `User` might be different when managing the user resource itself than when it's returned
as part of an authorization or a manager role, where only limited information is needed.
Prevent reusing messages for the creation and the retrieval of a resource.
Returning messages might contain additional information that is not required or even not available for the creation of the resource.
What might sound obvious when designing the CreateUserRequest for example, where only an `organization_id` but not the
`organization_name` is available, might not be so obvious when designing some sub-resource like a user's `IdentityProviderLink`,
which might contain an `identity_provider_name` when returned but not when created.
| Create | Create\<resource\> | Create a new resource. If the new resource conflicts with an existing resources uniqueness (id, loginname, ...) the creation MUST be prevented and an error returned. |
| Update | Update\<resource\> | Update an existing resource. In most cases this SHOULD allow partial updates. If there are exception, they MUST be explicitly documented on the endpoint. The resource MUST already exists. An error is returned otherwise. |
| Delete | Delete\<resource\> | Delete an existing resource. If the resource does not exist, no error SHOULD be returned. In case of an exception to this rule, the behavior MUST clearly be documented. |
| Set | Set\<resource\> | Set a resource. This will replace the existing resource with the new resource. In case where the creation and update of a resource do not need to be differentiated, a single `Set` method SHOULD be used. It SHOULD allow partial changes. |
| Get | Get\<resource\> | Retrieve a single resource by its unique identifier. If the resource does not exist, an error MUST be returned. |
| List | List\<resource\> | Retrieve a list of resources. The endpoint SHOULD provide options to filter, sort and paginate. |
Methods on a list of resources MUST be named using the following convention:
| Add | Add\<resource\> | Add a new resource to a list. Any existing unique constraint (id, loginname, ...) will prevent the addition and return an error. |
| Remove | Remove\<resource\> | Remove an existing resource from a list. If the resource does not exist in the list, no error SHOULD be returned. In case of an exception to this rule, the behavior MUST clearly be documented. |
| Set | Set\<resource\> | Set a list of resources. This will replace the existing list with the new list. |
Additionally, state changes, specific actions or operations that do not fit into the CRUD operations SHOULD be named according to the action that is performed:
-`Activate` or `Deactivate` for enabling or disabling a resource.
-`Verify` for verifying a resource.
-`Send` for sending a resource.
- etc.
## Authentication and Authorization
The API uses OAuth 2 for authorization. There are corresponding middlewares that check the access token for validity and
automatically return an error if the token is invalid.
Permissions grated to the user might be organization specific and can therefore only be checked based on the queried resource.
In such case, the API does not check the permissions itself but relies on the checks of the functions that are called by the API.
If the permission can be checked by the API itself, e.g. if the permission is instance wide, it can be annotated on the endpoint in the proto file (see below).
In any case, the required permissions need to be documented in the [API documentation](#documentation).
### Permission annotations
Permissions can be annotated on the endpoint in the proto file. This allows the API to automatically check the permissions for the user.
The permissions are checked by the middleware and an error is returned if the user does not have the required permissions.
The following example requires the user to have the `iam.web_key.write` permission to call the `CreateWebKey` method.
In case the permission cannot be checked by the API itself, but all requests need to be from an authenticated user, the `auth_option` can be set to `authenticated`.
The API MUST enforce a reasonable maximum limit for the number of resources that can be retrieved and returned in a single request.
The default limit is set to 100 and the maximum limit is set to 1000. If the client requests a limit that exceeds the maximum limit, an error is returned.
// - user_missing_information: The request is missing required information (either given_name, family_name and/or email) or contains invalid data for the creation of the user. Check error details for the missing or invalid fields.
// ListUsers will return all matching users. By default, we will return all users of your instance that you have permission to read. Make sure to include a limit and sorting for pagination.
//
// Required permission:
// - user.read
// - no permission required to own user
//
// Error Codes:
// - invalid_request: Your request does not have a valid format. Check error details for the reason.
// - permission_denied: You do not have the required permissions to access the requested resource.
// - unauthenticated: You are not authenticated. Please provide a valid access token.