# AI gateway in Go: capped model calls for GoCommerce

> One place a GoCommerce store calls a model: the install’s Anthropic key paid from AI credit, or the store’s own key and cap, with data-sharing switches.

- Canonical: https://kitcommerce.store/integrations/ai-gateway/
- Last updated: 2026-10-30

---

Platform

## AI gateway in Go

A Go package that every model call in a GoCommerce store goes through. On an install with an Anthropic key of its own, every store has AI with nothing to set up, paid from its AI credit; a store may bring its own key and a monthly cap instead. Every run is recorded, and switches decide which kinds of data may leave the store. Beside it sits a queue where a person approves what an agent proposes.

- **Platform** module
- **28** settings
- **100** tests
- **16** API operations
- **ext/ai-gateway**

### What it does

In the package’s own words, it “is the one place in the engine that calls a model.” A module that wants model work does not write a prompt and call an API; it registers a named task in Go, with its instructions, the JSON Schema its answer must satisfy, a small and a strong model to try in turn, and a check of its own. The gateway runs it, records it and holds it to the store’s credit or cap.

Give the install an Anthropic key of its own, ANTHROPIC_API_KEY on the reference binary, and the AI gateway plugin is on for every store from the start. A store that enters no key runs on the install’s key, at the models and prices the install names, and each call is paid from the store’s AI credit: a free trial allowance it starts with, plus what the install’s operator tops up with the admin token. A store may paste its own Anthropic or OpenAI key instead; it is then billed by its provider and draws no credit. Without an install key the gateway installs idle, and a store needs a key, a monthly cap and a price for each model before anything is called.

Every run leaves one row in ai_executions: the task and its version, each step tried, the model that answered, the input, output and cache tokens, how long it took, the outcome, and the cost, which is tokens times the price per million in millionths of a minor unit, an integer with no rounding. The owner decides which kinds of store data may leave: the catalogue, order lines, contact details, message bodies and documents. Contact details and message bodies stay in until switched on, and documents too unless the install runs AI on its own key.

The panel gains an AI section with three screens: Usage, which sets this month’s spend by day, task and model beside the store’s AI credit; Jobs, the queue of model work with retry and cancel; and Approvals, where a person decides what an agent proposed. Four modules use the gateway today: Create from photos (photo-products), Improve with AI (catalog-ai), review summaries (reviews), and the Amazon importer’s rewrite of a listing. None has registered an action for the approval queue yet.

### Configuration

The install’s own key, models, prices and currency rates are Config fields, which the reference binary reads from ANTHROPIC_API_KEY and the AI_PLATFORM\_ variables. Everything a store chooses is a setting of the AI gateway plugin, under Settings › Plugins, read again on every run so a key or a cap typed a moment ago counts. The reference binary installs the module with -ai-gateway, and -photo-products and -catalog-ai bring it with them.

*AI gateway module settings — 28 settings, 0 required*

