// Key takeaways

For some context on why this is important, see the blog post I wrote on Adobe's move to the Config Service from file-based configs. You'll need to roll your own CI/CD these days, and to do that you'll first need an API key.

Here's what to do:

You need an admin session to call the key‑creation endpoint. In a browser:

(1) Open https://admin.hlx.page/login/[YOUR_ORG]/[YOUR_SITE]/main and sign in with your Adobe ID.

(2) After redirect, open DevTools → Application → Cookies for admin.hlx.page and copy the value of the auth_token cookie.

(3) Export it for the next step:
export ADMIN_COOKIE="<paste auth_token cookie value>"

(4) Verify it works: (note: You must hold the admin (or config_admin) role on the org/site to create keys.)

curl -s -o /dev/null -w "%{http_code}\n" \
  -H "x-auth-token: $ADMIN_COOKIE" \
  https://admin.hlx.page/config/[YOUR_ORG]/sites/[YOUR_SITE].json
# expect: 200

2 | Create the persistent API key

Pick the scope that matches what your proposed CI/CD or workflows are actually going to do. The workflows in the project I tested these commands on only read/write site config files in Config Service, so a site‑scoped key with the config role is the right level of least privilege.

Available roles (pick minimum needed): basic_publish, basic_author, author, publish, develop, config, config_admin, admin. For full publish/preview automation you'd use publish; for config‑file sync only, config is theoretically enough. Theoretically.

curl -s -X POST \
  -H "x-auth-token: $ADMIN_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "GitHub Actions - mycoolsite-config-sync",
    "roles": ["admin"]
  }' \
  https://admin.hlx.page/config/[YOUR_ORG]/sites/[YOUR_SITE]/apiKeys.json

If you'd rather create an org‑level key for your org (works for any site under your org), instead use: https://admin.hlx.page/config/[YOUR_ORG]/apiKeys.json

You'll get a response like:

{
  "id": "…",
  "description": "GitHub Actions - mycoolsite-config-sync",
  "value": "eyJhbGciOi…(long JWT)…",
  "created": "2026-05-21T…Z",
  "expiration": "…",
  "subject": "…"
}

Copy the value field now — it is shown only once. That JWT is your persistent token.

3 | Verify the key

Run this to verify:

export AUTH_TOKEN="<paste value from response>"
curl -s -o /dev/null -w "%{http_code}\n" \
  -H "Authorization: token $AUTH_TOKEN" \
  https://admin.hlx.page/config/[YOUR_ORG]/sites/[YOUR_SITE].json

You should get a 200.

Then, in my example, you can safely just create a github repository secret and store the above as a secret for github action usage.

// Related reading

CTA Band