Skip to main content
Customer guide

AI gateway and API

Route a named application through a verified gateway path and observe the downstream decision.

For: Application administrator, Security policy owner, Developer

Before you begin

Choose the application, provider, model and test account. Obtain the application owner’s approval to route only that workload, and use a synthetic prompt rather than a production credential or customer record.

  1. Confirm the provider integration and proof status on /integrations.
  2. Keep provider credentials in your authorized application configuration, not in a support message.

Supported scope and current status

Checks what configured applications explicitly route through RedactWall and what comes back, before either direction is forwarded. Every gateway decision is recorded, and a request that cannot be recorded is refused rather than allowed through. Direct provider traffic bypasses it. The published Anthropic live-service proof is dated August 14, 2026. It does not establish current release readiness or browser coverage. Other provider integrations show distinct build/test status.

  1. Identify the exact routed application and direction.
  2. Do not extend Anthropic proof to another provider or to browser interception.

Compare this path with the published coverage table and the coverage guide.

Set up the path

Have the application administrator configure the supported gateway endpoint and approved model/policy mapping using release-specific instructions. RedactWall assists with the tenant-side handoff; your team controls the application route.

  1. Verify the intended application route before enabling users.
  2. Keep a controlled way to disable or roll back the route.

Use the workflow

Send an allowed synthetic request and a sensitive synthetic request through the configured application. Observe streamed and non-streamed completion separately if both are in scope.

  1. Check the response or refusal delivered to the application.
  2. Compare it with a deliberate direct-provider control to expose bypass.

Verify the result

Verify the bytes or refusal the upstream provider and application actually receive, then match a content-free decision event. A gateway record is not proof for a request that used a different route.

  1. Check the selected provider/model and policy revision.
  2. Confirm a failed evidence commit refuses an inline send on the verified route.

Coverage references: 13 requirements, 0 currently passed

This guide is bound to 13 requirements in RedactWall's acceptance crosswalk, which is maintained internally and not published. A requirement counts as passed here only after current evidence for every bound scenario and authority has been published; none has been published yet.

See the public verification overview and the documentation coverage guide.

Denials and recovery

If routing, authorization, provider scope or evidence is uncertain, pause the application change and use the agreed fallback. Never silently send sensitive data directly to the provider to make a failed test pass.

  1. Read the error without copying secrets.
  2. Restore the last approved route and re-test with synthetic data.

For customer-side next steps, read Recovery and support.

Billing and integration handoffs

Gateway integration is separate from device-seat admission and from a provider’s own charges. The proposed first pilot can include an Anthropic application only when it is explicitly scoped and independently verified.

  1. Confirm the supported provider and your provider agreement.
  2. Review /pricing for the RedactWall commercial boundary.

Limits to keep in view

A gateway cannot govern traffic an application never routes through it. Dated live proof does not establish current release readiness, every SDK behavior or every provider integration.

  1. Publish the exact provider, application and route tested.
  2. Keep unsupported streaming, model and bypass cases explicit.

Review the current Disclosures before relying on a capability.

Scan API developer quickstart

Call POST /v1/scans from your application to obtain an advisory inspection result. This is separate from the provider gateway described above: it does not forward a prompt to a provider, enforce the returned decision, or create an evidence receipt. The result carries evidence_recorded: false.

RedactWall remains pre-release and targets a supervised pilot. These recipes describe source at revision ef77201d9aeee1f0280a204aa9cb3258d6adfdc3. Source availability to authorized repository users does not establish registry publication, a deployed Scan API, public repository access, or parity between language clients. To inspect a source reference below, run its read-only git show command in your authorized skellywix/RedactWall checkout containing this revision. These local references require no off-site navigation.

Prepare the caller

  1. Obtain the exact source revision through your approved source-access process and choose the language below.
  2. For a synthetic trial, use a localhost TLS fixture with a test key and a scripted response. The Python and Java source examples include such fixtures. The recipes below are callable functions; they need fixture inputs and do not start a server or enroll a key.
  3. For a separately authorized deployment, obtain its HTTPS origin, dedicated scan_client enrollment, admitted detector revision and Ed25519 signing authority from the operator. A freshly generated key is not an enrollment. Use only scheme, host and optional port for the origin, with no trailing slash, path, credentials, query or fragment. Each transport appends /v1/scans itself.
  4. Keep input synthetic. Do not log submitted content, prepared request bodies, private keys or raw server responses. Retain TLS certificate and hostname verification, including when supplying private fixture roots.
Go source recipe

Use an authorized RedactWall source checkout at the revision above with Go 1.26.9. The module path is github.com/skellywix/redactwall-v2; import its scanclient package. For a separate application, resolve that module to your local checkout with a go.mod replace directive. This is a local source dependency, not a published module-version recommendation.

Supply a synthetic fixture key, its detector revision and a trusted HTTP client for your local HTTPS fixture. For an admitted deployment, these inputs must instead come from the approved scan_client enrollment. Client and Now are required. Retain certificate and hostname verification in the supplied transport.

