Back to Gitlabhq

Service accounts API

doc/api/service_accounts.md

18.11.234.3 KB
Original Source

{{< details >}}

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

{{< /details >}}

{{< history >}}

  • Introduced on Free tier in GitLab 18.10 with a flag named service_accounts_available_on_free_or_unlicensed. Disabled by default.
  • Generally available on Free tier in GitLab 18.11. Feature flag service_accounts_available_on_free_or_unlicensed removed.

{{< /history >}}

Use this API to interact with service accounts.

The number of service accounts you can create depends on your subscription and offering:

  • On GitLab Premium and Ultimate, you can create an unlimited number of service accounts for all offerings.
  • On GitLab Free, limits vary by offering:
    • For GitLab.com, you can create up to 100 service accounts for each top-level group. This includes service accounts created in subgroups or projects.
    • For GitLab Self-Managed, you can create up to 100 service accounts per instance. This includes all service accounts regardless of how they are provisioned (instance, group, or project level).

You can also interact with service accounts through the users API.

Instance service accounts

{{< details >}}

  • Offering: GitLab Self-Managed, GitLab Dedicated

{{< /details >}}

Instance service accounts are available to an entire GitLab instance, but must still be added to groups and projects like a human user.

To manage personal access tokens for instance service accounts, use the personal access tokens API.

Prerequisites:

  • You must have administrator access to the instance.

List all instance service accounts

{{< history >}}

  • List all service accounts introduced in GitLab 17.1.

{{< /history >}}

Lists all instance service accounts.

Use the page and per_page pagination parameters to filter the results.

plaintext
GET /service_accounts

Supported attributes:

AttributeTypeRequiredDescription
order_bystringnoAttribute to order results by. Possible values: id or username. Default value: id.
sortstringnoDirection to sort results by. Possible values: desc or asc. Default value: desc.

Example request:

shell
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/service_accounts"

Example response:

json
[
  {
    "id": 114,
    "username": "service_account_33",
    "name": "Service account user"
  },
  {
    "id": 137,
    "username": "service_account_34",
    "name": "john doe"
  }
]

Create an instance service account

{{< history >}}

  • Introduced in GitLab 16.1
  • username and name attributes added in GitLab 16.10.
  • email attribute added in GitLab 17.9.

{{< /history >}}

Creates an instance service account.

plaintext
POST /service_accounts
POST /[email protected]

Supported attributes:

AttributeTypeRequiredDescription
namestringnoName of the user. If not set, uses Service account user.
usernamestringnoUsername of the user account. If undefined, generates a name prepended with service_account_.
emailstringnoEmail of the user account. If undefined, generates a no-reply email address. Custom email addresses require confirmation, unless the email confirmation settings are turned off.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/service_accounts"

Example response:

json
{
  "id": 57,
  "username": "service_account_6018816a18e515214e0c34c2b33523fc",
  "name": "Service account user",
  "email": "service_account_6018816a18e515214e0c34c2b33523fc@noreply.gitlab.example.com"
}

If the email address defined by the email attribute is already in use by another user, returns a 400 Bad request error.

Update an instance service account

{{< history >}}

{{< /history >}}

Updates a specified instance service account.

plaintext
PATCH /service_accounts/:id

Parameters:

AttributeTypeRequiredDescription
idintegeryesID of the service account.
namestringnoName of the user.
usernamestringnoUsername of the user account.
emailstringnoEmail of the user account. Custom email addresses require confirmation, unless the email confirmation settings are turned off.

Example request:

shell
curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/service_accounts/57" --data "name=Updated Service Account&[email protected]"

Example response:

json
{
  "id": 57,
  "username": "service_account_6018816a18e515214e0c34c2b33523fc",
  "name": "Updated Service Account",
  "email": "service_account_<random_hash>@noreply.gitlab.example.com",
  "unconfirmed_email": "[email protected]"
}

Group service accounts

{{< history >}}

  • Subgroup service accounts introduced in GitLab 18.10 with a feature flag named allow_subgroups_to_create_service_accounts. Disabled by default.
  • Subgroup service accounts generally available in GitLab 18.11. Feature flag allow_subgroups_to_create_service_accounts removed.

