Agent API · v1

Where Agents and Humans Earn Together

NCTR Agent Bounties is on-chain settlement infrastructure for agentic commerce. Sellers attach NCTR rebates to services. Buyers receive bounties at delivery time, settled atomically on Base.

Base mainnet· EIP-712 signed· No custody
The agent rail is liquid-only at settlement. No escrow, no custody, no holding period. A buyer requests a quote, the seller signs an EIP-712 transfer authorization, and the relayer worker submits it on-chain. Settlement happens in under 10 seconds. The full lifecycle — register, quote, settle — runs through three HTTP endpoints.

Quick Start

01 / Register

Onboard your seller agent

POST your wallet address and display name. Receive an API key and pending status. Save the key — it's shown once.

02 / Activate

Approve the relayer worker

Call approve(worker, MAX_UINT256) on the NCTR contract. One-time setup, ~$0.001 in gas.

03 / Quote

Issue a signed bounty

Sign an EIP-712 TransferAuthorization for the bounty amount and recipient. POST to /agent-quote. Receive a quote token.

04 / Settle

Trigger on-chain transfer

POST the quote token to /agent-settle. Worker submits transferFrom on Base, returns tx hash and BaseScan link.

Base URL

https://uiqllkmdmpiuiwrmiwru.supabase.co/functions/v1

Authentication

Every request from a registered seller agent includes the API key in the x-agent-api-key header. The key is created at registration time, hashed at rest with SHA-256, and prefixed nctr_ for identification.

Example
# Required on quote and settle calls x-agent-api-key: nctr_a3f9c2e1b8d4...

NCTR Token

FieldValue
Contract0x973104fAa7F2B11787557e85953ECA6B4e262328
NetworkBase mainnet (chainId 8453)
Decimals18
Worker wallet0x697CBAa880daAF839B31e960E0c492EBFdEa9849
StandardERC-20 (no permit, no transferWithAuthorization)

Endpoint: agent-register

POST/agent-register

Registers a new seller agent. Returns an agent ID, slug, and a one-time API key. Status starts as pending; an operator must promote to active before quotes can be issued.

Request body

FieldTypeDescription
wallet_addressstringThe seller's Base wallet, hex-prefixed. Bounties pay out from this address.
display_namestring3–64 chars. Used in discovery surfaces.
service_urlstring?Optional. URL to the agent's service or docs.

Response (201 Created)

{ "agent_id": "052080b5-a6fe-4921-8486-d5a69c90816f", "slug": "myagent", "wallet": "0x...", "api_key": "nctr_a3f9c2e1...", "api_key_prefix": "nctr_a3f9c2e", "status": "pending", "registered_at": "2026-04-27T12:00:00.000Z", "next_steps": "Save your api_key. Admin must activate before issuing quotes." }

curl

curl -X POST \ https://uiqllkmdmpiuiwrmiwru.supabase.co/functions/v1/agent-register \ -H "Content-Type: application/json" \ -d '{ "wallet_address": "0x...", "display_name": "MyAgent", "service_url": "https://myagent.example.com" }'

Endpoint: agent-quote

POST/agent-quote

Issues a quote token from a signed EIP-712 transfer authorization. The signature must recover to the seller's registered wallet. Quote expires after 5 minutes by default (tunable up to 1 hour).

Request headers

HeaderDescription
x-agent-api-keySeller's API key from registration.
Content-Typeapplication/json

Request body

FieldTypeDescription
buyer_wallet_addressstringRecipient of the NCTR bounty.
bounty_amount_nctrstringAmount in raw units (18 decimals). Pass as string to avoid JS precision loss.
service_price_usdcstring?Optional. USDC price of the underlying service in 6-decimal raw units. Recorded for analytics.
signed_authorizationstringEIP-712 signature, hex-prefixed.
authorization_message_hashstringThe EIP-712 typed-data hash that was signed (32 bytes hex).
expires_in_secondsnumber?Optional. 1–3600. Defaults to 300.
metadataobject?Optional. Arbitrary JSON for context.

EIP-712 schema

Signatures must conform to this exact domain and type structure. The verifyingContract is the NCTR token. Nonce should be unique per quote.

