> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chipipay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# DeFi Intelligence

> AI portfolio advisor with real-time signals, plus on-chain swap execution on Starknet.

Base URL: `https://api.chipipay.com/v1`

## When to use

`/ai/think` and `/ai/execute` work together to power autonomous DeFi agents. Think decides **what** to do; Execute builds the **how**.

| | `/ai/think` | `/ai/execute` |
| - | - | - |
| **What it does** | Analyzes a portfolio with live market signals and returns a decision (`swap`, `supply`, `withdraw` or `hold`) | Builds unsigned swap calldata from AVNU (Starknet DEX aggregator) |
| **Best for** | Autonomous agents, portfolio advisors, risk-managed bots | Executing the decision — turning a `swap` decision into a real transaction |
| **Input** | Portfolio balances + risk score | Token pair + USD amount + wallet address |
| **Output** | Structured JSON: action, reason, confidence, risk params | Unsigned transaction calls ready to sign and submit |
| **Cost** | Per token (same as /chat) | \$0.002 flat per call |

### What you can build

* **Autonomous DeFi agent** — `/think` runs on a schedule (hourly, daily), if it says `swap` → `/execute` builds the swap → your agent signs and submits via session key. Fully automated, gasless.
* **Portfolio advisor app** — Show users a dashboard with AI recommendations. `/think` with their real balances + chosen risk level. They review the suggestion and approve manually.
* **Risk-managed vault** — A smart contract-backed strategy where `/think` enforces risk params (max drawdown, min stablecoins) before any rebalance.
* **Telegram trading bot** — User sends portfolio snapshot, bot calls `/think`, replies with the recommendation and a "execute" button that triggers `/execute`.
* **Yield optimizer** — `/think` includes DeFi yield data from DefiLlama. An agent can compare swap gains vs. yield APY and pick the better move.

> [!NOTE]
>
> `/think` automatically fetches live signals (RSI, MACD, Fear & Greed, yields) — you don't need to call `/signals` first. Just send the portfolio.

***

## POST /ai/think

DeFi portfolio advisor. Analyzes your portfolio with real-time market signals (RSI, MACD, Fear & Greed, yields) and returns a structured JSON decision: `swap`, `supply`, `withdraw` or `hold`, with confidence and reasoning.

**Cost:** Per token (same as /chat — the model call is the cost)

```bash Request theme={null}
curl -X POST https://api.chipipay.com/v1/ai/think \
  -H "Authorization: Bearer sk_prod_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "haiku",
    "portfolio": {
      "USDC": {"balance": 100, "usd": 100},
      "ETH": {"balance": 0.04, "usd": 88},
      "STRK": {"balance": 500, "usd": 17}
    },
    "riskScore": 7,
    "chain": "starknet"
  }'
```

```json Response (201) theme={null}
{
  "decision": {
    "action": "hold",
    "reason": "ETH RSI at 45 (neutral), Fear & Greed at 16 (Extreme Fear). No signal exceeds minSignalStrength threshold of 0.38.",
    "confidence": 0.4
  },
  "riskParams": {
    "riskScore": 7,
    "maxSingleTradePercent": 38,
    "minStablecoinPercent": 15,
    "maxDrawdownPercent": 29.5,
    "minSignalStrength": 0.38,
    "minExpectedGainPercent": 0.57
  },
  "model": "haiku",
  "provider": "anthropic",
  "usage": {"inputTokens": 369, "outputTokens": 102, "totalTokens": 471},
  "cost": {"charged": 0.001231, "currency": "USD"},
  "latencyMs": 1507
}
```

### Request body

| Field | Type | Default | Description |
| - | - | - | - |
| `portfolio` | object | Required | Token balances and USD values. Keys are symbols, values have `balance` and `usd`. |
| `riskScore` | number | 5 | 1 (ultra conservative) to 10 (max risk). All thresholds scale with this score. |
| `chain` | string | `"starknet"` | Chain for yield data in signals. |
| `model` | string | `"haiku"` | Any model from [Models & Pricing](/services/ai-api/models). |

### Risk parameter overrides

All optional. Defaults scale linearly with `riskScore`. Override any individual param without affecting others.

| Field | Type | Description |
| - | - | - |
| `maxSingleTradePercent` | number | Max % of portfolio per trade |
| `minStablecoinPercent` | number | Min % to keep in stablecoins |
| `maxDrawdownPercent` | number | Max acceptable drawdown % |
| `minSignalStrength` | number | Min signal strength to act (0-1) |
| `minExpectedGainPercent` | number | Min expected gain to justify a swap |

### How risk scoring works

Risk parameters scale with `riskScore` from conservative (1) to aggressive (10):

| Parameter | riskScore = 1 | riskScore = 5 | riskScore = 10 |
| - | - | - | - |
| Max single trade | 14% | 30% | 50% |
| Min stablecoins | 45% | 25% | 5% |
| Max drawdown | 8.5% | 22.5% | 40% |
| Min signal strength | 0.74 | 0.50 | 0.20 |
| Min expected gain | 1.11% | 0.75% | 0.30% |

