Valiquo
On this page
Documentation

Valiquo technical docs.

Every field name, response shape, and number on this page is pulled directly from the running backend's source and verified against live requests — not invented.

Getting started

Overview

Valiquo is a negotiated-price payment layer in front of live financial and on-chain intelligence data. Instead of a single flat rate per API call, a buyer agent proposes what it's willing to pay, and the seller responds by accepting, countering at its real cost floor, or rejecting — resolved in the same request/response round trip.

That negotiation matters because most machine-readable data APIs charge the same price regardless of what a request is actually worth in the moment, forcing every pricing decision to be made once, in advance, by a human. Valiquo lets the price move instead, in real time, decided by the agents actually doing the requesting.

Once a price is agreed, settlement happens on-chain via Circle Gateway and the x402 protocol on Arc — no invoices, subscriptions, or manual reconciliation on either side. Today Valiquo has a single live data seller (BTC Cycle Intelligence, five tools), but the negotiation and settlement layer underneath isn't specific to that seller.

Getting started

Architecture

The backend is a single Express API (src/server.ts) that owns three responsibilities: negotiating a price over HTTP, gating data delivery behind a Circle Gateway/x402 payment, and calling out to an external MCP server to fetch the actual intelligence data once payment settles.

Negotiation and payment state live entirely in memory — a map of quotes keyed by quote id, a per-negotiation round counter, and a small array of rejected-proposal records.

Known limitation

None of this state survives a server restart. There's no database behind it yet, so restarting the process clears all negotiation history. This is a real, currently-accepted tradeoff for this phase — not a bug being hidden.

Each quote moves through a small state machine: OPEN → PROCESSING → FULFILLED. It exists to prevent double-payment and race conditions on a single quote — the transition to PROCESSING only happens once Circle Gateway's middleware confirms a real signed payment payload has arrived (never on a plain unpaid 402 probe), and if verification or settlement fails partway through, the quote recovers back to OPEN rather than getting stuck. Only after payment is confirmed does the server call into the seller's actual data source — currently a single external MCP server for BTC Cycle Intelligence — and return the result.

What Valiquo is not

Valiquo consumes an external MCP server; it does not expose one itself. There is no CLI tool, no chat bot, and no separately hosted "MCP server" product — just this HTTP API.
API reference

POST /quote

Propose a price for a tool. Returns a decision of accept, counter, or reject in the same response — no polling required.

Request body

{
  "tool": string,              // one of the 5 real tool names below
  "proposedPrice": number,     // USDC
  "args"?: object,             // forwarded to the tool after payment
  "negotiationId"?: string     // omit to start a new session
}

Response shape (accept / counter)

{
  "decision": "accept" | "counter",
  "quoteId": string,
  "agreedPrice": number,
  "reason": string,
  "payUrl": "/pay/{quoteId}",
  "expiresInSeconds": 120,
  "negotiationId": string,
  "round": number
}

Response shape (reject)

{
  "decision": "reject",
  "reason": string,
  "negotiationId": string,
  "round": number
}

Real examples — captured live against the running backend

accept — get_btc_cycle_regime @ 0.006
$ curl -X POST http://localhost:3000/quote \
  -H "Content-Type: application/json" \
  -d '{"tool":"get_btc_cycle_regime","proposedPrice":0.006}'

{"decision":"accept","quoteId":"15935f20-3069-4f68-b6a3-ca298a5b81ea","agreedPrice":0.006,"reason":"Offer clears cost floor; accepted at proposed price.","payUrl":"/pay/15935f20-3069-4f68-b6a3-ca298a5b81ea","expiresInSeconds":120,"negotiationId":"18561973-c914-4e6f-988d-b87d2f458c9c","round":1}
counter — get_entry_risk @ 0.001 (floor is 0.0015)
$ curl -X POST http://localhost:3000/quote \
  -H "Content-Type: application/json" \
  -d '{"tool":"get_entry_risk","proposedPrice":0.001}'

