Get OBOL
$PONTICAat launch
OBOL protocol · Agent guide

Pontica for agents

OBOL credits live on Robinhood Chain, and each one activates to $1 of inference at OpenRouter's list price. An agent can get OBOL, activate it for its own wallet, sign once for an API key and call any model through one OpenAI compatible endpoint, with no person at a checkout in between.

Status

The basic idea

OBOL is an ERC-20 token with 6 decimals, like USDG. The Mint issues it one for one against USDG that goes straight to the treasury, the wallet that pays OpenRouter for the inference. Holders can list OBOL below $1 on the book; a buy fills the deepest discount first and mints the rest at $1, so a buyer never pays more than list.

Activation burns OBOL and credits the same amount, less the activation fee, to the API balance of the wallet you name. That wallet signs one message to get its key. Every request then draws on its balance at the model's OpenRouter list price. Nothing on chain turns OBOL back into USDG.

How an agent uses it

1Get OBOL

Buy with buyWith on the Exchange and set mintRemainder: the book fills every ask that beats $1 after the fee, and whatever it cannot beat is minted at $1 through the Mint in the same transaction. Quote first with getBestQuote(usdgIn, maxFills), which returns exactly what buyWith will do. Approve exactly the USDG you spend to the Exchange.

// EXCHANGE and USDG are in the contract table below; 6 decimals for USDG and OBOL
const usdgIn = parseUnits('20', 6);
const [book, mintUsdg, mintOut] = await pub.readContract({ address: EXCHANGE, abi: exchangeAbi,
  functionName: 'getBestQuote', args: [usdgIn, 64n] });
const minCreditOut = ((book.creditOut + mintOut) * 995n) / 1000n; // other buys may land first
await wallet.writeContract({ address: USDG, abi: erc20Abi, functionName: 'approve', args: [EXCHANGE, usdgIn] });
await wallet.writeContract({ address: EXCHANGE, abi: exchangeAbi, functionName: 'buyWith', args: [{
  usdgIn, minCreditOut, recipient: account.address, maxFills: 64n, mintRemainder: true, referrer: zeroAddress,
}] });

To skip the book, mint directly: fund(usdgIn, recipient) on the Mint (approve USDG to the Mint first), or fundETH(minUsdgOut, recipient, deadline) with ETH as the value, which swaps on the WETH/USDG 0.01% pool and mints what the swap returns. Quote ETH by calling fundETH with eth_call; there is no quoter on this chain.

The classic buy and buyAndActivate are book only. Only buyWith and buyAndActivateWith with mintRemainder promise that you never pay more than $1 for an OBOL.

2Activate what it needs

Call activate(amount, beneficiary) on the OBOL token. The whole amount is burned from the caller; the beneficiary is credited the amount less the activation fee. previewActivation(amount) returns both numbers first. To buy and activate in one transaction use buyAndActivateWith(args, beneficiary) on the Exchange, or fundAndActivate(usdgIn, beneficiary) and fundETHAndActivate(minUsdgOut, beneficiary, deadline) on the Mint.

const [credited, fee] = await pub.readContract({ address: OBOL, abi: obolAbi,
  functionName: 'previewActivation', args: [parseUnits('10', 6)] });
await wallet.writeContract({ address: OBOL, abi: obolAbi, functionName: 'activate',
  args: [parseUnits('10', 6), account.address] });

The API balance of a wallet is creditedOf(wallet) on the OBOL token, the running total of everything credited to it. The gateway reads it with one call.

3Sign once for API access

Sign this Sign-In with Ethereum text with the wallet that holds the balance (personal_sign over the UTF-8 bytes), then send it to POST https://pontica.gg/api/v1/keys as { address, message, signature }. Lines are joined with a newline and there is no trailing newline. The nonce is 16 lowercase hex characters, the times are UTC with seconds, and the message expires at most 10 minutes after it was issued.

pontica.gg wants you to sign in with your Ethereum account:
{address, EIP-55 checksum}

Issue a Pontica API key for this wallet. This retires any key it already has.

URI: https://pontica.gg
Version: 1
Chain ID: 4663
Nonce: {16 lowercase hex}
Issued At: {e.g. 2026-09-22T09:30:00Z}
Expiration Time: {Issued At + 10 minutes}

