Skip to main content
A service account is a member of your Gecko team that has no login and owns exactly one API token. Use one for anything that must keep working when people change roles or leave: CI pipelines, internal developer platforms, scheduled exports, and secret-rotation jobs.
Service accounts are available on Pro and Enterprise plans, and only team Admins can create them.
This page covers Gecko API tokens. The GitLab service account is a different thing: a user on your GitLab instance whose personal access token Gecko uses to read code. See Connect self-managed GitLab.

Personal keys and service account tokens

Both authenticate the v1 API and MCP the same way. They differ in who they act as. Gecko resolves the role on every request. Change a service account’s role in Settings > Members and the token’s access changes on its next call.

Create a service account

1

Open the create dialog

Go to Settings > API Keys, click Create API Key, and select Service account token.
2

Name it after the workload

Use a name that identifies the system that holds the token, such as gitlab-ci-prod or secops-export. The name appears in the API Keys table and on the Members page.
3

Pick the narrowest role

Read Only is the default. See Choose a role.
4

Set an expiration

Choose 7, 30, 90, or 365 days. Every token expires.
5

Store the token

Gecko shows the token once. Put it straight into your secrets manager; afterward only a masked preview is shown.
The service account then appears in Settings > Members with a Service tag, and its token appears in Settings > API Keys with a Service account tag.

Choose a role

Pick the lowest role that covers every endpoint the workload calls. The full matrix is in Teams & permissions.

Architecture considerations

Give each workload its own service account

Create one service account per system and environment, such as CI, your developer platform, and your SIEM export, rather than one shared token. Separate accounts give you:
  • A clear record. Everything a token does is recorded against its service account, so the scans list and finding history show which system acted.
  • A separate rate-limit budget. Rate limits apply per key, and a service account has one key, so a noisy export can’t throttle your CI.
  • Smaller blast radius. You can revoke one system’s access without touching the others.
  • Least privilege. A read-only export never needs the Member role your CI needs to start scans.
Each service account uses a member seat, so plan seats for them.

The token reads every repository in the team

A service account isn’t filtered by Git host permissions. A token can read findings for every repository connected to the team, whatever its role. That’s what a central pipeline or export needs. It also means the token must never reach individual developers or their tools. Don’t bake it into a developer machine image or a global environment variable, a shared CLI config, an AI coding agent’s skill or plugin, or repository CI variables that every project maintainer can read. Anyone who can read it can list every finding in the team.

Let developers and agents scan through your own service

To let developers, or the coding agents they run, scan their own work without Gecko seats or credentials, put a service you own between them and Gecko. Only that service holds the token. Gecko scans code on your Git host, not on the developer’s machine, so work in progress has to be pushed first. A typical flow:
1

Push the work

The developer or agent pushes to a branch, such as a short-lived scan branch, and calls your service with the repository and commit SHA.
2

Authorize the request

Your service authenticates the caller with your existing identity, such as SSO or their Git host token, and checks on your Git host that they have the access you require to scan that repository. Reading a repository isn’t enough on its own: every scan uses your team’s quota, so require write access, such as having pushed the commit.
3

Reuse or start a scan

To skip a duplicate, look in your own records for a scan your service already started for the same Git host, repository, and commit whose status is completed or still running. Don’t search GET /scans for one: its repository filter matches the path on every connected Git host, and a scan doesn’t say which host it came from, so a match could belong to a same-named repository the caller can’t access. Otherwise, including when your recorded scan failed, was cancelled, or was skipped, call POST /scans with name, repository, and commit; commit pins the scan to that exact commit. For GitLab, also send provider: "gitlab" or pass the full project URL as repository: a bare group/project path is treated as GitHub.Make the create idempotent, so a lost response doesn’t cost a second scan. Record a new Idempotency-Key before you call POST /scans, and resend the same key and the same body on network retries. Once the first request has finished, Gecko replays its response for 24 hours from the first attempt. While it’s still running, a retry gets 409 with idempotency_in_flight: back off and retry with the same key, rather than giving up on a scan that’s still starting. Use a new key only when you deliberately start a fresh scan, such as after a failed, cancelled, or skipped one.
4

