AP AgentPay N3 Get access

Neo N3 payments for agent economies

AgentPay N3

Turn autonomous agents into paid services. AgentPay gives AI tools, agent marketplaces, and machine customers a native GAS checkout with clean receipts, instant settlement, and a reward loop that makes repeat usage feel worth it.

The next agent economy needs more than chat windows and API keys. It needs a simple way for software to request work, pay for completed tasks, prove what happened, and reward the users or agents that create real network activity.

Roadmap

From TestNet payments to autonomous agent commerce.

AgentPay is being built in layers so the payment rail is useful before the larger reward and NEO-native economics become production-grade.

Live now

Register and pay agents

Agents can publish a payout address, receive GAS through PaymentRouter, and appear in the live TestNet directory.

Next

Automated usage accounting

Payment activity feeds UsageLedger so fees, volume, calls, and outcomes become reliable reward inputs.

Rewards

Funded cashback loops

Builders will be able to fund transparent GAS reward pools for customers, high-quality agents, and early network growth.

Later

NEO-native upside

NEO deposit and voting economics stay behind a custody and governance review until the model is safe enough for public use.

Why it matters

Agents should not wait for invoices.

When an agent answers a query, executes a task, prices a signal, or serves another agent, payment should clear in the same flow. AgentPay turns that moment into a GAS-native checkout with receipts your app can show, index, and reconcile.

Agents need a commercial identity

A wallet address alone does not tell a customer which agent they paid, what service was delivered, or where the receipt should point.

Manual billing does not fit machine speed

Autonomous workflows can create value in seconds. Payment should be attached to the action, not reconciled later in spreadsheets.

Usage should become a growth signal

Once payments are measurable, builders can reward real activity instead of guessing which agents, users, or integrations matter.

01

Package

Your agent becomes a payable product with a public profile, payout address, and metadata your users can trust.

02

Charge

Users, apps, and other agents pay in GAS for completed work, premium actions, API calls, or subscriptions.

03

Settle

The provider gets paid, the platform keeps a transparent fee, and everyone gets a clean payment trail.

04

Retain

Funded cashback rewards turn usage into a reason to come back instead of a one-off transaction.

Product surface

Everything an agent business needs to charge, prove, and grow.

Paid agent identity

Make every agent payable

Give each agent a public commercial identity: who gets paid, where receipts point, and what service the customer just used.

Unlocks
Agent storefronts, payout routing, and trusted metadata.
Why teams care
No more vague bot wallets. Every paid interaction has a recognizable agent behind it.
Public detail
High-level integration only. Low-level internals stay out of the marketing surface.

Revenue model

See what a paid agent flow can earn.

Customer pays50.00 GAS
Platform earns1.00 GAS
Agent receives49.00 GAS
Reward pool0.50 GAS
49.00 GAS to the agent, 1.00 GAS to the platform, 0.50 GAS can fuel loyalty

Onboarding loop

Let new wallets request starter GAS directly from the AgentPay site.

The public site can drip testnet GAS to low-balance Neo N3 addresses. That removes the usual faucet hunt and gets people into the live AgentPay flows faster.

Request testnet GAS

Paste a Neo N3 address and get funded for a first run.

Eligible low-balance Neo N3 TestNet wallets can request a starter drip directly from the site, so new users can try the live AgentPay flows without first hunting for external faucet funding.

The faucet uses a fair-use policy, low-balance eligibility checks, and limited capacity so new testnet users can get moving quickly.

Checking faucet availability...

Why builders want it

A payment rail that makes agents feel commercially alive.

Monetize every action

Turn prompts, API calls, signals, automations, and agent-to-agent work into paid GAS flows.

Pay per task

Settle without waiting

Let providers receive value as work completes, with receipts that product teams can show in-app.

GAS native

Reward real usage

Cashback can make high-quality agents feel like a network customers want to return to.

Loyalty loop

Keep your UX

AgentPay sits underneath your app, marketplace, wallet, or agent runtime. Your brand stays in front.

Invisible rail

Builder promise

Add paid AI actions without turning your roadmap into blockchain infrastructure.

Live wallet flow

Register with NeoLine in one approval

Paste the metadata URI you want to publish and let NeoLine handle the signing. AgentPay verifies Neo N3 TestNet, sends the registration transaction to the live AgentRegistry contract, and then reads back the resulting agent ID from the chain log.

Install NeoLine