Call NewScanClient once when configuring the workload and reuse the returned Publisher for every ScanSynthetic call. Its concurrency limit is per Publisher; constructing another instance creates another independent allowance. The caller retains ownership of the supplied HTTP transport.

package example

import (
    "context"
    "crypto/ed25519"
    "net/http"
    "time"

    "github.com/skellywix/redactwall-v2/scanclient"
)

func NewScanClient(origin string,
    key ed25519.PrivateKey, revision string,
    trustedHTTP *http.Client) (*scanclient.Publisher, error) {
    return scanclient.New(scanclient.Config{
        BaseURL: origin,
        SigningKey: key,
        DetectorRevision: revision,
        Client: trustedHTTP,
        Now: time.Now,
        RequestTimeout: 5 * time.Second,
        MaxConcurrent: 1,
    })
}

func ScanSynthetic(ctx context.Context, client *scanclient.Publisher) (scanclient.Result, error) {
    return client.Scan(ctx, []byte("Synthetic demonstration content."))
}

Timeout scope: The five-second context starts inside Scan after input validation and admission, before projection and signing. It bounds context-aware HTTP work, but cannot preempt synchronous signing or a caller-supplied transport that ignores context. Client construction and caller work are outside this budget.

Handle the returned error before reading the result. errors.As can extract scanclient.RefusalError (Status and Code); errors.Is can identify scanclient.ErrRefused. An empty Code means the refusal body did not provide a usable code.

  • Go client APIgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/scanclient.go
  • Go contract testsgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/contract_conformance_test.go
Node.js source recipe

With Node 24.19.0, save this ESM module at the authorized RedactWall checkout root so the relative import resolves. For a separate application, the source package consists of package.json, index.mjs and index.d.mts in scanclient/node. Its declared name is @redactwall/scanclient, version 0.0.0, private: true. No npm registry install is implied.

Supply an Ed25519 private KeyObject, the fixture revision and its HTTPS origin. ca is optional PEM trust for that fixture; verification stays enabled. Pass an AbortSignal when the caller needs cancellation. Keep the signing key in the caller process.

Call createScanClient once during workload setup and reuse that client for every scanSynthetic call. The in-flight counter belongs to that instance, so a new client for each call would bypass the intended workload cap.

import { ScanClient } from './scanclient/node/index.mjs';

export function createScanClient({
  origin, signingKey, detectorRevision, ca,
}) {
  return new ScanClient({
    baseURL: origin,
    signingKey,
    detectorRevision,
    requestTimeoutMs: 5000,
    maxConcurrent: 1,
    ca,
  });
}

export async function scanSynthetic(client, { signal } = {}) {
  return await client.scan('Synthetic demonstration content.', { signal });
}

Timeout scope: The five-second deadline starts inside scan before content encoding and signing, and is checked again before transmission. Synchronous work cannot be interrupted by its timer. Construction and caller processing are outside this budget; it is not an end-to-end runtime guarantee.

Let a rejected promise stop the caller workflow. ScanError.kind identifies failures; RefusalError additionally carries status and refusalCode. The refusal code may be empty. A successful HTTP response with an invalid result is answer_unusable, not an allow decision.

  • Node API and typesgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/node/index.d.mts
  • Private source packagegit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/node/package.json
  • External Node consumer testgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/node/test/consumer.test.mjs
Python source recipe

With Python 3.10+ at the authorized checkout revision above, run python scanclient/python/build-archive.py <existing-owned-directory>/redactwall-scanclient.zip from the checkout root. Replace <existing-owned-directory> with an existing directory you own; the output ZIP must not exist. The standalone archive contains only redactwall_scanclient.py and redactwall_https.py and uses the Python standard library. Copy it to your application and replace the path placeholder below with its absolute ZIP path before importing the modules. The build does not install anything or contact a service; this is not a published PyPI package or a complete SDK for other API operations. The separate upstream synthetic TLS fixture also requires Node and OpenSSL.

The caller supplies a raw 32-byte Ed25519 public key and a signer callback returning a raw 64-byte signature over the exact projection bytes it receives. Do not replace the signer with a dummy signature. The source example provides a synthetic signer and ephemeral localhost TLS fixture; a real integration needs an approved key provider.

Call create_scan_transport once and reuse that transport for every scan_synthetic call. Keep using the same instance after a timeout: a worker still blocked in OS DNS retains its capacity until it actually exits. Recreating the transport would discard that shared admission bound.

from datetime import datetime, timezone
import sys

# Replace with the absolute path to your built ZIP, before either SDK import.
sys.path.insert(0, "/absolute/path/to/redactwall-scanclient.zip")
from redactwall_scanclient import prepare_request
from redactwall_https import HTTPSScanTransport


def create_scan_transport(origin, ca_pem=None):
    return HTTPSScanTransport(
        origin, request_timeout_ms=5000, max_concurrent=1, ca_pem=ca_pem,
    )


