Documentation
Protect a PoC in five minutes
POCX is a hosted access gate. Your app keeps a single-file SDK that verifies signed session tokens; identity, terms and sessions run on POCX’s servers.
New here? Start with the step-by-step tutorials → Or check the FAQ.
Quickstart (5 min)
Create your PoC
Sign up (email OTP, no password), create a PoC in the dashboard and invite your evaluators’ emails. Only allowlisted emails will ever get a login code.Copy the three env vars
From the PoC’s Overview page, copy the credentials into your app’s server environment (
.env.localfor Next.js):.env.localPOCX_URL=https://pocx-production.up.railway.app POCX_PROJECT_KEY=pocx_pk_… POCX_SECRET=pocx_sk_… # server-side only — never expose to the browserPOCX_SECRETauthenticates server-to-server calls. Keep it out of the browser and out of git.Download the SDK
One TypeScript file, zero dependencies, runs on Node and edge runtimes:
terminalcurl -o lib/pocx.ts https://pocx-production.up.railway.app/sdk/pocx.tsWire the gate
Next.js 16 (App Router): create
proxy.tsat the project root. On Next.js 15 and earlier, name the filemiddleware.tsand exportmiddlewareinstead ofproxy.proxy.tsimport { createPocxGate } from "./lib/pocx"; const gate = createPocxGate(); export const proxy = gate.nextProxy(); export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"], };Deploy
Visiting the app now 307-redirects to your branded gate athttps://pocx-production.up.railway.app/gate/<slug>. After OTP login and terms acceptance, the evaluator lands back in your app with a signed session.
How the flow works
Under the hood, a first visit runs this sequence:
Redirect
An unauthenticated request hits the SDK, which 307-redirects to the hosted gate for this PoC.Gate OTP
The evaluator enters their email. If it’s on the allowlist, POCX emails a 6-digit code (hashed at rest, single-use, rate-limited, 5-attempt lockout).Terms e-signature
The current Terms of Access are shown; the evaluator signs electronically. POCX records the timestamp, IP, user agent and the SHA-256 hash of the exact text, and emails a signed PDF certificate.Single-use grant
POCX redirects back to your app’s callback with a single-use grant that expires in 2 minutes.Server-side exchange
The SDK exchanges the grant server-to-server (authenticated withPOCX_SECRET) for an HS256-signed session token.Cookie on your domain
The session token is set as a cookie on your app’s own domain — POCX is out of the request path from here.Local verification
Every request is verified locally against the token signature, and revalidated against POCX every 60 seconds — picking up revocations, PoC pauses and terms version bumps.
Express / any Node app
The same SDK file ships an Express-style middleware. Mount it before your routes:
import express from "express";
import { createPocxGate } from "./lib/pocx";
const app = express();
const gate = createPocxGate();
app.use(gate.expressMiddleware());Anything that can run a Node middleware chain works the same way — the gate protects every route below it.
Configuration reference
Environment variables (all required):
| Variable | Description |
|---|---|
| POCX_URL | Origin of your POCX deployment, e.g. https://pocx-production.up.railway.app. |
| POCX_PROJECT_KEY | Public project key for this PoC (pocx_pk_…). Identifies the PoC to the gate. |
| POCX_SECRET | Server secret (pocx_sk_…). Signs the exchange call and session verification. Server-side only. |
Options for createPocxGate(options):
| Option | Default | Description |
|---|---|---|
| cookieName | "pocx_session" | Name of the session cookie set on your app’s domain. |
| publicPaths | [] | Path prefixes to leave unprotected (e.g. ["/api/health"]). Everything else is gated. |
| logEvents | false | Stream page_view events into the Pro audit trail. Also settable via env POCX_LOG_EVENTS=true. |
const gate = createPocxGate({
cookieName: "pocx_session", // default
publicPaths: ["/api/health"], // prefixes left unprotected
logEvents: true, // stream page_view events (Pro)
});Terms customization
Every PoC ships with the standard protective Terms of Access template — including the clause that makes POCX worth using:
“No reuse without engagement. If you or your organisation (whether directly or through any third party) develop, commission or implement any product, service or solution that is derived from, substantially based on, or that incorporates the PoC or the concepts embodied in it, you agree to engage {{OWNER_ENTITY}} in respect of that work on terms to be agreed in good faith.”
The template resolves per-PoC placeholders; you can also supply fully custom text (which may still use the same placeholders):
- Template mode — the standard protective terms with your entity, PoC name and purpose substituted in.
- Custom mode — bring your own text verbatim; placeholders still resolve if you use them.
- Version bumps — incrementing the terms version forces every evaluator to re-accept before their next request is allowed through.
The on-screen terms, the signed PDF and the stored SHA-256 hash are all derived from the same resolved string, so the three are guaranteed identical.
Security model
- OTP codes are hashed at rest, single-use, rate-limited, and lock the email out after 5 failed attempts.
- No evaluator passwords exist anywhere — there is nothing to leak.
- Sessions are revocable server-side: the SDK revalidates against POCX every 60 seconds, so a revoke, PoC pause or terms bump takes effect within a minute.
POCX_SECRETnever reaches the browser — the grant-for-token exchange happens server-to-server.- The callback grant is single-use and expires after 2 minutes.
- The gate never open-redirects: it only returns evaluators to the registered protected app URL.
For coding agents
The fastest integration is not doing it yourself. POCX publishes agent-executable instructions at /llms.txt — paste this into Claude Code, Codex or Cursor:
Add POCX protection to this app. Follow the instructions at https://pocx-production.up.railway.app/llms.txt exactly.
The agent reads the instructions, downloads the single-file SDK, wires the middleware and verifies the redirect — end-to-end.