Overview

The Verification API returns structured error responses with consistent formatting. All error responses include an HTTP status code, error type, human-readable message, optional details, and timestamp.

Error Response Format

{
  "error": "Human-readable error message",
  "errorType": "ERROR_TYPE_CODE",
  "details": {},
  "timestamp": 1707408000000
}
FieldTypeDescription
errorstringHuman-readable error message
errorTypestringMachine-readable error type from the table below
detailsobjectOptional additional context (varies by error type)
timestampnumberUnix timestamp in milliseconds

Note: The details field varies by error type and may contain helpful debugging information (e.g., SIGNATURE_INVALID includes agentId and owner address).

Error Types

VALIDATION_ERROR

HTTP Code: 400

When It Occurs: Request body fails schema validation (missing required fields, wrong data types, invalid format).

Common Causes:

  • Missing required fields in request
  • agentId is not a numeric string
  • signature is not in format 0x + 130 hex characters
  • apiKey doesn't match format kya_live_v1_[a-f0-9]{64}
  • timestamp is not a number or is negative

Resolution: Check that your request matches the documented schema. Common fixes:

  • Ensure agentId and nonce are strings, not numbers
  • Verify signature is exactly 65 bytes (0x + 130 hex chars)
  • Use current Unix timestamp in seconds for timestamp field

Example:

{
  "error": "Invalid request body: agentId must be a numeric string",
  "errorType": "VALIDATION_ERROR",
  "details": {
    "field": "agentId",
    "received": 42
  },
  "timestamp": 1707408000000
}

SIGNATURE_INVALID

HTTP Code: 401

When It Occurs: The provided EIP-712 signature doesn't match the registered owner of the agent NFT.

Common Causes:

  • Signing with the wrong private key
  • Agent ownership transferred but old owner is still signing
  • Incorrect EIP-712 domain parameters (wrong chainId or verifyingContract)
  • Malformed signature

Resolution: Ensure you're signing with the private key of the wallet that owns the agent NFT. Verify:

  • Domain chainId is 8004
  • Domain verifyingContract is 0xA1393CB409E2fE5573C0840189622aA0e33947b2 (IdentityRegistry)
  • Signer address matches the result of IdentityRegistry.ownerOf(agentId)

Example:

{
  "error": "Signature does not match agent owner",
  "errorType": "SIGNATURE_INVALID",
  "details": {
    "agentId": "42",
    "owner": "0x3CDA80d87cDde4612C9b66B657d45055Fa03Ce99",
    "recoveredSigner": "0x1234567890123456789012345678901234567890"
  },
  "timestamp": 1707408000000
}

REPLAY_DETECTED

HTTP Code: 400

When It Occurs: The same nonce was reused for the same agent, or the timestamp is outside the acceptable window (too old or too far in the future).

Common Causes:

  • Reusing a nonce from a previous request
  • System clock is incorrect (timestamp too old or in the future)
  • Retrying a failed request with the same nonce

Resolution: Generate a fresh random nonce for each request. Use the current Unix timestamp (in seconds). Nonces are tracked per-agent to prevent replay attacks.

// Generate fresh nonce
const nonce = BigInt(Math.floor(Math.random() * 1e18));
const timestamp = BigInt(Math.floor(Date.now() / 1000));

Example:

{
  "error": "Nonce has already been used for this agent",
  "errorType": "REPLAY_DETECTED",
  "details": {
    "agentId": "42",
    "nonce": "123456789"
  },
  "timestamp": 1707408000000
}

AGENT_NOT_FOUND

HTTP Code: 404

When It Occurs: The specified agentId doesn't correspond to a minted NFT in the IdentityRegistry contract.

Common Causes:

  • Agent ID was never registered
  • Typo in agent ID
  • Agent ID is 0 (reserved value)

Resolution: Verify the agent was successfully registered on-chain. Token IDs start at 1 (0 is reserved). Check on KYAScan or query IdentityRegistry.ownerOf(agentId) directly.

Example:

{
  "error": "Agent ID 9999 not found in IdentityRegistry",
  "errorType": "AGENT_NOT_FOUND",
  "details": {
    "agentId": "9999"
  },
  "timestamp": 1707408000000
}

