Developer docs

Integrate in one minute.

Gatefare is an x402 payment proxy for APIs. AI agents pay USDC per request; publishers get 90% split on-chain. Two tracks — one if you're an agent (buying), one if you're a developer (selling or integrating). Complete endpoint reference at the bottom.

0 · Before you start

Four facts everyone hits on their first call. Read once, then copy any snippet below without guessing.

Base URL
https://gatefare.io. All paths in this doc are relative to it. Self-hosted deployments swap the origin — the paths and shapes are identical.
CSRF header (required)
Every non-GET request must carry X-Gatefare-Request: 1 (any non-empty value works). Without it the server replies 403 · CSRF_HEADER_REQUIRED. This is a simple anti-CSRF gate: browsers can't forge custom headers cross-origin. All curl / fetch / httpx examples on this page already include it.
Auth header
Pass a JWT or a PAT in Authorization: Bearer <token>. PATs are recommended for scripts (prefix gfpat_, never expire by default). Details in step II / III.
Rate limits
120/min per IP on catalog reads · 60/min per IP on the payment proxy · 20/15min per IP on auth endpoints. Responses on the 429 path carry standard RateLimit-* headers so clients can back off automatically.
Network
Production is Base mainnet (eip155:8453). Test environment is Base Sepolia (eip155:84532) — free USDC from Circle faucet. Testnet APIs are hidden from the public catalog by default; pass ?includeTestnet=1 to see them.
Errors
Every error response is JSON: { "error": "message", "code": "MACHINE_CODE" }. Stable machine codes at the bottom of this page — switch on them, not the message string.
What you need: a wallet on Base (chain ID 8453) with some USDC for paying APIs. Any EVM-compatible wallet works — viem, ethers, Coinbase AgentKit, MetaMask, private-key-only bots.
1

Sign in with your wallet (SIWE)

Gatefare uses EIP-4361 Sign-In With Ethereum. Your agent signs one message; that signature doubles as Terms acceptance and authentication. No email, no password.

python
# pip install requests eth-account
import requests
from eth_account import Account
from eth_account.messages import encode_defunct

WALLET_KEY = "0xYOUR_PRIVATE_KEY"   # Your Base wallet
BASE_URL = "https://gatefare.io"
H = {"Content-Type": "application/json", "X-Gatefare-Request": "1"}

account = Account.from_key(WALLET_KEY)
# 1. Ask for a nonce.
r = requests.post(f"{BASE_URL}/api/auth/siwe/nonce", headers=H, json={
    "wallet":  account.address,
    "chainId": 8453,  # Base mainnet
})
r.raise_for_status()
chal = r.json()
print(f"ToS version you're accepting by signing: {chal['tosVersion']}")

# 2. Sign the exact message (includes ToS acceptance).
msg = encode_defunct(text=chal["message"])
signed = Account.sign_message(msg, private_key=WALLET_KEY)

# 3. Verify → receive JWT + user.
r = requests.post(f"{BASE_URL}/api/auth/siwe/verify", headers=H, json={
    "wallet":    account.address,
    "signature": signed.signature.hex(),
})
r.raise_for_status()
session = r.json()
print(f"Logged in as user {session['user']['id']}, JWT: {session['token'][:20]}…")
2

Mint a long-lived access token (PAT)

The JWT from step 1 expires in 7 days. For long-running agents, exchange it immediately for a personal access token (gfpat_…). Store it securely — if it leaks, revoke from the dashboard.

bash
curl -X POST https://gatefare.io/api/auth/pat \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -H "X-Gatefare-Request: 1" \
  -d '{"label":"agent-prod","scopes":["read"],"expiresInDays":365}'
# → { "token": "gfpat_abc123…", "summary": { "id": 1, "label": "agent-prod", ... } }
#
# Save the "token" string in a secret manager. You can't retrieve it again.
# Use it exactly like a JWT:
curl https://gatefare.io/api/auth/me \
  -H "Authorization: Bearer gfpat_abc123…"

Tokens carry the gfpat_ prefix so scanners like gitleaks flag leaks in public repos instantly. Choose scopes carefully — see the PAT scopes table.

3

Discover APIs in the marketplace

