Public API: Authentication

The public API uses service tokens: scoped, revocable Bearer credentials bound to an organization. They authenticate external integrations, CI pipelines, and any automation that needs to manage AvsB resources without a human session.

Service Tokens vs Personal Access Tokens

Service tokens (this page) are organization-scoped, carry explicit permission scopes, and outlive any individual user. They are managed at Organization Settings → Service Tokens. Personal access tokens are user-scoped, used by the A vs B CLI and personal scripts, and live at Account Settings → Personal Access Tokens. See Personal Access Tokens for that flow, and Credentials for all four A vs B credentials in one table.

Token format

Every service token starts with the prefix avsb_svc_ and contains 32 random bytes of entropy, base64url-encoded:

Plain text
avsb_svc_abc12345_KMv3l4...VeryLongRandomString
Plain text1 line

Tokens are shown once, at creation time. AvsB stores only a SHA-256 hash of the secret. You must save the token somewhere safe at creation; if you lose it, rotate or revoke and create a new one.

Creating a token

1

Open Service Tokens

From the A vs B dashboard, go to Organization Settings → Service Tokens. You need OWNER or ADMIN privileges to manage service tokens.

2

Generate a new token

Click Create token. Give the token a descriptive name (visible in the audit log), an optional description, and an expiry (Never, 7d, 30d, 90d, or 1 year).

3

Pick scopes

Choose the minimum set of scopes the token needs. Scopes are organised by resource family (Projects, Experiments, Flags, Audiences, etc.) and split into read and write permissions. The admin:* superuser scope grants everything and is intended for Terraform provider tokens or org-wide automation only.

4

Copy the secret

