On this page
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.
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.
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
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
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
$ 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}$ 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}$ 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}$ curl -X POST http://localhost:3000/quote \
-H "Content-Type: application/json" \
-d '{"tool":"get_btc_cycle_regime"}'
{"error":"tool and proposedPrice are required"}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
$ 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
{}{
"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"
}
}]
}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){
"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
}GET /activity
Metadata about past negotiations. Accepts an optional ?limit= query param (default 100). Sorted newest first.
[
{
"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
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.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.
{
"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 }
]
}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 -> rejectWorked 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 -> rejectSessions & 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:
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}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
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.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.