{"decision":"counter","quoteId":"e8e3ffe7-e72d-4698-816d-e6b00d6178b1","agreedPrice":0.0015,"reason":"Offer below cost floor; countering at floor price.","payUrl":"/pay/e8e3ffe7-e72d-4698-816d-e6b00d6178b1","expiresInSeconds":120,"negotiationId":"06e9f49d-b9a0-4972-a567-23022da85ec7","round":1}
reject — get_lth_behavior @ 0.0002 (floor is 0.0015)
$ curl -X POST http://localhost:3000/quote \
  -H "Content-Type: application/json" \
  -d '{"tool":"get_lth_behavior","proposedPrice":0.0002}'

{"decision":"reject","reason":"Offer too far below cost floor to be worth countering.","negotiationId":"381088c9-5844-4e66-aff9-7a0de4d373d5","round":1}
400 — missing proposedPrice
$ curl -X POST http://localhost:3000/quote \
  -H "Content-Type: application/json" \
  -d '{"tool":"get_btc_cycle_regime"}'

{"error":"tool and proposedPrice are required"}
API reference

GET /pay/:id

The x402-gated payment route returned as payUrl from an accepted or countered quote. An unpaid request returns 402 Payment Required with a Circle Gateway payment-requirements payload; a correctly signed payment completes the purchase and returns the real tool data.

Not something you curl directly

In normal use this route is paid via a Circle Gateway client that can sign the payment, not called bare. The shapes below are shown for completeness — the unpaid 402 response is real and safe to reproduce with plain curl; the paid success response is the real documented shape from the source, not demonstrated live here (see Limitations).
402 — unpaid request (real, reproducible)
$ curl -i http://localhost:3000/pay/15935f20-3069-4f68-b6a3-ca298a5b81ea

HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64-encoded payment requirements>
Content-Type: application/json

{}
the PAYMENT-REQUIRED header, decoded
{
  "x402Version": 2,
  "resource": {
    "url": "/pay/15935f20-3069-4f68-b6a3-ca298a5b81ea",
    "description": "Paid resource",
    "mimeType": "application/json"
  },
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:5042002",
    "asset": "0x3600000000000000000000000000000000000000",
    "amount": "6000",
    "payTo": "0x1b777a0aE8d7f22d394A9BAB3f40d92664dcaAC1",
    "maxTimeoutSeconds": 604900,
    "extra": {
      "name": "GatewayWalletBatched",
      "version": "1",
      "verifyingContract": "0x0077777d7eba4688bdef3e311b846f25870a19b9"
    }
  }]
}
error cases (real)
404  {"error":"Unknown or expired quote"}
409  {"error":"Quote already redeemed"}                     (state is FULFILLED)
409  {"error":"Payment already in progress for this quote"} (state is PROCESSING)
410  {"error":"Quote expired - request a new /quote"}       (>120s since /quote)
success — after a valid signed payment (real shape, from source)
{
  "message": "Payment accepted - here is your data.",
  "tool": string,
  "agreedPrice": number,
  "data": unknown,          // the actual paid tool output — the one place
                             // in this whole API that appears
  "negotiationId": string,
  "round": number
}
API reference

GET /activity

Metadata about past negotiations. Accepts an optional ?limit= query param (default 100). Sorted newest first.

real response — GET /activity?limit=3
[
  {
    "quoteId": "e8e3ffe7-e72d-4698-816d-e6b00d6178b1",
    "negotiationId": "06e9f49d-b9a0-4972-a567-23022da85ec7",
    "round": 1,
    "tool": "get_entry_risk",
    "decision": "countered",
    "agreedPrice": 0.0015,
    "createdAt": "2026-07-06T14:36:19.860Z",
    "state": "OPEN"
  },
  {
    "quoteId": null,
    "negotiationId": "381088c9-5844-4e66-aff9-7a0de4d373d5",
    "round": 1,
    "tool": "get_lth_behavior",
    "decision": "rejected",
    "agreedPrice": null,
    "createdAt": "2026-07-06T14:36:19.930Z",
    "state": null
  }
]

What this deliberately does not expose

Never the actual paid intelligence data/content itself — only metadata about how a price got agreed. For rejected offers, only tool, negotiationId, round, and a timestamp are kept — never the proposed price or the rejection reason, since either would reveal how close a lowball offer came to the real cost floor. Both exclusions are deliberate: this endpoint is activity metadata, and the whole product depends on not giving away for free what people pay for.
API reference

