Skip to content

MAINNET ALPHA Unaudited. A bug or an exploit could take everything in it, and nobody would pay you back. $100 total deposit cap. Put in only what you can lose. Read the risks.

For wallets and agents

The rules API.Every call the app makes.

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.

Key or account

NoneCall it from anywhere

Endpoints

16Every one, below

Sources covered

5What each one stands on

Spec

OpenAPI 3.1openapi.json

Start here

Five calls.
Each one a curl.

Each one runs as written. Put any Solana address where it says <wallet>.

  1. 01Start here

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

    curl https://api.getventura.net/sources
  2. 02Ask 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"
  3. 03Price 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"}'
  4. 04Change 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}}'
  5. 05Get 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"}]}'

Reference

Every endpoint.
Nothing private behind them.

The request and response shapes are in the OpenAPI file.

Every endpoint of the Ventura API
EndpointWhat it returns
Sources
GET/sourcesEvery 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}/historyWhat the 15-minute facts cron recorded, newest first, within the retention window.
A wallet and your rules
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 the same path to override individual rules.
POST/allocate/previewWhere an amount would go under a rule set, explained line by line.
POST/tx/buildUnsigned, simulated transactions for an allocation's legs.
POST/rpcSolana JSON-RPC with a method allowlist, so you can send what you signed without holding an endpoint key.
Ventura USD
GET/vaultVentura USD as the program values it: NAV, each market's share against its cap, the fee and cash reserve, cash owed to the withdrawal queue, and when the keeper last checked in.
GET/vault/position/{wallet}One wallet's shares and what they are worth now, its open claims and their place in the queue, and its history in the vault.
POST/vault/tx/depositAn unsigned, simulated deposit: USDC in, shares out at the NAV the program works out inside the transaction.
POST/vault/tx/request-withdrawAn unsigned withdrawal that pays what it can now and queues the rest as a claim, which keeps its place and keeps earning until it settles.
POST/vault/tx/withdrawAn unsigned withdrawal paid in full now or not at all, from cash or from one Kamino market in the same transaction.
POST/vault/rpcThe same allowlisted JSON-RPC, pointed at the vault's chain. Signed vault transactions go here.
GET/receiptsThe keeper's decisions, one receipt per cycle, newest first: what it saw, which rule applied, what it decided and what happened when it sent it. A cycle that did nothing gets one too. Only the keeper writes them.
Usage
GET/eventsPublic usage counts, rolled up by day. Nothing in them is about anyone. POST the same path to count one use.

Typed

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);

What to expect

Honest defaults.
No uptime promise.

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 to 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).

The whole contract

Read the spec.
Or the app built on it.