Skip to Content
Quickstart

Quickstart

Send your first governed AI call in under 60 seconds.

Prerequisites

Sign up for Keel to get started. In the Keel dashboard , create a project, generate your API key, add a provider key, and set your first control.

Once approved, you will have access to the Keel dashboard  where you:

  1. Create a project.
  2. Copy the project API key.
  3. Add a provider key (OpenAI, Anthropic, etc.) to that same project.
  4. Set a starting control for that project.

For a first run, use the dashboard’s built-in template flow:

  • Starter: apply a template such as Provider Allowlist or Daily Budget Cap.
  • Growth and above: apply a template first, or create a custom policy if you need it.

The quickstart stays template-first because it is the safest onboarding path. If you need custom authoring later, use the policy authoring reference together with Plans & Entitlements for the current tier boundaries.

Step 1: Install the SDK

pip install keel-sdk

Step 2: Set your environment variables

export KEEL_BASE_URL="https://api.keelapi.com" export KEEL_API_KEY="keel_sk_your_project_key" export KEEL_PROJECT_ID="your-project-uuid"

Step 3: Your first governed AI call

Use the provider wrapper — same interface you already know, with governance built in.

from keel_sdk.providers.openai import OpenAI client = OpenAI() response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Reply with exactly: keel works"}], max_tokens=16, temperature=0, ) print(response["choices"][0]["message"]["content"])

Expected output:

keel works

What just happened

That single call triggered four things transparently:

  1. Permit evaluated — Keel checked your project’s policies and budget before anything reached OpenAI. If the request was not allowed, the wrapper would have raised a KeelError and no provider call would have been made.
  2. Budget enforced — Token estimates were checked against your project’s spending limits.
  3. Provider executed — Keel proxied the request to OpenAI using your project’s stored provider key. Your app never handled raw OpenAI credentials.
  4. Audit recorded — Keel recorded the decision, routing, token usage, and execution evidence. You can view this in the dashboard or query it via the API.

Your code saw a standard OpenAI-shaped response. The governance was invisible.

Step 4: Inspect what Keel decided

The wrapper hides the governance details for ergonomics, but you can pull them up explicitly. This step is what to do after the first call when you want to see the permit, the policy match, and the audit record.

Get the permit id

Every Keel-managed response carries the permit id in a response header:

x-keel-permit-id: permit_01jyf4m3n8q2r6t9v1w5x7y0z

In the SDK, the wrapper exposes the same value on the response object. Capture it after a successful call:

permit_id = response.headers.get("x-keel-permit-id") print("permit:", permit_id)

Fetch the permit record

curl -sS https://api.keelapi.com/v1/permits/$KEEL_PERMIT_ID \ -H "Authorization: Bearer $KEEL_API_KEY" | jq

The returned permit captures the decision in full:

{ "id": "permit_01jyf4m3n8q2r6t9v1w5x7y0z", "decision": "allow", "reason_code": "ok", "policy_id": "default", "policy_version": "1.0.0", "subject": {"type": "user", "id": "agent_42"}, "action": {"name": "ai.generate.text"}, "resource": {"type": "request", "attributes": {"provider": "openai", "model": "gpt-4o"}}, "budgets": { "envelope_id": null, "reserved": null, "remaining": null }, "constraints": null, "created_at": "2026-04-25T18:00:00Z" }

The fields you most often want:

  • decisionallow, deny, or challenge. The first governed call should produce allow.
  • reason_code — a stable code describing why the decision came out that way. Full list at Errors › Permit reason codes.
  • policy_id and policy_version — which policy and version the decision was evaluated against.
  • budgets — the budget envelope state at decision time, when envelopes are configured.
  • constraints — any constraints the policy imposed on the request (for example, a max output token cap).

Replay the timeline

For a chronological view of everything Keel did — permit, routing, dispatch, usage — fetch the timeline by request id:

curl -sS https://api.keelapi.com/v1/requests/$KEEL_REQUEST_ID/timeline \ -H "Authorization: Bearer $KEEL_API_KEY" | jq

The response is a sequence of execution events: permit.allowed, routing.selected_model, provider.request_sent, provider.response_received, usage.recorded, request.completed. See Timeline Replay for the full event taxonomy.

Where to go next

