Authentication

Delegated OAuth to start self-serve, service credentials for unattended backends.

How to authenticate

ModeWhoCredentialIssued bySetup
API keyYour own backend calling your own organizationA static key (agk_…) sent as Authorization: BearerAginera — Settings → APISelf-serve — create a key and paste it; nothing to exchange
DelegatedAgents and backends acting for a signed-in user; people in ChatGPT, Claude or another MCP clientOAuth 2.1 authorization code + PKCE, with refresh tokenshttps://auth.aginera.aiSelf-serve — register a public client and start today
ServiceFully unattended partner backends via EntraOAuth 2.0 client credentialsMicrosoft Entra ID (Aginera tenant)Enterprise onboarding

All three produce a bearer credential for Authorization: Bearer … against https://api.aginera.ai/partner/v1, and all hit the same services, permissions and billing. Browser session tokens are never accepted.

Which to use. Calling Aginera from your own backend for your own organization? Create an API key in Settings → API — paste it and go, no OAuth handshake. Building an agent, or acting on behalf of other users? Use delegated OAuth (below). See the REST quickstart for each flow end to end.

API keys

The simplest credential — a static key you use directly, with no token to exchange or refresh:

curl https://api.aginera.ai/partner/v1/projects -H "Authorization: Bearer agk_..."

Create a key

Any signed-in organization admin can create one from the app — no code required:

1. Open Settings → API and find the API keys card. Click Create API key, give it a name, and choose the scopes it needs. Request the narrowest set — the read scopes are on by default; takeoffs:run is marked billable.

The Create API key form in Settings → API — name the key and choose its scopes

2. Click Create. The key is shown once — copy it now and store it somewhere safe. You won't be able to see it again; if you lose it, revoke it and create a new one.

The new API key, shown once, with a copy button and a ready-to-run curl

3. Use it on every request as Authorization: Bearer agk_… against https://api.aginera.ai/partner/v1.

A key is scoped to the organization and to the scopes chosen at creation, is metered and billed like any other usage, and can be listed and revoked at any time on the same screen. Automating provisioning instead? The same actions are available as POST / GET / DELETE /oauth/api-keys (session-authed). The key is the credential — keep it secret.

How the OAuth handshake works

There's no API key to paste. Instead your app does a short, one-time handshake with auth.aginera.ai and comes away with a token it can use — and refresh — from then on. Think of it like a valet key: the user approves once, and your app gets access that's limited to the scopes they granted, tied to their organization, and set to expire.

Four parties take part: your app (the "client"), the user who approves, Aginera's authorization server (auth.aginera.ai, which issues tokens), and the API (api.aginera.ai/partner/v1, which accepts them).

1Register your app — oncePOST auth.aginera.ai/oauth/register → client_id2Make a PKCE paira random verifier (kept secret) + its SHA-256 challenge3User signs in and approvesauth.aginera.ai/oauth/authorize → consent screen4Aginera returns a one-time coderedirect back to your app ?code=…5Exchange the code for tokensPOST /oauth/token (code + verifier) → access_token + refresh_token6Call the API with the tokenapi.aginera.ai/partner/v1 · Authorization: Bearer <access_token>Steps 1–5 happen once. After that you refresh the token — the user never re-approves.

Step by step:

  1. Register your app — once. POST to the registration endpoint with a name and a redirect_uri (where Aginera sends the user back). Because it's a public client (token_endpoint_auth_method: "none") no secret is issued — you get a client_id you reuse forever.
  2. Make a PKCE pair. Since there's no secret, PKCE proves it's really your app finishing the flow: generate a random verifier (keep it) and send its SHA-256 challenge in the next step.
  3. Send the user to approve. Open a browser to authorize with your client_id, redirect_uri, the code_challenge, and the scopes you want. The user signs in and clicks Allow — this ties the token to their organization and only the scopes they approved.
  4. Aginera returns a one-time code. It redirects back to your redirect_uri with ?code=…. The code is useless on its own.
  5. Exchange the code for tokens. POST the code plus the verifier to /oauth/token. Aginera checks the verifier against the earlier challenge and returns an access_token (valid ~1 hour) and a refresh_token.
  6. Use it, and keep it alive. Send Authorization: Bearer <access_token> on every API call; before the hour is up, POST grant_type=refresh_token for a fresh one — no user needed.

The quickest way — let the app do it

If you're signed in to Aginera, open Settings → API → Get a token now: it runs this whole handshake in your browser, then hands you a real access token (and a ready-to-run curl) to copy. The REST quickstart has the same flow as runnable code.

Delegated: register a client

No client secret is issued. Register a public client (token_endpoint_auth_method: "none") at the registration endpoint, or advertise a Client ID Metadata Document — both are supported (client_id_metadata_document_supported: true). Then run authorization code + PKCE (code_challenge_method=S256) and exchange the code for an access token plus a rotating refresh token.

Scopes

projects:read/write/delete, documents:read/write/delete, takeoffs:read/run/review/delete, exports:read/create, estimates:read/generate, billing:read/write, events:read, webhooks:manage. A token only ever carries the scopes it was granted; request the narrowest set you need. Billable scopes (takeoffs:run, estimates:generate) and destructive scopes (*:delete) are highlighted on the consent screen.

Discovery

  • Authorization server metadata: https://auth.aginera.ai/.well-known/oauth-authorization-server (lists authorization_endpoint, token_endpoint, registration_endpoint and scopes_supported)
  • Protected resource metadata: https://mcp.aginera.ai/.well-known/oauth-protected-resource (agents) and https://auth.aginera.ai/.well-known/oauth-protected-resource (REST → https://api.aginera.ai/partner/v1)
  • Public signing keys: https://auth.aginera.ai/.well-known/jwks.json

Delegated access tokens are RS256, iss=https://auth.aginera.ai, aud=https://mcp.aginera.ai, and expire in one hour; refresh before expiry with grant_type=refresh_token.