PHP

PHP has no first-party OpenAI SDK. This page uses openai-php/client, the community-maintained library most PHP projects standardise on. It is configured through a factory, so routing through the firewall is two calls — withBaseUri and withApiKey. Everything else about your code stays the same, and the provider key stays in the vault.

Install

composer require openai-php/client

Configure

<?php

use OpenAI;

$org = getenv('VULNETIX_ORG_UUID');

$client = OpenAI::factory()
    ->withApiKey(getenv('VULNETIX_API_KEY')) // Vulnetix key, not an OpenAI key
    ->withBaseUri("guardrails.vulnetix.com/openai/{$org}/v1")
    ->make();

$result = $client->chat()->create([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => 'Hello'],
    ],
]);

echo $result->choices[0]->message->content;

Swap openai in the path for any other provider slug and pass that provider’s own model string — the gateway forwards model verbatim.

Streaming

Unchanged. The gateway relays the provider’s SSE stream.

$stream = $client->chat()->createStreamed([
    'model' => 'gpt-4o-mini',
    'messages' => [['role' => 'user', 'content' => 'Hello']],
]);

foreach ($stream as $response) {
    echo $response->choices[0]->delta->content ?? '';
}

Handling a guardrail block

A request your policy refuses never reaches the provider. It returns an OpenAI-shaped 403, which the client throws as OpenAI\Exceptions\ErrorException.

use OpenAI\Exceptions\ErrorException;

try {
    $result = $client->chat()->create([
        'model' => 'gpt-4o-mini',
        'messages' => [['role' => 'user', 'content' => $prompt]],
    ]);
} catch (ErrorException $e) {
    // getErrorCode() is the `code` field from the firewall's error body.
    if ($e->getErrorCode() === 'request_blocked') {
        throw new RuntimeException(
            'AI firewall blocked this request: ' . $e->getErrorMessage(),
            previous: $e,
        );
    }
    throw $e; // provider_denied, model_denied, model_not_allowed, provider_key_missing
}

getErrorCode() is what tells your organisation refused this apart from the provider refused this:

codeMeaning
request_blockedA content guardrail matched. The message names the rule.
provider_deniedPolicy does not allow this provider.
model_denied / model_not_allowedPolicy does not allow this model.
provider_key_missingNo provider key in the vault for this provider.

The exception exposes the standard OpenAI error fields — getErrorMessage(), getErrorCode(), getErrorType() — but not Vulnetix’s blocked_by and violations. The rule name is also in the message text; if you need the structured fields, call the endpoint with your own HTTP client and read the body. See curl & raw HTTP for the exact envelope.

Note Redaction is silent — nothing is thrown. A pii_redact rule rewrites the matched spans in your prompt to the literal [REDACTED] and forwards the request. You get an ordinary completion back, about redacted text.

Tool / function calling

Tools are forwarded untouched. Guardrails inspect the request you send, which includes the tool-result messages you append before the next call.

Gotchas

  • withApiKey takes your Vulnetix key. An OpenAI key here is the most common 401.
  • withBaseUri follows the library’s convention of a host-and-path string with no scheme (guardrails.vulnetix.com/openai/{org}/v1); it defaults to HTTPS. Keep the /v1 suffix.
  • This is a community library. If your project uses a different PHP client, the two settings are the same — find its base-URI and API-key options, and make sure the request lands on …/{orgUuid}/v1/chat/completions.