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>
Tip — override parent CSS. If your site's stylesheet sets 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:

  1. Active subscription — the domain has a current Domain Trust plan registered with KXCO.
  2. 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.

ParameterTypeRequiredDescription
domainstring required* The fully-qualified domain to check, e.g. www.kxco.ai. Normalised to lowercase before hashing.
hashhex 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.
colorwaystring optional black (default) · gold · white

*Either domain or hash must be provided.

Response headers

HeaderValue
Content-Typeimage/svg+xml
X-Attestation-Statusverified · unverified · grace · expired
X-Attestation-Score0–100 (only when verified)
X-Attestation-SurfaceDomain · Document · Article · Email (only when verified)
X-Attestation-AtUnix timestamp of attestation (only when verified)
Cache-Controlpublic, max-age=300

Colorways

Choose the colorway that fits your site's background:

black colorway=black
gold colorway=gold
white 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 caseRecommended sizeStyle
Footer (compact)120 × 40width:120px;height:40px;
Footer (standard)160 × 53width:160px;height:53px;
Landing page / hero240 × 80width:240px;height:80px;
Always specify both 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

NetworkKXCO Chain (Chain ID 1111)
RPChttps://chain.kxco.ai/rpc
Contract0x17E0DE1f1DdE7BFC149f979f554865ABf11b57b2
Explorerchain.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))
Canonical form. Always pass the domain as 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);
}