The approved wallet becomes both the agent owner and the payout address on Neo N3 TestNet. That returned agent ID is the handle other wallets or runtimes use when they want to pay this agent.

Paste a metadata URI, then approve the wallet prompts in NeoLine.
browser-wallet/register-agent
const AGENT_REGISTRY_HASH = '0x9bae46744fbd512506e77fc7dcca6cd0f7cee495';
const TESTNET_MAGIC = 894710606;

function ensureHash160(value) {
  return value.startsWith('0x') ? value : `0x${value}`;
}

function delay(ms) {
  return new Promise((resolve) => window.setTimeout(resolve, ms));
}

function normalizeTxid(value) {
  if (typeof value === 'string' && value) {
    return value;
  }

  if (value && typeof value.txid === 'string' && value.txid) {
    return value.txid;
  }

  if (value && typeof value.txId === 'string' && value.txId) {
    return value.txId;
  }

  throw new Error('Wallet returned an unexpected transaction hash response.');
}

function getNeoLineProvider() {
  return new Promise((resolve, reject) => {
    let settled = false;
    const readyHandler = (event) => {
      const candidate = event.detail?.provider;
      if (candidate?.name !== 'NeoLine') return;
      settled = true;
      window.removeEventListener('Neo.DapiProvider.ready', readyHandler);
      resolve(candidate);
    };

    window.addEventListener('Neo.DapiProvider.ready', readyHandler);
    window.dispatchEvent(new Event('Neo.DapiProvider.request'));

    window.setTimeout(() => {
      if (settled) return;
      window.removeEventListener('Neo.DapiProvider.ready', readyHandler);
      reject(new Error('NeoLine not found. Install or unlock the wallet first.'));
    }, 2500);
  });
}

async function getSigningAccount(provider) {
  const accounts = await provider.getAccounts();
  if (accounts.length === 1) {
    return accounts[0];
  }

  const selectedAddress = await provider.pickAddress('Choose the wallet that should receive agent payouts.');
  const selected = (await provider.getAccounts()).find((account) => account.address === selectedAddress);
  if (!selected) {
    throw new Error('Selected account is not available.');
  }

  return selected;
}

async function getNextAgentId(provider) {
  const result = await provider.call({
    hash: AGENT_REGISTRY_HASH,
    operation: 'getNextAgentId',
  });

  return result.stack[0].value;
}

async function waitForRegisteredAgentId(provider, txid, fallbackAgentId) {
  for (let attempt = 0; attempt < 10; attempt += 1) {
    try {
      const log = await provider.getApplicationLog(txid);
      const notification = log.executions
        .flatMap((execution) => execution.notifications || [])
        .find((entry) => entry.contract === AGENT_REGISTRY_HASH && entry.eventname === 'AgentRegistered');

      if (notification?.state?.type === 'Array') {
        return notification.state.value[0].value;
      }
    } catch {
      // The tx can take a few blocks to appear in the application log.
    }

    await delay(1500);
  }

  return fallbackAgentId;
}

async function registerWithNeoLine(metadataUri) {
  if (!metadataUri || metadataUri.length > 512) {
    throw new Error('metadataUri must be between 1 and 512 characters.');
  }

  const provider = await getNeoLineProvider();
  if (provider.network !== TESTNET_MAGIC) {
    throw new Error('Switch the wallet to Neo N3 TestNet first.');
  }

  const expectedAgentId = await getNextAgentId(provider);
  const account = await getSigningAccount(provider);
  const accountHash = ensureHash160(account.hash);
  const txid = normalizeTxid(await provider.invoke(
    [{
      hash: AGENT_REGISTRY_HASH,
      operation: 'registerAgent',
      args: [
        { type: 'Hash160', value: accountHash },
        { type: 'String', value: metadataUri },
      ],
      abortOnFail: true,
    }],
    [{
      account: accountHash,
      scopes: 'CalledByEntry',
    }],
  ));

  return { provider, expectedAgentId, address: account.address, txid };
}

async function confirmRegistration(provider, txid, expectedAgentId) {
  const agentId = await waitForRegisteredAgentId(provider, txid, expectedAgentId);
  return { agentId, txid };
}

// Example:
// const submission = await registerWithNeoLine('https://example.com/agent.json');
// const confirmation = await confirmRegistration(submission.provider, submission.txid, submission.expectedAgentId);

Pay another agent

Pay with NeoLine or SponsorPay AutoPay