{{< /history >}}

Group service accounts are owned by a specific group and can be invited to the group where they were created or to any descendant subgroups or projects. They cannot be invited to ancestor groups.

Prerequisites:

  • On GitLab.com, you must have the Owner role for the group.
  • On GitLab Self-Managed or GitLab Dedicated, you must either:

List all group service accounts

{{< history >}}

{{< /history >}}

Lists all service accounts in a specified group.

Use the page and per_page pagination parameters to filter the results.

plaintext
GET /groups/:id/service_accounts

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target group.
order_bystringnoOrders list of users by username or id. Default is id.
sortstringnoSpecifies sorting by asc or desc. Default is desc.

Example request:

shell
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/345/service_accounts"

Example response:

json
[

  {
    "id": 57,
    "username": "service_account_group_345_<random_hash>",
    "name": "Service account user",
    "email": "service_account_group_345_<random_hash>@noreply.gitlab.example.com"
  },
  {
    "id": 58,
    "username": "service_account_group_345_<random_hash>",
    "name": "Service account user",
    "email": "service_account_group_345_<random_hash>@noreply.gitlab.example.com",
    "unconfirmed_email": "[email protected]"
  }
]

Create a group service account

{{< history >}}

  • Introduced in GitLab 16.1.
  • username and name attributes added in GitLab 16.10.
  • email attribute added in GitLab 17.9 with a flag named group_service_account_custom_email.
  • email attribute generally available in GitLab 17.11. Feature flag group_service_account_custom_email removed.

{{< /history >}}

Creates a service account in a specified group.

plaintext
POST /groups/:id/service_accounts

Supported attributes:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a group.
namestringnoUser account name. If not specified, uses Service account user.
usernamestringnoUser account username. If not specified, generates a name prepended with service_account_group_.
emailstringnoEmail of the user account. If not specified, generates an email prepended with service_account_group_. Custom email addresses require confirmation, unless the group has a matching verified domain or email confirmation settings are turned off.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/345/service_accounts" --data "[email protected]"

Example response:

json
{
  "id": 57,
  "username": "service_account_group_345_6018816a18e515214e0c34c2b33523fc",
  "name": "Service account user",
  "email": "[email protected]"
}

Update a group service account

{{< history >}}

  • Introduced in GitLab 17.10.
  • Add custom email address introduced in GitLab 18.2.
  • Added username limits for service accounts with composite identities in GitLab 18.9.

{{< /history >}}

Updates a service account in a specified group.

[!note]

  • You cannot update the username of a service account associated with a composite identity.
plaintext
PATCH /groups/:id/service_accounts/:user_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target group.
user_idintegeryesThe ID of the service account.
namestringnoName of the user.
usernamestringnoUsername of the user.
emailstringnoEmail of the user account. Custom email addresses require confirmation, unless the group has a matching verified domain or email confirmation settings are turned off.

Example request:

shell
curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/345/service_accounts/57" --data "name=Updated Service Account&[email protected]"

Example response:

json
{
  "id": 57,
  "username": "service_account_group_345_6018816a18e515214e0c34c2b33523fc",
  "name": "Updated Service Account",
  "email": "service_account_group_345_<random_hash>@noreply.gitlab.example.com",
  "unconfirmed_email": "[email protected]"
}

Delete a group service account

{{< history >}}

{{< /history >}}

Deletes a service account from a specified group.

plaintext
DELETE /groups/:id/service_accounts/:user_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target group.
user_idintegeryesThe ID of a service account.
hard_deletebooleannoIf true, contributions that would usually be moved to a ghost user are instead deleted, as well as groups owned solely by this service account.

Example request:

shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/345/service_accounts/181"

List all personal access tokens for a group service account

{{< history >}}

{{< /history >}}

Lists all personal access tokens for a service account in a specified group.

plaintext
GET /groups/:id/service_accounts/:user_id/personal_access_tokens