Browse every public API with a single HTTP GET. Filter by category, price, or full-text search. No auth required for catalog reads.

bash
# Browse by category + price
curl "https://gatefare.io/api/catalog?category=ai-ml&price_max=0.05&sort=popular"

# Full-text search
curl "https://gatefare.io/api/catalog?q=weather&sort=popular"

# Autocomplete suggestions (up to 8)
curl "https://gatefare.io/api/catalog/search/suggest?q=weath"

# Trending this week (system-curated collection)
curl "https://gatefare.io/api/catalog/collections/system:trending"

# Category list with API counts
curl "https://gatefare.io/api/catalog/categories"

See the public marketplace and llms.txt (LLM-friendly site map) for structured discovery.

4

Pay per request with x402

Call the proxy URL. First call returns 402 Payment Required with the full x402 v2 payload. Second call, with an X-Payment header (base64-encoded signed USDC transfer), returns the upstream response. x402 clients handle this handshake automatically.

python
# pip install x402-client requests
from x402.client import PaymentClient

client = PaymentClient(wallet_private_key="0xYOUR_KEY", chain_id=8453)
response = client.get("https://gatefare.io/p/alice/weather")
# First call returns 402; client auto-signs USDC transfer + retries.
# Returns the upstream response body.
print(response.json())

The proxy caps every payment at 1.1× the posted price server-side; larger X-Payment amounts are rejected. This protects agents from a malicious publisher raising the price between discovery and sign.

5

Budget limits — don't overspend

Every x402-aware client should also enforce its own budget:

  • Per-call cap: reject any API whose price exceeds your max.
  • Per-task budget: sum costs across all calls, abort when you hit the limit.
  • Balance check: read your wallet USDC balance before each call if you're on a tight budget.
  • Retry with ceiling: if you see 402 after a successful signing round, the price probably changed — refresh the quote, don't silently re-sign.

Coinbase AgentKit works out of the box

AgentKit ships with an x402 helper. Point it at https://gatefare.io/p/…, supply the signer, done.

PAT scopes

Token scopes.

Scopes are monotonic — each one implies everything weaker. Pick the narrowest one your use case needs; you can always mint a second token if you need more.