RPC_ERROR

HTTP Code: 503

When It Occurs: KYA Chain RPC node is unreachable, timed out, or returned an error when querying on-chain data.

Common Causes:

  • RPC node is down or overloaded
  • Network connectivity issues
  • RPC rate limiting

Resolution: Retry the request after a short delay (exponential backoff recommended). If the issue persists, check KYA Chain network status at https://status.kyachain.xyz.

Example:

{
  "error": "Failed to fetch on-chain data: RPC request timed out",
  "errorType": "RPC_ERROR",
  "details": {
    "rpcUrl": "https://rpc.kyachain.xyz",
    "method": "eth_call"
  },
  "timestamp": 1707408000000
}

INTERNAL_ERROR

HTTP Code: 500

When It Occurs: Unexpected server error that doesn't fit other categories.

Common Causes:

  • Database connection failure
  • Unhandled exception in API code
  • Redis cache unavailable

Resolution: Retry the request. If the issue persists, report it with the timestamp value for debugging.

Example:

{
  "error": "An unexpected error occurred",
  "errorType": "INTERNAL_ERROR",
  "timestamp": 1707408000000
}

INVALID_API_KEY

HTTP Code: 401

When It Occurs: API key is not found in the key store, has been revoked, or doesn't match the requested agentId.

Common Causes:

  • API key was revoked via DELETE /keys
  • API key was rotated and the old key is being used
  • API key doesn't belong to the requested agent
  • Typo in API key

Resolution: Generate a new key via POST /keys/generate (if no key exists) or POST /keys/rotate (if key was lost). Ensure the key matches the agent you're verifying.

Example:

{
  "error": "API key not found or has been revoked",
  "errorType": "INVALID_API_KEY",
  "details": {
    "agentId": "42"
  },
  "timestamp": 1707408000000
}

KEY_ALREADY_EXISTS

HTTP Code: 409

When It Occurs: Attempted to generate an API key for an agent that already has one.

Common Causes:

  • Calling POST /keys/generate for an agent that already has a key
  • Forgot to check key status before generating

Resolution: Use POST /keys/rotate to get a new key (invalidates the old one), or DELETE /keys first then generate.

Example:

{
  "error": "Agent 42 already has an API key. Use /keys/rotate to get a new one.",
  "errorType": "KEY_ALREADY_EXISTS",
  "details": {
    "agentId": "42"
  },
  "timestamp": 1707408000000
}

RATE_LIMITED

HTTP Code: 429

When It Occurs: Exceeded the rate limit for the agent's trust tier.

Common Causes:

  • Making too many requests within the rate limit window
  • Agent is low tier (Bronze = 1 req/min)
  • Burst of traffic exceeds sliding window limit

Resolution: Wait for the duration specified in the Retry-After header before retrying. Upgrade trust tier by staking more LABS in the TrustVault contract.

Rate Limits by Tier:

  • Tier 1 (Bronze): 1 request/minute
  • Tier 2 (Silver): 16 requests/minute
  • Tier 3 (Gold): 166 requests/minute
  • Tier 4 (Diamond): 2700 requests/minute

Example:

{
  "error": "Rate limit exceeded for agent tier",
  "errorType": "RATE_LIMITED",
  "details": {
    "agentId": "42",
    "tier": 1,
    "limit": 1,
    "retryAfter": 45
  },
  "timestamp": 1707408000000
}

Response Headers:

  • X-RateLimit-Limit: 1
  • X-RateLimit-Remaining: 0
  • Retry-After: 45

TIER_BLOCKED

HTTP Code: 403

When It Occurs: Agent is Tier 0 (no LABS staked) and cannot use the Verification API.

Common Causes:

  • Agent has never staked LABS
  • Agent unstaked all LABS and fell back to Tier 0
  • TrustVault stake fell below Tier 1 threshold

Resolution: Stake at least 1,000 LABS in the TrustVault contract to reach Bronze tier (Tier 1). See the TrustVault documentation for staking instructions.

Example:

