Quick start
Add the KXCO Verified badge to any webpage in one line:
<img src="https://chain.kxco.ai/verify/api/badge?domain=yourdomain.com&colorway=gold" alt="KXCO Verified" width="120" height="40" style="width:120px;height:40px;display:block;margin:0;" />
Wrap it in an anchor to link to the public verification page:
<a href="https://chain.kxco.ai/verify/?domain=yourdomain.com" target="_blank" rel="noopener noreferrer"> <img src="https://chain.kxco.ai/verify/api/badge?domain=yourdomain.com&colorway=gold" alt="KXCO Verified" style="width:120px;height:40px;display:block;margin:0;" /> </a>
img { width: ...; margin: ... } on all images, add
style="width:120px;height:40px;display:block;margin:0;"
directly on the <img> to prevent those rules from resizing or misplacing the badge.
How verification works
A badge shows as verified only when two independent conditions are both true:
- Active subscription — the domain has a current Domain Trust plan registered with KXCO.
- On-chain attestation — an attestation record for that domain exists on KXCO Chain and has not been revoked.
If either condition fails the badge returns the grey unverified SVG. If the subscription has lapsed for 1–30 days, the badge shows grey with a 30-day grace period. After 30 days it returns the red expired SVG.
The badge is served as SVG with Cache-Control: public, max-age=300 (5 minutes).
Revocations propagate within one cache TTL.
GET /api/badge
Returns an SVG badge image reflecting the current attestation status of a domain.
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | required* | The fully-qualified domain to check, e.g. www.kxco.ai. Normalised to lowercase before hashing. |
hash | hex string | optional* | Pre-computed keccak256 target hash (0x-prefixed). Use when you already hold the hash. Bypasses subscription gate — use domain for the full two-gate check. |
colorway | string | optional | black (default) · gold · white |
*Either domain or hash must be provided.
Response headers
| Header | Value |
|---|---|
Content-Type | image/svg+xml |
X-Attestation-Status | verified · unverified · grace · expired |
X-Attestation-Score | 0–100 (only when verified) |
X-Attestation-Surface | Domain · Document · Article · Email (only when verified) |
X-Attestation-At | Unix timestamp of attestation (only when verified) |
Cache-Control | public, max-age=300 |
Colorways
Choose the colorway that fits your site's background:
colorway=black
colorway=gold
colorway=white
- black — dark background, gold text. Use on light pages.
- gold — black background, gold text. Use on light or medium-tone pages.
- white — white background, dark text. Use on dark pages.
Sizing
The badge SVG has a native size of 240 × 80 px (3:1 ratio). You can display it at any size while preserving the ratio. Common sizes:
| Use case | Recommended size | Style |
|---|---|---|
| Footer (compact) | 120 × 40 | width:120px;height:40px; |
| Footer (standard) | 160 × 53 | width:160px;height:53px; |
| Landing page / hero | 240 × 80 | width:240px;height:80px; |
width and height in CSS. Using height:auto may not render correctly on all browsers when loading an SVG via <img>.
GET /api/attestation
Returns JSON with the full attestation record and subscription status for a domain.
GET /verify/api/attestation?domain=www.kxco.ai // or by pre-computed hash: GET /verify/api/attestation?hash=0x95a8b8e400e4b415...
Response schema
{
"verified": true,
"attestation": {
"artifactHash": "0x...", // keccak256 of the signed scan envelope
"surface": "Domain", // Domain | Document | Article | Email
"score": 100, // 0–100 integrity score
"attestedAt": 1748012345, // Unix timestamp
"signerKid": "0xaa29f37ab7f4b2cf", // 8-byte PQ signer key ID
"verifyUrl": "https://chain.kxco.ai/verify/?domain=...",
"revoked": false,
"revokeReason": null
},
"subscription": {
"status": "active", // active | grace | expired | unverified
"subscription": { ... } // full subscription record if active
}
}
Returns { "verified": false, "attestation": null, "subscription": ... } if no attestation exists.
Contract reference
| Network | KXCO Chain (Chain ID 1111) |
| RPC | https://chain.kxco.ai/rpc |
| Contract | 0x17E0DE1f1DdE7BFC149f979f554865ABf11b57b2 |
| Explorer | chain.kxco.ai/explorer |
Read functions
// Returns the latest attestation for a target hash, or reverts UnknownTarget() function latest(bytes32 targetHash) view returns (tuple( bytes32 artifactHash, uint8 surface, uint8 score, uint64 attestedAt, bytes8 signerKid, string verifyUrl, bool revoked, string revokeReason )) // Number of attestations ever written for a target function countOf(bytes32 targetHash) view returns (uint256) // Full history array function historyOf(bytes32 targetHash) view returns (tuple[...])
Verify via RPC (no KXCO servers)
You can verify any attestation directly against KXCO Chain without using this API. Use ethers.js or any JSON-RPC client:
import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://chain.kxco.ai/rpc'); const contract = new ethers.Contract( '0x17E0DE1f1DdE7BFC149f979f554865ABf11b57b2', ['function latest(bytes32) view returns (tuple(bytes32,uint8,uint8,uint64,bytes8,string,bool,string))'], provider ); const domain = 'www.kxco.ai'; const targetHash = ethers.keccak256(ethers.toUtf8Bytes(domain.toLowerCase().trim())); const attestation = await contract.latest(targetHash); console.log('score:', attestation.score); // 100 console.log('revoked:', attestation.revoked); // false console.log('attestedAt:', Number(attestation.attestedAt)); // unix ts
hashTarget function
All domains and document identifiers are hashed before being stored on-chain. The hash is computed identically on every platform:
// JavaScript (ethers.js) function hashTarget(value) { return ethers.keccak256(ethers.toUtf8Bytes(value.toLowerCase().trim())); } // Python from eth_hash.auto import keccak def hash_target(value: str) -> str: return '0x' + keccak(value.lower().strip().encode()).hex() // Solidity (on-chain) keccak256(abi.encodePacked(value))
www.kxco.ai (with subdomain, lowercase, no trailing slash).
The hash of kxco.ai and www.kxco.ai are different — attest and query the exact form you want to display.
Integration example — plain HTML
<a href="https://chain.kxco.ai/verify/?domain=www.example.com" target="_blank" rel="noopener noreferrer" style="display:inline-block;line-height:0;" > <img src="https://chain.kxco.ai/verify/api/badge?domain=www.example.com&colorway=gold" alt="KXCO Verified" style="width:120px;height:40px;display:block;margin:0;" /> </a>
Integration example — Next.js
import Image from 'next/image'; export function KxcoVerifiedBadge({ domain }: { domain: string }) { return ( <a href={`https://chain.kxco.ai/verify/?domain=${domain}`} target="_blank" rel="noopener noreferrer" > <Image src={`https://chain.kxco.ai/verify/api/badge?domain=${domain}&colorway=gold`} alt="KXCO Verified" width={120} height={40} unoptimized /> </a> ); }
Pass unoptimized so Next.js doesn't try to reprocess the remote SVG.
Integration example — JS fetch (status check)
const res = await fetch('https://chain.kxco.ai/verify/api/attestation?domain=www.example.com'); const data = await res.json(); if (data.verified) { console.log('Attested at:', new Date(data.attestation.attestedAt * 1000).toISOString()); console.log('Score:', data.attestation.score); } else { console.log('Not attested. Subscription status:', data.subscription?.status); }