Platform

Platform overviewArchitectureWorkflow orchestrationGitOps configurationGovernance and AAAAI and MCPKnowledge and contextRuntime and executionEvidence and monitoring

Use cases

All use casesProduction incidentRelease preparationHotfix to productionSecurity scan triage
Why NopsAIIntegrationsSecurity

Resources

All resourcesAI agent governanceMCP governanceMCP securitySelf-hosted platforms
PricingGitHub

Company

How a run worksAboutContactBook a demo

Calling the API

One worked path from a login to a run: get a token, call a route, read the response, and handle the failure modes.

TutorialDeveloperAutomation authorOperator

What you will do

  • Everything except the public routes needs Authorization: Bearer <token>.
  • Three token kinds reach the same surface: a session access token, a personal access token, and a service account token.
  • A system that calls the API should hold a service account token, not a token minted from a person's account.
  • Token values are returned once, at creation. There is no route that reads one back.
  • The nopsai CLI drives the same routes with the same authorization: it adds no server behaviour of its own.
  • Install the CLI from the latest GitHub Release assets before using CLI examples; future CLI upgrades are nopsai update --version <x.y.z>.

Before you start

A reachable API
The API address, http://localhost:8080 on a local installcurl -s "$NOPSAI_URL/livez"
Credentials
A local account, or an existing personal or service account token
Tools
curl and jq, or the released nopsai CLI from https://github.com/nopsai/nopsai/releases/latestcurl --version && jq --version

Steps

  1. 01

    Get a token

    Logging in gives a short-lived access token. For anything automated, exchange it once for a personal access token — or better, use a service account.

    Important
    • The first login of the bootstrap administrator must rotate its password before other routes will answer.
    Log in and mint a personal tokenbash
    ACCESS=$(curl -sX POST "$NOPSAI_URL/v1/auth/login" \
      -H "Content-Type: application/json" \
      -d "{\"identifier\":\"[email protected]\",\"password\":\"$PASSWORD\"}" | jq -r .access_token)
    
    curl -sX POST "$NOPSAI_URL/v1/auth/personal-tokens" \
      -H "Authorization: Bearer $ACCESS" \
      -H "Content-Type: application/json" \
      -d '{"name":"integration"}' | jq
    Replace before running
    • $PASSWORD is the account password; the first login forces a rotation.
    Expected result
    • A token value, returned once. Store it where you keep other credentials.
  2. 02

    Confirm who you are

    This is the fastest way to tell an authentication problem from an authorization one.

    Read the current identitybash
    curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/auth/me" | jq
    Expected result
    • The identity, its roles, and its effective capabilities. A 401 here means the token is wrong; a 403 elsewhere means the token is right and the access is not.
  3. 03

    Call a route

    Every authenticated route follows the same shape, so one working call generalises.

    List runsbash
    curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/runs?limit=5" | jq '.[] | {run_id, pipeline_name, status}'
    Verify
    • A JSON array comes back, filtered to what this caller is allowed to see.
  4. 04

    Ask for JSON when a route can answer either way

    A few routes answer with plain text unless the request asks for JSON. Starting a run is the one most integrations hit first.

    Start a run and read the run IDbash
    curl -sX POST "$NOPSAI_URL/v1/run/first-pipeline" \
      -H "Authorization: Bearer $NOPSAI_TOKEN" \
      -H "Accept: application/json" \
      -H "Content-Type: application/json" \
      -d '{"scope":"platform/production"}' | jq -r .run_id
    Expected result
    • Without Accept: application/json the same call returns Pipeline run created successfully with ID: <uuid> as text.
  5. 05

    Use the CLI when you would rather not hand-roll requests

    The CLI carries a generated route catalogue that is parity-tested against the registered routes, so it cannot drift from the API. Install it from the latest GitHub Release archive, extract the binary onto PATH, and remove the archive before using these commands.

    The same calls through the CLIbash
    nopsai context add local --api "$NOPSAI_URL"
    NOPSAI_TOKEN=nopat_<secret> nopsai api request GET /v1/runs
    nopsai api call GET '/v1/runs/{runID}' --path runID=<run-id>
    nopsai api routes --output json
    Replace before running
    • Replace nopat_<secret> and <run-id> with real values.

How it works

Authorization is resolved per resource, not per route. Two callers hitting the same list endpoint can legitimately receive different rows, because AAA filters the result to what each may see.

A 401 is about the token: missing, expired, or malformed. A 403 is about the caller: the token is valid and the action is not permitted on that resource. Treat them as different bugs.

Public routes are the exception rather than the rule: the platform probes, the setup routes, login and token refresh, the OIDC and OAuth2 callbacks, provider webhook ingress, and the runner bootstrap download.

Implementation evidence

  • services/nopsai/routes.go

    The registered route surface and its middleware chain.

  • doc/jwt-authentication.md

    Token kinds, claims, refresh, and service tokens.

  • internal/cli/apicatalog/catalog.go

    Generated route catalogue the CLI drives.