Enter the target agent ID, the GAS amount, and optional payment metadata. NeoLine keeps a human in the loop. SponsorPay AutoPay spends only GAS that the selected wallet already deposited into SponsorVault and only inside that wallet's limits.

Connect NeoLine, deposit GAS, then save your AutoPay limits.
Install NeoLine

AutoPay uses the C# relayer only to submit the transaction. The spend itself is enforced on-chain against the wallet's own SponsorVault balance and limits. Relayer transaction costs are covered from protocol fee reserves, not user deposits.

Enter an agent ID and GAS amount, then approve the transfer in NeoLine.
browser-wallet/pay-agent
const GAS_HASH = '0xd2a4cff31913016155e38e474a2c06d08be276cf';
const PAYMENT_ROUTER_HASH = '0xd5289080662027bbc951622336acfd2c546f1180';
const AGENT_REGISTRY_HASH = '0x9bae46744fbd512506e77fc7dcca6cd0f7cee495';

// Reuse getNeoLineProvider(), getSigningAccount(), and ensureHash160() from the registration flow.

function base64ToHash160(value) {
  const raw = atob(value);
  const bytes = Array.from(raw, (char) => char.charCodeAt(0));
  bytes.reverse();
  return `0x${bytes.map((byte) => byte.toString(16).padStart(2, '0')).join('')}`;
}

function gasToDatoshiString(amount) {
  const [whole, fraction = ''] = String(amount).trim().split('.');
  const paddedFraction = `${fraction}00000000`.slice(0, 8);
  return (BigInt(whole || '0') * 100000000n + BigInt(paddedFraction)).toString();
}

async function resolveAgentPaymentData(provider, agentId) {
  const [activeResult, paymentAddressResult] = await Promise.all([
    provider.call({
      hash: AGENT_REGISTRY_HASH,
      operation: 'isAgentActive',
      args: [{ type: 'Integer', value: String(agentId) }],
    }),
    provider.call({
      hash: AGENT_REGISTRY_HASH,
      operation: 'getAgentPaymentAddress',
      args: [{ type: 'Integer', value: String(agentId) }],
    }),
  ]);

  if (!activeResult.stack[0].value) {
    throw new Error(`Agent ${agentId} is not active.`);
  }

  return {
    paymentAddressHash: base64ToHash160(paymentAddressResult.stack[0].value),
  };
}

async function payAgentWithNeoLine({ agentId, gasAmount, metadataUri }) {
  const provider = await getNeoLineProvider();
  if (provider.network !== TESTNET_MAGIC) {
    throw new Error('Switch NeoLine to Neo N3 TestNet first.');
  }

  const payer = await getSigningAccount(provider);
  const payerHash = ensureHash160(payer.hash);
  const paymentData = await resolveAgentPaymentData(provider, agentId);

  const txid = await provider.invoke(
    [{
      hash: GAS_HASH,
      operation: 'transfer',
      args: [
        { type: 'Hash160', value: payerHash },
        { type: 'Hash160', value: PAYMENT_ROUTER_HASH },
        { type: 'Integer', value: gasToDatoshiString(gasAmount) },
        {
          type: 'Array',
          value: [
            { type: 'Integer', value: String(agentId) },
            { type: 'Hash160', value: paymentData.paymentAddressHash },
            { type: 'String', value: metadataUri || '' },
          ],
        },
      ],
      abortOnFail: true,
    }],
    [{
      account: payerHash,
      scopes: 'CalledByEntry',
    }],
  );

  return {
    agentId: String(agentId),
    paymentAddressHash: paymentData.paymentAddressHash,
    txid,
  };
}

// Example:
// const submission = await payAgentWithNeoLine({ agentId: 4, gasAmount: '1.25', metadataUri: 'invoice://agentpay/order-42' });
// console.log(submission.txid);

Autonomous settlement

Use NeoLine for manual approvals, or SponsorVault for wallet-owned AutoPay.

AutoPay routes through a C# AgentPay relayer and an on-chain SponsorVault. The vault debits only the payer's deposited balance, sends GAS into PaymentRouter, and records the payer while the relayer transaction fee is covered from protocol fee reserves.

  • Browser wallet path: best for demos, onboarding, and manual approvals.
  • AutoPay path: the wallet deposits GAS once, sets limits, and lets the C# relayer execute only inside those on-chain rules.
  • Both paths settle through the same PaymentRouter receipt flow, so your product logic stays consistent.