The rules API

Everything the Ventura app does, it does through these calls — there is no private endpoint behind it. They are public and take no key. A Solana address is the only identifier any of them accepts, nothing about you is stored, and signing never leaves you: transactions come back unsigned and already simulated.

No key, no accountOpenAPI 3.15 sources

Start here

What every source pays right now, and what each one depends on.

curl https://api.getventura.net/sources

Ask what a wallet is standing on

Positions of all three shapes — share tokens, lending deposits that are not wallet tokens, and held tokens priced at what selling them quotes — with what each depends on and which of your rules it breaks. Say where the holder lives, or every source fails the eligibility rule: each one names jurisdictions it is not available in.

curl "https://api.getventura.net/exposure/<wallet>?preset=conservative&jurisdiction=MX"

Price an allocation, with its reasons

Deterministic: dollars per source, why each one is there, every reason the others are not, what stays idle and why, and a timestamp for every fact it used. No optimiser, no scoring. Pass the wallet and what it already holds fills its sources' caps first — a limit is a share of everything you have, not of the money you are moving today, so the allocation tops up what is short instead of what is already full.

curl -X POST https://api.getventura.net/allocate/preview \
  -H 'Content-Type: application/json' \
  -d '{"amountUsd": 5000, "wallet": "<wallet>",
       "preset": "conservative", "jurisdiction": "MX"}'

Change a rule

Presets are bundles of rules, and every rule underneath is yours to set. An unknown key is refused rather than ignored, so a typo cannot quietly loosen a limit.

curl -X POST "https://api.getventura.net/rebalance/<wallet>?preset=max_yield&jurisdiction=MX" \
  -H 'Content-Type: application/json' \
  -d '{"rules": {"max_per_source_pct": 25, "max_exit_bps": 30}}'

Get something to sign

Each leg is built from the protocol's own API and simulated here before it is returned. You sign and send — through /rpc if you have no endpoint of your own. A leg that fails to build leaves the others signable, and the response carries both.

curl -X POST https://api.getventura.net/tx/build \
  -H 'Content-Type: application/json' \
  -d '{"wallet": "<wallet>", "jurisdiction": "MX",
       "legs": [{"source_id": "jupiter-lend-usdc", "action": "deposit", "amount": "100.00"}]}'

Every endpoint

GET/sources
Every source with its live facts and how old each fact is. Unranked: which one is right depends on what you refuse to hold.
GET/sources/{id}
One source's whole reviewed profile — evidence links, incidents, issuer, eligibility, redemption terms.
GET/sources/{id}/history
What the 15-minute facts cron recorded, newest first, within the retention window.
GET/exposure/{wallet}
What the wallet holds, what each holding depends on, and which of your rules it breaks. POST the same path to override individual rules.
GET/rebalance/{wallet}
What would have to leave for the wallet to fit your rules, and where the proceeds would go. Only sells on a rule a holding is known to break — never on a fact that could not be read.
POST/allocate/preview
Where an amount would go under a rule set, explained line by line.
POST/tx/build
Unsigned, simulated transactions for an allocation's legs.
POST/rpc
Solana JSON-RPC with a method allowlist, so you can send what you signed without holding an endpoint key.
GET/events
Public usage counts, rolled up by day. Nothing in them is about anyone.

The client the app itself uses

@ventura/client is dependency-free and holds no keys. The consumer app is built on it and nothing else, so what you can do is exactly what the app does.

import { createClient } from "@ventura/client";

const ventura = createClient();
const me = { jurisdiction: "MX", accredited: false };

const { sources } = await ventura.sources();
const { exposure } = await ventura.exposure(wallet, me, { preset: "conservative" });
const { allocation } = await ventura.preview(5000, me, {
  preset: "balanced",
  rules: { max_per_source_pct: 25 },
});

// Unsigned and already simulated — you sign them.
const { legs } = await ventura.build(wallet, allocation.legs.map((leg) => ({
  source_id: leg.source_id,
  action: "deposit",
  amount: leg.amount_usd.toFixed(2),
})), me);

Honest defaults

A fact that could not be read is null

Never a guess and never a stale number passed off as current. Every fact carries the time it was read and the upstream it came from, and the rules count an unknown as failing.

Facts are 15 minutes old at most

A cron refreshes them, and anything that becomes a transaction is re-fetched first. Freshness is itself a rule you can set.

Nothing is scored

There is no 0–100 rating in any response. Sources come back unranked with their facts; the ranking is what your rules do to them.

No keys, either direction

No API key to call it, and no key of yours ever reaches it. Transactions are returned for you to sign.

This is a hackathon build on mainnet, not a service with an uptime promise. There is no rate limit today and no versioning yet; if you build on it, say hello first. The 5 sources are Jupiter Lend USDC (lending), Kamino USDC, main market (lending), Kamino USDC, OnRe market (reinsurance-backed lending), Ondo USDY (tokenized t-bills), Maple syrupUSDC (private credit).