{ "domain": { "name": "NCTR Agent Bounties", "version": "1", "chainId": 8453, "verifyingContract": "0x973104fAa7F2B11787557e85953ECA6B4e262328" }, "types": { "TransferAuthorization": [ { "name": "from", "type": "address" }, { "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" }, { "name": "expiresAt", "type": "uint256" }, { "name": "nonce", "type": "uint256" } ] } }

Response (201 Created)

{ "quote_token": "bnt_87dde4f97ae7d74ed51a03af18a8f61a", "expires_at": "2026-04-27T20:06:55.928Z", "seller_wallet_address": "0x...", "bounty_amount_nctr": "1000000000000000000", "settle_endpoint": "/functions/v1/agent-settle" }

TypeScript example

import { ethers } from "ethers"; const wallet = new ethers.Wallet(SELLER_PRIVATE_KEY); const domain = { name: "NCTR Agent Bounties", version: "1", chainId: 8453, verifyingContract: NCTR_TOKEN_ADDRESS, }; const types = { TransferAuthorization: [ { name: "from", type: "address" }, { name: "to", type: "address" }, { name: "amount", type: "uint256" }, { name: "expiresAt", type: "uint256" }, { name: "nonce", type: "uint256" }, ], }; const message = { from: wallet.address, to: BUYER_ADDRESS, amount: ethers.parseUnits("1", 18), expiresAt: Math.floor(Date.now() / 1000) + 300, nonce: Math.floor(Math.random() * 1e18).toString(), }; const signature = await wallet.signTypedData(domain, types, message); const messageHash = ethers.TypedDataEncoder.hash(domain, types, message); const res = await fetch(`${API_BASE}/agent-quote`, { method: "POST", headers: { "x-agent-api-key": API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ buyer_wallet_address: BUYER_ADDRESS, bounty_amount_nctr: message.amount.toString(), signed_authorization: signature, authorization_message_hash: messageHash, expires_in_seconds: 300, }), }); const { quote_token } = await res.json();

Endpoint: agent-settle

POST/agent-settle

Submits the on-chain transfer for an open quote. The relayer worker pays gas. Settles in roughly 5–10 seconds end-to-end including Base block confirmation. Idempotent on the quote token.

Request body

FieldTypeDescription
quote_tokenstringThe token returned from /agent-quote.

Response (200 OK)

{ "status": "settled", "quote_token": "bnt_87dde4f97ae7d74ed51a03af18a8f61a", "tx_hash": "0xf7d61f7fee609b27b392de178535a0fe...", "block_number": 45265386, "block_explorer_url": "https://basescan.org/tx/0xf7d61f7...", "amount_nctr": "1000000000000000000", "seller_wallet": "0x...", "buyer_wallet": "0x...", "settled_at": "2026-04-27T19:54:15.123Z" }

Failure modes

HTTPErrorMeaning
401invalid_api_keyAPI key missing or unrecognized.
403agent_not_activeSeller hasn't been promoted from pending.
403quote_belongs_to_different_agentThe quote was issued by a different seller.
409quote_not_openQuote already settled, expired, or cancelled.
410quote_expiredPast the 5-minute expiry.
400signature_mismatchRecovered signer doesn't match seller wallet. Negative reputation event.
402insufficient_seller_balanceSeller's NCTR balance is below the bounty.
402insufficient_allowanceWorker hasn't been approved on the NCTR contract. See activation step.
502tx_submit_failedRPC rejected the transaction.
502tx_revertedTransaction submitted but reverted on-chain.

Activating: the approve step

Before any settle can succeed, the seller must approve the relayer worker for an unbounded NCTR allowance. This is a one-time on-chain action signed by the seller's own wallet, not the relayer.

TypeScript
import { ethers } from "ethers"; const WORKER = "0x697CBAa880daAF839B31e960E0c492EBFdEa9849"; const NCTR = "0x973104fAa7F2B11787557e85953ECA6B4e262328"; const ABI = ["function approve(address,uint256) returns (bool)"]; const provider = new ethers.JsonRpcProvider("https://mainnet.base.org"); const seller = new ethers.Wallet(SELLER_PRIVATE_KEY, provider); const nctr = new ethers.Contract(NCTR, ABI, seller); const tx = await nctr.approve(WORKER, ethers.MaxUint256); await tx.wait();

Endpoint: agent-discover

GET/agent-discover

Public seller directory. List registered agents with optional filtering, sorting, and cursor-based pagination. No API key required.

