Back

Proxy Customization_Oryx

When to use proxy?

Proxying your requests to Contextual AI is highly recommended for production deployments to protect your account.

The only exception is when using OIDC (enterprise plans only, contact us). In that case, tokens can be passed directly in the client fetcher — though a proxy still works if you prefer centralized control.

Transforming the URL

Use transform to rewrite the target path based on the incoming request, such as when agent ID needs to be extracted from the query string, or when you need to set agent ID dynamically based on the user's authentication state.

ts

import { createOryxSSEProxy } from "@contextualai/oryx-proxy-node";

export const POST = createOryxSSEProxy({
  baseUrl: "https://api.contextual.ai",
  transform: (request) => {
    const url = new URL(request.url);
    const agentId = url.searchParams.get("agentId");
    if (!agentId) throw new Error("Missing agentId");

    // /api/chat?agentId=123 -> /v1/agents/123/query.
    return { url: `/v1/agents/${agentId}/query` };
  },
  extendHeaders: () => ({
    Authorization: `Bearer ${process.env.CONTEXTUAL_API_KEY}`,
  }),
});

Extending headers

extendHeaders injects headers into the upstream request. You can use this function to validate your user's authentication state, or inject Contextual AI API key conditionally.

ts

import { createOryxSSEProxy } from "@contextualai/oryx-proxy-node";

export const POST = createOryxSSEProxy({
  baseUrl: "https://api.contextual.ai",
  transform: (request) => ({
    url: `/v1/agents/${process.env.CONTEXTUAL_AGENT_ID}/query`,
  }),
  extendHeaders: async (request) => {
    // Example: inject user's OIDC token.
    const userToken = request.headers.get("x-user-token");
    if (!userToken) throw new Error("Unauthorized");

    return {
      Authorization: `Bearer ${userToken}`,
    };
  },
});

Custom error mapping

Override mapErrorBody to customize error event payloads.

ts

import { createOryxSSEProxy } from "@contextualai/oryx-proxy-node";

export const POST = createOryxSSEProxy({
  baseUrl: "https://api.contextual.ai",
  transform: (request) => ({
    url: `/v1/agents/${process.env.CONTEXTUAL_AGENT_ID}/query`,
  }),
  extendHeaders: () => ({
    Authorization: `Bearer ${process.env.CONTEXTUAL_API_KEY}`,
  }),
  mapErrorBody: (rawBody, status) => {
    const parsed = typeof rawBody === "string" ? JSON.parse(rawBody) : {};

    return {
      status,
      message: parsed.reason ?? "Something went wrong.",
      error_code: parsed.code,
    };
  },
});

Full control with createOryxSSEProxyHandler

createOryxSSEProxy handles most use cases out of the box. But you can still fully customize when you need:

ts

import { createOryxSSEProxyHandler } from "@contextualai/oryx-proxy-node";

export async function POST(request: Request): Promise<Response> {
  const body = await request.json();

  const oidcToken = request.headers.get("x-oidc-token");
  const agentId = request.headers.get("x-agent-id");

  const handler = createOryxSSEProxyHandler({
    buildUpstreamRequest: async () => ({
      url: `https://api.contextual.ai/v1/agents/${agentId}/query`,
      method: "POST",
      headers: {
        Authorization: `Bearer ${oidcToken}`,
        "Content-Type": "application/json",
        Accept: "text/event-stream",
      },
      data: {
        ...body,
        // Inject additional fields with your specific needs.
        metadata: { source: "web" },
      },
    }),
  });

  return handler(request);
}

API reference: createOryxSSEProxy

API reference: createOryxSSEProxyHandler

Backtrack

Styling Guide

Read Next

React Hooks

© 2025 Contextual AI, Inc.

Proudly open sourced under the Apache 2.0 license.