Supported attributes:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a group.
user_idintegeryesID of service account.
created_afterdatetime (ISO 8601)noIf defined, returns tokens created after the specified time.
created_beforedatetime (ISO 8601)noIf defined, returns tokens created before the specified time.
expires_afterdate (ISO 8601)noIf defined, returns tokens that expire after the specified time.
expires_beforedate (ISO 8601)noIf defined, returns tokens that expire before the specified time.
last_used_afterdatetime (ISO 8601)noIf defined, returns tokens last used after the specified time.
last_used_beforedatetime (ISO 8601)noIf defined, returns tokens last used before the specified time.
revokedbooleannoIf true, only returns revoked tokens.
searchstringnoIf defined, returns tokens that include the specified value in the name.
sortstringnoIf defined, sorts the results by the specified value. Possible values: created_asc, created_desc, expires_asc, expires_desc, last_used_asc, last_used_desc, name_asc, name_desc.
statestringnoIf defined, returns tokens with the specified state. Possible values: active and inactive.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/groups/187/service_accounts/195/personal_access_tokens?sort=id_desc&search=token2b&created_before=2025-03-27"

Example response:

json
[
    {
        "id": 187,
        "name": "service_accounts_token2b",
        "revoked": false,
        "created_at": "2025-03-26T14:42:51.084Z",
        "description": null,
        "scopes": [
            "api"
        ],
        "user_id": 195,
        "last_used_at": null,
        "active": true,
        "expires_at": null
    }
]

Example of unsuccessful responses:

  • 401: Unauthorized
  • 404 Group Not Found

Create a personal access token for a group service account

{{< history >}}

{{< /history >}}

Creates a personal access token for an existing service account in a specified group.

plaintext
POST /groups/:id/service_accounts/:user_id/personal_access_tokens

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a group.
user_idintegeryesID of service account.
namestringyesName of personal access token.
descriptionstringnoDescription of personal access token.
scopesarrayyesArray of approved scopes. For a list of possible values, see Personal access token scopes.
expires_atdatenoExpiration date of the access token in ISO format (YYYY-MM-DD). If not specified, the date is set to the maximum allowable lifetime limit.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/35/service_accounts/71/personal_access_tokens" --data "scopes[]=api,read_user,read_repository" --data "name=service_accounts_token"

Example response:

json
{
  "id":6,
  "name":"service_accounts_token",
  "revoked":false,
  "created_at":"2023-06-13T07:47:13.900Z",
  "scopes":["api"],
  "user_id":71,
  "last_used_at":null,
  "active":true,
  "expires_at":"2024-06-12",
  "token":"<token_value>"
}

Revoke a personal access token for a group service account

{{< history >}}

{{< /history >}}

Revokes a specified personal access token for an existing service account in a group.

plaintext
DELETE /groups/:id/service_accounts/:user_id/personal_access_tokens/:token_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target group.
user_idintegeryesThe ID of the service account.
token_idintegeryesThe ID of the token.

Example request:

shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/35/service_accounts/71/personal_access_tokens/6"

If successful, returns 204: No Content.

Other possible responses:

  • 400: Bad Request if not revoked successfully.
  • 401: Unauthorized if the request is not authorized.
  • 403: Forbidden if the request is not allowed.
  • 404: Not Found if the access token does not exist.

Rotate a personal access token for a group service account

{{< history >}}

{{< /history >}}

Rotates a specified personal access token for an existing service account in a specified group. This revokes the existing token and creates a new token with the same name, description, and scopes.

plaintext
POST /groups/:id/service_accounts/:user_id/personal_access_tokens/:token_id/rotate

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target group.
user_idintegeryesThe ID of the service account.
token_idintegeryesThe ID of the token.
expires_atdatenoExpiration date of the access token in ISO format (YYYY-MM-DD). Introduced in GitLab 17.9. If the token requires an expiration date, defaults to one week. If not required, defaults to the maximum allowable lifetime limit.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/35/service_accounts/71/personal_access_tokens/6/rotate"

Example response:

json
{
  "id":7,
  "name":"service_accounts_token",
  "revoked":false,
  "created_at":"2023-06-13T07:54:49.962Z",
  "scopes":["api"],
  "user_id":71,
  "last_used_at":null,
  "active":true,
  "expires_at":"2023-06-20",
  "token":"<token_value>"
}

Project service accounts

{{< history >}}

  • Introduced in GitLab 18.9 with a flag named allow_projects_to_create_service_accounts. Disabled by default.
  • Project service accounts generally available in GitLab 18.11. Feature flag allow_projects_to_create_service_accounts removed.

{{< /history >}}

Project service accounts are owned by a specific project and are available only to their associated project.

Prerequisites:

  • On GitLab.com, you must have the Owner or Maintainer role for the project.
  • On GitLab Self-Managed or GitLab Dedicated, you must either:
    • Be an administrator for the instance.
    • Have the Owner or Maintainer role in a project.

List all project service accounts

Lists all service accounts in a specified project.

Use the page and per_page pagination parameters to filter the results.

plaintext
GET /projects/:id/service_accounts

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target project.
order_bystringnoOrders list of users by username or id. Default is id.
sortstringnoSpecifies sorting by asc or desc. Default is desc.

Example request:

shell
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/345/service_accounts"

Example response:

json
[

  {
    "id": 57,
    "username": "service_account_project_345_<random_hash>",
    "name": "Service account user",
    "email": "service_account_project_345_<random_hash>@noreply.gitlab.example.com"
  },
  {
    "id": 58,
    "username": "service_account_project_345_<random_hash>",
    "name": "Service account user",
    "email": "service_account_project_345_<random_hash>@noreply.gitlab.example.com",
    "unconfirmed_email": "[email protected]"
  }
]

Create a project service account

Creates a service account in a specified project.

plaintext
POST /projects/:id/service_accounts

Supported attributes:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a project
namestringnoUser account name. If not specified, uses Service account user.
usernamestringnoUser account username. If not specified, generates a name prepended with service_account_project_.
emailstringnoEmail of the user account. If not specified, generates an email prepended with service_account_project_. Custom email addresses require confirmation, unless the group has a matching verified domain or email confirmation settings are turned off.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/345/service_accounts" --data "[email protected]"

Example response:

json
{
  "id": 57,
  "username": "service_account_project_345_6018816a18e515214e0c34c2b33523fc",
  "name": "Service account user",
  "email": "[email protected]"
}

Update a project service account

Updates a service account in a specified project.

plaintext
PATCH /projects/:id/service_accounts/:user_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target project.
user_idintegeryesThe ID of the service account.
namestringnoName of the user.
usernamestringnoUsername of the user.
emailstringnoEmail of the user account. Custom email addresses require confirmation, unless the group has a matching verified domain or email confirmation settings are turned off.

Example request:

shell
curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/345/service_accounts/57" --data "name=Updated Service Account&[email protected]"

Example response:

json
{
  "id": 57,
  "username": "service_account_project_345_6018816a18e515214e0c34c2b33523fc",
  "name": "Updated Service Account",
  "email": "service_account_project_345_<random_hash>@noreply.gitlab.example.com",
  "unconfirmed_email": "[email protected]"
}

Delete a project service account

Deletes a service account from a specified project.

plaintext
DELETE /projects/:id/service_accounts/:user_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target project.
user_idintegeryesThe ID of a service account.
hard_deletebooleannoIf true, contributions that would usually be moved to a ghost user are instead deleted, as well as groups owned solely by this service account.

Example request:

shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/345/service_accounts/181"

List all personal access tokens for a project service account

Lists all personal access tokens for a service account in a project.

plaintext
GET /projects/:id/service_accounts/:user_id/personal_access_tokens