Wait for it

Poll GET /scans/{id} until is_done is true. If you subscribe to webhooks, use them to check sooner, but keep a slower poll running: an event that fails every delivery attempt is never resent. Failed and cancelled scans are done too, so check that status is completed before you read findings, and treat any other status as a failure rather than a clean result.
5

Return only that scan's findings

Read GET /scans/{id}/vulnerabilities, following next_cursor until has_more is false, and return those findings to the caller. Record the scan ID with its Git host, repository, and commit, and against each caller you served it to, and serve later reads only for scans recorded against them.
Keep the branch until the scan finishes. The scanner fetches the commit from your Git host while it runs, and a commit that’s no longer on any branch may not be fetchable. Delete a temporary branch only once is_done is true.
If the agent fixes a finding and you want that recorded in Gecko, your service can call PATCH /vulnerabilities/{id} on the caller’s behalf, which needs the Member role. Gecko only checks the service account’s role, so your service decides who may triage: allow it only for callers with write access to the repository, and only for findings from scans recorded against them. For dismiss and accept_risk, the reason is saved as the finding’s dismissal reason; for resolve, it’s kept as a note in the finding’s activity history.

Keep your own record of who asked

Gecko records every scan and triage action against the service account, not the person behind your service or pipeline. Log the human or pipeline identity in your system for each call, together with the X-Request-Id header Gecko returns. That lets you trace any Gecko scan or triage decision back to whoever asked for it.

Plan rotation before the first expiry

Every token expires, and Gecko doesn’t send expiry reminders for API keys. An expired token gets 401 with an authentication_error, so a forgotten expiry shows up as a failing pipeline. A service account has exactly one token, so you rotate by replacing the service account:
1

Create the replacement

Create a new service account with the same role, and store its token in your secrets manager.
2

Roll it out

Deploy the new token to the workload and confirm its calls succeed.
3

Remove the old account

In Settings > Members, choose Remove from Team on the old service account.
During the overlap both accounts use a seat. Track each token’s date in the Expires column of Settings > API Keys, and schedule the rotation well before it.

No interactive sign-in

A service account can’t sign in to the dashboard, so SSO and MFA don’t apply to it. The token is the only credential: store it in a secrets manager, inject it at runtime, and never commit it to source control. Send it over HTTPS as Authorization: Bearer <token> or X-API-Key: <token>.

One team per token

A token is bound to the team it was created in. If you run several Gecko teams, such as one per business unit, create a service account in each.

Network egress

API calls go to https://app.gecko.security/api/v1. If your workloads egress through a proxy or TLS inspection layer, allow that host.

Reference patterns

A Member service account per CI system. The pipeline starts a scan with POST /scans for the merge request’s branch or commit, polls GET /scans/{id} until is_done is true, using webhooks only to check sooner. It fails the job unless status is completed, then pages through GET /scans/{id}/vulnerabilities until has_more is false and fails the job above your severity threshold. So a retried job doesn’t start a second scan, send an Idempotency-Key on POST /scans that stays the same across retries, such as one built from the pipeline ID and commit SHA, with the same request body. A fresh random key on each attempt starts a new scan. Change the key only when you deliberately rescan after a failed, cancelled, or skipped scan.
A Member service account held only by an internal service, as in Let developers and agents scan through your own service. The agent’s skill pushes its work, asks your service for a scan of that commit, and gets back only that scan’s findings to fix before it opens a merge request. Scan once when the work is done rather than on every commit.
A Read Only service account. Run a scheduled job that pages through GET /vulnerabilities with cursor pagination, or receive webhook events and pull full records on change.
When your secrets manager rotates the GitLab service account’s personal access token, a Manager service account calls PATCH /integrations/gitlab with the new token. Gecko validates it against your instance before storing it. Monitor GET /integrations/gitlab for the token’s expiry date.

Revoke access

  • Remove the service account with Remove from Team in Settings > Members. The token stops working on its next request and the seat frees up.
  • Delete the token in Settings > API Keys. The token stops working immediately, but the service account stays a member and keeps its seat until you remove it.
Removing the admin who created a service account doesn’t affect it or its token.