GET /pricing

Read-only pricing configuration: the real cost floor and asking price /quote negotiates against for each tool, plus the seller address and settlement network.

real response — GET /pricing
{
  "sellerAddress": "0x1b777a0aE8d7f22d394A9BAB3f40d92664dcaAC1",
  "network": "eip155:5042002",
  "tools": [
    { "tool": "get_btc_cycle_regime", "costFloor": 0.003,  "askPrice": 0.008 },
    { "tool": "get_lth_behavior",     "costFloor": 0.0015, "askPrice": 0.004 },
    { "tool": "get_entry_risk",       "costFloor": 0.0015, "askPrice": 0.004 },
    { "tool": "compare_to_2021_top",  "costFloor": 0.002,  "askPrice": 0.005 },
    { "tool": "get_nupl_sentiment",   "costFloor": 0.0015, "askPrice": 0.004 }
  ]
}
How negotiation works

Decision logic

Every proposal is checked against two real numbers for that tool — its cost floor and its asking price — in this order:

offer >= askPrice        -> accept, at askPrice
offer >= costFloor       -> accept, at the proposed price
offer >= costFloor * 0.5 -> counter, at costFloor
offer <  costFloor * 0.5 -> reject

Worked example using get_entry_risk (real floor $0.0015, real ask $0.004):

propose >= $0.004               -> accept @ $0.004 (the ask)
propose in [$0.0015, $0.004)    -> accept @ the proposed price
propose in [$0.00075, $0.0015)  -> counter @ $0.0015 (the floor)
propose <  $0.00075             -> reject
How negotiation works

Sessions & rounds

Omit negotiationId to start a new session — the server generates one and returns it. Pass an existing negotiationId back on a re-proposal (e.g. after a counter) to continue the same session; the server tracks the round count itself, independent of whatever the caller thinks the round is.

A session is capped at 5 rounds. The 6th call on the same negotiationId is rejected outright, regardless of price:

real 6-round session, same negotiationId throughout
round 1..5: {"decision":"reject","reason":"Offer too far below cost floor to be worth countering.","negotiationId":"84793b1d-c350-4f6e-ae4a-6b2ff9a7471f","round":1..5}

round 6:    {"decision":"reject","reason":"Max negotiation rounds (5) exceeded for this session.","negotiationId":"84793b1d-c350-4f6e-ae4a-6b2ff9a7471f","round":6}
Payments & settlement

Gateway & x402

Payment is gated by Circle Gateway using the x402 protocol. A signed payment moves an off-chain optimistic balance first, which is fast — but the underlying on-chain batch settlement is a separate step that can take longer, especially on testnet. This API does not claim instant on-chain finality: a quote flips to FULFILLED once verify and settle both succeed, and if either fails partway through, the quote recovers back to OPEN so it can be paid again rather than getting stuck.

Settlement runs on Arc Testnet (chain id eip155:5042002), where USDC functions as the native gas-equivalent asset rather than a separate token bridged in for the purpose. That's what makes sub-cent payments (this backend's real prices run from $0.0015 to $0.008) economically viable at all — there's no separate gas currency eating a payment many times its own size.

CORS

The API allows cross-origin requests (cors() with default settings) so the web frontend can call it directly from the browser. This is wide open for local development and is meant to be restricted to the real production frontend origin before public deployment.
Limitations & roadmap

Known limitations

  • In-memory state does not persist across restarts. Quotes, negotiation rounds, and rejection records are all held in process memory with no database behind them. This is accepted for the current phase, not something being hidden.
  • One live data seller today. Every tool documented here is served by a single external BTC Cycle Intelligence MCP server. The negotiation and settlement architecture isn't seller-specific, but multi-seller support doesn't exist yet.
  • Wallet-based payment signing in the web UI isn't wired up yet. The landing page's "Try It" widget negotiates a real price against this real API, but stops before an actual on-chain payment — clicking "Pay" is currently a stubbed step, not a live wallet transaction.