{
  "error": "Agent is Tier 0 (unverified) and cannot use the API. Stake at least 1,000 LABS to reach Bronze tier.",
  "errorType": "TIER_BLOCKED",
  "details": {
    "agentId": "42",
    "currentTier": 0,
    "requiredTier": 1,
    "requiredStake": "1000000000000000000000"
  },
  "timestamp": 1707408000000
}

INSUFFICIENT_DEPOSIT

HTTP Code: 400

When It Occurs: FeedbackEscrow doesn't have enough LABS deposited for the agent to cover the feedback relay fee.

Common Causes:

  • Agent's FeedbackEscrow balance is too low
  • Feedback relay requires a deposit that hasn't been made

Resolution: Deposit more LABS into the FeedbackEscrow contract for the agent. Check the agent's escrow balance and ensure it covers the feedback fee.

Example:

{
  "error": "Insufficient LABS deposited in FeedbackEscrow to relay feedback",
  "errorType": "INSUFFICIENT_DEPOSIT",
  "details": {
    "agentId": "42",
    "currentBalance": "100000000000000000",
    "requiredAmount": "1000000000000000000"
  },
  "timestamp": 1707408000000
}

RELAY_FAILED

HTTP Code: 500

When It Occurs: Feedback relay transaction failed on-chain (transaction reverted or was rejected).

Common Causes:

  • Agent's escrow balance is insufficient
  • Gas estimation failed
  • On-chain validation failed (e.g., agent doesn't exist)

Resolution: Check the agent's FeedbackEscrow balance. Verify relay parameters are correct. If the issue persists, check the transaction hash in the details for more information.

Example:

{
  "error": "Failed to relay feedback transaction on-chain",
  "errorType": "RELAY_FAILED",
  "details": {
    "agentId": "42",
    "reason": "Transaction reverted",
    "txHash": "0x..."
  },
  "timestamp": 1707408000000
}

Rate Limit Headers

All successful responses (200, 201) and rate limit errors (429) include these headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window for the agent's tier
X-RateLimit-RemainingRequests remaining in the current window
Retry-AfterSeconds to wait before retrying (only on 429 errors)

Example:

X-RateLimit-Limit: 16
X-RateLimit-Remaining: 12

On rate limit exceeded:

X-RateLimit-Limit: 16
X-RateLimit-Remaining: 0
Retry-After: 37

Error Handling Best Practices

  1. Check error types, not just status codes: Multiple errors can share the same HTTP code (e.g., 400 for VALIDATION_ERROR and REPLAY_DETECTED).

  2. Parse details for context: The details object often contains actionable information like field names, current values, or expected formats.

  3. Implement exponential backoff: For RPC_ERROR and INTERNAL_ERROR, retry with exponential backoff (e.g., 1s, 2s, 4s, 8s).

  4. Respect Retry-After headers: For RATE_LIMITED errors, wait the specified duration before retrying.

  5. Log timestamps: The timestamp field helps correlate errors with server logs for debugging.

  6. Handle TIER_BLOCKED gracefully: Show users a clear message about needing to stake LABS, with a link to the TrustVault.

Error handling example
const response = await fetch('https://api.kyachain.xyz/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ apiKey, agentId }),
});

if (!response.ok) {
  const error = await response.json();

  switch (error.errorType) {
    case 'VALIDATION_ERROR':
      console.error('Invalid request:', error.details);
      break;

    case 'SIGNATURE_INVALID':
      console.error('Signature mismatch. Expected owner:', error.details.owner);
      break;

    case 'RATE_LIMITED':
      const retryAfter = error.details.retryAfter || 60;
      console.log(`Rate limited. Retry in ${retryAfter} seconds.`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      // Retry request
      break;

    case 'TIER_BLOCKED':
      console.error('Agent is Tier 0. Stake LABS to unlock API access.');
      // Redirect user to staking flow
      break;

    case 'RPC_ERROR':
    case 'INTERNAL_ERROR':
      console.error('Server error. Retrying...');
      // Implement exponential backoff
      break;

    default:
      console.error('Unknown error:', error);
  }

  throw new Error(error.error);
}

const data = await response.json();
console.log('Verification successful:', data);

On this page