| Setting | Environment variable | Required | What it does |
| --- | --- | --- | --- |
| `PlatformAnthropicKey` | `ANTHROPIC_API_KEY` | No | The install’s own Anthropic key. A store with no key of its own makes its calls on it and pays from its AI credit; the store never sees it. Empty: only a store with a key of its own has AI. |
| `PlatformSmallModel` | `AI_PLATFORM_SMALL_MODEL` | No | The small model calls on the install’s key use. Empty is claude-haiku-5-5. |
| `PlatformStrongModel` | `AI_PLATFORM_STRONG_MODEL` | No | The strong model calls on the install’s key use. Empty is claude-sonnet-5-5. |
| `PlatformSmallPrices` | `AI_PLATFORM_SMALL_PRICES` | No | What Anthropic charges for the small model, in US dollars per million tokens: input, output, cache read and cache write. Empty is Anthropic’s published price for the default model. A model named without prices is not called on the install’s key. |
| `PlatformStrongPrices` | `AI_PLATFORM_STRONG_PRICES` | No | The same, for the strong model. |
| `PlatformUSDRates` | `AI_PLATFORM_USD_RATES` | No | Units of each currency to one US dollar, as comma-separated CODE=rate pairs. A store in US dollars needs none; a store in a currency with no rate cannot use the install’s key, because no rate is assumed. |
| `FreeTrialMinor` | — | No | The AI credit each new store starts with, in minor units of its currency. The figure shipped is a placeholder for the install’s operator to set, and it can also be set per store with the admin token. Go only. |
| `provider` Provider | — | No | anthropic or openai; anthropic by default. Used only with the store’s own key. Each provider’s API address is a constant in the code, so there is no custom address to set. |
| `api_key` API key | — | No | The store’s own key, from console.anthropic.com or platform.openai.com; calls are billed to it and draw no AI credit. Needed when the install has no key of its own; on one that has, the field reads “Use your own key instead” and may stay empty. A secret field, never handed to the storefront, and stored sealed when the install sets GOCOMMERCE_SECRETS_KEY. |
| `small_model` Small model | — | No | Tried first, with the store’s own key. Defaults to claude-haiku-5-5, so a store on OpenAI names one of OpenAI’s models here. A store that saved its settings earlier keeps the model it saved. |
| `strong_model` Strong model | — | No | Asked when the small model’s answer fails its checks, with the store’s own key. Defaults to claude-sonnet-5-5. |
| `monthly_cap` Monthly cap | — | No | The most the store spends on models in a calendar month (UTC), in minor units of its currency: 5000 is 50.00 in a two-decimal currency. A fraction rounds down. Needed with the store’s own key; optional on the install’s, where the AI credit is the limit, and held there too when set. Work that would pass it waits for a person. |
| `small_price_input` Small model: input price | — | No | Minor units per million input tokens, from your provider’s price list: $1.00 per million is 100. Needed with the store’s own key: a model without an input and an output price, or priced at 0, is never called. |
| `small_price_output` Small model: output price | — | No | Minor units per million output tokens. A fraction rounds up, so it can only make the cap stricter. |
| `small_price_cache_read` Small model: cache read price | — | No | Per million tokens read from the provider’s cache. Empty or 0 means the input price. |
| `small_price_cache_write` Small model: cache write price | — | No | Per million tokens written to the provider’s cache. Empty or 0 means the input price. |
| `strong_price_input` Strong model: input price | — | No | As for the small model. Without it, a run that climbs to the strong model stops there. |
| `strong_price_output` Strong model: output price | — | No | Minor units per million output tokens. |
| `strong_price_cache_read` Strong model: cache read price | — | No | Empty or 0 means the input price. |
| `strong_price_cache_write` Strong model: cache write price | — | No | Empty or 0 means the input price. |
| `share_catalogue` Share the catalogue | — | No | On by default. Product titles, descriptions, attributes and prices may be sent. |
| `share_order_lines` Share order lines | — | No | On by default. What was bought, how many and the totals — never names or addresses. |
| `share_contact_details` Share contact details | — | No | Off by default. Customers’ names, emails, phone numbers and addresses. |
| `share_message_bodies` Share message bodies | — | No | Off by default. The text of customers’ messages, which review summaries need. |
| `share_documents` Share documents | — | No | PDFs and images, sent to the provider as files. On by default when the install has a key of its own, so Create from photos works as it is; off otherwise. |
| `CallTimeout` | — | No | Bounds one call to a provider; 60 seconds when zero. Go only. |
| `PollInterval` | — | No | How often the job runner looks for due work; five seconds when zero. Go only. |
| `Client` | — | No | Replaces the HTTP client, which tests do to answer in a provider’s place. The provider hosts stay constants either way. Go only. |

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own `main()` you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

### Setting it up

1. **Install the module** — Run the reference binary with -ai-gateway, or with -photo-products or -catalog-ai, which bring it; or pass aigateway.New to gocommerce.New in your own main(), as below. The site’s backend + admin quick start does not install it.
2. **The install’s key, or each store’s** — Give the engine an Anthropic key in ANTHROPIC_API_KEY and every store with no key of its own runs on it; a store outside US dollars needs its currency in AI_PLATFORM_USD_RATES. Without an install key, each store sets a key, a monthly cap and each model’s prices under Settings › Plugins › AI gateway.
3. **AI credit** — Each store starts with a free trial allowance. The install’s operator tops a store up, or changes its free trial, on the AI usage screen with the install’s admin token. A store cannot buy credit itself.
4. **Give it work** — Create from photos, Improve with AI and review summaries run through it, and so does the Amazon importer’s rewrite. A module of your own registers a task and runs it now, or queues it in the transaction that caused it.

