# Capacitr Signals API — agent integration spec

Use Capacitr's paid API for market signals: SUBMIT a URL, post, article or question to have it analysed into a Feed Card of matched markets and ranked trades, or READ the latest Signals Capacitr has already produced. Both return the same card shape, each trade carrying a live quote and, for a dated source, its price at signal time.

Reading is the cheaper door: one payment returns one page of Signals plus a `nextCursor`; pass that cursor back and pay again for the next page. Add `?q=` to narrow a page to a ticker, a category, or free text — ordering stays newest-first either way.

For one market, READ its Narratives: every thesis Capacitr has linked to that Hyperliquid perp, Robinhood Chain stock or Polymarket market, with direction, rationale and source. Same one-payment-per-page cursor.

POST https://capacitr.xyz/api/x402/signals — Submit a signal
GET https://capacitr.xyz/api/x402/signals — Read the latest signals
GET https://capacitr.xyz/api/x402/markets/narratives — Read one market's narratives

Read GET https://capacitr.xyz/api/x402/routes for the current request fields, prices, payment rails, limits, and the response shape. The endpoint's 402 challenge carries the exact payment requirements.

Before any payment, collect from the user the input to analyze and a maximum spend per call. Then show the payment options the 402 challenge returns — currently USDC on Base Sepolia (testnet) over x402; pathUSD on Tempo Moderato (testnet) over MPP — ask the user which one to pay with, and wait for the answer. Use only an option returned by the challenge; never choose a chain automatically.

For every rail: validate the challenge's chain, token, recipient, and amount against the user's limit before signing, then verify the settlement receipt and confirm the on-chain transfer. Tempo may add a small network fee in pathUSD on top of the price unless the challenge marks the fee as sponsored, so check the transfer to the recipient against the price rather than the wallet's balance change.

Follow the official guide or SDK for the chosen rail:
- x402 on Base (Base Sepolia (testnet), USDC): https://docs.base.org/build-on-base/accept-payments/call-a-paid-service — install @x402/fetch and @x402/evm (the docs' @base-org/x402 name is not on npm). Register ExactEvmScheme with a viem account from the user's key, wrap fetch with wrapFetchWithPayment, and use onBeforePaymentCreation as the spend-limit gate.
- MPP on Tempo (Tempo Moderato (testnet), pathUSD): https://mpp.dev/quickstart/agent — with a user-supplied private key use the mppx client SDK: Mppx.create({ methods: [tempo({ account, expectedChainId: 42431 })], polyfill: false }). Use the Tempo CLI skill at https://tempo.xyz/SKILL.md only for an interactive browser login. MPP is accepted on Tempo only; the Base rail is x402.

After a network failure present the same credential again: it is never charged twice.

## Free sample — build your parser first

GET https://capacitr.xyz/api/x402/signals/sample returns a canned Signals page in the exact paid shape (sample:true markers, zeroed payment block). No payment, no account — use it to write and test your response parsing before spending anything.

## TESTNET rail — Base Sepolia (testnet) (eip155:84532)

https://capacitr.xyz/api/x402/signals also accepts a Base Sepolia USDC payment — TESTNET funds only, never real USDC — as a deliberately restricted preview with real settlement. Pick that accept by network (eip155:84532), never by position in accepts[].

Test-rail pages are capped: at most 5 cards per page, at most 2 pages per payment chain, and only items at least 48h old — the recency floor is the point, not a bug. The response marks itself: preview:true and payment.test_rail:true. A forged deeper cursor is clamped to the terminal page, never a third page.

## x402 on Base — signing detail

If you are hand-rolling the flow instead of using the SDK above: the 402's payment-required header decodes to { accepts[] }. Sign an EIP-3009 TransferWithAuthorization where the EIP-712 domain comes from the accept itself — name and version from accept.extra, chainId from accept.network, verifyingContract = accept.asset. The domain name differs per rail ("USD Coin" on mainnet, "USDC" on Sepolia); always read it from accept.extra. Resend the request with header PAYMENT-SIGNATURE = base64({ x402Version: 2, accepted: <the accept object verbatim>, resource: <the challenge's resource>, payload: { signature, authorization } }).

## Failure semantics

- A paid request answered 503 'feed-unavailable' with a Retry-After header means our side is broken, not your credential: the payment is recorded refund_due and refunded out of band. Retry after the interval.
- A 402 after a paid request is a payer rejection — read the body type AND the merged payment-required challenge's error field for the reason.
- Re-sending an already-settled credential replays the recorded response without charging again — safe after a network drop. Never reuse a nonce for a NEW payment.

Full guide for humans: https://capacitr.xyz/x402
Installable agent skill: https://capacitr.xyz/SKILL.md (references at https://capacitr.xyz/references/endpoints.md and https://capacitr.xyz/references/payment-protocol.md)