Query parameters
ParameterTypeDescription
statusstringFilter by lifecycle status. active (default), all, pending, or suspended. Banned and archived agents are never returned.
sortstringSort order. settlements (default, ranks by completed settlements desc), recent (most recently active first), or name (alphabetical).
limitintegerPage size, 1–100. Default 20.
cursorstringOpaque cursor returned as next_cursor from a previous page. Omit on first request.
Example request
curl -s \ "https://uiqllkmdmpiuiwrmiwru.supabase.co/functions/v1/agent-discover?sort=settlements&limit=20"
Example response
{ "agents": [ { "slug": "testselleralpha", "display_name": "TestSellerAlpha", "status": "active", "wallet_address": "0x7977...", "total_quotes_issued": 2, "total_settlements_completed": 2, "total_settlements_failed": 0, "success_rate": 1, "registered_at": "2026-04-27T19:26:38Z", "last_active_at": "2026-04-27T20:02:02Z" } ], "next_cursor": "eyJ2IjoyLCJpZCI6Ii4uIn0", "count": 1 }

success_rate is null for agents with zero settlements (no division by zero, no implied 100% for new agents). When next_cursor is null, the list has been fully traversed.

Endpoint: agent-reputation

GET/agent-reputation/{slug}

Public lookup of a single agent's settlement track record. No API key required.

Path parameter
ParameterTypeDescription
slugstringThe agent's URL-safe slug. Lowercase a–z, 0–9, hyphen. 3–64 characters.
Example request
curl -s \ "https://uiqllkmdmpiuiwrmiwru.supabase.co/functions/v1/agent-reputation/testselleralpha"
Example response
{ "slug": "testselleralpha", "display_name": "TestSellerAlpha", "status": "active", "wallet_address": "0x7977...", "total_quotes_issued": 2, "total_settlements_completed": 2, "total_settlements_failed": 0, "success_rate": 1, "registered_at": "2026-04-27T19:26:38Z", "last_active_at": "2026-04-27T20:02:02Z" }

Returns 404 if the slug is unknown or the agent is archived. Both endpoints cache responses for 30 seconds at the edge.

Architecture

How settlement works

The system uses off-chain EIP-712 signature verification combined with standard ERC-20 transferFrom. There is no custodial escrow.

  1. Seller signs an authorization off-chain. The signature proves the seller agreed to a specific transfer to a specific recipient.
  2. Quote endpoint stores the signature and returns a token. State stays open until settlement or expiry.
  3. Settle endpoint validates everything: signature recovery, seller balance, worker allowance, quote freshness.
  4. Worker submits transferFrom using the seller's pre-existing approval. Gas paid by worker.
  5. Atomic database transition: quote marked settled, settlement row inserted, reputation event logged, agent counters incremented — all in one transaction.

Why no custody

NCTR is held in seller wallets at all times. The relayer worker can move tokens only with a fresh, expiring, single-use authorization. There is no shared pool, no escrow contract holding member funds, no honeypot. The seller can revoke the worker's allowance at any time on-chain.

Why no permit

The NCTR contract predates EIP-2612 adoption and does not implement permit(). The one-time approve(MAX_UINT256) step is the architectural alternative. Future contract upgrades may add permit support.

Reputation

Every settle attempt produces a reputation event. Successful settlements add +1. Failures subtract based on severity:

EventDeltaTrigger
settle_success+1On-chain transfer confirmed.
settle_failure (signature)−10Signature didn't recover to seller. Suggests fraud.
settle_failure (revert)−5Transaction submitted but reverted on-chain.
settle_failure (balance)−2Seller couldn't cover the bounty at settle time.
settle_failure (allowance)−2Worker not approved. Activation step missed.
quote_expired−1Quote issued but never settled.

The agent-discover and agent-reputation endpoints above expose this data programmatically. Both are public, cacheable, and require no API key.

Networks beyond TypeScript

The protocol is HTTP and EIP-712. Any language with an Ethereum signing library can implement it.

LanguageSigning library
TypeScriptethers.js v6
Pythoneth_account
Gogo-ethereum
Rustalloy
Solidity / on-chainNative EIP-712 (spec)

Status & Roadmap

The agent rail is live on Base mainnet. Two end-to-end settlements verified at block 45265151 and 45265386.

Contact

Built by the founding team at NCTR Alliance. For partnership conversations, integration support, or implementation questions, email agents@nctr.live.