ZEAM::Pass

01 · Node

@zeam-labs/pass

Requires
Node 18 or later
Version
1.0.2

Install

npm install @zeam-labs/pass express

app.mjs

import express from 'express'
import { pass } from '@zeam-labs/pass'

const agents = pass({
  name: 'acme',
  site: 'https://acme.example',
  mode: 'paywall',
  price: '0.02',
  payout: '0xYourWalletAddress',
})
agents.tool({
  name: 'add',
  description: 'Adds two numbers.',
  inputSchema: {
    type: 'object',
    properties: { a: { type: 'number' }, b: { type: 'number' } },
    required: ['a', 'b'],
  },
  run: async ({ a, b }) => ({ sum: a + b }),
})

const app = express()
app.use(agents.express('/agents'))
app.listen(3000)

Put your wallet address in payout. pass() refuses a placeholder.

node app.mjs

Your tools are at http://localhost:3000/agents/mcp. On a fetch host, serve agents.handle('/agents') instead of Express. With no name, pass() reads ./pass.json.

02 · Python

zeam-pass

Requires
Python 3.9 or later
Installs
coincurve, pycryptodome

Install

pip install zeam-pass fastapi uvicorn

app.py

from fastapi import FastAPI
from zeam_pass import Pass

agents = Pass(name="acme", payout="0xYourWalletAddress", price="0.01")

@agents.tool(description="Multiplies two numbers.", input_schema={"type": "object", "properties": {"a": {"type": "number"}, "b": {"type": "number"}}, "required": ["a", "b"]})
def multiply(a, b):
    return {"product": a * b}

app = FastAPI()
app.mount("/agents", agents.asgi())

Put your wallet address in payout.

uvicorn app:app --port 3000

Your tools are at http://localhost:3000/agents/mcp. Flask mounts the WSGI app:

app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {"/agents": agents.wsgi()})

03 · WordPress

ZEAM Pass

Requires
WordPress 6.0 or later, tested to 7.1
PHP
7.4 or later, with GMP or BCMath, and sodium
Version
1.0.1

Your site must be reachable from the internet and use pretty permalinks.

Install

  1. Plugins → Add New, search “ZEAM Pass”, Install Now.
  2. Or download zeam-pass.zip from wordpress.org/plugins/zeam-pass and use Plugins → Add New → Upload Plugin.

Set up

  1. Download the plugin: https://zeampass.com/downloads/zeam-pass-1.0.1.zip (its SHA-256 is next to it, at the same address plus .sha256). Plugins → Add New → Upload Plugin, choose the zip, Install Now, then Activate. Coming to the WordPress.org plugin directory.
  2. Settings → ZEAM Pass.
  3. Connect your payout wallet: your browser wallet, or paste the address.
  4. Choose gate, paywall or both. Paywall: set a price per call; optional, a price or Free per tool and free calls an hour per address. Gate: list the addresses of the keys you admit. "Contact for access": a web address or a mailto: address where an agent asks to be admitted. Agents see it in every 402 and when a key is refused. Empty: your site's address; your admin email is never shown.
  5. Gate, optional: the Grants box signs a grant with your browser wallet, when it holds a listed key.
  6. Save. The page shows your split, earnings, gate usage and the credit wallet to fund.

Add an encryption key of at least 32 random characters to wp-config.php and keep it:

define('ZEAM_PASS_KEY', '…');

Agents get two tools, search_posts and read_post, over your posts.

04 · Settings

Settings.

mode

Paywall, gate or both.

Node
mode
Python
mode
WordPress
Mode
Default
paywall

price

USD per call, up to 6 decimals ("0.02"); the price of a tool with none of its own; required for paywall and both unless prices is set.

Node
price
Python
price
WordPress
Price per call (USD)
Default
none

payout

The wallet address earnings go to; a gate's zero-value proofs name it, and nothing is paid to it.

Node
payout
Python
payout
WordPress
Payout wallet
Default
none

admit

The addresses of the keys a gate admits (gate and both).

Node
admit
Python
admit
WordPress
Admitted keys
Default
[]

contact

An https:// URL or a mailto: address; goes in every 402, in the 403 refused answer (how and contact) and in openapi.json info.contact.

Node
contact
Python
contact
WordPress
Contact for access
Default
Node and Python none; WordPress your site's address

name

2 to 32 of a-z, 0-9 and -, starting with a letter; fixes your split's address.

Node
name
Python
name
WordPress
Name
Default
none

site

Your public origin, used in the 402's resource and refund URL.

Node
site
Python
site
WordPress
your site
Default
the request's origin

onEmpty

Gate credit at 0: refuse, or allow and warn.

Node
onEmpty
Python
on_empty
WordPress
When gate credit runs out
Default
refuse

state dir

Keys, channel records, gate usage; relative to the working directory.

Node
stateDir
Python
state_dir
WordPress
its database
Default
Node $PASS_STATE_DIR or ./.pass; Python ~/.zeam-pass/<name>, or PASS_STATE_DIR

05 · Pricing

Per call, per tool, per unit, by time.

Per call

One price for every tool with none of its own.

Node
price
Python
price
WordPress
Price per call (USD)
Default
none; paywall and both need price or prices

Per tool

A tool's own price, else prices[tool], else price.

Node
price on tool(), or prices: { tool: '0.05' } or (tool, args) => price
Python
@agents.tool(price=...), or prices
WordPress
Per tool: a price per tool; the zeam_pass_prices filter
Default
none

Per unit used

The call reserves the tool's price. The tool reports whole units. Charge: units × unit, at most the reserve. No units reported: nothing charged.

