> ## Documentation Index
> Fetch the complete documentation index at: https://docs.averta.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Protect an OpenAI agent loop with Averta decisions.

Use this page when your application already calls the OpenAI SDK. The wrappers keep the OpenAI client shape and add Averta checkpoints around supported calls.

## Install

<CodeGroup>
  ```bash npm theme={null}
  npm install openai @averta-security/sdk-openai
  ```

  ```bash yarn theme={null}
  yarn add openai @averta-security/sdk-openai
  ```

  ```bash pnpm theme={null}
  pnpm add openai @averta-security/sdk-openai
  ```

  ```bash Python source theme={null}
  python3 -m venv .venv
  . .venv/bin/activate
  python3 -m pip install "openai>=2" -e packages/python-core -e packages/python-openai
  ```
</CodeGroup>

<Warning>
  Python support is source-install only until `averta-openai` is published to PyPI. Run the Python install command from the SDK repository.
</Warning>

```bash theme={null}
export OPENAI_API_KEY="your-openai-key"
export AVERTA_API_KEY="your-averta-key"
```

The OpenAI wrapper reads `AVERTA_API_KEY` from the environment. Pass `avertaApiKey` or `averta_api_key` only when this client should use a different Averta key.

## Wrap the Client

<CodeGroup>
  ```typescript TypeScript theme={null}
  import OpenAI from "openai";
  import { wrapOpenAI } from "@averta-security/sdk-openai";

  let client = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY!,
  });

  client = wrapOpenAI(client);
  ```

  ```python Python theme={null}
  import os

  from openai import OpenAI
  from averta_openai import wrap_openai


  client = wrap_openai(OpenAI(api_key=os.environ["OPENAI_API_KEY"]))
  ```
</CodeGroup>

Do not wrap the same OpenAI client twice. Create a fresh OpenAI client for each distinct Averta configuration.

## Send a Tool-capable Request

<CodeGroup>
  ```typescript TypeScript theme={null}
  const tools = [
    {
      type: "function" as const,
      name: "search_docs",
      description: "Search the internal support documentation.",
      strict: true,
      parameters: {
        type: "object",
        properties: {
          query: { type: "string" },
        },
        required: ["query"],
        additionalProperties: false,
      },
    },
  ];

  const response = await client.responses.create({
    model: process.env.OPENAI_MODEL ?? "gpt-5.4-mini",
    input: "Search the docs for password reset guidance.",
    tools,
  });
  ```

  ```python Python theme={null}
  tools = [
      {
          "type": "function",
          "name": "search_docs",
          "description": "Search the internal support documentation.",
          "strict": True,
          "parameters": {
              "type": "object",
              "properties": {"query": {"type": "string"}},
              "required": ["query"],
              "additionalProperties": False,
          },
      }
  ]

  response = client.responses.create(
      model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
      input="Search the docs for password reset guidance.",
      tools=tools,
  )
  ```
</CodeGroup>

At this point Averta has run the request checkpoint. If policy returns `restrict_tools`, the wrapper forwards only the allowed tools to OpenAI.

## Continue the Tool Loop

OpenAI function calls include a `call_id`. Use that value when you send the result back.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const functionCall = response.output.find(
    (item) => item.type === "function_call"
  );

  if (functionCall) {
    const nextResponse = await client.responses.create({
      model: process.env.OPENAI_MODEL ?? "gpt-5.4-mini",
      input: [
        ...response.output,
        {
          type: "function_call_output",
          call_id: functionCall.call_id,
          output: JSON.stringify({
            matches: ["Password reset links expire after 24 hours."],
          }),
        },
      ],
      tools,
    });

    console.log(nextResponse.output_text);
  }
  ```

  ```python Python theme={null}
  function_call = next(
      (item for item in response.output if item.type == "function_call"),
      None,
  )

  if function_call:
      next_response = client.responses.create(
          model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
          input=[
              *response.output,
              {
                  "type": "function_call_output",
                  "call_id": function_call.call_id,
                  "output": '{"matches":["Password reset links expire after 24 hours."]}',
              },
          ],
          tools=tools,
      )

      print(next_response.output_text)
  ```
</CodeGroup>

When the continuation request is sent, Averta evaluates the tool result before OpenAI sees it.

## Confirm Decisions

With an allowing policy and a tool call, Events should show a sequence like:

```text theme={null}
request -> tool_call -> tool_result -> output
```

The exact sequence depends on whether the model calls a tool. A request with no tool call can skip `tool_call` and `tool_result`. The SDK generates `requestId` and `traceId` automatically; pass `requestContext` only when you need your own `conversationId`, `requestId`, or `traceId`.

## Runnable Example

The SDK repository includes runnable OpenAI examples:

<CodeGroup>
  ```bash Node.js theme={null}
  cp examples/.env.example examples/.env
  npm --prefix examples/openai/basic install
  npm run example:openai:basic:start
  ```

  ```bash Python theme={null}
  cp examples/.env.example examples/.env
  python3 -m venv .venv
  . .venv/bin/activate
  python3 -m pip install "openai>=2" -e packages/python-core -e packages/python-openai
  npm run example:python:openai:start
  ```
</CodeGroup>

Fill `OPENAI_API_KEY` and `AVERTA_API_KEY` in `examples/.env` before running an example.

## Chat Completions

The same wrapped client also guards supported Chat Completions calls.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const completion = await client.chat.completions.create({
    model: process.env.OPENAI_MODEL ?? "gpt-5.4-mini",
    messages: [
      {
        role: "user",
        content: "Explain password reset link expiration in one sentence.",
      },
    ],
  });

  console.log(completion.choices[0]?.message.content);
  ```

  ```python Python theme={null}
  completion = client.chat.completions.create(
      model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
      messages=[
          {
              "role": "user",
              "content": "Explain password reset link expiration in one sentence.",
          }
      ],
  )

  print(completion.choices[0].message.content)
  ```
</CodeGroup>

## Python Support

Python V1 wraps sync `OpenAI` clients and guards `responses.create(...)`, `responses.create(stream=True, ...)`, `responses.stream(...)`, `chat.completions.create(...)`, and `chat.completions.create(stream=True, ...)`.

## Next Steps

<CardGroup cols={2}>
  <Card title="Responses API" icon="message" href="/openai/responses-api">
    See the guarded Responses lifecycle.
  </Card>

  <Card title="Tools" icon="toolbox" href="/openai/tools">
    Understand tool exposure and tool-call checks.
  </Card>

  <Card title="Output checks" icon="file-shield" href="/openai/output-checks">
    Evaluate final answers before returning them.
  </Card>

  <Card title="Events" icon="activity" href="/dashboard/events">
    Investigate decisions in the dashboard.
  </Card>
</CardGroup>