> [!NOTE]
>
> The `/think` endpoint automatically injects live market data (signals, yields, Fear & Greed) into the AI prompt. You don't need to fetch signals separately — just send the portfolio and risk score.

### Pay per call with x402

An agent can pay a `/think` call itself, in USDC from its session key, instead of from your org's credits. Chipi offers this only when your credits are short and you call with a secret key (`sk_`). The 402 then carries an x402 offer:

| Offer field | Production value |
| - | - |
| `maxAmountRequired` | `15000` (USDC base units: **\$0.015** per call) |
| `extra.payableModels` | `haiku`, `gpt-4.1-mini`, `gpt-4o-mini` |
| `extra.maxPromptBytes` | `2048` (your portfolio, `history.recentDecisions` and `chain`, as printed in the prompt) |
| `extra.maxOutputTokens` | `300` (a decision is about 100) |

The price covers the model, the gas Chipi sponsors for your payment and the platform margin, for the worst case of every payable model. Credits stay cheaper (about \$0.002 a decision on `haiku`), because they need no payment transaction.

`sdk.ai.think` pays for you with `payWithSession`. Without it, a 402 is thrown as before.

```ts theme={null}
import type { ChipiServerSDK } from "@chipi-stack/backend";
import type { SessionKeyData, WalletData } from "@chipi-stack/types";

export async function decidePaying(
  sdk: ChipiServerSDK,
  wallet: WalletData,
  session: SessionKeyData,
  encryptKey: string
) {
  const res = await sdk.ai.think(
    { portfolio: { USDC: { balance: 10, usd: 10 } }, model: "haiku" },
    // At most $0.02 per call: a higher price is refused before anything is paid.
    { payWithSession: { encryptKey, wallet, session, maxAmount: 20_000n } }
  );
  return res.x402Payment; // set when the call was paid over x402
}
```

> [!WARNING]
>
> Pay from a wallet of the organization that owns the `sk_`. The API refuses a payment from any other wallet with `PAYER_NOT_IN_ORG`, because transaction hashes are public and only the payer's own organization may spend its transfer. On 14.15.0 that refusal comes after the USDC has moved; 14.15.1 checks first.

What the SDK does with a 402 offer:

1. **Checks before paying.** It refuses `X402_PRICE_ABOVE_MAX`, `X402_MODEL_NOT_PAYABLE`, `X402_PAYLOAD_TOO_LARGE` or `X402_INVALID_MAX_AMOUNT`, and nothing is paid. From 14.15.1 it also names the wallet in an `X-PAYER` header, and refuses with `X402_PAYER_NOT_IN_ORG` when the offer's `extra.payer` says a payment from it would not be accepted.
2. **Pays** with a session-signed USDC `transfer` to the offer's `payTo` and waits for the receipt.
3. **Sends `X-PAYMENT` only if the USDC reached `payTo`.** A transfer the wallet refused comes back succeeded with nothing moved: that throws `X402_PAYMENT_FAILED` and is never sent. Whitelist `transfer` in the session and cap USDC.
4. **Hands a paid-but-unserved call back.** If the call fails after paying (`X402_PAYMENT_PENDING`, or an API error on the paid retry), `error.details.xPayment` holds the payment: pass it as `options.xPayment` to retry without paying again. A payment is spent only once a call is served.

***

## POST /ai/execute

Build unsigned swap calldata from AVNU (Starknet DEX aggregator). Returns the transaction calls — you sign and submit via session key or wallet.

**Cost:** \$0.002 per call (flat, not per token)

```bash Request theme={null}
curl -X POST https://api.chipipay.com/v1/ai/execute \
  -H "Authorization: Bearer sk_prod_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "starknet",
    "action": "swap",
    "from": "USDC",
    "to": "ETH",
    "amountUsd": 10,
    "walletAddress": "0x0189e2ebb955fc19bf37bd8fc0400de24c123363e7955282bcfb99679a773e61",
    "slippage": 0.005
  }'
```

```json Response (201) theme={null}
{
  "calls": [
    {
      "contractAddress": "0x033068f6...",
      "entrypoint": "approve",
      "calldata": ["0x...", "0x..."]
    },
    {
      "contractAddress": "0x042ab...",
      "entrypoint": "multi_route_swap",
      "calldata": ["0x...", "0x..."]
    }
  ],
  "quote": {
    "sellToken": "USDC",
    "buyToken": "ETH",
    "sellAmount": "10000000",
    "buyAmount": "4500000000000000",
    "sellAmountUsd": 10.0,
    "buyAmountUsd": 9.98,
    "priceImpactPct": 0.12,
    "route": "AVNU best route"
  },
  "cost": {"charged": 0.002, "currency": "USD"}
}
```