The answer is 201 with { key, hash, base_url, address, activated_usd, used_usd, limit_usd, remaining_usd, replaced, note }. The secret key appears in this answer only; keep hash (the SHA-256 of the key) to sync later. A wallet has one live key: issuing a new one retires the old one. Treat the signed message like a password until it expires.

4Work

The base URL is https://pontica.gg/api/v1 and the key is a bearer token. Any OpenAI or OpenRouter client works: POST /chat/completions (streaming with stream: true) and GET /models for the live catalogue.

import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://pontica.gg/api/v1', apiKey: process.env.PONTICA_API_KEY });
const reply = await client.chat.completions.create({
  model: 'anthropic/claude-sonnet-5',
  messages: [{ role: 'user', content: 'Plan the next task in three steps.' }],
});

5Know your balance

GET /api/v1/key with the bearer answers OpenRouter's key object, where limit_remaining is what the key can still spend, plus a pontica block: { address, activated_usd, used_usd, remaining_usd, retired, needs_sync }. needs_sync: true means an activation is not in the key's limit yet.

curl https://pontica.gg/api/v1/key -H "Authorization: Bearer $PONTICA_API_KEY"

6Refill

Activate more OBOL to the same wallet, then raise the key's limit to what the chain proves: POST /api/v1/keys/sync with the bearer (or with the body { hash }). No signature is needed; the answer is { address, hash, activated_usd, used_usd, limit_usd, remaining_usd, synced }. The key stays the same.

curl -X POST https://pontica.gg/api/v1/keys/sync -H "Authorization: Bearer $PONTICA_API_KEY"

7Get funded

People can fund an agent through AI Funding: a fund names the agent's wallet as its beneficiary, with a goal in OBOL, a deadline and an optional daily cap. Once the fund succeeds, the beneficiary calls draw(id, amount, to) or drawAndActivate(id, amount, account) on the Funds contract, at most the daily cap per UTC day (drawable(id) says what is left today). If the deadline passes below the goal, backers take their OBOL back with refund(id).

Where the discount comes from

Only from holders who list OBOL below $1 with sell(obolAtoms, price). Prices sit on a grid of 2.5% steps from 97.5% of list down to 2.5%, and a buy takes the deepest discount first, the oldest ask first within a price. When the book is empty there is no discount and every buy mints at $1. Sellers are paid in USDG and claim it with claim(to).

Fees and limits

Read live from the contracts on this page load. A fee increase is announced by the owner and takes force after one day (pendingFee() shows it); decreases apply at once.

WhatValueWhere to read it
Book fee, inside the buyer's budgetExchange.feeBps()
Referrer's share of the book feeExchange.referralShareBps()
Mint feeMint.mintFeeBps()
Activation feeObol.activationFeeBps()
Most asks one buy fillsExchange.MAX_FILLS()
Smallest askExchange.MIN_ORDER()
Price grid2.5% steps, 2.5% to 97.5% offPRICE_STEP(), MIN_PRICE(), MAX_PRICE()
Request body4.5 MB at mostlarger inputs: openrouter.ai/api/v1 with the same key
Streaming response300 s at mostlonger generations: openrouter.ai/api/v1
Keys per wallet5 in 24 hours429 too_many_keys

Errors

Pontica's own errors share one body; errors from OpenRouter pass through unchanged.

{ "error": { "message": "Plain sentence.", "type": "invalid_request_error", "code": "signature_expired", "param": "message" } }
HTTPCodesWhat to do
400bad_json missing_field bad_address bad_message wrong_chain wrong_domain address_mismatch signature_expired signature_from_future unsupported_parameterFix the request or sign a fresh message.
401missing_key bad_signature not_a_pontica_key key_retiredUse the current key, or issue a new one.
402nothing_activatedActivate OBOL to this wallet first.
404no_key not_foundThis wallet has no key yet.
409signature_used issue_conflictAnother key request crossed this one. Sign again.
413body_too_largeSend large inputs to openrouter.ai/api/v1 with the same key.
429too_many_keysFive keys in 24 hours. Try again later.
502upstream_unavailable chain_unavailableThe gateway could not reach OpenRouter or Robinhood Chain. Try again.
503gateway_not_connected gateway_key_expiredThe inference gateway is not connected. Keys and chat open when it is.

Contracts

Robinhood Chain, chain id 4663. Every contract is verified on Sourcify; the explorer is Blockscout.

Contract and addressABI

The same list, as plain text: agents.md and llms.txt.

Connect a wallet

Pontica never holds your keys. Connecting shares your address only.