main.go

```
import (
	"os"

	"github.com/itswadesh/gocommerce/core"
	aigateway "github.com/itswadesh/gocommerce/ext/ai-gateway"
	catalogai "github.com/itswadesh/gocommerce/ext/catalog-ai"
	photoproducts "github.com/itswadesh/gocommerce/ext/photo-products"
	"github.com/itswadesh/gocommerce/ext/reviews"
)

// With no install key it starts idle: nothing is called until a store sets a key, a cap and prices.
gw := aigateway.New(aigateway.Config{PlatformAnthropicKey: os.Getenv("ANTHROPIC_API_KEY")})

app, err := gocommerce.New(cfg, gw,
	photoproducts.New(photoproducts.Config{Gateway: gw}),
	catalogai.New(catalogai.Config{Gateway: gw}),
	reviews.New(reviews.Config{Gateway: gw}),
)
```

Wired as the reference binary wires it in cmd/gocommerce/main.go; cfg is your gocommerce.Config. Hand the gateway to the Amazon importer the same way, amazon.Config{Gateway: gw}, to move its rewrite onto it. Import path `github.com/itswadesh/gocommerce/ext/ai-gateway`.

### How it works

- **One run, one record**

  A run tries the task’s deterministic step, then the cache, then each model on its ladder. An answer is checked against the task’s schema with unknown fields refused, then by the task’s own check; one that fails moves up the ladder with the reason written down.

- **Reserved before the call**

  The most a call could cost, every input token at the dearest input-side price plus every output token, is held with one conditional UPDATE against the store’s AI credit on the install’s key, and against the month’s cap, so runs racing for the last of the money cannot both have it. Afterwards it is settled to what the provider reported.

- **Cost in integers**

  Prices are minor units per million tokens, so a call costs tokens times price in millionths of a minor unit, exact with no division. The install’s dollar prices become the store’s currency at its rate, rounded up. A call that left and reported nothing back is charged at its ceiling and marked as an estimate.

- **The install’s key stays the install’s**

  A store never sees the install’s key. When Anthropic refuses a call on it, the store sees the status and the kind of failure, and the operator’s log has Anthropic’s words. A store’s own key that will not open is not quietly swapped for the install’s.

- **Only what the owner allows leaves**

  A task tags what it sends by class, and a class the owner has not allowed is dropped before sending. With contact details off, an email address or an international phone number found elsewhere is replaced. What is sent is fenced in \<data> blocks the model is told to treat as data.

- **Retries only where waiting helps**

  Queued work is claimed with FOR UPDATE SKIP LOCKED, stores taking turns. A timeout, a rate limit or a provider outage is retried with backoff, up to 12 attempts; a refusal, an answer that fails on the strong model, a spent cap or credit, or a missing price goes straight to failed, for a person.

- **Approval runs what was seen**

  A proposal waits seven days. Its preview is recomputed when opened and again on approval; if the store moved in between, nothing runs. Only a person signed in to the panel decides — not an API key or the admin token — holding ai.approve and the action’s own right.

### What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

- **Anthropic and OpenAI only** — Two providers, each at a fixed host: Anthropic’s Messages API and OpenAI’s chat completions, and the install’s own key is Anthropic’s. There is no custom address, so a self-hosted or other model cannot be reached through the gateway, and a provider that redirects is not followed.
- **No credit, no calls** — On the install’s key, a store with no AI credit left is refused before any model is called, and a store cannot buy credit itself: the install’s operator tops it up with the admin token. On a store’s own key, a missing key, cap or price stops the call, and a model priced at 0 is never called.
- **A currency needs a rate** — The install’s key is priced in US dollars. A store in another currency can use it only when the install gives that currency a rate; otherwise the store is told so and nothing is sent.
- **The approval queue has no actions yet** — The queue, its rules and its screen are built, but no module registers an action, so nothing can be proposed into it today. Agent keys only read for the same reason.
- **Nothing queues work yet** — Every task today, from photos to review summaries, runs directly rather than through the job queue, so the Jobs screen stays empty until a module queues work.
- **No embeddings** — An Embedder interface is declared and nothing implements it. There is no vector or semantic search.
- **Not in the quick start** — The site’s backend + admin quick start does not install the AI gateway. It is a module you install when you run GoCommerce yourself, and this page describes the module, not any hosted panel.
- **Not tried against a live provider** — The tests run against PostgreSQL, with each provider answered by a recorded response from a local test server; none calls Anthropic’s or OpenAI’s real API.