### Request body

| Field | Type | Default | Description |
| - | - | - | - |
| `chain` | string | Required | `"starknet"` (more chains coming soon). |
| `action` | string | Required | `"swap"` (more actions coming soon). |
| `from` | string | Required | Sell token symbol: USDC, ETH, STRK, WBTC, USDT, DAI. |
| `to` | string | Required | Buy token symbol: USDC, ETH, STRK, WBTC, USDT, DAI. |
| `amountUsd` | number | Required | USD amount to swap (converted to token amount using live prices). |
| `walletAddress` | string | Required | Your Starknet wallet address. |
| `slippage` | number | 0.005 | Slippage tolerance. Default: 0.5%. Max: 50%. |

> [!WARNING]
>
> `/execute` returns **unsigned calls**. It does NOT submit the transaction.
> You sign with your wallet or session key and submit via the Chipi paymaster (gasless).
> Swaps with more than 3% price impact are rejected.

### Putting it together: Think + Execute

A typical DeFi agent flow:

1. **Think** — send portfolio + risk score, get a decision
2. If the decision is `swap` → **Execute** — get unsigned swap calldata
3. Sign the calls with your wallet or session key
4. Submit via Chipi's gasless paymaster

```typescript theme={null}
// 1. Get AI decision
const decision = await fetch("https://api.chipipay.com/v1/ai/think", {
  method: "POST",
  headers: { "Authorization": "Bearer sk_prod_YOUR_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    portfolio: { USDC: { balance: 100, usd: 100 }, ETH: { balance: 0.04, usd: 88 } },
    riskScore: 7,
  }),
}).then(r => r.json());

// 2. If actionable, build swap calldata
if (decision.decision.action === "swap") {
  const swap = await fetch("https://api.chipipay.com/v1/ai/execute", {
    method: "POST",
    headers: { "Authorization": "Bearer sk_prod_YOUR_KEY", "Content-Type": "application/json" },
    body: JSON.stringify({
      chain: "starknet",
      action: "swap",
      from: "USDC",
      to: "ETH",
      amountUsd: 10,
      walletAddress: "0x...",
    }),
  }).then(r => r.json());

  // 3. Sign swap.calls with your wallet and submit
  console.log("Calls to sign:", swap.calls);
}
```

### With the SDK (14.14.0+)

`@chipi-stack/backend` wraps these endpoints as `sdk.ai`. It authenticates with your secret key and refuses to run without one, so it is server-only.

```ts theme={null}
import { ChipiServerSDK, isThinkDecision } from "@chipi-stack/backend";

const sdk = new ChipiServerSDK({
  apiPublicKey: process.env.CHIPI_API_PUBLIC_KEY!,
  apiSecretKey: process.env.CHIPI_API_SECRET_KEY!,
});

export async function decide(walletAddress: string) {
  const signals = await sdk.ai.signals({ tokens: ["ETH", "STRK"] });

  const { decision, cost } = await sdk.ai.think({
    portfolio: { USDC: { balance: 100, usd: 100 }, ETH: { balance: 0.04, usd: 88 } },
    riskScore: 4,
  });

  // `decision` is either a structured decision or `{ raw }` when the model did
  // not return JSON. isThinkDecision also rejects actions outside the enum.
  if (!isThinkDecision(decision) || decision.action !== "swap" || !decision.from || !decision.to) {
    return { action: "hold" as const, spentUsd: cost.charged, fearGreed: signals.market.fearGreedIndex };
  }

  const { calls, quote } = await sdk.ai.execute({
    chain: "starknet",
    action: "swap",
    from: decision.from,
    to: decision.to,
    amountUsd: 10, // your own cap, not the model's amount
    walletAddress,
  });
  return { action: "swap" as const, calls, priceImpactPct: quote.priceImpactPct };
}
```

| Method | Endpoint |
| - | - |
| `sdk.ai.prices({ tokens?, chain? })` | `GET /v1/ai/prices` |
| `sdk.ai.signals({ tokens?, chain? })` | `GET /v1/ai/signals` |
| `sdk.ai.think(params, options?)` | `POST /v1/ai/think` (`options.payWithSession`: pay a 402 over x402) |
| `sdk.ai.execute(params)` | `POST /v1/ai/execute` |
| `sdk.ai.chat({ messages, model?, max_tokens? })` | `POST /v1/ai/chat` |
| `sdk.ai.models()` | `GET /v1/ai/models` |

API errors throw `ChipiApiError` with the API's `code` and `status`, for example `INSUFFICIENT_BALANCE` (402), `MODEL_RATE_LIMITED` (429), `MODEL_UNAVAILABLE` (503) or `SIGNALS_UNAVAILABLE` (503). The full error body is on `error.details`, which is how you read the x402 offer of a 402.

> ✅ Verified against the live API on **2026-10-05**.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.