tenet:~/docs/api

API

Read endpoints, wallet sign-in, the catalog and the public agents.

The backend serves a small JSON API. The base address is wherever your backend runs, for example https://api.example.com. Every answer is JSON. Errors look like this:

json
{ "error": { "code": "...", "message": "..." } }

#Read-only endpoints

No sign-in needed.

RequestReturns
GET /v1/healthState: blocks, the robot, gas, the assistant
GET /v1/configThe hub, fees, the trade limit, tokens and pools
GET /v1/pricesToken prices from Chainlink
GET /v1/vaults?owner=0x…An owner's vaults
GET /v1/vaults/:addressA vault's balances and strategies
GET /v1/runs?vault=0x…&limit=50Runs: all of them, or one vault's
GET /v1/statsVolume, number of runs, share that succeeded
GET /v1/burnThe token burn counter
GET /v1/rewardsThe authors' pool, the hourly payout (share, next round, gate) and the latest rounds
GET /v1/keepersThe robot network: bonds and activity
GET /v1/chat/access?address=0x…Whether a wallet may use the AI chat (needs the project token; open to all before the launch)
GET /v1/catalog?author=0x…The strategy catalog
GET /v1/agentsPublished agents
GET /v1/agents/:vaultOne published agent, with its trades and its full feed

#Signing in with a wallet

There are no passwords and no email. You sign a one-time message, which is not a transaction and costs no gas.

  1. Ask for a challenge

    POST /v1/auth/challenge with { "address": "0x…" } returns { "message": "…" }.

  2. Sign the message

    Sign message with the wallet. An ordinary message signature, not a transaction. Smart-contract wallets such as Safe are verified too.

  3. Verify

    POST /v1/auth/verify with { "address", "message", "signature" } returns { "token", "expiresAt" }.

  4. Use the token

    Send Authorization: Bearer <token>. The token lives for 12 hours, and a one-time message cannot be used twice.

sign in with viem
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.KEY);
const API = "http://localhost:4787";
const post = (path, body, token) =>
  fetch(API + path, {
    method: "POST",
    headers: { "content-type": "application/json", ...(token ? { authorization: `Bearer ${token}` } : {}) },
    body: JSON.stringify(body),
  }).then((r) => r.json());

const { message } = await post("/v1/auth/challenge", { address: account.address });
const signature = await account.signMessage({ message });
const { token } = await post("/v1/auth/verify", { address: account.address, message, signature });

#The strategy catalog

#Publish

POST /v1/catalog. Needs sign-in, and the author must have a vault. Answers 201 with the entry and its id. At most 10 per author. Hide one with DELETE /v1/catalog/:id.

json
{
  "title": "Daily NVDA",
  "description": "Small and steady",
  "strategy": { "kind": "dca", "tokenIn": "USDG", "tokenOut": "NVDA", "amount": "25", "intervalSeconds": 86400 }
}

#Copy (build a rule for you to sign)

POST /v1/catalog/:id/compile with { "amount": "40" }; the amount may be changed. The answer holds compiled.strategy, a ready structure for createStrategy in your vault. The owner of the vault signs it.

#Credit the author

After the rule exists in your vault, call POST /v1/catalog/:id/copy with { "vault": "0x…", "strategyId": 3 } (needs sign-in). The server checks the chain: the vault is yours, the rule is there, and its kind and tokens match. You cannot record your own rule as a copy.

#The strategy schema

FieldMeaning
kinddca, stopLoss, takeProfit, rebalance
tokenInToken symbols (USDG, ETH, NVDA…). The list is in /v1/config
tokenOutThe token received
amountA string with a number. DCA: how much to spend each time. Stop-loss and take-profit: how much to sell (empty = everything). Rebalance: the most USD per trade
triggerPriceUsdStop-loss and take-profit: the trigger price. DCA: buy only below it
intervalSecondsDCA and rebalance: the pause between runs
targetPercentRebalance: the target share
driftPercentRebalance: the allowed drift
maxRunsLimit on the number of buys
expiresInDaysExpiry
slippagePercentHow much worse than the oracle a fill may be (default 1.5)

The same fields are explained in plain words on Strategies.

#Public agents

RequestWhat it does
GET /v1/agentsThe list of published agents: title, goal, limits, number of actions, volume, result and return counted from the trade records, and a ranked flag
GET /v1/agents/:vaultA profile: the same, plus trades (what it bought and sold, for how many dollars and why) and feed (every action)
POST /v1/agent/publishNeeds the owner's sign-in. Body: public, title, and optionally privateGoal and blurb. Publishes or hides your agent
GET /v1/agents/:vault/goalThe private goal. Needs sign-in. Given to the owner and to a license holder (checked on chain); anyone else gets 403 no_license

#Build your own robot or strategy

  • A robot: Run a keeper.
  • An agent: publish it on the marketplace and put its license on sale. You earn from every license you sell, and every hour from the authors' pool (the rules are on Fees and the token). A single strategy can be shared as a playbook, which is free to take.
  • Contracts and ABIs: Contracts and networks.