FAQ

### Questions about the AI gateway module

**Does a store need its own key?**

Not on an install with an Anthropic key of its own: the plugin is on for every store, pictures may be sent, and a store with no key runs on the install’s, paid from its AI credit. Without an install key, a store sets its own key, a monthly cap and each model’s prices before anything is called.

**Which models can it use?**

On the install’s key, the models the install names: Claude Haiku 5.5 and Claude Sonnet 5.5 unless AI_PLATFORM_SMALL_MODEL and AI_PLATFORM_STRONG_MODEL say otherwise. On a store’s own key, whatever that key reaches, named in the Small model and Strong model settings: claude-haiku-5-5 and claude-sonnet-5-5 by default on Anthropic, or OpenAI’s models by name. Check connection on the AI usage screen says whether the provider offers each name.

**Who pays for the calls?**

On the install’s key, the store pays per use from its AI credit, starting with a free trial allowance. Only a model call draws credit: a cached answer, an answer worked out without a model and every feature that is not AI draw none. On its own key, the store pays its provider and draws no credit; the gateway works out each call’s cost from the prices typed in and stops at the monthly cap, and the provider’s bill is the one that counts.

**Does customer data reach the model?**

Only the kinds the owner allows. The catalogue and order lines are allowed by default, and documents too on an install with its own key; contact details and message bodies are off until switched on. With contact details off, an email address or an international phone number that slipped into other data is replaced before sending, and each run’s record keeps the policy it ran under.

**Is this an Anthropic or OpenAI partnership?**

No. The module calls their public APIs with the install’s key or one the store supplies. Neither company endorses GoCommerce, and no store is known to run this module in production.

### Related modules

Each is a directory under `ext/`, imported the same way. Where this one fits in the store: [AI in GoCommerce: the gateway, agent keys and MCP](https://kitcommerce.store/features/ai/).

- [Storefront banners in Go Keep a GoCommerce storefront’s home page pictures as rows: slides across the top, grids of tiles under a heading, a phone picture, a switch and one saved order.](https://kitcommerce.store/integrations/banners/)
- [CMS content pages in Go Add about, terms and delivery pages to a GoCommerce store: one page per slug and language, draft or published, served at /x/cms/pages/{slug}.](https://kitcommerce.store/integrations/cms/)
- [Contact form API in Go A GoCommerce contact form and product enquiries in one inbox: announced by email, answered from the admin, rate-limited, with a honeypot against bots.](https://kitcommerce.store/integrations/contact/)
- [Ecommerce FAQ API in Go Give a GoCommerce store a page of questions and answers: grouped into sections, ordered by hand, draft or published, served whole at /x/faq.](https://kitcommerce.store/integrations/faq/)

### Source

Everything on this page is read from [`ext/ai-gateway`](https://github.com/itswadesh/gocommerce/tree/main/ext/ai-gateway) in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.Anthropic, Claude and OpenAI are trademarks of their owners; this module calls their public APIs with the install’s key or one the store supplies, and implies no endorsement by either company. See [trademarks](https://kitcommerce.store/about/#trademarks).

- [ext/ai-gateway on GitHub](https://github.com/itswadesh/gocommerce/tree/main/ext/ai-gateway)
- [All GoCommerce modules](https://kitcommerce.store/integrations/)

### Try it against a store of your own

The backend + admin quick start runs GoCommerce’s API and admin on your own machine, without a storefront. Add this module to it and try it on test orders before a real one depends on it.

[Backend + admin quick start](https://kitcommerce.store/#one-command) · [Read the module](https://github.com/itswadesh/gocommerce/tree/main/ext/ai-gateway) · [All integrations](https://kitcommerce.store/integrations/)
