Skip to Content
Depot docs

CI and agents

Publish from CI or an AI agent with an organization API key. Permissions, environment variables, a GitHub Actions workflow and safe retries.

Everything a studio does on Depot goes through the public API, and the depot CLI is a client of that API. A CI job or an AI agent can create a game, push builds, move channels and publish a store page with the same commands you run by hand. It authenticates with an organization API key instead of a person's sign-in.

Organization API keys

An API key (dpk_…) belongs to your organization, not to a person. It keeps working if the person who made it leaves, and it can only do what its permissions allow.

Create one while signed in as yourself:

depot api-key create --name ci-push \
  --permissions release:publish,channel:write,game:read \
  --expires-in-days 90 --out ci-push.key

Prop

Type

The secret is shown once. Depot stores only a hash of it and can't show it again. Put it in your CI's secret store and delete the local file.

Only people manage keys. Creating a key needs a signed-in member with the apiKey:create permission (owners and admins), and an API key can never create, rotate or revoke keys or change members.

Permissions

Give each key only what its job needs. A key's permissions must be a subset of your own role's permissions when you create it.

PermissionLets the key
game:createCreate games.
game:readRead games, releases, channels, packages and store pages.
game:updateEdit games and store pages, upload art and media, publish pages, define packages.
release:publishPush releases.
channel:writeMove channels, including rollbacks.
signingKey:manageEnroll and revoke signing keys, and register a package's content key on its first push.
keys:issue, keys:read, keys:revokeIssue, list and revoke game key batches.
entitlement:grant, entitlement:read, entitlement:revokeGrant, list and revoke players' entitlements.
retailer:delegateLet a retailer organization issue keys for your packages.
retail:issueIssue keys under a delegation your organization holds.

A key can't hold organization, member, invitation or apiKey permissions.

Common sets:

JobPermissions
Push builds and move channelsrelease:publish,channel:write,game:read
Push builds for testers, promote by handrelease:publish,game:read
Publish the store page tooadd game:update
An agent that sets up a new game end to endgame:create,game:read,game:update,release:publish,channel:write,signingKey:manage

Rotate and revoke

depot api-key list
depot api-key rotate --id <key id> --grace-seconds 3600 --out ci-push.key
depot api-key revoke --id <key id>

rotate creates a replacement with the same name and permissions. The old key stops at once, or after --grace-seconds so you have time to update your secret store. revoke stops a key immediately. Every create, rotate and revoke is in the audit log.

Environment variables

VariableWhat it does
DEPOT_APIThe API base URL. Use https://api.staging.depot.games.
DEPOT_TOKENThe organization API key. The CLI uses it before any stored key or depot login session.
DEPOT_CONFIG_DIRWhere the CLI looks for config, signing keys and content key backups. Default ~/.config/depot.
DEPOT_STATE_DIRWhere the CLI keeps staged builds and caches. Default ~/.local/state/depot.

Check what a job is running as:

depot auth status

With an API key, this prints the key's organization and permissions.

What a push job needs

A push from CI needs three secrets, not one:

  1. The API key, as DEPOT_TOKEN.
  2. The signing key file, after you've enrolled it with depot keys enroll. The file records which key id it has for each game, so copy it after enrolling. Pass it with --key.
  3. The content key backup for each package you push, from ~/.config/depot/content-keys/. Pass it with --content-key.

Do the first push of each package from your own machine. The first push generates the package's content key and registers it, which needs signingKey:manage. After that, a key with release:publish and channel:write is enough.

The signing key and content key files are as sensitive as the API key. Anyone with all three can publish builds of your game. Keep them in your CI's secret store, never in the repository.

GitHub Actions example

This workflow builds a Linux build on every tag and pushes it to stable. Store DEPOT_TOKEN, DEPOT_SIGNING_KEY (the signing key file's contents) and DEPOT_CONTENT_KEY (the content key backup's contents) as repository secrets. Replace the build step with your own.

.github/workflows/release.yml
name: Release

