Skip to content

This page is for the engineers who will add HEIP to your site. In short: one script in your page, one call on your server.

Your first verdict in 30 minutes.

One script tag in your page. One call on your server. Start in observe mode, so nothing changes for your users until you are ready.

  • Claude Code
  • Cursor
  • Codex

Paste this into any coding agent

Cursor, Claude Code, Codex, whatever you use. It adds the SDK, wires one protected action, and stops for your real keys.

The SDK and keys come with your HEIP account.

You're adding HEIP to this project. HEIP tells our server whether a real person is doing an important action. Get me to one verified action, nothing more.

1. Install the SDK: npm install heip-sdk (Node.js 18+). It comes with our HEIP account; if the install fails, stop and tell me.
2. Add HEIP_SITE_KEY= and HEIP_SECRET_KEY= to .env, and add .env to .gitignore. Read both from the environment. Never hardcode or print them.
3. Find the one form or button I most want to protect (ask me if it's unclear) and give the action a short name, like "checkout".
4. In the page, initialise the browser SDK with the site key. When that form is submitted, call HEIP.prepareAction("<action>") and send sessionId and actionNonce to the server with the request.
5. In the server route that handles it, before doing the work, create new HeipServer({ secretKey: process.env.HEIP_SECRET_KEY }) and call heip.verify({ sessionId, actionNonce, action }). If allow(result) is true, continue. If result.decision is "STEP_UP", return 401 and leave a TODO for the extra step. Otherwise return 403. verify throws if HEIP can't be reached: catch it and refuse the action. Log result.reasons and result.traceId.
6. Stop here and tell me to paste my keys into .env. Don't work around missing keys: no dummy values, no mocked responses.
7. When I confirm the keys are in, run the app, submit the form once, and show me the decision and mode from the server log.

Rules while you work:
- The site key may reach the browser. The secret key is server-only: never put it in client code, never log or print it.
- Call prepareAction when the protected form is submitted, not on page load. Its token works once and expires in seconds.
- Don't retry verify with the same token, and don't invent HEIP endpoints. The browser SDK handles its own calls.
- Treat any extra fields in the response as diagnostics: log them, don't branch on them.

The integration, in four steps

  1. Create a site

    List the domains it runs on. You get a public site key and a private secret key.

  2. Add the browser SDK

    Load it in your page with the site key.

  3. Get an action token

    When the visitor presses a protected button, the page calls prepareAction.

  4. Verify on your server

    Your server calls verify with the secret key and reads the decision.

Then read the decision, log the reasons, and decide what to do.

The code

Your page. Add HEIP and protect a button.
<script src="https://<sdk-host>/sdk.js" data-site-key="pk_live_…" async></script>

<script>
  form.addEventListener("submit", async (e) => {
    e.preventDefault();
    const { sessionId, actionNonce } = await HEIP.prepareAction("checkout");
    await fetch("/api/checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ sessionId, actionNonce, ...formData }),
    });
  });
</script>

With a bundler: import { init, prepareAction } from "heip-sdk";

Your server. Ask HEIP before you commit the action.
import { HeipServer, allow } from "heip-sdk/server";

const heip = new HeipServer({ secretKey: process.env.HEIP_SECRET_KEY });

app.post("/api/checkout", async (req, res) => {
  const { sessionId, actionNonce } = req.body;
  const result = await heip.verify({ sessionId, actionNonce, action: "checkout" });

  if (result.decision === "STEP_UP") return res.status(401).json({ next: "otp" });
  if (!allow(result)) return res.status(403).end();

  // ...commit the checkout
});
Any language. The same call over HTTPS.
curl -X POST https://<api-host>/v2/verify \
  -H "X-HEIP-SECRET-KEY: $HEIP_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sessionId":"…","actionNonce":"…","action":"checkout"}'
Response. What comes back.
{
  "success": true,
  "decision": "ALLOW",
  "reasons": [],
  "mode": "enforce",
  "traceId": "…"
}

The browser SDK opens the session and sends what it needs by itself. You only call prepareAction in the page and verify on your server.

SDKs

SDKRuns onStatus
Browser, script tag or npmDesktop and mobile browsersAvailable
ServerNode.js 18+, ESM and CommonJSAvailable
WebViewWorks in principle, not yet certifiedPlanned
Native iOS and AndroidNot yetPlanned
Other server languagesUse the HTTPS APIAvailable

Policies, per action

You name your actions (login, post, withdraw, change_payout, agent_execute, and so on) and give each a policy. Your server then sends just the action name. HEIP evaluates; you decide what to do.

Critical
Withdrawals, payout changes, admin actions
Fast
Confirming trades or orders, quick publishing
Standard
Sign-up, posting, messaging
Observe
Reading and browsing: never blocks

Roll out safely

  1. Observe

    Switch the site to observe mode. HEIP records what it would do and never blocks.

  2. Review

    Look at decisions and reasons in the dashboard for a week of real traffic.

  3. Enforce

    One action at a time. Start with the action that hurts most when abused.

Built to be easy to check

GET /v2/ping
check your page's key and domain
GET /v2/ping/server
check your server's secret key
localhost switch
test locally without allowing localhost as a domain
2 secret keys per site
rotate without downtime (the old key lives 24 h)
X-HEIP-Reason
tells you in the network tab why a browser call was refused

Trust has to move with the action.

When digital actions can be automated, trust must move with them.