All developer docs

Proof-of-Life ยท Integration guide

Node.js and Express

import express from 'express';
import crypto from 'node:crypto';

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());

const POL_API = 'https://api.heliusnetwork.app';
const POL_SECRET = process.env.POL_SECRET; // sk_...

async function siteverify(fields) {
  const r = await fetch(`${POL_API}/v1/siteverify`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ secret: POL_SECRET, ...fields }),
  });
  return r.json();
}

// PoL Gate on a sign-up form
app.post('/signup', async (req, res) => {
  const result = await siteverify({ response: req.body['pol-token'] });
  if (!result.success) return res.status(400).send('Please complete the Proof-of-Life check.');
  // result.subject is a stable pseudonymous id for this person on your site:
  // use it to stop the same person creating many accounts.
  res.send('Welcome!');
});

// PoL Step-up before a transfer
const accountHint = (userId) =>
  crypto.createHmac('sha256', process.env.HINT_SALT).update(String(userId)).digest('base64url');

app.post('/transfer/start', async (req, res) => {
  const r = await fetch(`${POL_API}/v1/stepup/start`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ secret: POL_SECRET, action: 'transfer', account_hint_hash: accountHint(req.user.id) }),
  });
  res.json(await r.json()); // { client_token } goes to the browser
});

app.post('/transfer/confirm', async (req, res) => {
  const result = await siteverify({
    response: req.body.token,
    expected_action: 'transfer',
    expected_account_hint_hash: accountHint(req.user.id),
  });
  if (!result.success) return res.status(403).json(result);
  // perform the transfer
  res.json({ ok: true });
});

Browser side of the step-up:

const { client_token } = await (await fetch('/transfer/start', { method: 'POST' })).json();
const token = await PoL.execute('pk_your_site_key', { action: 'transfer', stepup: client_token });
await fetch('/transfer/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token }) });

Proof-of-Life is in early access. Request keys, read the API reference or the privacy notice.