# Gateway integration

Switching with the OpenAI SDK, Responses API and Chat Completions, streaming, mask-only usage, and virtual keys.

When you move your existing OpenAI integration to the Gateway, only two values change:

- `base_url` → `https://gw-tr.gurubase.io/v1`
- API key → the virtual key you generate in the [panel](https://gateway-tr.gurubase.io)

The rest is the standard OpenAI SDK; the model name, parameters, and response format stay the same. Masking runs automatically on every request: the input is masked before it is forwarded to the model.

## Drop-in switch

In the examples below, only the `base_url` and key lines are specific to the Gateway; the rest of the code is identical to the version that goes directly to the provider.

### Responses API

The default path is the Responses API. The name and the TCKN (Turkish national ID number) in the example are masked before reaching the model.

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://gw-tr.gurubase.io/v1",
    api_key="SANAL_ANAHTAR",
)

resp = client.responses.create(
    model="gpt-4o-mini",
    input="Ahmet Yılmaz, TCKN 10000000382, adres değişikliği istiyor.",
)
print(resp.output_text)
```

```bash
curl https://gw-tr.gurubase.io/v1/responses \
  -H "Authorization: Bearer $SANAL_ANAHTAR" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "Ahmet Yılmaz, TCKN 10000000382, adres değişikliği istiyor."
  }'
```

```ts
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://gw-tr.gurubase.io/v1",
  apiKey: process.env.SANAL_ANAHTAR,
});

const resp = await client.responses.create({
  model: "gpt-4o-mini",
  input: "Ahmet Yılmaz, TCKN 10000000382, adres değişikliği istiyor.",
});
console.log(resp.output_text);
```

### Chat Completions

If your code uses `chat.completions`, you do not need to switch to the Responses API; the same two changes are enough here as well. The Python and TypeScript examples from this point on continue with the `client` defined above.

```python
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Ayşe Demir'in talebini özetle."},
    ],
)
print(resp.choices[0].message.content)
```

```bash
curl https://gw-tr.gurubase.io/v1/chat/completions \
  -H "Authorization: Bearer $SANAL_ANAHTAR" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "user", "content": "Ayşe Demir'\''in talebini özetle." }
    ]
  }'
```

```ts
const resp = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "Ayşe Demir'in talebini özetle." }],
});
console.log(resp.choices[0].message.content);
```

## Streaming

When you set `stream: true`, the response arrives chunk by chunk over SSE. The masking step does not move: the input is masked before it goes to the model, and the stream is generated from the masked text.

```python
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    stream=True,
    messages=[{"role": "user", "content": "Toplantı notlarını madde madde özetle."}],
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="", flush=True)
```

```ts
const stream = await client.chat.completions.create({
  model: "gpt-4o-mini",
  stream: true,
  messages: [{ role: "user", content: "Toplantı notlarını madde madde özetle." }],
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```

## Mask-only (`gurubase-siper`)

You can get masking only, from the same endpoint, without sending the text to a language model. Set the `model` field to the reserved value `gurubase-siper`; the Gateway masks the text and returns the masked version directly.

```bash
curl https://gw-tr.gurubase.io/v1/responses \
  -H "Authorization: Bearer $SANAL_ANAHTAR" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gurubase-siper",
    "input": "Vatandaş Ahmet Yılmaz, TCKN 10000000382, başvuru durumu nedir?"
  }'
```

The masked text is returned in the `output_text` field:

```text
Vatandaş <PERSON_1>, TCKN <TCKN_1>, başvuru durumu nedir?
```

The request never reaches any language model; `gurubase-siper` is not a language model but the reserved model name the Gateway sets aside for masking, and it also works with Chat Completions. If masking cannot be performed, the request stops with a 502 and the raw text is not returned either (fail-closed). If you also need the detection report (the list of categories and positions), use the `/mask` endpoint directly: [Mask-only usage](/docs/en/guides/mask-only/).

## Virtual key

All requests are authenticated with the virtual key in the `Authorization: Bearer` header. You generate the virtual key in the panel; the real provider key stays inside the Gateway only, so you do not need to keep it in your application. You can revoke a key in the panel and generate a new one. See [Panel](/docs/en/panel/) for the steps.

## Listing models

You get the models you can access from the `/v1/models` endpoint; the reserved `gurubase-siper` name also appears in the list.

```bash
curl https://gw-tr.gurubase.io/v1/models \
  -H "Authorization: Bearer $SANAL_ANAHTAR"
```

To use masking without the Gateway, as a step in your own pipeline, see [Mask-only usage](/docs/en/guides/mask-only/); to try it without writing code, see [Playground](/docs/en/guides/playground/).

If you are looking for a ready-made enterprise assistant instead of writing your own application, [Gurubase](https://gurubase.io) offers agents that connect to your organization’s knowledge sources (Confluence, Zendesk, Google Drive, your website, and more), ground their answers in those sources, and cite them; it can be deployed in the cloud or on-premise.