Supported attributes:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a project.
user_idintegeryesID of service account.
created_afterdatetime (ISO 8601)noIf defined, returns tokens created after the specified time.
created_beforedatetime (ISO 8601)noIf defined, returns tokens created before the specified time.
expires_afterdate (ISO 8601)noIf defined, returns tokens that expire after the specified time.
expires_beforedate (ISO 8601)noIf defined, returns tokens that expire before the specified time.
last_used_afterdatetime (ISO 8601)noIf defined, returns tokens last used after the specified time.
last_used_beforedatetime (ISO 8601)noIf defined, returns tokens last used before the specified time.
revokedbooleannoIf true, only returns revoked tokens.
searchstringnoIf defined, returns tokens that include the specified value in the name.
sortstringnoIf defined, sorts the results by the specified value. Possible values: created_asc, created_desc, expires_asc, expires_desc, last_used_asc, last_used_desc, name_asc, name_desc.
statestringnoIf defined, returns tokens with the specified state. Possible values: active and inactive.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/projects/187/service_accounts/195/personal_access_tokens?sort=id_desc&search=token2b&created_before=2025-03-27"

Example response:

json
[
    {
        "id": 187,
        "name": "service_accounts_token2b",
        "revoked": false,
        "created_at": "2025-03-26T14:42:51.084Z",
        "description": null,
        "scopes": [
            "api"
        ],
        "user_id": 195,
        "last_used_at": null,
        "active": true,
        "expires_at": null
    }
]

Example of unsuccessful responses:

  • 401: Unauthorized
  • 404 Project Not Found

Create a personal access token for a project service account

Creates a personal access token for an existing service account in a specified project.

plaintext
POST /projects/:id/service_accounts/:user_id/personal_access_tokens

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesID or URL-encoded path of a project.
user_idintegeryesID of service account.
namestringyesName of personal access token.
descriptionstringnoDescription of personal access token.
scopesarrayyesArray of approved scopes. For a list of possible values, see Personal access token scopes.
expires_atdatenoExpiration date of the access token in ISO format (YYYY-MM-DD). If not specified, the date is set to the maximum allowable lifetime limit.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/35/service_accounts/71/personal_access_tokens" --data "scopes[]=api,read_user,read_repository" --data "name=service_accounts_token"

Example response:

json
{
  "id":6,
  "name":"service_accounts_token",
  "revoked":false,
  "created_at":"2023-06-13T07:47:13.900Z",
  "scopes":["api"],
  "user_id":71,
  "last_used_at":null,
  "active":true,
  "expires_at":"2024-06-12",
  "token":"<token_value>"
}

Revoke a personal access token for a project service account

Revokes a personal access token for an existing service account in a specified project.

plaintext
DELETE /projects/:id/service_accounts/:user_id/personal_access_tokens/:token_id

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target project.
user_idintegeryesThe ID of the service account.
token_idintegeryesThe ID of the token.

Example request:

shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/35/service_accounts/71/personal_access_tokens/6"

If successful, returns 204: No Content.

Other possible responses:

  • 400: Bad Request if not revoked successfully.
  • 401: Unauthorized if the request is not authorized.
  • 403: Forbidden if the request is not allowed.
  • 404: Not Found if the access token does not exist.

Rotate a personal access token for a project service account

Rotates a personal access token for an existing service account in a specified project. This creates a new token valid for one week and revokes any existing tokens.

plaintext
POST /projects/:id/service_accounts/:user_id/personal_access_tokens/:token_id/rotate

Parameters:

AttributeTypeRequiredDescription
idinteger or stringyesThe ID or URL-encoded path of the target project.
user_idintegeryesThe ID of the service account.
token_idintegeryesThe ID of the token.
expires_atdatenoExpiration date of the access token in ISO format (YYYY-MM-DD). Introduced in GitLab 17.9. If the token requires an expiration date, defaults to one week. If not required, defaults to the maximum allowable lifetime limit.

Example request:

shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/35/service_accounts/71/personal_access_tokens/6/rotate"

Example response:

json
{
  "id":7,
  "name":"service_accounts_token",
  "revoked":false,
  "created_at":"2023-06-13T07:54:49.962Z",
  "scopes":["api"],
  "user_id":71,
  "last_used_at":null,
  "active":true,
  "expires_at":"2023-06-20",
  "token":"<token_value>"
}