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

# AI Gateway Module

> Connect any OpenAI-compatible SDK to Base44's managed models via base44.aiGateway.

<Warning>
  This page is part of an AI coding agent skill and is written for agents, not humans. For the human-readable Base44 docs, see the [developer documentation](/developers).
</Warning>

# AI Gateway Module

Connect any OpenAI-compatible SDK to Base44's managed models via `base44.aiGateway`.

> **Note:** Intended for backend functions. It uses your app's models, billing, and
> credit quota — there is no API key to manage.

## Overview

The AI Gateway exposes an **OpenAI-compatible Chat Completions endpoint** backed by
Base44's managed models. `connection()` returns the `baseURL` and bearer `token` to
hand to any OpenAI-compatible client (Vercel AI SDK, Mastra, the OpenAI SDK, and
others). Calls are metered against your app's credit quota, exactly like
`integrations.Core.InvokeLLM`.

## When to use it

The gateway is for **code agents** — a backend function running an agent loop (tools,
multiple steps) the app owns. Compared to the other AI surfaces:

| Use                                 | When                                                                                                                                                                                                          |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`integrations.Core.InvokeLLM`**   | A **single** call, no tools. Don't chain it to simulate an agent loop. See [integrations.md](https://docs.base44.com/developers/skills/base44-sdk/references/integrations.md).                                |
| **In-app agents** (`base44.agents`) | **Managed and conversational** — app users talk to it and the platform runs the agent loop for you. See [base44-agents.md](https://docs.base44.com/developers/skills/base44-sdk/references/base44-agents.md). |
| **Code agents** (the gateway)       | **Programmable, not a conversation** — a backend function where **your** code owns the loop, tools, model, and result; triggered by an entity event / schedule / webhook, not a chat.                         |

## Methods

| Method         | Signature             | Description                                                  |
| -------------- | --------------------- | ------------------------------------------------------------ |
| `connection()` | `AiGatewayConnection` | Returns `{ baseURL, token }` for an OpenAI-compatible client |

Available in user mode (`base44.aiGateway`, the default — runs with the caller's
permissions) and with the service-role token (`base44.asServiceRole.aiGateway`) for
genuine cross-user or system work.

## Build a code agent

1. Guard the function with `await base44.auth.me()`, then get the connection with
   `base44.aiGateway.connection()` → `{ baseURL, token }`.
2. Point an agent SDK's OpenAI-compatible provider at it (`baseURL` + `apiKey: token`).
3. Give the agent tools that read/act on your app via `base44.*`, and let it finish by
   recording its result through a tool.

**Rules:**

* **Backend function only** (`createClientFromRequest(req)`). All other backend-function
  rules (deployment, secrets, error handling) apply — see the functions guide.
* **Run in the caller's scope by default.** Use `base44.aiGateway.connection()` and
  `base44.entities.*` so the agent runs with the calling user's permissions (RLS applies)
  and can't exceed them; guard the function with `await base44.auth.me()`. Reach for
  `asServiceRole` only for genuine cross-user/system work — and then **scope tools to
  trusted context, not agent-chosen inputs** (e.g. fix `customer_email` from the request,
  not an agent parameter), since `asServiceRole` runs with full access.
* **Stateless between invocations.** Persistent memory means storing and replaying state
  (e.g. in an entity).
* Use model **`automatic`** unless the task needs a specific model — non-default models
  use more credits: only when needed, and tell the user.
* **No streaming.**
* **Don't chain `InvokeLLM`** to fake a tool loop — use a real agent loop.
* **Always bound the loop.** `stopWhen` is an OR-list — the first condition to fire wins
  (mix a step cap like `stepCountIs`, a finish tool like `hasToolCall`, or a custom check).
  Give it room to finish but stop a runaway: **every step is another metered model call.**

Example with the Vercel AI SDK — a background reviewer the app runs on a return request:

```javascript theme={null}
import { createClientFromRequest } from "npm:@base44/sdk@0.8.36";
import { ToolLoopAgent, tool, stepCountIs, hasToolCall } from "npm:ai@7.0.16";
import { createOpenAICompatible } from "npm:@ai-sdk/openai-compatible@3.0.5";
import { z } from "npm:zod@4.4.3";

Deno.serve(async (req) => {
  const base44 = createClientFromRequest(req);
  const user = await base44.auth.me();
  if (!user) return Response.json({ error: "Unauthorized" }, { status: 401 });

  const { return_id } = await req.json();
  const request = await base44.entities.ReturnRequest.get(return_id);

  const { baseURL, token } = base44.aiGateway.connection();
  const base44Models = createOpenAICompatible({ name: "base44", baseURL, apiKey: token });

  const agent = new ToolLoopAgent({
    model: base44Models("automatic"),
    instructions:
      "Decide whether this return looks fine or needs the owner's attention. " +
      "Check the customer's past orders as many times as you need, then submit your verdict.",
    tools: {
      searchOrders: tool({
        description: "This customer's past orders, optionally filtered by status",
        inputSchema: z.object({ status: z.string().optional() }),
        execute: ({ status }) => {
          const query = { customer_email: request.customer_email };
          if (status) query.status = status;
          return base44.entities.Order.filter(query, "-created_date", 50);
        },
      }),
      submitVerdict: tool({
        description: "Record the final verdict. Call this once, when you've decided.",
        inputSchema: z.object({ decision: z.enum(["approved", "flagged"]), reason: z.string() }),
        execute: ({ decision, reason }) =>
          base44.entities.ReturnRequest.update(return_id, { status: decision, review_note: reason }),
      }),
    },
    // stops at the first to trigger — submitVerdict was called, or 8 steps elapsed;
    // mix whatever conditions fit the task (a step cap, a finish tool, a custom condition)
    stopWhen: [stepCountIs(8), hasToolCall("submitVerdict")],
  });

  await agent.generate({ prompt: `Review this return request: ${JSON.stringify(request)}` });
  return Response.json({ ok: true });
});
```

**Images:** when the agent needs to see an image, pass it as an image part in `messages`:

```javascript theme={null}
const { text } = await agent.generate({ messages: [{ role: "user", content: [
  { type: "text", text: `Review this receipt: ${JSON.stringify(receipt)}` },
  { type: "image", image: receipt.image_url },
]}]});
```

Any OpenAI-compatible agent SDK works the same way — construct its provider/client with
the gateway's `baseURL` and `token`.

## Models

Pass a model id as the client's `model`. Use **`automatic`** (the default, cheapest)
unless the task needs a specific model (e.g. `claude_sonnet_4_6`). Non-default models
cost more credits — use them only when needed, and tell the user.

## Notes

* **Backend only.** The realistic entry point is a backend function via
  `createClientFromRequest(req)`. `token` is the current caller's bearer — the app
  user's token for `base44.aiGateway`, the service-role token for
  `base44.asServiceRole.aiGateway`, or an empty string when unauthenticated.
* **No streaming.**
* **Billing:** metered per call against your app's credit quota (same as InvokeLLM).

## Type Definitions

```typescript theme={null}
/**
 * A connection to the Base44 AI Gateway — the base URL and bearer token to use
 * with any OpenAI-compatible client pointed at the gateway.
 */
interface AiGatewayConnection {
  /** Base URL of the gateway's OpenAI-compatible endpoint. */
  baseURL: string;
  /** Bearer token used to authenticate requests to the gateway. */
  token: string;
}

interface AiGatewayModule {
  connection(): AiGatewayConnection;
}
```
