Quick Start

Seal is the product. Aqta is the company. Same gateway, same signed receipts.

Use Seal for one real workflow first. Point an OpenAI-compatible client at the gateway, send a routed call, then inspect and independently verify the signed decision record.

0. Try it first, without an account

One signed record, no key, no sign-up. This is the action boundary: you propose a tool call, Seal applies a policy and signs the decision either way.

bash
curl -s -X POST https://api.aqta.ai/v1/public/demo/action \
  -H "Content-Type: application/json" \
  -d '{"tool":"git.push_production","args":{"branch":"main"},"agent":"my-agent/1.0"}'

You get back outcome: BLOCKED and a signed ACTION-v1 record. Try github.create_issue instead and you get ALLOWED. A refusal is a record in its own right, which is the part a sample file cannot show you.

Now check it yourself, offline, against the key we publish:

bash
# save the "record" object from the response as record.json
curl -s https://api.aqta.ai/v1/attestation/public-key      # the pinned key
npx aqta-verify-receipt record.json --profile action-1 --key <that key>

Change one character in the record and run it again. The signature fails.

Two honest bounds on the demo: the record carries org_id: "demo-public" and is not written to the transparency log, so it has no inclusion proof. Real records carry your organisation's id and appear in the log. The limit is 20 records an hour.

Everything below needs a key.

1. Get pilot access and an API key

Pilot access is issued for a defined workflow. After access is enabled, create a key in Settings → API Keys. Aqta keys begin with aqta_.

Keep the key out of source control and store it in an environment variable.

2. Configure a provider

Add credentials for the provider and model you plan to route through Seal in Settings → Provider keys. Model availability depends on the provider credentials configured for your organisation.

3. Route a call

Point your existing OpenAI client at Seal.

Python

python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.aqta.ai/v1",
    api_key="aqta_your_key",
)

raw = client.chat.completions.with_raw_response.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Summarise this case in three bullets."}],
)

completion = raw.parse()
body = raw.http_response.json()
receipt = body["aqta"]["attestation"]

print(completion.choices[0].message.content)
print(receipt["outcome"])

TypeScript / Node.js

typescript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://api.aqta.ai/v1',
  apiKey: process.env.AQTA_API_KEY,
});

const response = await client.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Summarise this case in three bullets.' }],
});

console.log(response.choices[0].message.content);

cURL

bash
curl https://api.aqta.ai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer aqta_your_key" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

4. Inspect the record

Each routed outcome includes an aqta.attestation envelope. It records the outcome and is signed with the active Aqta Ed25519 key. A policy denial is also recorded, so a reviewer can distinguish a blocked call from a missing event.

The dashboard is convenient for investigation. The signature is the evidence: you can check it independently.

5. Verify without Aqta

Install the public verifier:

bash
pip install aqta-verify-receipt

Pin a trusted copy of the published key, then verify a receipt locally:

python
from aqta_verify_receipt import fetch_published_public_key, verify_receipt

trusted_key = fetch_published_public_key()
result = verify_receipt(receipt, trusted_public_key=trusted_key)

if not result.valid:
    raise RuntimeError(result.reason)

Once you have pinned a trusted key, receipt verification does not need an Aqta API call.

Intent-bound sessions

An agent session can register the instruction it runs under. Pass an opaque aqta_session_id to group calls into a session, and aqta_intent on the first call (or POST /v1/sessions/{id}/intent) to register the instruction. The intent is immutable once set: a later, different aqta_intent on the same session is refused with 409.

json
{
  "model": "gpt-4o",
  "messages": [{"role": "user", "content": "Find the cheapest flight to Dublin"}],
  "aqta_session_id": "run-2026-08-18-042",
  "aqta_intent": "Book the cheapest returnable flight to Dublin under 200 EUR"
}

A policy with a require_intent rule refuses any call that does not run under a session with a registered intent. The refusal happens before the provider is reached, and the refusal itself is signed. Decisions made under a registered intent carry it in the policy snapshot served at GET /v1/receipts/{id}/rules-in-force.

What this establishes: every decision in the session ran under one recorded, immutable instruction, and refusals are independently verifiable records. It does not detect drift or manipulation, and does not claim to: whatever decides to refuse (this rule, your own policies), the signed record is what survives.

Resource-limit policies

A policy with a carbon_budget rule sets a ceiling, in grams of CO2 equivalent, on a single call. A request whose estimate exceeds the ceiling is refused before the provider is reached, and the refusal is signed with the policy named in policy_applied.

json
{
  "name": "Inference budget",
  "rules": [{"type": "carbon_budget", "value": "2.5"}]
}

The refusal message carries both real figures, the estimate and the ceiling, so the reason a call stopped is legible without opening a dashboard.

The estimate is modelled, not metered. It is derived from a static model energy profile and a regional carbon intensity figure. Seal does not measure energy at the provider and does not claim to. What the signed record establishes is that a declared constraint governed the decision, and that the request behind the estimate is bound into request_hash, so a reviewer can recompute the figure under their own factors and disagree with ours.

Two deliberate behaviours: a call with no available estimate is never blocked, and a rule with a missing or non-numeric ceiling is not recognised at all, so a policy that enforced nothing is never named on a receipt.

What Seal does in the call path

  1. Evaluates the configured policy before the provider call.
  2. Stops the provider call when policy blocks it.
  3. Signs the routed outcome as an ATTESTATION-v1 record.
  4. Returns the result and record for later review.

Next steps

Questions about a pilot workflow: hello@aqta.ai

Last updated: May 2026