def scan_synthetic(client, revision, public_key, signer):
    request = prepare_request(
        b"Synthetic demonstration content.",
        detector_revision=revision,
        observed_at=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
        public_key=public_key,
        signer=signer,
    )
    return client.send(request)

Timeout scope: Request preparation and signing run outside the five-second transport budget, which starts on admission in send. Budget the signer separately. A timed-out DNS worker can outlive the caller deadline while still occupying the shared transport capacity.

Propagate ScanError and TransportError instead of creating a clean result. RefusalError carries status and refusal_code. PreparedRequest.body contains the submitted content: never print or log it. The HTTPS adapter owns its bounded worker/socket cleanup; it does not expose the Node AbortSignal API.

  • Standalone Python ZIP buildgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/python/build-archive.py
  • External Python ZIP consumer testgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/python/test_archive_consumer.py
  • Python request and result APIgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/python/redactwall_scanclient.py
  • Python HTTPS adaptergit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/python/redactwall_https.py
  • Runnable synthetic Python fixturegit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/python/example_synthetic.py
Java source recipe

Use JDK 21 and the authorized checkout. scanclient/java/build-jar.ps1 -OutputPath <existing-directory>/redactwall-scanclient.jar builds the four production classes into a new local JAR; the output file must not exist. Put that JAR on your application classpath. No Maven coordinates or registry publication are established by this build.

Supply a synthetic KeyPair and revision, the fixture HTTPS origin, a caller-resolved InetAddress, and the fixture certificate roots. The transport connects to that address but verifies the origin hostname. DNS resolution belongs to the caller and occurs outside the transport deadline. A null roots argument selects platform trust.

Call createClient once and reuse the transport throughout the workload. Pass a per-call Cancellation to scanSynthetic and retain it if cancellation is needed. In the owning workload's finally block, call closeClient once at shutdown, after all intended scans; do not close the shared client after each scan.

import com.redactwall.scanclient.ScanProtocol;
import com.redactwall.scanclient.ScanTransport;
import java.net.InetAddress;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;

public final class ScanExample {
    public static ScanTransport createClient(
            String origin, InetAddress address, List<X509Certificate> roots) throws Exception {
        return new ScanTransport(origin, address, roots, Duration.ofSeconds(5), 1);
    }

    public static ScanProtocol.Result scanSynthetic(
            ScanTransport client, KeyPair key, String revision,
            ScanTransport.Cancellation cancellation) throws Exception {
        var request = ScanProtocol.prepare(
            "Synthetic demonstration content.", revision,
            Instant.now().truncatedTo(ChronoUnit.SECONDS), key);
        return client.start(request, cancellation).await();
    }

    public static void closeClient(ScanTransport client) throws InterruptedException {
        client.close();
        if (!client.awaitTermination(Duration.ofSeconds(5))) {
            throw new IllegalStateException("Scan transport cleanup incomplete");
        }
    }
}

Timeout scope: The five-second transport deadline starts in start. Caller DNS resolution, client construction, request preparation and signing occur beforehand. The shutdown wait in closeClient has a separate five-second budget and is not part of the request timeout.

ScanProtocol.ScanException reports preparation/decoding failures. ScanTransport.TransportException exposes kind() and, for refusals, refusal(). At workload shutdown, close the transport and await termination; do not treat an interrupted or incomplete shutdown as a successful integration.

  • Java protocol APIgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/java/src/com/redactwall/scanclient/ScanProtocol.java
  • Java transport APIgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/java/src/com/redactwall/scanclient/ScanTransport.java
  • Local JAR buildgit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/java/build-jar.ps1
  • Runnable synthetic Java fixturegit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/java/examples/com/redactwall/scanclient/SyntheticScanExample.java
  • External Java consumergit show ef77201d9aeee1f0280a204aa9cb3258d6adfdc3:scanclient/java/consumer/ExternalConsumer.java

Handle the result before continuing

Configure one caller-owned client for the workload and reuse it across calls. Each example selects a five-second timeout and capacity of one for that instance. This is not a five-second wall-clock guarantee for the whole helper, caller processing or shutdown; the language notes above define the scope. Creating a client per call would give each call its own capacity instead of limiting the workload. Input must be nonempty valid UTF-8, at most 128 KiB of content and 256 KiB after request serialization; responses are bounded at 4 KiB. A refusal, malformed answer, timeout or cancellation is not a clean scan. Stop the caller workflow on failure and use an explicit recovery decision. These clients do not automatically retry; a manual repeat is a new scan that may be metered even when the previous call timed out.

On success, inspect action, outcome and hard_stop before deciding what your application does next. An interaction, transformation, hold or block outcome needs the corresponding caller-side handling. A scan does not return redacted content. Even raw_release_permitted is advisory; the application remains responsible for release and enforcement. A scripted fixture result proves no detection, production enrollment, evidence storage or provider coverage.

Back to gateway prerequisites