Storefront renderProxy & configuration

Proxy & configuration

Browser-side storefront calls do not hit a bank engine directly. They go through the render app’s proxy route, which applies an allowlist and security filters before forwarding to the box backend.

Proxy route

/api/proxy/[...path]  →  {API_URL}/{path}

The proxy forwards only known storefront-facing prefixes and strips everything else.

Allowed prefixes

inquiries · payments · bookings · orders · invoices · digital-files
cart · carts · waitlist · collections · merchant-subscriptions · members
reviews · loyalty · public · discounts · shipping · products · blog

A path that does not start with an allowed prefix is rejected.

Header forwarding

IncomingForwarded asPurpose
x-tenant-slugX-Tenant-SlugTenant scoping
x-session-idX-Session-IdCart/guest session
x-customer-idX-Customer-IdKnown customer
authorizationAuthorizationMember JWT
x-vercel-ip-*X-Geo-*Country, region, city, lat/lon, timezone

Security filters

  • Rate limit: 100 requests/minute per IP (in-memory; back with Redis in production).
  • Path validation: rejects .. and //, and anything outside the allowed prefixes.
  • No body forwarding for GET / HEAD / DELETE.
⚠️

The default rate limiter is in-memory and per-instance. For multi-instance deployments, move it to a shared store (Redis) so limits hold across replicas.

Environment variables

VariablePurpose
API_URLInternal API base (server-side only) — the proxy target
NEXT_PUBLIC_API_URLPublic API base for the browser
CONTROL_PLANE_URLControl plane for GET /boxes/resolve host resolution
REVALIDATE_SECRETShared secret for POST /api/revalidate
JWT_SECRETHS256 secret for pb_preview_token JWTs (must match the API)
DISCOVERED_TEMPLATE_IDSOptional comma-separated template id list

Host resolution falls back through CONTROL_PLANE_URL → API_URL → NEXT_PUBLIC_API_URL → http://localhost:4000 when resolving a backend.