# Freshness Validator API documentation

Base URL: `https://api.myuiaf.com`

## Authentication
Send the agent's API key as `Authorization: Bearer fv1.<agent_id>.<key_id>.<secret>`. `agent_id` in a request body is optional; if present it must match the key's agent (else 403). Keys are shown once, when created. Revoked keys stop working immediately. Ten failed attempts from one IP in ten minutes block that IP for fifteen minutes.

## Credits
Each agent has a wallet denominated in US dollars. A validation call deducts the per-call rate for the agent's tier. Registering a source costs twice the per-call rate. `credits_deducted` and `remaining_balance` are in dollars. The wallet endpoint reports the balance as `balance_usdc`, meaning dollar-denominated credits.

## POST /api/v1/validate
Fields: `context` (required, at most 50,000 characters), `source_url` (optional public https URL), `last_validated` (optional ISO 8601), `metadata.content_type` (`verbatim` default, or `paraphrase`), `metadata.freshness_policy` (`1h`-`8760h` or `1d`-`365d`, default `24h`), `agent_id` (optional).
```json
{
  "context": "The new rate limit is 100 req/min",
  "source_url": "https://example.com/api-docs",
  "last_validated": "2026-11-01T00:00:00Z",
  "metadata": { "content_type": "verbatim", "freshness_policy": "24h" }
}
```
Response (200):
```json
{
  "freshness_score": 72,
  "is_stale": false,
  "confidence": 0.85,
  "source_match": { "method": "overlap", "overlap": 0.95 },
  "flagged_issues": [],
  "suggestions": [],
  "source_status": "monitored",
  "source_hash": "a1b2c3d4e5f6...",
  "source_last_checked": "2026-11-04T14:00:00.000Z",
  "source_last_changed": null,
  "context_hash": "9f8e7d6c5b4a...",
  "validated_at": "2026-11-04T14:30:00.000Z",
  "credits_deducted": 0.03,
  "remaining_balance": 4.97
}
```
Score: 80+ fresh, 70-79 warning, below 70 stale (`is_stale` true). `source_match.method` is `exact`, `overlap`, `keyword`, or `none`. `source_status` is `unmonitored`, `monitored`, or `error`. The context is never stored.

With insufficient credits the result is still returned with HTTP 402, `credits_deducted: 0`, `"error": "Insufficient credits"`, `"code": "insufficient_credits"`.

## POST /api/v1/source/register
Registers a public https URL for monitoring. Fetched once immediately as a baseline. Costs twice the per-call rate. `check_frequency`: `1h`, `6h`, `24h` (default), `7d`, `30d`. Re-registering a URL only updates its frequency, free. If the page cannot be fetched (422) nothing is registered or charged. With insufficient credits: 402. Limit: 100 sources per agent.
```json
{ "source_url": "https://example.com/compliance-policy", "check_frequency": "24h" }
```
Response (200):
```json
{
  "source_id": "src_3fa9c21b7d",
  "source_url": "https://example.com/compliance-policy",
  "check_frequency": "24h",
  "last_checked": "2026-11-04T14:00:00.000Z",
  "last_changed": null,
  "next_check": "2026-11-05T14:00:00.000Z",
  "status": "monitored",
  "change_count": 0,
  "last_error": null,
  "created": true,
  "credits_charged": 0.06,
  "remaining_balance": 4.91
}
```

## GET /api/v1/sources
Returns `{ "sources": [...] }`. Free.

## DELETE /api/v1/sources/:source_id
Stops monitoring and deletes the stored text. Free.

## Monitoring rules
- Source URLs must be public `https` (no IP addresses, `localhost`, private names, or custom ports). Redirects are checked the same way.
- User agent `FreshnessValidator/1.0 (+https://myuiaf.com)`. 10 second timeout, first 1 MB read. HTML, plain text, JSON, XML. No JavaScript is run.
- A sweep runs every 15 minutes and checks sources that are due.
- A source counts as changed when the SHA-256 of its normalized text (markup, scripts, styles removed) differs from the previous check.
- After 3 failed checks in a row the status becomes `error`; retries are hourly; one success recovers it.

