Skip to main content
Use @neus/sdk for api.neus.network so headers and paths stay correct.

Browser vs server

LayerUse
BrowsergetHostedCheckoutUrl, VerifyGate, polling — default user ceremony on NEUS (Quickstart)
ServergateCheck with gateId; advanced: verifyFromApp, access keys
Do not put npk_* or other secrets in browser bundles. If you need calls the SDK does not expose from the client, proxy through your backendAPI overview.

Install

npm install @neus/sdk

Hosted URL (browser default)

import { getHostedCheckoutUrl } from '@neus/sdk';

window.location.assign(
  getHostedCheckoutUrl({
    gateId: 'gate_your-app-name',
    returnUrl: 'https://myapp.com/callback',
  }),
);
getHostedCheckoutUrl supports gateId, returnUrl, mode, intent, origin, oauthProvider. The hosted page also accepts returnTo and connect=1 (append manually). Hosted Verify. React: Widgets.

Client configuration

const client = new NeusClient({
  // Optional: API base URL (default: https://api.neus.network)
  apiUrl: 'https://api.neus.network',
  // Optional: request timeout (ms)
  timeout: 30000,
});

App attribution (appId)

Set appId only for advanced server/app attribution flows. It is public, not a secret, and it is not required for published gate checkout or gateCheck({ gateId }).
const client = new NeusClient({
  apiUrl: 'https://api.neus.network',
  appId: 'acme-web',
});

Verification options

OptionWhen to Use
persist: truePersist a reusable qHash
ipfs: true / pin: trueIPFS-backed storage
strategy: 'reuse-or-create'Eligible proof first, else create (default)
strategy: 'fresh'Always create a new proof
strategy: 'reuse'Eligible proofs only; never create
Verification patterns for privacy and widget options.

Optional: client.verify() (signs in the browser)

Use only when you intentionally keep signing in your page (wallet extension or injected provider):
import { NeusClient } from '@neus/sdk';

const client = new NeusClient({ apiUrl: 'https://api.neus.network' });
const provider = window.ethereum; // EVM injected provider

const res = await client.verify({
  verifier: 'ownership-basic',
  content: 'Hello NEUS',
  wallet: provider,
});

const qHash = res.qHash;
const record = await client.getProof(qHash);

Advanced: manual signing (full control)

When you assemble verifierIds / data yourself, then sign the standardized string. The example below is EVM. For non-EVM, pass the provider explicitly and include chain as a CAIP-2 value. See CAIP-380 Portable Proof.
import { NeusClient, standardizeVerificationRequest, signMessage } from '@neus/sdk';

const provider = window.ethereum; // EVM injected provider
const client = new NeusClient({ apiUrl: 'https://api.neus.network' });
const [walletAddress] = await provider.request({ method: 'eth_requestAccounts' });
const signedTimestamp = Date.now();
const body = {
  verifierIds: ['ownership-basic'],
  data: {
    owner: walletAddress,
    content: 'Hello NEUS',
    reference: { type: 'url', id: 'https://example.com' }
  },
  walletAddress,
  signedTimestamp,
};

const standardized = await standardizeVerificationRequest(body, {
  apiUrl: 'https://api.neus.network',
});

const signature = await signMessage({
  provider,
  walletAddress,
  message: standardized.signerString
});

const res = await client.verify({
  ...body,
  signature,
  options: { privacyLevel: 'private' }
});
Live verifier list: GET /api/v1/verification/verifiers.

Gate checks: gateCheck vs checkGate

MethodUse when
gateCheck()Allow/deny via GET /api/v1/proofs/check (server-enforced).
checkGate()Preview against proofs you already loaded. Not a substitute for gateCheck() where trust matters.
For typical UX, use Hosted Verify so wallet selection and secondary signing stay on NEUS. Direct mode is for integrations that already control the secondary wallet and provider.
const walletLinkData = await client.createWalletLinkData({
  primaryWalletAddress: '0x0000000000000000000000000000000000000001',
  secondaryWalletAddress: '0x0000000000000000000000000000000000000002',
  wallet: window.ethereum, // EVM provider; pass explicit provider + chain for non-EVM
  relationshipType: 'linked',
  label: 'my-wallet'
});

const res = await client.verify({
  verifier: 'wallet-link',
  data: walletLinkData
});

Gate checks from your servers

const res = await client.gateCheck({
  gateId: 'gate_your-app-name',
  address: 'YOUR_WALLET_OR_DID',
  since: Date.now() - 60 * 60 * 1000
});

if (!res.data?.eligible) {
  throw new Error('Access denied');
}
gateCheck uses public and unlisted proofs by default. Private proofs count when that user is signed in. For strict live checks, create a fresh proof and wait for verified status.
The gate stores verifier requirements, billing owner, sponsor/x402 policy, and attribution. Direct verifierIds checks are advanced protocol calls; do not use them as the normal product checkout path.

Polling

pollProofStatus() backs off on 429 and transient errors.

Advanced: private proof operations

// EVM examples. For non-EVM, pass an explicit wallet/provider and CAIP-2 chain options.

// Private proof by qHash
const privateData = await client.getPrivateProof(qHash, window.ethereum);

// Private proofs by wallet/DID (requires owner signature)
const privateProofs = await client.getPrivateProofsByWallet(
  'YOUR_WALLET_OR_DID',
  { limit: 50, offset: 0 },
  window.ethereum
);

// Revoke your proof
await client.revokeOwnProof(qHash, window.ethereum);

React widgets

Widgets overview.
import { VerifyGate, ProofBadge } from '@neus/sdk/widgets';
Last modified on June 8, 2026