on:
  push:
    tags: ["v*"]

jobs:
  push:
    runs-on: ubuntu-latest
    env:
      DEPOT_API: https://api.staging.depot.games
      DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }}
    steps:
      - uses: actions/checkout@v4

      - name: Build the game
        run: ./scripts/build-linux.sh out/linux

      - name: Install the depot CLI
        # There's no prebuilt download yet: build it from the Depot source
        # (see "Install the CLI") or restore a binary from your cache.
        run: depot --version

      - name: Write the signing and content keys
        env:
          DEPOT_SIGNING_KEY: ${{ secrets.DEPOT_SIGNING_KEY }}
          DEPOT_CONTENT_KEY: ${{ secrets.DEPOT_CONTENT_KEY }}
        run: |
          umask 077
          printf '%s' "$DEPOT_SIGNING_KEY" > "$RUNNER_TEMP/signing-key.json"
          printf '%s' "$DEPOT_CONTENT_KEY" > "$RUNNER_TEMP/content-key.json"

      - name: Push to Depot
        run: |
          depot push --game my-game --platform linux-x64 \
            --release "${GITHUB_REF_NAME#v}" \
            --input out/linux --launch-file launch-linux.json \
            --key "$RUNNER_TEMP/signing-key.json" \
            --content-key "$RUNNER_TEMP/content-key.json" \
            --channel stable --note "Release ${GITHUB_REF_NAME}" \
            --json

Notes:

  • Re-running a failed job is safe. An unfinished push of the same name resumes. A published release name is refused with a 409, so a re-run never publishes twice. If the release was published but the channel didn't move, move it with depot channel set.
  • To ship several platforms, run one push per platform, each with its own --platform, input folder and launch file. Each platform's stable channel moves on its own.
  • To promote by hand instead, drop --channel and --note and move the channel later with depot channel set.

Driving Depot from an AI agent

An agent can publish a game end to end with the CLI, the same way a person does. Give it an API key with the permissions from the table above and these two documents:

Tips for agents:

  • Pass --json where a command has it, and read the JSON. Most commands without --json print JSON anyway.
  • Run depot auth status first to see which organization and permissions the key has.
  • Never put a key on the command line. DEPOT_TOKEN and depot auth login (which reads from standard input) keep it out of shell history and logs.
  • Errors from the API are problem+json objects with a stable title code, such as revision_mismatch or forbidden. Branch on the code, not on the message. See the API overview.

A full setup an agent can run looks like this. Everything except the first sign-in and key creation works with an API key:

depot game create --slug my-game --name "My Game"
depot keys generate && depot keys enroll --game my-game
depot push --game my-game --platform linux-x64 --release 1.0.0 \
  --input build/ --launch-file launch.json --channel stable --note "First build."
depot game art --game my-game --kind cover --file art/cover.png
depot game page --game my-game --tagline "A short line about the game." \
  --short-description "Shown in link previews." --access free --publish public

The last command prints the page URL.

Idempotency keys

Networks fail. When a request times out, you don't know if it happened. Idempotency keys make a retry safe.

Send an Idempotency-Key header on a POST. If Depot has already handled a request with the same key from the same credential on the same route, it returns the stored response instead of acting again, with the header idempotent-replay: true. If you reuse the key with a different body, you get 422 idempotency_mismatch.

  • Keys are 8 to 128 characters of letters, digits, ., _, : and -.
  • Use a new key for each distinct action, and the same key for retries of that action.
  • Some requests require a key: granting an entitlement and issuing a batch of game keys. For game keys, a retry returns the batch without the codes, because codes are delivered once.

The CLI uses idempotency keys for you where it matters. depot game-keys create takes --idempotency-key so you can retry a timed-out batch without issuing a second one:

depot game-keys create --game my-game --quantity 100 --out keys.txt \
  --idempotency-key launch-batch-2026-12

Channel moves don't need an idempotency key: they're compare-and-swap on the channel's revision. See Channels and releases.

On this page