The objects above — permits, governed requests, routing records, execution events, and timelines — are the substrate every other Keel surface refers to. For the orienting glossary, see Concepts. For the full per-mode comparison and trade-offs, see Execution Modes.

Which route should I use?

For most teams, the provider wrappers shown above are the recommended starting point. They handle permits, budget, execution, and usage reporting automatically.

If you need more control, Keel also exposes direct API routes:

  • Use /v1/execute as the primary public runtime surface when you already have provider-shaped input and want normalized output.
  • Use /v1/executions when you want Keel to execute through the provider-neutral contract.
  • Use /v1/proxy/* when you want provider-native payloads and provider-native responses.
  • Use /v1/permits when you want decision-first governance and your app will execute the provider call itself.

If you are new to Keel, start with the provider wrappers unless you specifically need permit-first, provider-shaped input, or provider-native proxy behavior.

Route comparison

RouteUse whenRequest shapeResponse shapeWho executes provider callTypical first-time user?Idempotency location
SDK provider wrappersYou want the fastest integration with automatic governance.Native provider SDK interface.Native provider response.Keel (via wrapper)YesManaged by wrapper
/v1/executeYou want the primary public runtime surface and already have provider-shaped input.Provider-shaped body with provider, model, and input.Normalized execution envelope plus resolved.KeelSometimes, when you already have provider-shaped inputIdempotency-Key header
/v1/executionsYou want Keel to execute and your request is provider-neutral.Canonical operation plus messages or inputs.Normalized execution envelope.KeelSometimesIdempotency-Key header
/v1/proxy/*You want provider-native payloads and provider-native responses.Provider-native payload.Provider-native response.KeelUsually no, unless you need provider parityIdempotency-Key header
/v1/permitsYou want decision-first governance and your app will call the provider itself.Canonical permit body with project_id, subject, action, and resource.Permit decision object only.Your appSometimes, for permit-first integrationsJSON body idempotency_key

curl / raw API

If you prefer to test with curl before integrating the SDK:

export KEEL_API_KEY="keel_sk_your_project_key"
curl -sS https://api.keelapi.com/v1/execute \ -H "Authorization: Bearer $KEEL_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: quickstart-exec-001" \ -d '{ "provider": "openai", "model": "gpt-4o-mini", "input": { "messages": [ { "role": "user", "content": "Reply with exactly: keel works" } ], "max_tokens": 16, "temperature": 0 } }' | jq

Example response:

{ "id": "exec_req_01hy0m9m1d3z5r8j52x6m7n8pq", "object": "execution", "created_at": "2026-03-11T00:00:00Z", "status": "completed", "status_code": 200, "output": { "content": [ { "type": "text", "role": "assistant", "text": "keel works" } ] }, "output_assets": [], "routing": { "requested_provider": "openai", "requested_model": "gpt-4o-mini", "selected_provider": "openai", "selected_model": "gpt-4o-mini", "reason_code": "explicit_request", "fallback_occurred": false }, "governance": { "decision": "allow", "reason": "ok", "actions": [], "constraints": null, "budgets": null }, "usage": { "input_tokens": 13, "output_tokens": 3, "total_tokens": 16, "cost_usd_micros": 7, "estimated_final": false, "metrics": [ {"meter": "input_tokens", "quantity": 13, "unit": "tokens"}, {"meter": "output_tokens", "quantity": 3, "unit": "tokens"} ] }, "timing": { "started_at": "2026-03-11T00:00:00Z", "completed_at": "2026-03-11T00:00:01Z", "duration_ms": 731 }, "error": null, "resolved": { "provider": "openai", "model": "gpt-4o-mini", "alias": null } }

If you need the associated permit id for correlation, read the x-keel-permit-id response header. The body’s governance block stays focused on the decision outcome.

Next

  • See the full SDK reference for all provider wrappers, streaming, error handling, and advanced client access.
  • If you want a decision-first integration later, start with the permit-first flow.
  • If you want the full route matrix later, come back to Route comparison.

Acceptance checks

  • I know which route to start with.
  • I know whether Keel or my app executes the provider call.
  • I know whether the response is normalized or provider-native.
  • I know where to put idempotency.
  • I know how errors are shaped.
Last updated on Edit this page on GitHub