Saltar al contenido

Proxy de servidor

El navegador habla con tu backend y tu backend con Cord: ninguna llave llega a la página.

Cord Elements funciona de dos maneras: con una llave publicable (pk_) directo a Cord, o con proxyUrl, donde tu propio backend atiende las peticiones y llama a Cord con una llave de servidor. Usa el proxy cuando quieras que el Builder lea tu directorio de clientes, mande la cotización por correo o fije precios negociados: cosas que una pk_ nunca puede hacer.

El proxy vive en @flouviahq/node, el SDK de servidor. Ese paquete reemplaza al antiguo @flouviahq/elements/server, que sigue funcionando pero ya no recibe cambios.

Montarlo

npm install @flouviahq/node
// app/api/cord/[...path]/route.ts (Next.js App Router)
import { createElementsProxy } from '@flouviahq/node';

const proxy = createElementsProxy({
  secretKey: process.env.CORD_SECRET_KEY!,
  authorizeClients: async (req) => Boolean(await getSession(req)),
});

export const GET = proxy;
export const POST = proxy;
<CordProvider proxyUrl="/api/cord">
  <CordBuilder />
</CordProvider>

getSession es tu propia función de sesión. createElementsProxy devuelve un handler (Request) => Promise<Response>, así que funciona igual en Next.js, Astro, Remix, Hono, Bun o Cloudflare Workers. cord init lo crea por ti en un proyecto de Next.js.

Qué atiende

Petición del navegador Llama a Cord Condición
GET {proxyUrl}/elements/config GET /api/v1/elements/config Siempre.
GET {proxyUrl}/productos GET /api/v1/productos Siempre.
POST {proxyUrl}/cotizaciones POST /api/v1/cotizaciones Siempre, con el cuerpo saneado.
POST {proxyUrl}/elements/ai-draft POST /api/v1/elements/ai-draft Siempre. El stream de la IA se reenvía tal cual; archivo de hasta 4 MB.
GET {proxyUrl}/clientes GET /api/v1/clientes?limit=200 Solo si authorizeClients devuelve true. Si no, 403 con code: "clients_require_proxy".

Cualquier otra ruta o método responde 404. El proxy no reintenta: el navegador ya reintenta por su cuenta.

Opciones

Opción Detalle
secretKey Obligatoria. Una llave sk_ o rk_.
allowedOrigins Orígenes que pueden usar el proxy. Por defecto, solo el origen de la propia petición: un proxy abierto a cualquier sitio equivale a publicar tu llave.
authorizeClients(request) Autoriza leer el directorio de clientes. Sin ella, nunca se lee.
authorizeSellerFields(request) Autoriza los campos de vendedor al crear: cliente_id, send (enviar por correo), fiscal_currency, y en cada línea precio_negociado y costo_unitario. Sin ella, se descartan y la cotización nace como borrador, igual que con una pk_.
baseUrl Origen de Cord. Default https://cordhq.app.
fetch Para pruebas.
const proxy = createElementsProxy({
  secretKey: process.env.CORD_PROXY_KEY!,
  allowedOrigins: ['https://portal.tuempresa.com'],
  authorizeClients: async (req) => (await getSession(req))?.rol === 'vendedor',
  authorizeSellerFields: async (req) => (await getSession(req))?.rol === 'vendedor',
});

El proxy reenvía la Idempotency-Key del navegador (el Builder manda una por intento de envío), y devuelve los errores de Cord con su code, request_id y doc_url.

Dale al proxy una llave restringida

El proxy no necesita una Secret Key con todos los permisos. Crea una llave restringida (rk_) en Desarrolladores › Llaves con solo esto:

Recurso Nivel Para qué
elements escritura Configuración y llenado de partidas con IA
productos lectura El catálogo del Builder
cotizaciones escritura Crear la cotización
clientes lectura Solo si usas authorizeClients
Diálogo "Nueva API key EN VIVO" con el tipo Restringida (Backend) seleccionado y los permisos por recurso del proxy de Elements: Cotizaciones y Elements en escritura, Productos y Clientes en lectura, el resto sin acceso; las herramientas del MCP de lectura y de escritura de borradores, sin las acciones con efectos externos; una IP permitida y vencimiento a 90 días.

Si tu servidor se ve comprometido, esa llave no puede leer facturas, cobranza ni webhooks. Puedes además fijar las IPs de tu servidor y ponerle vencimiento. Ver Autenticación.

Depurar

Cada llamada del proxy a Cord queda en Desarrolladores › Registros del Workbench con su request_id, método, ruta, estado, duración e IP. El mismo request_id llega al navegador en el header Cord-Request-Id y en el cuerpo de un error.