Node
unit on tool(); meter.units(n) in run
Python
@agents.tool(unit=...); units(n)
WordPress
unit in the zeam_pass_tools filter; $meter->units($n)
Default
none

By time

The agent buys blocks with buy_time, opens a line, and calls meter: 'time' tools on it with no payment per call. Time burns while a call runs, plus idleMs after each. Unburned time goes back with a refund. Paywall and both only. Adds buy_time, line and POST <base>/line.

Node
time: { block, blockMs, idleMs, maxBlocks }; meter: 'time' on tool()
Python
time={...}; @agents.tool(meter="time")
WordPress
Line time (USD per block) and ms; 'meter' => 'time' in the zeam_pass_tools filter
Default
off; blockMs 250, idleMs 0, maxBlocks 14,400 and at most $1,000 of blocks

Free

No payment, no key. Arguments still checked.

Node
free: ['ping'], or free: true on tool()
Python
free=[...], or @agents.tool(free=True)
WordPress
Free, per tool
Default
none

Free limit

Free calls per tool, per client address, per clock hour. Over it: 429 free_limit.

Node
freeLimit: 60
Python
free_limit=60
WordPress
Free calls an hour per address
Default
no limit

app.mjs

import express from 'express'
import { pass } from '@zeam-labs/pass'

const run = async () => ({ ok: true })
const agents = pass({
  name: 'acme', payout: '0xYourWalletAddress', price: '0.02', freeLimit: 60,
  time: { block: '0.00025', blockMs: 250, idleMs: 0, maxBlocks: 14400 },
})
agents.tool({ name: 'report', price: '0.05', run })
agents.tool({ name: 'ping', free: true, run })
agents.tool({
  name: 'words', price: '0.05', unit: '0.0001',
  run: async ({ text }, meter) => {
    meter.units(text.length)
    return { ok: true }
  },
})
agents.tool({ name: 'scan', meter: 'time', run: async (args, { signal, deadline }) => ({ until: deadline }) })

const app = express()
app.use(agents.express('/agents'))
app.listen(3000)

app.py

from fastapi import FastAPI
from zeam_pass import Pass, deadline_ms, units

agents = Pass(name="acme", payout="0xYourWalletAddress", price="0.02", free_limit=60,
              time={"block": "0.00025", "blockMs": 250, "idleMs": 0, "maxBlocks": 14400})


@agents.tool(price="0.05")
def report():
    return {"ok": True}


@agents.tool(free=True)
def ping():
    return {"ok": True}


@agents.tool(price="0.05", unit="0.0001", input_schema={"type": "object", "properties": {"text": {"type": "string"}}, "required": ["text"]})
def words(text):
    units(len(text))
    return {"ok": True}


@agents.tool(meter="time")
def scan():
    return {"until": deadline_ms()}


app = FastAPI()
app.mount("/agents", agents.asgi())

report: $0.05 per call. ping: free, 60 calls an hour per address. words: reserves $0.05, charges $0.0001 per unit. scan: burns line time; without a line, a paid call of $0.02 that runs up to 20 s.

The 402 carries this call’s amount, pricing for it, and prices for every tool. tools/list: _meta["zeam-pass/price"]. OpenAPI: x-price.

06 · What it creates

Keys and split.

Settle key

Made on first run. It signs your claims and refunds and holds no money. Node and Python keep it in keys.json in the state dir, mode 0600; set PASS_KEY_SECRET to seal it. WordPress keeps it encrypted in its database. Back it up: a lost settle key cannot claim what your channels owe you.

Credit wallet

Made for gate and both. In gate mode, send it USDC on Base; it needs no ETH. In both mode it needs nothing.

Split

Your earnings go to a split contract that nobody owns. It pays 90.01% to your payout wallet and is created by your first payout. Its address depends on your name and payout wallet.

Node, Python
agents.status(): receiver (split), settleKey, creditWallet
WordPress
Settings → ZEAM Pass: Your split, Settle key, Credit wallet

07 · What agents see

MCP, HTTP, OpenAPI, 402.

MCP
/agents/mcp · /wp-json/zeam-pass/mcp
HTTP
POST /agents/v1/<tool> · POST /wp-json/zeam-pass/v1/<tool>
OpenAPI
/agents/openapi.json · /wp-json/zeam-pass/openapi.json
Refunds
POST /agents/refund · POST /wp-json/zeam-pass/refund

An unpaid call answers 402 with your price: accepts[].amount in micro-USDC, "20000" is $0.02. Over MCP, the tool result carries the same terms. The agent pays in USDC on Base over x402 and gets the answer.

Bad arguments, or a tool that fails, cost the agent nothing. What an agent deposits and does not spend, it takes back at the refunds route.

Paying needs no ETH. A refund the seller sends needs no ETH. selfSend, initiateWithdraw and finalizeWithdraw are transactions from your wallet and need ETH on Base for gas.

A gate

A gate’s 402 asks for amount: "0". The agent signs it with its own key, as a zero-value x402 payment: nothing is paid, the key needs no funds and no ETH, and nothing goes on chain. You list the keys you admit in admit.

A key you admit lets one other key in with a grant, sent as the x-grant header. Sign one with signGrant in Node, sign_grant in Python, or the Grants box on the WordPress settings page. The grant works only for the key it names.

09 · Costs

You keep 90.01% of every sale.

Paywall
you keep 90.01% of each sale; ZEAM pays the gas
Gate
10,000 checks a month free, then 2,000 checks for $1 USDC
Both
you keep 90.01% of each sale; paid calls are not gate checks
Payouts
to your wallet once a payout covers its gas; the first waits for about $0.10

For a gate, keep $1 USDC on Base in the credit wallet.