KocAlgo: verifiable sports data for autonomous agents
1. Abstract
KocAlgo is an HTTP API that sells football and basketball data (live scores, results, match events and odds) to software agents, one request at a time. There are no accounts or API keys. Each request is paid with the x402 protocol (HTTP 402 Payment Required) in USDC on Algorand. Each paid endpoint publishes the x402 Bazaar discovery extension, so an agent that has never heard of KocAlgo can find it in a catalog, read its schemas and price, pay, and use the data. Every response is signed with Ed25519, and finalized results are committed to Algorand as hourly Merkle roots, so a consumer can check that the data it bought is the data we published, and when.
2. Problem
Autonomous agents increasingly need facts about the world: a prediction-market agent needs a final score, a trading or betting assistant needs live state, a research agent needs historical results. Today's sports APIs are built for humans and companies:
- Onboarding. Accounts, contracts and monthly plans do not fit an agent that needs ten requests once.
- Discovery. An agent has to be told the provider's URL in advance; it cannot search for "verified football results" and find one.
- Trust. A response is just JSON. A downstream contract or counterparty cannot tell whether the data was altered after it left the provider.
KocAlgo addresses all three: payment per request without onboarding, machine discovery, and cryptographic provenance.
3. System overview
- Ingestion. A worker reads live boards continuously (long-poll with a polling fallback) and scans today's and yesterday's fixtures every five minutes. Rows that do not match the expected source format are rejected and reported rather than guessed.
- Storage. Every match gets a canonical id. Score and status changes are written to an append-only change log with a monotonic cursor. A finalized result is immutable; a later correction becomes a new revision rather than an overwrite.
- API. Request parameters are validated before any payment is requested (a malformed request gets
400, not402). Paid handlers serve from stored data and refresh from the source when it is older than 45 seconds. - Payment layer. The official x402 SDK produces the 402 challenge, verifies the payment through a facilitator and settles it only after the handler has succeeded.
4. Data model
Canonical events
Event ids are stable and sport-prefixed: fb-<id> for football, bb-<id> for basketball. Each event carries competition, season, home and away teams (id and name), score, half-time score, red cards, kickoff time and a normalized status:
scheduled · live · halftime · finished · finished_aet · finished_pen · postponed · awarded
Response envelope
{
"data": { ... },
"meta": { "sourceTimestamp": "...", "servedAt": "...", "freshnessSeconds": 11, "stale": false },
"proof": { "algorithm": "ed25519-sha256-jcs", "contentHash": "...", "signature": "...", "keyId": "...", "signedAt": "..." },
"anchor": { "status": "anchored", "merkleRoot": "...", "merkleProof": [...], "network": "...", "txId": "...", "round": 0 } // final results only
}
meta.freshnessSeconds is the age of the underlying data at serving time; meta.stale is true when the source could not be refreshed and the last stored data was served instead.
Endpoints and prices
| Endpoint | Content | USDC |
|---|---|---|
/v1/{football,basketball}/live | Events in play | 0.005 |
/v1/{football,basketball}/results | Events by date, competition, team, status; historical dates supported | 0.002 |
/v1/{football,basketball}/events/:eventId | Single event; football adds goals, assists, cards, substitutions, lineups | 0.002 |
/v1/{football,basketball}/events/:eventId/odds | Betting markets with outcomes and prices | 0.005 |
/v1/events/changes | Changes since a cursor or ISO time, with the next cursor | 0.001 |
/v1/results/final | Finalized results across both sports, with anchor data | 0.002 |
Lists are paginated (limit ≤ 200, opaque cursor). Prices are configuration and may change; the authoritative price is always the one in the 402 response.
5. Payments with x402 on Algorand
- The agent sends a normal
GET. - The server replies
402with aPAYMENT-REQUIREDheader: x402 version 2, schemeexact, network (Algorand), asset (USDC, ASA31566704on MainNet,10458941on TestNet), amount in base units, recipient, and the Bazaar extension. - The agent signs an Algorand transfer for that exact amount and repeats the request with the payment attached.
- The server asks the facilitator to verify the payment, runs the handler, and only if the handler returns a successful response asks the facilitator to settle. If the data cannot be produced (for example the source is down or the event does not exist), the payment is never settled and the agent pays nothing.
The facilitator used today is the GoPlausible facilitator, which supports x402 V2 on Algorand and co-signs network fees, so the buyer pays only the asset amount. The facilitator and discovery provider are configuration, not code: KocAlgo is not bound to a single operator.
6. Discovery through the x402 Bazaar
Every paid endpoint declares the official Bazaar discovery extension: HTTP method, input schema (query and path parameters), output schema and a realistic example, plus a description written for machines (sport, live or final, freshness, inputs, output, price, asset, network, and how to verify). Dynamic routes are published as templates (/v1/football/events/:eventId), so the catalog holds one entry per endpoint, not one per match.
A Bazaar catalog lists a resource after the first settled payment whose payload carries the extension. KocAlgo's publication tool performs exactly that: one real payment from a dedicated buyer wallet, followed by a check that the catalog entry matches our configuration (URL, method, version, scheme, network, asset, price, description and schemas). A scheduled audit then checks, without paying, that every resource is still listed and correct.
7. Verifiability: signatures and on-chain anchoring
Signed responses
- The
dataobject is serialized with the JSON Canonicalization Scheme (RFC 8785). contentHash= SHA-256 of those bytes.- The server signs the canonical form of
{algorithm, contentHash, keyId, signedAt}with its Ed25519 key.keyIdis the first 16 hex characters of the public key. - Public keys are served at
/.well-known/sports-data-keys.json. Ed25519 is also Algorand's signature scheme, so the same check can be done with Algorand tooling or on-chain.
A consumer recomputes the hash from the data it received, checks it against contentHash, and verifies the signature with the published key. Any modification of the data breaks the check.
Merkle anchoring of final results
Every hour, the hashes of results finalized since the last batch become leaves of a Merkle tree (leaf = SHA-256(0x00 ‖ contentHash), inner node = SHA-256(0x01 ‖ left ‖ right)). The root is written to Algorand in the note of a zero-amount transaction from a dedicated anchoring account, with the note sportsdata:v1:merkle:<root>. Responses for finalized results include the Merkle proof, transaction id and round, or anchor.status = "pending" until the next batch. One transaction per hour covers any number of results.
This proves that a given result existed in this exact form no later than the anchoring round. It does not prove that the underlying sporting fact is correct; it proves what we published and when.
8. Access requirement: KC token
On Algorand MainNet, access requires that the paying wallet hold at least 1 KC:
| Asset | KOC (unit KC), Algorand Standard Asset 1035899249, MainNet |
|---|---|
| Decimals / supply | 1 decimal · total supply 100,000 KC (1 KC = 10 base units) |
| Rule | Payer balance ≥ 1 KC at request time; the wallet must be opted in to the asset |
| When checked | After the payment is verified (the payer address is then known) and before data is produced |
| If not met | 402 with the x402 error reason kc_holding_required and an explanatory message; the verified payment is cancelled and never settled, so the agent is not charged |
| Availability of the check | Fails closed: if the balance cannot be read from Algorand, the request is rejected with kc_check_unavailable (again without charge) rather than served without the check. Results are cached for 5 minutes (holders) and 30 seconds (non-holders) |
| Disclosure | Stated in the 402 challenge and in every Bazaar description |
| TestNet | No holding requirement |
Token governance, stated plainly: the KC creator account also holds the asset's manager, reserve, freeze and clawback roles. That account can therefore freeze or claw back KC held by any wallet. Agents and their operators should take this into account before acquiring KC. KC is an access requirement for this service; it is not offered as an investment and carries no claim on revenue.
9. Service levels and operations
| Objective (30-day window) | Target |
|---|---|
| Availability of paid endpoints (non-5xx responses) | ≥ 99% |
| Server time for paid requests from stored data, p95 (payment verification excluded) | ≤ 300 ms |
| Live data freshness, p95 | ≤ 60 s |
| Resources listed in the discovery catalog | 10 of 10 |
Pre-launch measurements on TestNet infrastructure: p95 server time 33 ms over 300 paid requests, p95 live freshness 41 s over three minutes of sampling. A watchdog samples health, freshness, error rate and latency every five minutes and stores the samples for SLO reporting. Deployments are immutable releases with an automatic rollback when the post-deployment check fails. Every response carries an X-Request-Id for support.
10. Limitations and risks
- Data source. Data is normalized from public sports sources that do not offer an official API. KocAlgo is not affiliated with any league, club or official data provider and does not claim a data licence. A change in a source's format can interrupt a feed; such rows are rejected and reported rather than served wrong.
- Correctness. Signatures and anchoring prove integrity and timing of what we publish, not the truth of the underlying event. Consumers settling high-value outcomes should combine sources.
- Single host. The service currently runs on a single machine behind a Cloudflare tunnel. A host outage makes the API unavailable; this is reflected in the 99% availability objective.
- Payment assets. Only USDC is accepted. The Algorand x402
exactscheme in the official SDK and the facilitator currently support asset transfers but not native ALGO payments. - Semantic search. The current facilitator lists catalog resources but does not offer the Bazaar
/discovery/searchendpoint. Agents find us by listing and filtering the catalog until search is available. - Token requirement. The KC holding rule on MainNet adds a step for new agents and depends on the governance of the KC asset described above.
11. Roadmap
- Public TestNet endpoint and catalog listing, then MainNet launch.
- MCP tools (
get_live_football_matches,get_live_basketball_games,get_match_result,get_results_since,verify_match_result) published through the Bazaar MCP extension, sharing the same business logic as the HTTP API. - Native ALGO payments when supported by the SDK and facilitator.
- Semantic search verification when supported by the discovery provider.
12. Disclaimer
KocAlgo provides sports data for informational purposes. Odds data is informational and is not betting or financial advice. KC is a utility requirement for accessing the service and is not an offer of securities or an investment. Service objectives are targets, not guarantees. Specifications in this document describe the system as of version 0.1 and may change; the 402 challenge and the published schemas are authoritative.