The full secret appears once in a reveal modal. Copy it to a secrets manager (1Password, Vault, AWS Secrets Manager, your CI's secret store). After closing the modal, only the prefix is visible.

Organization Settings, Service Tokens tab: every token's name, prefix, scopes, expiry, and last-used metadata.
  1. Open the Service Tokens tab.
  2. Click Create token.
The Create service token form. The secret itself is not shown here: it appears once, after you click Create.
  1. Name the token so you recognise it later.
  2. Pick how long the token should live.
  3. Turn on only the read and write scopes this integration needs.

Scopes

Scopes are the token's permission system. Each scope is read/write per resource family. The auth layer rejects requests with a missing scope using a 403 response and a structured scope_missing error code naming the missing scope.

The complete scope vocabulary:

Plain text
org:read              org:writeprojects:read         projects:writeexperiments:read      experiments:writeflags:read            flags:writeaudiences:read        audiences:writesegments:read         segments:writemetrics:read          metrics:writeresults:read          (no write, results are computed, not authored)members:read          members:writeroles:read            roles:writewebhooks:read         webhooks:writeintegrations:read     integrations:writecatalog:read          catalog:writedatasets:read         datasets:writerecommendations:read  recommendations:writeorders:read           (no write, orders arrive from your store)audit:read            (no write, the audit log is system-authored)tokens:read           tokens:writeadmin:*               (superuser wildcard, covers everything)
Plain text19 lines

Two of these are selectable but unused today, so granting them changes nothing: org:write (no public route writes the org profile) and tokens:read / tokens:write (token management is deliberately dashboard-only, so no public route consumes them).

Personal access tokens on the management API

A personal access token (avsb_pat_...) works as a Bearer credential on /api/v1 as well as on the CLI, so a script you run as yourself does not need an organization-wide service token.

curl https://app.avsb.cloud/api/v1/projects \  -H "Authorization: Bearer avsb_pat_..."
Shell2 lines

Which organization it acts on

A service token belongs to one organization. A personal token belongs to a person, who may be in several. So:

  • If you are a member of exactly one organization, that is the one used. Nothing extra to send.
  • If you are in more than one, name it with an AvsB-Org-Id header. The header takes either the organization id or the short numeric id from the dashboard URL. Without it the API answers 400 and the message says so.
curl https://app.avsb.cloud/api/v1/projects \  -H "Authorization: Bearer avsb_pat_..." \  -H "AvsB-Org-Id: 100042"
Shell3 lines

Which permissions it has

A personal token has no scope list of its own. Its scopes are derived from your role in that organization, so it only ever reaches the resource families your role can already reach (with one exception, in the callout below):

Your role carriesThe token gets
Membership (any role)org:read, projects:read, experiments:read, flags:read, audiences:read, segments:read, metrics:read, members:read, roles:read, webhooks:read, integrations:read, catalog:read, datasets:read, recommendations:read, orders:read
View reportsresults:read
Export dataresults:read
Manage projectsprojects:write
Edit project settingsprojects:write
Create experimentsexperiments:write, flags:write, audiences:write, segments:write, metrics:write
Edit code variationsexperiments:write
Manage integrationsintegrations:write, webhooks:write, catalog:write, datasets:write, recommendations:write
Built-in Owner or Adminaudit:read, members:write, roles:write

Four scopes are never granted to a personal token, whatever your role: tokens:read, tokens:write, admin:* and org:write. A credential that can mint credentials turns one leak into permanent access, so token management stays a dashboard action.

Warning

Scopes are per resource family, not per environment. A role that can author flags but cannot publish to production in the dashboard can still pause a production flag through the API with its personal token, because there is no environment-level scope to express the difference. Use service tokens for CI, and treat issuing a personal token as granting API access at that person's authoring level.

When to use which

  • Service token for CI, Terraform, and anything that must keep working when a person leaves. It belongs to the organization and its scopes are explicit.
  • Personal access token for your own scripts, the CLI, and one-off calls. It belongs to you and it disappears with your access.

Rotating a token

Rotation issues a new secret and keeps the OLD one working for 24 hours, so you can roll it out without downtime. Use rotation when:

  • A developer who knew the secret leaves the team.
  • A secret may have leaked (commit history, logs, screenshots).
  • Routine credential hygiene, quarterly or per security policy.

Rotate from the dashboard Service Tokens tab (Rotate button on each row). Token management is dashboard-only; a service token cannot create, rotate, or revoke tokens through the public API.

What happens when you rotate:

  1. The new secret is shown once, on a new row with the same name, description, scopes and expiry.
  2. The row you rotated keeps the old secret working and is renamed "<name> (previous secret)", with its expiry set 24 hours out. Its row shows exactly when the old secret stops working.
  3. After that moment the old secret answers 401 with the code token_expired, so a deployment you forgot to update tells you precisely what happened.

The grace window never extends a token past its own expiry, and it is configurable per deployment. If you believe a secret has leaked, do not rotate: revoke it, which takes effect immediately.

Warning

Revoking the new token does not kill the old secret. They are separate rows, so a revoke stops the one you clicked and the "previous secret" row keeps working until its grace expiry. If a secret may have leaked during a rotation, revoke both rows.

Revoking a token

Revocation is a soft-delete: the token row is preserved (so audit history continues to resolve to it), but every request authenticating with it returns 401 immediately. There is no undo.

Revoke from the dashboard Service Tokens tab (Revoke on each row). As with rotation, this is a dashboard-only action; it is not exposed on the public service-token API.

Expiry

Tokens can be created with an optional expiry up to one year out. Expired tokens fail with a 401 and a token_expired error code. The Service Tokens tab shows each token's expiry as a relative date (for example "in 12 days") and marks it Expired once it has passed, but it does not warn you ahead of time. Track expiry yourself: set a calendar reminder, or rotate ahead of time.

Last-used tracking

Every authenticated request updates the token's last-used timestamp, IP address, and user-agent. The Service Tokens dashboard tab shows this metadata so you can identify dormant tokens and revoke them, or trace which client is using which token.

Security recommendations

  • Use scoped tokens, not admin:*. Limit blast radius by granting only the scopes the integration genuinely needs.
  • Set expiry. Default to one year. Rotate ahead of expiry rather than letting tokens lapse and breaking integrations.
  • One token per integration. Don't share tokens across services. The last-used metadata is only useful if a token uniquely identifies its caller.
  • Store in a secrets manager. Never commit tokens to version control. Use environment variables wired from your secrets backend.
  • Revoke on suspicion. A token revocation is cheap; investigating a credential leak after the fact is not.
Was this helpful?