CLI and SDK

The tollgate npm package ships both a command line tool and a small SDK in one module: publish paid resources from a folder, and fetch x402-protected URLs with automatic payment from any Node script. It requires Node 20 or newer. The only dependency is viem, and it is loaded lazily, only when you pay on-chain with the exact scheme.

npx tollgate            # prints usage and the active base URL
# or, from a checkout of this repo:
node sdk/bin/tollgate.js

Environment variables

Variable Format Used by Purpose
TOLLGATE_URL URL publish, me, agents Platform base URL. Defaults to https://web-production-095eb.up.railway.app. A trailing slash is stripped. get and pay take full URLs, so they ignore this.
TOLLGATE_PUBLISHER_KEY tg_pk_ + 32 hex chars publish, me, agents Publisher key, sent as Authorization: Bearer. Find it on your storefront dashboard. Required for these commands, the CLI exits 1 without it.
TOLLGATE_API_KEY tg_sk_ + 32 hex chars get, pay Agent key for the custodial tollgate-credit scheme. The platform settles from the agent's balance.
TOLLGATE_EVM_KEY 0x… private key get, pay EVM private key for the exact scheme, real USDC signed locally via EIP-3009. The key never leaves your machine, only the signature is sent.

Commands

tollgate publish

tollgate publish <dir> --price 0.004 [--title T] [--slug s] [--description D] [--kind folder] [--unit request]

Walks <dir> recursively, collects text files, and POSTs them to POST /api/resources as one resource. Requires TOLLGATE_PUBLISHER_KEY.

Flags:

Flag Required Default Notes
--price yes none USD per unit, for example 0.004. Minimum 0.001, up to 6 decimal places.
--title no basename of <dir> Trimmed server-side, must be non-empty.
--slug no slugified title Lowercased, non-alphanumerics become hyphens, max 40 chars. The resource goes live at /r/<slug>.
--description no empty Truncated to 300 characters server-side.
--kind no folder One of feed, folder, dataset, site, tool. Anything else silently falls back to folder.
--unit no request One of request, document, copy, query. Anything else falls back to request.

Publishing to a slug you already own updates that resource in place (title, description, kind, price, unit, and the full file set are replaced). Publishing to a slug owned by someone else fails with 409 slug_taken.

Which files get picked up:

Server-side caps (from src/routes/publisher-api.ts):

On success the CLI prints the live URL, price, unit, and paths:

live at https://web-production-095eb.up.railway.app/r/eu-rates
price $0.004 / request · paths: /today /history.csv

The first line says updated at … instead of live at … when an existing slug was overwritten.

tollgate get

tollgate get <url> [--scheme credit|exact]

Fetches a URL through payFetch (see below). If the server answers 200 directly, the body is printed and nothing is paid. If it answers 402, the CLI pays once using the selected scheme and prints the body to stdout. The receipt line goes to stderr, so piping stdout gives you clean content:

TOLLGATE_API_KEY=tg_sk_... npx tollgate get https://web-production-095eb.up.railway.app/r/eu-rates/today > today.md
# stderr: paid · receipt tg_9f2e4c1a

With --scheme exact the receipt line also includes the transaction hash when the settlement response carries one.

Scheme selection: --scheme accepts exactly credit or exact. Any other value (or no flag) falls through to auto-detection: exact if TOLLGATE_EVM_KEY is set and TOLLGATE_API_KEY is not, otherwise credit.

tollgate pay

tollgate pay <url> [--scheme credit|exact]

Same as get, but prints only the receipt line, never the body. Useful for scripted spending checks. On a free resource it prints nothing and exits 0.

tollgate me

TOLLGATE_PUBLISHER_KEY=tg_pk_... npx tollgate me

Prints your display name, email, and balance, then one line per resource with live status, title, price per unit, and URL. Calls GET /api/me.

tollgate agents

TOLLGATE_PUBLISHER_KEY=tg_pk_... npx tollgate agents

