Skip to content

Developers

Quickstart

From an empty account to a traced, policy-evaluated action: create an organization and an API key, connect an AI system, send an event, write a policy.

Six steps

  1. 01Create an organization
  2. 02Issue a scoped key
  3. 03Install the SDK
  4. 04Register your AI system
  5. 05Evaluate an action
  6. 06Watch it refuse

Nothing here deploys anything. Nothing changes in your systems until step 5 returns an authorization and your code chooses to honour it.

Before the steps

This is the setup path. The concepts are next door.

Six steps from an empty account to a decision you can see, ending on a refusal rather than a success. If you already have an account and want the conceptual loop — connect, register, write a policy, evaluate, trace — the documentation quickstart is the one to read.

You are on the right page if

  • You want an API key and a working call today.
  • You have an AI system already running that takes an action.
  • You want to see a refusal before you trust an authorization.

Read the other one if

  • You want to understand what a policy is before writing one.
  • You want the six trace stages explained.
  • You are evaluating the model rather than the API.

Documentation quickstart

The setup

Six steps, and the last one is the interesting one.

Everything before step 5 is credentials and registration. Step 5 is the loop, and step 6 is the half of it most quickstarts leave out.

01

Create an organization

An organization is the tenant boundary. Every record OpsAI writes carries it as part of the primary key rather than as a filter applied in application code, which is the distinction worth checking in any product that claims isolation.

Use a sandbox organization for this walkthrough. Every step is reversible, but step 5 files a real evidence record and evidence cannot be edited afterwards — that is the point of it.

02

Issue a scoped key

Keys are scoped by capability and prefixed accordingly, so the blast radius of a leaked key is legible from the key itself. For this walkthrough you want an evaluate key.

Key scopes
sk_read_...     # read the estate, traces, evidence
sk_evaluate_... # evaluate actions; cannot change policy
sk_admin_...    # publish policy versions, manage connections

export OPSAI_API_KEY="sk_evaluate_..."

A key is shown once and stored as a digest. There is no endpoint that returns a key value, so a lost key is rotated rather than recovered.

03

Install the SDK

Install
npm install @opsai/sdk      # or: pip install opsai

The SDK is a typed wrapper over the HTTP API and nothing more. Everything below works with curl if you would rather see the wire — the API overview covers the conventions.

04

Register your AI system

Register the thing that already exists and already proposes actions. Note what is required and what is not: the accountable human is required, the framework is descriptive and nothing branches on it.

register.ts
import { OpsAI } from '@opsai/sdk';

const opsai = new OpsAI({ apiKey: process.env.OPSAI_API_KEY });

const agent = await opsai.agents.create({
  id: 'refund-resolver',
  framework: 'langgraph',        // descriptive only
  model: 'claude-sonnet',
  owner: 'you@example.com',      // required: one accountable human
  attempts: ['issue.refund'],
});

05

Evaluate an action

The loop. Your AI system proposes; OpsAI decides before anything reaches a system of record.

evaluate.ts
const decision = await opsai.actions.evaluate({
  agent: 'refund-resolver',
  action: 'issue.refund',
  subject: 'ORD-40122',
  amount: { currency: 'INR', value: 18400 },
  idempotency_key: 'ACT-7512',
});

decision.outcome;   // 'authorized'
decision.bound;     // 'refund.ceiling'
decision.evidence;  // 'EV-7512'
decision.latency_ms;// 11

Three possible outcomes. authorized attaches a grant scoped to this one action. held means a person has to decide, and the hold expires rather than queueing. denied names the check that failed.

Confirm it landed: GET /actions/ACT-7512/trace returns the six stages whatever the outcome was.

06

Watch it refuse

Send the same call with an amount above the ceiling. This is the step worth doing before you wire the happy path.

422 bound_violation
{
  "error": {
    "code": "bound_violation",
    "bound": "refund.ceiling",
    "bound_version": "v7",
    "check": "amount <= ceiling",
    "observed": { "amount": 41200, "ceiling": 25000 },
    "evidence": "EV-7601"
  }
}

Note the evidence reference. A refusal produces a record exactly as complete as an authorization does, which is the property that makes the record usable in a review — a control that only writes down its successes cannot answer what the system tried to do and what stopped it.

Where to go

You have a decision and a record. Now make it not depend on your code asking.

Evaluating explicitly is the fastest way in and the weakest form of the control, because it works only where somebody remembered to call it. A connection closes that gap.