1. Discover the feeds
The hosted base URL is https://pulse.kascov.io. These read-only endpoints need no API key and support browser requests. A normal HTTP client is all you need to get started.
curl --fail --silent --show-error --max-time 10 \
https://pulse.kascov.io/v1/feeds
The response contains round, timestamp, count, and a feeds array. Use this lightweight catalog for a board or picker. It is a summary, not a signed attestation.
| Endpoint | Use it for |
|---|---|
GET /v1/feeds | Discover pairs and refresh a lightweight dashboard. |
GET /v1/feed/KAS-USD | Read one full feed, including its signatures and provenance. |
GET /v1/feed | Read all full feeds and the KCC20 market census, including refusals. |
GET /v1/committee | Inspect the candidate public signing keys and threshold. |
GET /health | Check service freshness and live-feed counts; not a verdict on a particular feed. |
Use the pair returned by the API. In a URL, replace / with -: KAS/USD becomes KAS-USD. An unknown pair returns HTTP 404.
2. Read one signed price
curl --fail --silent --show-error --max-time 10 \
https://pulse.kascov.io/v1/feed/KAS-USD
The exact value is mant × 10^expo. For example, mant = 278600000 and expo = -10 represent 0.02786 USD. That is a numerical example, not a current quote. Preserve the integers for precise comparisons; do not use the legacy price_e8 field for tiny token prices.
The signed message has this format:
kaspulse/v2|PAIR|mant|expo|ts|round
Its five fields must exactly match pair, mant, expo, signed_ts, and signed_round in the response. Timestamps are Unix seconds, not milliseconds. The outer envelope's current round is not a substitute for the feed's signed round.
A newly fetched response can contain an old price. A halted feed may retain its last signed observation. Check its signed time and safety status even when the HTTP request succeeds.
3. Verify before using the value
Try the browser first: open the KAS/USD feed and choose its verification button. Your browser checks BIP340 Schnorr signatures over the BLAKE2b-256 message digest, signed-field binding, and the bound covenant attestation when present.
For your application, use the JavaScript API verification client or Python API verification client. These are standalone consumers of the hosted API, not oracle-server software. Their MIT license is separate from the proprietary service.
Authenticate the committee once
Inspect /v1/committee, then compare the keys and threshold with a previously trusted pin or an authenticated artifact from a separate channel. Store that approved committee in your application's configuration. Do not trust a new committee merely because the price server returned it. A compromised origin could replace both the price and the keys.
Example Node.js integration, after saving the JavaScript client as kaspulse.mjs and an independently approved committee as committee-pin.json:
import { readFile } from 'node:fs/promises';
import { Kaspulse } from './kaspulse.mjs';
const pin = JSON.parse(await readFile(
new URL('./committee-pin.json', import.meta.url), 'utf8'
));
const response = await fetch(
'https://pulse.kascov.io/v1/feed/KAS-USD',
{ cache: 'no-store', signal: AbortSignal.timeout(8000) }
);
if (!response.ok) throw new Error(`API returned ${response.status}`);
const feed = await response.json();
if (feed.pair !== 'KAS/USD') throw new Error('Unexpected pair');
const api = new Kaspulse();
const verified = api.verifyWithCommittee(feed, pin);
if (!verified.ok) throw new Error(verified.error || 'Verification failed');
// Example policy: reject signatures older than 30 seconds.
const displayValue = api.checkedValue(feed, { maxAgeMs: 30_000 });
console.log({ pair: feed.pair, displayValue, signedAt: feed.signed_ts });
// Keep feed.mant and feed.expo for exact decimal arithmetic.
The pinned check requires enough distinct, valid pinned signers; repeated keys do not count twice. The separate age check rejects stale signatures and timestamps more than 30 seconds in the future. Catch failures in your app and mark the price unavailable; do not replace a rejected value with zero.
The signed-message specification describes the exact bytes and verification rules. A browser check or verifyFeed alone demonstrates cryptographic consistency with the supplied keys; it does not establish an independent identity pin or freshness policy.
4. Treat refusal as useful information
Your app should have distinct states for a usable observation, an old observation, a halted feed, and a failed request. These are different situations, and users should be able to tell them apart.
- Halted: do not consume the held price, even if its signatures verify.
- Too old or implausibly future-dated: pause the action and check your device clock and age policy.
- Thin, degraded, or divergent: show the warning and decide whether your use case permits the market. A valid signature does not remove these risks.
- Missing or malformed data: fail closed. Do not substitute another pair, infer missing units, or accept a smaller quorum.
- HTTP error or timeout: retry with backoff. Keep any previous display visibly stale and stop treating it as a current quote.
For dashboard refreshes, poll the catalog instead of downloading every full feed. Avoid overlapping requests, pause background tabs when practical, and back off on failures. There is no public streaming endpoint to connect to; the website refreshes through HTTP polling.
/health can return 503 while the service warms up or has no live feeds. A healthy response only means the service is publishing and at least one feed is live. Your selected feed still needs its own checks.
5. Keep token identity and units intact
KCC20 feeds are identified by a covenant, not by a ticker. Use the full token_covenant_id as your application key. The API pair's shortened ID is for addressing a feed; familiar names and symbols are labels, not unique identifiers.
listed_* fields describe KRON registry metadata. Structural checks bind the listing to a covenant; they do not prove that the name or symbol is an on-chain fact. claimed_* fields are deployer-supplied. If neither is qualified, keep the deterministic name and covenant ID visible.
- Native price: the
/KASleg is KAS per token base unit. - Dollar price: the
/USDleg adds the KAS/USD conversion; it is not an independent token market. - Decimals: do not automatically rescale signed prices using a claimed or registry decimal count. If your display uses whole tokens, label and apply that conversion explicitly.
- Pricing basis: distinguish
spotfromlast_verified_state, and showlast_trade_age_s. A refreshed response is not a new trade.
Compare providers within the same token feed
The token feed's cross_reference object shows kascov and the official KRON SDK side by side. KasPulse matches the full token and pool covenant IDs, then compares fresh spot observations in KAS per token base unit. It does not compare a current SDK spot price with a historical verified state or the signed time-weighted price.
status: "agree" means the symmetric difference, measured against the average of both observations, is at most threshold_bps: 100 (1%). disagree means a larger difference; unavailable means a fresh matching observation is missing; not_comparable means their bases cannot be fairly compared. Check each provider's observed_at_ms and the comparison's expires_at_ms, in Unix milliseconds. The comparison has a maximum 60-second freshness window; retrieval time does not prove the age of underlying chain state.
Two providers do not imply two markets. KRON and kascov read the same pool, so num_markets remains 1. The cross-reference is unsigned advisory metadata, not an extra input in sources, the median, or the signing quorum. It never overrides halted or admits an otherwise refused token.
KRON's own node-comparison report is a different check: matched and unknown describe what its provider reports about node observations, not agreement with kascov or independent proof of the price.
The Kaspa token market page exposes admitted markets, refusals, source links, and the evidence behind each price. Names, liquidity, risk flags, and provenance are advisory metadata, not additional fields covered by the v2 price signature.
6. Know what the oracle does not promise
One operator today. The hosted committee uses five signing keys with a threshold of three, but all five currently share one operator. That is real threshold cryptography, not five independent organizations.
Kascov remains the signed token tier's dependency. KCC20 prices are checked against kascov's decoded market data. A KRON SDK cross-reference can reveal disagreement through another reader, but agreement is not independent chain verification. Repeating arithmetic checks cannot expose every systematic decoding error inside kascov. KasPulse and kascov also share an operator and infrastructure.
An observation is not a trading guarantee. KasPulse does not predict prices, guarantee liquidity, or promise execution at its quoted value. Your application remains responsible for its own risk limits.
What if my application uses on-chain covenant attestations?
The API's kaspulse/cov/v2 attestation binds pair, exponent, mantissa, round, and timestamp. Rebuild the preimage from those fields and compare it byte-for-byte before checking its signatures. A signature from another pair or exponent must never qualify.
Binding a timestamp does not enforce freshness on-chain. The demonstrated cov/v2 gate has no signed-round or time floor: an old genuine attestation can satisfy it indefinitely. Its exponent is fixed in the address, so a changed exponent needs a different covenant design or address.
A bare price gate does not protect a recipient. Once its price condition passes, public oracle bytes alone can satisfy it. A beneficiary signature or equivalent transaction-level authorization is a separate requirement. Binding a beneficiary still does not prevent that beneficiary from using an old qualifying observation.
On-chain examples and slashing experiments have only been exercised on testnet-10. There is no audited KasPulse mainnet consumer or mainnet bond protection to rely on. Earlier advice to solve oracle freshness using only a relative transaction timelock was retracted: it does not prove that an attestation is recent.
The original unbound covenant signature was withdrawn on 2026-07-27 and replaced with the bound domain. Withdrawal did not revoke already issued signatures; old unbound designs remain unsafe. Read the dated security and protocol history before interpreting historical proofs as current guarantees.