## GET /api/v1/wallet/:agent_id
An agent key can read its own wallet only.
```json
{
  "agent_id": "acme-bot",
  "tier": "early_testing",
  "balance_usdc": 4.91,
  "total_credited": 5,
  "total_spent": 0.09,
  "total_refunded": 0,
  "calls_this_month": 3,
  "calls_per_month_limit": 1000,
  "price_per_call": 0.03,
  "transactions": [
    { "tx_id": "001793000000000-a1b2c3", "type": "charge", "amount": 0.03, "balance_after": 4.91, "description": "validate", "created_at": "2026-11-04T14:30:00.000Z" }
  ]
}
```

## MCP
Endpoint: `POST https://api.myuiaf.com/mcp` (JSON-RPC 2.0, Streamable HTTP, JSON responses only). `initialize`, `ping`, and `tools/list` are public. `tools/call` requires the agent's API key. Supported protocol versions: `2025-06-18`, `2025-03-26`, `2024-11-05`. Notifications get an empty 202. Batch requests are unsupported. `GET /mcp` returns 405.

Initialize (the server echoes a supported version, otherwise answers `2025-06-18`):
```json
{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
  "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "my-agent", "version": "1.0.0" } } }
```
List tools (full JSON Schemas are in the response):
```json
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
```
Tools: `validate` (`context` required; `source_url`, `last_validated`, `metadata`, `agent_id`; same as POST /api/v1/validate) and `register_source` (`source_url` required; `check_frequency`, `agent_id`; same as POST /api/v1/source/register).
```json
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
  "params": { "name": "register_source", "arguments": { "source_url": "https://example.com/api-docs", "check_frequency": "6h" } } }
```
```json
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call",
  "params": { "name": "validate", "arguments": { "context": "The API rate limit is 100 req/min", "source_url": "https://example.com/api-docs" } } }
```
The result's `content[0].text` holds the REST JSON. `isError` is true when the call failed. A `validate` call with no credits is not an error; the text carries `"code": "insufficient_credits"`. Without a valid key, `tools/call` answers HTTP 401 with JSON-RPC error `-32001`.

Typical client entry (field names vary by client):
```json
{ "mcpServers": { "freshness-validator": { "url": "https://api.myuiaf.com/mcp", "headers": { "Authorization": "Bearer <api key>" } } } }
```

## Rate limits
| Tier | Requests per minute | Calls per month |
|---|---|---|
| Early Testing | 10 | 1,000 |
| Growing Product | 30 | 10,000 |
| Scale Revenue | 100 | 100,000 |
| Enterprise | 1,000 | Unlimited |

Every `validate` call counts toward the monthly allowance, charged or not; a registration counts as two. 429 codes: `rate_limited` (with `Retry-After`), `monthly_limit_reached`, `temporarily_blocked`.

## Errors
JSON: `{ "error": "message", "code": "machine_code" }`. 400 invalid field. 401 missing, invalid, or revoked key. 402 insufficient credits. 403 `agent_mismatch`, another agent's data, or `source_limit_reached`. 404 not found. 405 wrong method. 413 body over 256 KB or context over 50,000 characters. 422 source unusable (`source_unreachable`, `source_http_error`, `source_unsupported_type`, `source_empty`, `source_redirect_blocked`). 429 limits. 500 server error.

There are no packaged SDKs yet. Use any HTTP client.

## Operator endpoints (operator key required; agent keys get 401)
`POST /api/v1/agents/:agent_id/keys` (creates the agent and a key), `GET` the same path (lists keys), `DELETE /api/v1/agents/:agent_id/keys/:key_id` (also allowed for the key's own agent), `PUT /api/v1/agents/:agent_id` (set tier), `POST /api/v1/deposit` (manual credit), `POST /api/v1/webhook/stripe` (signed Stripe events).