ScopeImpliesWhat it unlocks
readCatalog reads, /my/* listing, balance / revenue views.
write:catalogreadRegister APIs, edit non-sensitive fields (name, description, categories, tags, price).
write:sensitiveread, write:catalogDelete APIs, trigger distribute(), edit owner wallet / URL.
write:walletRotate your session wallet. Non-delegatable (a child PAT can't carry this).
admin:patMint + revoke additional PATs. Non-delegatable.
fulleverything aboveGod-mode. Use only for ephemeral local testing.
Errors

Stable error codes.

All error responses are JSON with a human error string and a stable machine code. Switch on code; the string may be tuned for clarity.

StatusCodeWhat it means · how to fix
403CSRF_HEADER_REQUIREDMissing X-Gatefare-Request. Add the header to every non-GET request.
401UNAUTHENTICATEDNo valid JWT/PAT. Check Authorization: Bearer ….
403INSUFFICIENT_SCOPEYour PAT lacks the scope the endpoint needs. Mint a new PAT with a stronger scope.
400HANDLE_REQUIREDYour account has no publisher handle. PATCH /api/auth/me with { handle: "..." }.
400WALLET_SIGNATURE_REQUIREDownerWallet differs from your linked wallet. Call /api/wallet-challenge → sign → resubmit.
400WALLET_SIGNATURE_INVALIDSignature didn't recover to ownerWallet. Check EIP-191 personal_sign, not typed-data.
400TARGET_URL_HAS_QUERYtargetUrl contains ? or #. Move auth into the headers field instead.
402PAYMENT_REQUIREDExpected. Parse the accepts array, sign an EIP-3009 USDC transfer, retry with X-Payment.
409SLUG_TAKENAnother publisher already owns this urlName under your handle. Pick a new one.
429RATE_LIMITEDYou hit the per-IP ceiling. Back off per the RateLimit-Reset header.
Reference

Complete endpoint reference.

Every route exposed by the platform. Scopes marked apply to PATs; JWT sessions satisfy any scope.

Public

No auth required. Rate-limited per IP.

MethodPathScopeSummary
GET/api/infoPlatform info — version, network, public stats.
GET/api/networksSupported networks (Base mainnet, Base Sepolia).
GET/api/landingLanding-page payload (featured, latest, categories).
GET/api/catalogBrowse APIs. Filters: category, price_max, q, sort.
GET/api/catalog/:slugSingle API detail by slug.
GET/api/catalog/:handle/:urlNameSingle API by handle+urlName (canonical form).
GET/api/catalog/search/suggestAutocomplete suggestions — up to 8.
GET/api/catalog/categoriesCategory list with API counts.
GET/api/catalog/collectionsPublic collections (published only).
GET/api/catalog/collections/:slugCollection detail.
GET/api/publishers/:handlePublic publisher profile.

Auth

Email+password or SIWE. All mutations require the CSRF header.

MethodPathScopeSummary
POST/api/auth/registerCreate account. Requires acceptTerms: true.
POST/api/auth/loginEmail+password login → JWT.
POST/api/auth/logoutClear session cookie.
POST/api/auth/siwe/nonceRequest a SIWE challenge for a wallet.
POST/api/auth/siwe/verifySubmit signed SIWE message → JWT.
GET/api/auth/mereadCurrent user profile.
PATCH/api/auth/mereadUpdate profile. Set handle here.
POST/api/auth/verify-emailreadTrigger / verify email verification.
POST/api/auth/forgot-passwordEmail a password-reset link.
POST/api/auth/reset-passwordSubmit new password with reset token.
POST/api/auth/2fa/setupreadStart TOTP 2FA enrolment.
POST/api/auth/2fa/enablereadFinish TOTP 2FA enrolment.
POST/api/auth/2fa/disableread (fresh)Disable TOTP 2FA (requires recent auth).
GET/api/auth/me/auditreadYour own audit log (logins, PAT mints, etc.).
GET/api/auth/me/exportreadJSON data export (GDPR / portability).
POST/api/auth/me/deleteread (fresh)Account deletion.

Personal Access Tokens

Long-lived bearer tokens for scripts and CI.

MethodPathScopeSummary
POST/api/auth/patCreate a PAT. Body: { label, scopes[], expiresInDays }.
GET/api/auth/patreadList your PAT metadata (token strings never returned again).
DELETE/api/auth/pat/:idreadRevoke a PAT immediately.

Publisher

Register and manage APIs. Slug, urlName, wallet — see step 4.

MethodPathScopeSummary
POST/api/wallet-challengereadRequest an EIP-191 message to prove wallet ownership.
POST/api/registerwrite:catalogRegister a new API. Returns proxyUrl + splitAddress.
GET/api/myreadList your APIs.
GET/api/my/:slugreadSingle API — your ownership view.
PATCH/api/my/:slugwrite:catalog*Update API. Sensitive fields bump the requirement to write:sensitive.
DELETE/api/my/:slugwrite:sensitiveSoft-delete (30-day undelete window).
GET/api/my/:slug/balancereadOn-platform accumulated balance.
GET/api/my/:slug/split-balancereadUSDC currently sitting in the split contract.
GET/api/my/:slug/revenue-seriesread30-day revenue series for charting.
GET/api/my/:slug/requestsreadPaginated paid-request log.
POST/api/my/:slug/withdrawwrite:sensitiveAlias for distribute(), for legacy clients.
POST/api/my/:slug/distributewrite:sensitiveCall distribute() on the split contract on-chain.
GET/api/notificationsreadYour notifications feed.
GET/api/notifications/unread-countreadBadge counter for the nav bell.

Payment proxy

The consumer side of x402. No Gatefare auth; pay via USDC signature.

MethodPathScopeSummary
ANY/p/:handle/:urlNameCanonical proxy URL. First call: 402 + x402 payload. Second: upstream.
ANY/p/:slugLegacy form. Redirects to the canonical /:handle/:urlName.

Trust & safety

Abuse reports and public transparency data.

MethodPathScopeSummary
POST/api/abuse/reportSubmit abuse or DMCA notice. Rate-limited 5/hour per IP.
GET/api/abuse/transparencyPublic transparency stats — report volumes, enforcement counts.