Lists your agents with id, name, balance, wallet address, the tg_sk_ API key, and the schedule if one is set. Calls GET /api/agents.

Flag parsing

Flags take the next argument as their value (--price 0.004). A flag immediately followed by another flag becomes a boolean true, so always give value-flags an explicit value.

Exit behavior

SDK

import { payFetch, buildCreditHeader, buildExactHeader } from 'tollgate';

payFetch(url, opts)

Fetches a URL and transparently pays a 402 exactly once: first request without payment, and if the response is 402 it reads the JSON offer, builds an X-PAYMENT header for the chosen scheme, and retries the same URL once. There is no retry loop beyond that single paid attempt.

Options:

Option Type Meaning
apiKey string tg_sk_ agent key for the tollgate-credit scheme.
evmKey string 0x… private key for the exact scheme.
scheme 'credit' or 'exact' Force a scheme. Omitted: exact when only evmKey is given, otherwise credit.
fetchFn function Replacement for global fetch, useful in tests.
headers object Extra request headers, merged over the default Accept: application/json.

Return shape:

Field Present Meaning
response always The final Response. The first response if no 402 happened, the post-payment response otherwise.
paid always false if the first response was not a 402. After a payment attempt, true only when the retried request returned 200.
offer after a 402 The parsed 402 body, including the accepts array of payment requirements.
receipt after a 402 Value of the x402-receipt response header, undefined if absent.
settlement after a 402 The x-payment-response header, base64-decoded and JSON-parsed. For exact payments it includes the transaction hash under transaction.

Errors are thrown, not returned: no apiKey when the credit scheme is needed, no evmKey for exact, an offer that lacks the requested scheme, or an unknown scheme value all throw with a descriptive message.

buildCreditHeader(apiKey)

Synchronous. Returns the base64 X-PAYMENT header value for the custodial scheme: a JSON envelope with x402Version: 1, scheme: "tollgate-credit", network: "tollgate", and the key in payload.apiKey. Use it when you want to drive fetch yourself.

buildExactHeader(requirement, evmKey)

Async. Takes one entry from the offer's accepts array (the one with scheme: "exact") and a private key, signs an EIP-3009 TransferWithAuthorization with viem, and returns the base64 header value. Behavior details, all from sdk/index.js:

The signature is created locally, nothing is broadcast by the SDK. Settlement happens server-side via the facilitator when you submit the header.

Examples

Credit: pay with an agent key

// buy.mjs, run with: node buy.mjs
import { payFetch } from 'tollgate';

const url = 'https://web-production-095eb.up.railway.app/r/eu-rates/today';
const { response, paid, receipt } = await payFetch(url, {
  apiKey: process.env.TOLLGATE_API_KEY,
});

if (!response.ok) {
  const body = await response.json().catch(() => ({}));
  throw new Error(`${response.status} ${body.error ?? 'payment failed'}`);
}
if (paid) console.error(`paid, receipt ${receipt}`);
console.log(await response.text());
TOLLGATE_API_KEY=tg_sk_your_agent_key node buy.mjs

Exact: pay with real USDC from a funded wallet

// buy-onchain.mjs, run with: node buy-onchain.mjs
import { payFetch } from 'tollgate';

const url = 'https://web-production-095eb.up.railway.app/r/eu-rates/today';
const { response, paid, receipt, settlement } = await payFetch(url, {
  evmKey: process.env.TOLLGATE_EVM_KEY,
  scheme: 'exact',
});

if (!paid) {
  const body = await response.json().catch(() => ({}));
  throw new Error(`${response.status} ${body.error ?? 'payment failed'}`);
}
console.error(`paid, receipt ${receipt}, tx ${settlement?.transaction}`);
console.log(await response.text());
# The wallet must hold USDC on the offer's network (Base Sepolia by default).
TOLLGATE_EVM_KEY=0x...buyer_private_key... node buy-onchain.mjs

The same two flows are available without writing code: npx tollgate get <url> and npx tollgate get <url> --scheme exact. See Go live with real USDC for funding a test wallet.