Build on the chain made for games and AI agents.
Native asset system, sub-second confirmations, near-zero fees, and a hosted indexer + game API ready to call from any language. Mint NFTs, run player inventories, accept agent-to-agent payments, ship in a weekend.
Why Neoxa
Native assets, no smart contracts
Issue, reissue, transfer, sub-asset, unique, restricted. NFTs and fungible items at the protocol level - no Solidity, no audits, no upgradability bugs.
1-min blocks + InstantSend
Sub-second confirmation locks via smartnode quorums. Real-time enough for games, predictable enough for agent commerce.
Fees that don't matter
A typical asset transfer is < $0.001. Agents can micropay, players never feel taxed.
Hosted indexer
Asset API + Blockbook + WebSocket events all running. No need to spin up your own node before you ship.
Typed JavaScript SDK
@neoxa/game-sdk wraps every endpoint. Clean types, browser + Node + React Native.
Smartnode infra you inherit
~1700 active smartnodes provide chainlocks, instant-locks, and decentralized validation. Your app rides on top for free.
Live example: pets.neoxa.net ↗
A small game we built using only this SDK and Game API. Click claim, get a unique on-chain creature, and watch it earn NEOXAPETS automatically every block. Real Neoxa mainnet, no shortcuts.
What's actually happening behind the scenes
sdk.generateMnemonic()+sdk.deriveKeyAt(), fresh wallet per claimsdk.buildIssueUniqueAssetTx(), mints a one-of-oneNEOXAPETS#xxxxxxsub-assetsdk.buildTransferAssetTx(), every Neoxa block, sends 1 NEOXAPETS to the deterministic block championNeoxaGameClient.getBlockHash(), drives the championship picker/wallet/utxos,/tx/send,/blockhash/:height, every chain interaction
Single Node service, ~700 lines, no smart contracts. The same primitives are documented below.
Primitives demonstrated
Use as a reference. Open the dev tools on pets.neoxa.net and watch the network tab, every call hits the same endpoints listed below.
Quickstart
Three calls to get a feel - no SDK, no auth, no signup.
1. Health check
curl https://assets.neoxa.net/health
const r = await fetch('https://assets.neoxa.net/health');
console.log(await r.json());
import requests
print(requests.get('https://assets.neoxa.net/health').json())
using UnityEngine.Networking;
var req = UnityWebRequest.Get("https://assets.neoxa.net/health");
yield return req.SendWebRequest();
Debug.Log(req.downloadHandler.text);
local Http = game:GetService("HttpService")
print(Http:JSONDecode(Http:GetAsync("https://assets.neoxa.net/health")))
2. Pull a player's inventory
curl https://assets.neoxa.net/addresses/GN5Cowhpj5grEeU7Gm3fu549jqG3HH6wtu/assets
3. Gate a feature on asset ownership
curl -X POST -H 'Content-Type: application/json' \
-d '{"address":"GN5Cowhpj5grEeU7Gm3fu549jqG3HH6wtu","asset":"GUILD_PASS","minBalance":1}' \
https://assets.neoxa.net/game/verify-ownership
Auth & rate limits
All read endpoints are public, no auth required. Rate-limited per IP:
- GET / inventory / verify endpoints: 60 req/min/IP
- Broadcast / tx send / webhook register / delete: 120 req/min/IP
- Exceeded: HTTP 429 with
Retry-Afterheader
Wallet-side operations (mint, transfer, reissue) are signed locally by the JS SDK; the chain validates. No API key needed for those.
Errors
Every error is plain JSON with a stable error code. Core RPC errors are masked - never leaked.
{ "error": "INVALID_ADDRESS", "detail": "address format invalid" }
| Code | HTTP | Meaning |
|---|---|---|
INVALID_BODY | 400 | Body shape doesn't match what the endpoint expects |
INVALID_ADDRESS | 400 | Not a valid Neoxa address |
INVALID_ASSET_NAME | 400 | Asset name regex failure |
TOO_MANY_ADDRESSES | 400 | Batch endpoint capped at 50 addresses |
NOT_FOUND | 404 | Asset / tx / address has no data |
RATE_LIMITED | 429 | Slow down - see Retry-After |
RPC_TIMEOUT | 504 | Backend daemon was slow; retry |
RPC_ERROR | 500 | Unexpected daemon error (logged server-side) |
JavaScript SDK
A real wallet library, not just an HTTP client. Generate keys, derive HD addresses, sign messages, build asset transactions, broadcast. Browsers, Node 18+, React Native.
v0.5.0, self-hosted tarball. Install:
npm install https://assets.neoxa.net/sdk/neoxa-game-sdk-0.5.0.tgz
Pinned by URL (immutable, integrity-checked). Older versions still available: /sdk/neoxa-game-sdk-0.4.2.tgz, /sdk/neoxa-game-sdk-0.3.0.tgz.
What's new in 0.5.0 - agent QoL
- Inventory diff -
neoxa.getInventoryDiff({ address, sinceBlock })returns per-asset received / sent / net plus the current snapshot. Indexed by chain. - Reusable invoices -
createInvoice({ reusable: true, ref })andlistInvoicePayments({ sinceTxids }). One address, many payments, de-dup'd by txid. - Webhooks -
registerWebhook({ url, filter })for HMAC-signed POST on every matchingasset_transfer. Auto-retry 4 attempts at 0/1/5/25s; auto-disabled after 25 consecutive failures. - verifyWebhookSignature(body, header, secret) - drop-in HMAC verifier for incoming webhook deliveries.
- Python SDK 0.2.0 ships the same three primitives - same shapes, same constants.
Webhook receiver (Express, with verify)
import { verifyWebhookSignature } from '@neoxa/game-sdk';
import express from 'express';
const SECRET = process.env.NEOXA_WEBHOOK_SECRET; // stored at register-time
const app = express();
app.post('/hooks/neoxa', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifyWebhookSignature(req.body, req.headers['x-neoxa-signature'], SECRET)) {
return res.status(401).end();
}
const { event, data } = JSON.parse(req.body.toString());
if (event === 'asset_transfer') {
creditUser(data.to, data.amount, data.asset, data.txid);
}
res.status(204).end(); // 2xx = ack, anything else = retry
});
Reusable invoice + poll loop
const { invoice } = await neoxa.createInvoice({
address: paymentAddr, minAmount: 100_00000000, asset: 'CREDITS',
reusable: true, ref: 'cart:42', ttlBlocks: 1440,
});
// later, on a poll loop
const { payments } = await neoxa.listInvoicePayments({
address: invoice.address,
asset: invoice.asset,
sinceBlock: invoice.validFromBlock,
sinceTxids: alreadyCreditedTxids,
});
for (const p of payments) {
await creditUser(invoice.ref, p.amount, p.txid);
alreadyCreditedTxids.push(p.txid);
}
What's new in 0.4.0
- Qualifier assets -
agent.issueQualifier({ name: '#KYC' })burns 1000 NEOX - Restricted assets -
agent.issueRestricted({ name: '$STABLE', verifierString: '#KYC & !#AML' })burns 1500 NEOX - Tag / Freeze address -
agent.tagAddresses({ targets: [...] }),agent.freezeAddresses({ targets: [...] }) - Message channels -
agent.createMessageChannel({ parent, channel })+agent.sendMessage({ channel, ipfsHash }) - Asset-name classifier -
classifyAssetName('#KYC') === 'qualifier' - Low-level encoders:
buildTagAddressScript,buildFreezeAddressScript,buildVerifierStringScript,buildGlobalRestrictionScript
Regulated token issuance (restricted + qualifier)
// 1. Issue the qualifier ('#KYC' is a chain-tracked role token)
await agent.issueQualifier({ name: '#KYC', amount: 1_000_000 });
// 2. Issue a restricted asset gated on the qualifier
await agent.issueRestricted({
name: '$USDX', amount: 1_000_000, units: 8, reissuable: true,
verifierString: '#KYC', // must hold KYC tag to receive $USDX
});
// 3. Tag a customer's address with KYC so they can hold $USDX
await agent.tagAddresses({
targets: [{ address: 'G...customer', qualifier: '#KYC', flag: 1 }],
});
// 4. Optional: freeze a specific address's $USDX holdings
await agent.freezeAddresses({
targets: [{ address: 'G...bad', restrictedAsset: '$USDX', flag: 1 }],
});
On-chain message channels (Neoxa-specific pub/sub)
// Owner of GUILD! creates a channel
await agent.createMessageChannel({ parent: 'GUILD', channel: 'GENERAL' });
// Anyone with a channel token can broadcast an IPFS-anchored message
await agent.sendMessage({
channel: 'GUILD~GENERAL',
ipfsHash: Buffer.from('1220' + 'a'.repeat(64), 'hex'), // 34-byte multihash
expireTime: Math.floor(Date.now()/1000) + 86400,
});
What's new in 0.3.0
- Multisig P2SH helpers -
buildMultisig({ m, pubkeys })for M-of-N treasury wallets - CLTV timelock -
buildCLTVDescriptor({ beneficiary, lockBlockHeight })for vesting + expiry mailboxes - CSV timelock -
buildCSVDescriptor({ beneficiary, relativeBlocks })for escrow cooldowns - HTTP client retry/backoff - automatic retry on transient failures (network errors, 5xx, 429 with Retry-After). Configurable via
maxRetries+retryBaseMs. - CI script -
scripts/ci.shruns typecheck + build + 67 verification tests in one shot
Multisig P2SH (treasury, joint custody)
import { buildMultisig, generateKeyPair } from '@neoxa/game-sdk';
const k1 = generateKeyPair();
const k2 = generateKeyPair();
const k3 = generateKeyPair();
const ms = buildMultisig({
m: 2, // 2 of 3 must sign
pubkeys: [k1.publicKey, k2.publicKey, k3.publicKey],
});
ms.address; // 'r...' P2SH address
ms.redeemScript; // push when spending
CLTV (absolute timelock - vesting, expiry mailboxes)
import { buildCLTVDescriptor } from '@neoxa/game-sdk';
const vesting = buildCLTVDescriptor({
beneficiary: 'G...payout',
lockBlockHeight: 3_000_000, // unlocks at this block
});
// Spend later with: psbt.setLocktime(3_000_000) + sequence: 0xfffffffe
CSV (relative timelock - escrow cooldowns)
import { buildCSVDescriptor } from '@neoxa/game-sdk';
const escrow = buildCSVDescriptor({
beneficiary: 'G...refund',
relativeBlocks: 144, // ~144 confirmations needed
});
// Spend later with: addInput({ ..., sequence: 144 })
HTTP client retry policy
import { NeoxaGameClient } from '@neoxa/game-sdk';
const neoxa = new NeoxaGameClient({
maxRetries: 3, // default 3, set 0 to disable
retryBaseMs: 250, // 250 -> 500 -> 1000 -> 2000ms backoff
});
// Automatic on: network errors, 5xx, 429.
// 4xx is NOT retried (caller's bug).
// Honors Retry-After header on 429.
v0.2.0 features (still in)
- Multi-recipient NEOX send (one tx, many payouts)
- OP_RETURN data anchoring (up to 80 bytes)
- Asset transfer with attached IPFS hash or TXID notifier + expireTime
- InstantSend flag on broadcast (smartnode-locked ~2s confirms)
- BIP39 passphrase support across all derivation calls
Wallet primitives
BIP39 mnemonics, BIP44 HD derivation (slip44 1668), P2PKH address encoding (G prefix), and Neoxa-flavored signed messages.
import {
generateMnemonic, deriveAccount, deriveKeyAt,
generateKeyPair, keyPairFromWIF,
isValidAddress, verifyMessage,
} from '@neoxa/game-sdk';
// Fresh 12-word mnemonic
const phrase = generateMnemonic();
// Derive account 0 (path m/44'/1668'/0')
const acct = deriveAccount(phrase);
console.log(acct.firstAddress); // G...
console.log(acct.xpub); // xpub...
// Or jump straight to a single child
const key = deriveKeyAt(phrase, 0, 0); // first receiving address
// Sign + verify
const sig = key.signMessage('agent-login:abc123');
verifyMessage(key.address, sig, 'agent-login:abc123'); // → true
// Random one-shot keypair (no mnemonic backing)
const ephemeral = generateKeyPair();
// Import an existing WIF
const imported = keyPairFromWIF(process.env.AGENT_WIF);
Issue your own asset (the headline feature)
An agent funds its address with at least 500 NEOX (the issuance burn) plus a few hundred satoshis for fees, and mints in one call.
import { agentFromMnemonic } from '@neoxa/game-sdk';
const agent = agentFromMnemonic(process.env.AGENT_MNEMONIC);
// Issue a brand new fungible token
const { txid } = await agent.issueAsset({
name: 'AGENT_OF_HONOR', // A-Z, 0-9, ., _ ; 3 - 30 chars
amount: '1000', // total supply (decimal)
units: 0, // 0 = integer-only, up to 8 decimals
reissuable: true, // can mint more later
});
console.log('issued, txid:', txid);
chainparams.cpp.Send NEOX or transfer assets
// Plain NEOX
await agent.sendNeox({ to: 'G...recipient', amount: '0.5' });
// Transfer an asset (your wallet must hold it)
await agent.transferAsset({
to: 'G...recipient',
asset: 'AGENT_OF_HONOR',
amount: '10',
});
// Reissue: add supply or change metadata. Requires the owner asset (NAME!).
await agent.reissueAsset({
name: 'AGENT_OF_HONOR',
addedAmount: '500', // mint 500 more
reissuable: true,
});
// Sub-asset (PARENT/CHILD) - 100 NEOX burn, must own parent's NAME!
await agent.issueSubAsset({
parent: 'AGENT_OF_HONOR',
child: 'COMMON_LOOT',
amount: '10000',
});
// Unique asset (PARENT#TAG) - NFT-like, 5 NEOX burn, 1-of-1 forever
await agent.issueUniqueAsset({
parent: 'AGENT_OF_HONOR',
tag: 'LEGENDARY_001',
});
NeoxaAgent facade
One object that bundles a wallet + an HTTP client. Designed for AI agents, MCP servers, game backends, or any non-interactive process that owns a key and needs to act on chain.
import { createAgent, agentFromMnemonic, agentFromWIF } from '@neoxa/game-sdk';
const a = createAgent(); // fresh key
const b = agentFromMnemonic(MNEMONIC); // from BIP39 phrase
const c = agentFromWIF(WIF); // from exported WIF
a.address; // its public Neoxa address
a.exportWIF(); // its private key (treat as secret)
await a.invoice('1'); // accept 1 NEOX
await a.checkIncoming('1', { lookbackBlocks: 60 });
await a.sendNeox({ to: '...', amount: '0.5' });
await a.issueAsset ({ name: 'TOKEN', amount: '1000', units: 0, reissuable: true });
await a.issueSubAsset ({ parent: 'TOKEN', child: 'CHILD', amount: '100' });
await a.issueUniqueAsset ({ parent: 'TOKEN', tag: 'NFT001' });
await a.reissueAsset ({ name: 'TOKEN', addedAmount: '500' });
await a.transferAsset({ to: '...', asset: 'TOKEN', amount: '5' });
a.signMessage('hello'); // identity proof
NeoxaGameClient
import { NeoxaGameClient } from '@neoxa/game-sdk';
const neoxa = new NeoxaGameClient(); // defaults to https://assets.neoxa.net
await neoxa.health();
await neoxa.getInventory('G...address');
await neoxa.getInventoryBatch(['G...p1','G...p2','G...p3']);
await neoxa.verifyOwnership({ address:'G...', asset:'GUILD_PASS', minBalance:1 });
await neoxa.getAssetHolders('LEGENDARY_SWORD', 50);
await neoxa.assetExists('MY_NEW_ASSET');
await neoxa.smartnodesByAddresses(['G...','G...']);
// Agents
await neoxa.verifyMessage({ address:'G...', signature:'H..', message:'login:abc' });
await neoxa.checkPayment({ address:'G...', minAmount: 100_00000000, lookbackBlocks: 60 });
await neoxa.createInvoice({ address:'G...', minAmount: 100_00000000, ttlBlocks: 30 });
// Broadcast
await neoxa.broadcastTx('010000...signed-hex');
NeoxaEventStream - real-time pushes
import { NeoxaEventStream } from '@neoxa/game-sdk';
const stream = new NeoxaEventStream();
stream.on('asset_transfer', (e) => {
console.log(`${e.amount} ${e.asset} → ${e.to} (tx ${e.txid})`);
});
await stream.connect();
stream.subscribe({ assets: ['GUILD_PASS', 'LEGENDARY_SWORD'] });
Auto-reconnect, filter is re-applied. Browser uses native WebSocket; Node lazily loads ws.
Game API
REST endpoints purpose-built for game backends. All hosted at https://assets.neoxa.net.
Inventory · single + batch
Pull every asset balance for one or many players in a single round-trip. Cached server-side for 30s - efficient enough to hit on every wallet refresh.
GET /addresses/{address}/assets
POST /game/inventory/batch
body: { "addresses": ["G...", ... ] } // max 50
↳ { "players": [ { "address","neox",{balance,received},"assets":[{name,balance,received}, ...] } ] }
Ownership gates
Permission checks for in-game features. "Player must hold ≥ N of asset X to enter this dungeon."
POST /game/verify-ownership
body: { "address":"G...", "asset":"GUILD_PASS", "minBalance": 1 }
↳ { "owns": true, "balance": 3, "minBalance": 1, ... }
Asset holders · leaderboards
Top-N holders of any asset, sorted. Powers leaderboards, airdrop targeting, snapshot tooling.
POST /game/asset/holders
body: { "asset":"LEGENDARY_SWORD", "limit": 100 }
↳ { "asset","count","holders":[{"address","balance"}] }
Asset existence check
Before minting a new asset, fast existence check on the name.
POST /game/asset/exists
body: { "asset":"MY_NEW_ASSET" }
↳ { "asset":"MY_NEW_ASSET", "exists": false }
Live events WebSocket
Real-time push of asset transfers as they happen on-chain. Drives in-game notifications, "X just got Y" toasts, live trading UIs.
WS wss://assets.neoxa.net/game/events
// client → server
{ "type":"subscribe", "filter": { "assets": ["LEGENDARY_SWORD"] } }
{ "type":"subscribe", "filter": { "addresses": ["G...","G..."] } }
{ "type":"subscribe", "filter": { "all": true } } // firehose
// server → client
{ "type":"hello", "protocol":"neoxa-game-events/1" }
{ "type":"subscribed", "filter": {...} }
{ "type":"asset_transfer",
"txid":"...", "asset":"LEGENDARY_SWORD", "amount": 1,
"to":"G...recipient", "message": null, "time": 1714000000 }
AI agent API
Primitives for AI agents (and any non-human caller) to take payment, prove identity, and gate tool use behind verifiable on-chain actions.
Three concepts:
- Identity - an agent has a Neoxa wallet. It signs a server-issued nonce with its private key. You verify the signature on chain. No password DB, no OAuth.
- Invoice - when an agent wants to charge, it creates a structured invoice (address, amount, time window) the payer can present to its wallet.
- Payment check - payee polls until the chain confirms the funds, then delivers the tool result.
Identity verification
Verify an agent controls a wallet by checking a signmessage signature.
POST /agents/verify-message
body: { "address":"G...", "signature":"H..base64..", "message":"agent-login:nonce" }
↳ { "address":"G...", "valid": true }
verifyMessage(...) wraps this.Invoice creation
Generate a portable invoice object. Pair with checkPayment for a single-use invoice, or with listInvoicePayments for reusable ones.
POST /agents/invoice
body: {
"address":"G...recipient", "minAmount": 100000000,
"asset": null, "ttlBlocks": 30,
"reusable": false, // optional (v0.5+)
"ref": "cart:42" // optional opaque, echoed back
}
↳ {
"invoice": {
"version": 1,
"id": "inv_xxxxxxxxxxxxxxxx",
"address": "G...",
"minAmount": 100000000,
"asset": null,
"reusable": false,
"ref": "cart:42",
"validFromBlock": 2074808,
"validUntilBlock": 2074838,
"verifyUrl": "https://assets.neoxa.net/agents/payment/check",
"paymentsUrl": "https://assets.neoxa.net/agents/invoice/payments"
}
}
Payment check
"Did this address receive at least N satoshis (or N of asset X) since block Y?"
POST /agents/payment/check
body: { "address":"G...", "minAmount": 100000000, "asset": null, "afterBlock": 2074808 }
↳ {
"address": "G...",
"expected": { "minAmount": 100000000, "asset": null, "afterBlock": 2074808 },
"received": { "totalAmount": 100000000, "txids":["..."], "firstBlockHeight": 2074810, "count": 1 },
"satisfied": true,
"chainTip": 2074814
}
List invoice payments - for reusable invoices
Enumerate every distinct receipt to an address since a block. The same tx is counted once, regardless of how many vouts paid the address. Pass sinceTxids to skip txids you've already credited.
POST /agents/invoice/payments
body: {
"address":"G...", "sinceBlock": 2080000,
"asset": "CREDITS", // optional, null for NEOX
"untilBlock": null, // optional cap, defaults to chain tip
"sinceTxids": ["abcd...","ef01..."], // optional dedup list
"minPerPayment": 100000 // optional floor
}
↳ {
"address": "G...", "asset": "CREDITS",
"sinceBlock": 2080000, "untilBlock": 2080500, "chainTip": 2080500,
"count": 2, "totalAmount": 200000000,
"payments": [
{ "txid": "...", "amount": 100000000, "height": 2080124 },
{ "txid": "...", "amount": 100000000, "height": 2080128 }
]
}
Inventory diff - "what changed since block N?"
Returns the current inventory plus per-asset received / sent / net since sinceBlock. Indexed by chain (canonical). Window capped at 200,000 blocks.
GET /game/inventory/diff?address=G...&sinceBlock=2080000
↳ {
"address": "G...",
"sinceBlock": 2080000, "currentBlock": 2080500, "txCount": 12,
"current": { "neox": {...}, "assets": [...] },
"diff": {
"neox": { "received": ..., "sent": ..., "net": ..., "txids": [...] },
"assets": [
{ "name":"CREDITS", "received": 500, "sent": 100, "net": 400, "txids":[...] }
]
}
}
Webhooks - push instead of poll
Register a URL; receive an HMAC-signed POST every time an asset_transfer matching your filter lands on chain. Retries 4 attempts at 0/1/5/25s. Auto-disabled after 25 consecutive failures.
POST /agents/webhooks
body: {
"url": "https://you.example/hook",
"filter": { // OR'd; at least one of:
"all": false, // * subscribe to everything
"assets": ["CREDITS"], // * scope by asset
"addresses": ["G..."] // * scope by recipient
},
"secret": "whsec_..." // optional; server generates one if omitted
}
↳ { "webhook": { "id": "wh_xxxxxxxxxxxxxxxx", "secret": "whsec_...", ... } } // secret returned ONCE
GET /agents/webhooks/{id} ↳ status (secret redacted)
GET /agents/webhooks/{id}/log ↳ last 20 delivery attempts
DEL /agents/webhooks/{id} ↳ unregister
Delivery headers (every POST to your endpoint):
x-neoxa-event: asset_transfer
x-neoxa-webhook: wh_xxxxxxxxxxxxxxxx
x-neoxa-signature: sha256=<hex-hmac-sha256(secret, raw_body)>
x-neoxa-timestamp: 1778533285
Content-Type: application/json
{ "event":"asset_transfer", "webhook":"wh_...",
"data": { "txid":"...", "asset":"CREDITS", "amount":1000000, "to":"G...", "time": 1778533285 } }
verifyWebhookSignature(rawBody, header, secret) for both JS and Python.Recipe - pay-per-call paywall for an AI tool
Charge an agent (or human) per call to your AI tool. Each call requires a fresh on-chain payment.
// Server pseudocode
import { NeoxaGameClient } from '@neoxa/game-sdk';
const neoxa = new NeoxaGameClient();
const RECEIVING_ADDRESS = process.env.PAYMENT_ADDRESS;
const PRICE_NEOX = 1_00000000; // 1 NEOX in satoshis
app.post('/api/tool/run', async (req, res) => {
// 1. caller asks for an invoice first
if (req.body.intent === 'quote') {
const { invoice } = await neoxa.createInvoice({
address: RECEIVING_ADDRESS,
minAmount: PRICE_NEOX,
ttlBlocks: 30,
});
return res.json({ pay: invoice });
}
// 2. they POST again with proof of payment
const { sinceBlock } = req.body;
const check = await neoxa.checkPayment({
address: RECEIVING_ADDRESS,
minAmount: PRICE_NEOX,
afterBlock: sinceBlock,
lookbackBlocks: 60,
});
if (!check.satisfied) {
return res.status(402).json({
error: 'payment_required',
received: check.received.totalAmount,
need: PRICE_NEOX,
});
}
// 3. payment confirmed - run the tool
const result = await runTheTool(req.body.params);
res.json({ result, paidTxids: check.received.txids });
});
Recipe - agent identity for tool access
Gate access to an AI tool on the calling agent owning a specific subscription token.
// Bind agent to wallet at sign-up
app.post('/api/agent/login', async (req, res) => {
const { address, signature } = req.body;
const message = `neoxa-agent-login:${req.session.nonce}`;
const v = await neoxa.verifyMessage({ address, signature, message });
if (!v.valid) return res.status(401).json({ error: 'bad_signature' });
// Optional: require they hold a subscription token
const sub = await neoxa.verifyOwnership({
address, asset: 'AI_PRO_SUBSCRIPTION', minBalance: 1,
});
if (!sub.owns) return res.status(403).json({ error: 'subscription_required' });
req.session.agentAddress = address;
res.json({ ok: true });
});
// Now any tool route can trust req.session.agentAddress
app.post('/api/tool/run', requireAgentSession, async (req, res) => { ... });
Asset API · raw
Lower-level endpoints for asset directory + metadata. Use these if you don't want the game-flavored wrappers.
List assets
GET /assets?filter=*&count=50&start=0
↳ { "count":50, "assets":["001","002",...], "start":0 }
Get metadata
GET /assets/{name}
↳ { "name":"...", "amount":N, "units":N, "reissuable":1, "has_ipfs":0, ... }
Address balances
GET /addresses/{address}/assets
↳ { "address":"G...", "neox":{"balance","received"}, "assets":[{name,balance,received}] }
Broadcast a signed transaction
POST /tx/send
body: { "hex": "01000000...signed-raw-tx" }
↳ { "txid": "..." }
Wallet UX · Blockbook
Trezor's Blockbook indexer is hosted for NEOX. Use it for typical wallet operations: balances, paginated tx history, UTXOs, fee estimates, broadcast, WebSocket push.
https://blockbook.neoxa.net/api/v2/address/{addr}?details=txs&page=1&pageSize=25
https://blockbook.neoxa.net/api/v2/utxo/{addr}
https://blockbook.neoxa.net/api/v2/xpub/{xpub}?details=tokens
https://blockbook.neoxa.net/api/v2/estimatefee/{blocks}
https://blockbook.neoxa.net/api/v2/sendtx/{rawhex}
wss://blockbook.neoxa.net/websocket
Smartnode detection
Wallets with self-hosted smartnodes can detect them by collateral / payout / owner / voting address - so the 1M NEOX collateral UTXO never gets accidentally spent.
POST /smartnodes/by-addresses
body: { "addresses":["G...","G..."] } // max 50
↳ { "nodes":[{ proTxHash, collateralHash, collateralIndex, service, ... }] }
Chain parameters
| Coin name | Neoxa |
| Ticker | NEOX |
| Decimals | 8 (1 NEOX = 100 000 000 satoshis) |
| Address prefix | 0x26 → addresses start with G… |
| BIP44 slip44 | 1668 (path m/44'/1668'/0'/0/i) |
| xpub magic | 76067358 (standard xpub bytes) |
| Block time | ~60 seconds |
| Asset rules | Ravencoin-compatible (issue, reissue, transfer, sub-asset, unique, restricted) |
| Smartnode collateral | 1,000,000 NEOX |
Hosts & URLs
| Service | URL |
|---|---|
| Asset / Game / Agent API | https://assets.neoxa.net |
| Blockbook (Neoxa) | https://blockbook.neoxa.net |
| Bootstrap (chain snapshot) | https://bootstrap.neoxa.net |
| Developer portal (this site) | https://dev.neoxa.net |
Service status
Check liveness and current chain height at any time.
curl https://assets.neoxa.net/health
↳ { "ok": true, "blockHeight": 2074808, "cacheStats": { ... } }