Use @neus/sdk for api.neus.network so headers and paths stay correct.
Browser vs server
| Layer | Use |
|---|
| Browser | getHostedCheckoutUrl, VerifyGate, polling — default user ceremony on NEUS (Quickstart) |
| Server | gateCheck 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 backend — API overview.
Install
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
| Option | When to Use |
|---|
persist: true | Persist a reusable qHash |
ipfs: true / pin: true | IPFS-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
| Method | Use 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. |
Wallet-link: hosted first
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);
Widgets overview.
import { VerifyGate, ProofBadge } from '@neus/sdk/widgets';