.NET / C#
The official OpenAI NuGet package takes an endpoint and a credential. You set the
endpoint to the gateway and the credential to your Vulnetix API key; every call you
already make stays the same. The provider key lives in the vault, not in your
application settings.
Install
dotnet add package OpenAI
Configure
using System.ClientModel;
using OpenAI;
using OpenAI.Chat;
string org = Environment.GetEnvironmentVariable("VULNETIX_ORG_UUID")!;
ChatClient client = new(
model: "gpt-4o-mini",
credential: new ApiKeyCredential(Environment.GetEnvironmentVariable("VULNETIX_API_KEY")!),
options: new OpenAIClientOptions
{
Endpoint = new Uri($"https://guardrails.vulnetix.com/openai/{org}/v1")
});
ChatCompletion completion = client.CompleteChat("Hello");
Console.WriteLine(completion.Content[0].Text);
The credential is your Vulnetix API key, not an OpenAI key. Swap openai in
the path for any other provider slug and pass that provider’s own model string —
the gateway forwards it verbatim.
Streaming
Unchanged. The gateway relays the provider’s SSE stream.
AsyncCollectionResult<StreamingChatCompletionUpdate> updates =
client.CompleteChatStreamingAsync("Hello");
await foreach (StreamingChatCompletionUpdate update in updates)
{
if (update.ContentUpdate.Count > 0)
Console.Write(update.ContentUpdate[0].Text);
}
Handling a guardrail block
A request your policy refuses never reaches the provider. It returns an
OpenAI-shaped 403, which the SDK throws as
System.ClientModel.ClientResultException. The typed exception does not model
Vulnetix’s extra fields, so read them from the raw response.
using System.ClientModel;
using System.Text.Json;
try
{
ChatCompletion completion = client.CompleteChat(prompt);
}
catch (ClientResultException e) when (e.Status == 403)
{
using JsonDocument doc = JsonDocument.Parse(e.GetRawResponse()!.Content);
JsonElement error = doc.RootElement.GetProperty("error");
string code = error.GetProperty("code").GetString()!; // request_blocked, ...
string? rule = error.TryGetProperty("blocked_by", out var b) ? b.GetString() : null;
throw new InvalidOperationException(
$"AI firewall refused this request: {code} (rule: {rule ?? "n/a"})", e);
}
code is what tells your organisation refused this apart from the provider
refused this:
code | Meaning |
|---|---|
request_blocked | A content guardrail matched. blocked_by names the rule; violations lists every rule that matched. |
provider_denied | Policy does not allow this provider. |
model_denied / model_not_allowed | Policy does not allow this model. |
provider_key_missing | No provider key in the vault for this provider. |
pii_redact rule rewrites the
matched spans in your prompt to the literal [REDACTED] and forwards the request.
You get an ordinary ChatCompletion back, about redacted text.Tool / function calling
ChatTool definitions and the tool calls you get back are forwarded untouched.
Guardrails inspect the request you send — including the ToolChatMessage
results you add to the message list before the next call — so a tool that returns a
secret produces a request the firewall can block or redact.
Gotchas
- The
ApiKeyCredentialholds your Vulnetix key. A provider key here is the most common401. Endpointmust include the/v1suffix.ClientResultException.Statusis the HTTP status;GetRawResponse().Contentis the untouched body, which is the only placeblocked_byandviolationssurvive.- Azure OpenAI’s
AzureOpenAIClientis a different client with its own endpoint conventions — use the plainOpenAIpackage shown here when pointing at the gateway.