# Valiron API Reference

Machine-readable contract: [Valiron OpenAPI](https://www.valiron.co/openapi.json). [MCP setup](./MCP.md).

Base URL: `https://valiron-edge-proxy.onrender.com`

Supported integration endpoints:

- **Trust evaluation** (`/operator/agent/*`, `/operator/gate/*`, etc.) — Profile reads, runtime gate and identity-verification requests require an operator key; Pro trust signals and wallet intelligence require a Pro account with `Authorization: Bearer val_op_...`.
- **Agent-ready wrappers** (`/wrap/:operatorId/*`) — Public agent-facing URLs created from Dashboard endpoint configs. These can enforce x402/MPP payment, optional trust checks, rate limits, and upstream forwarding.

---

## Authentication

Get an operator API key from [the dashboard](https://www.valiron.co/dashboard). Send `Authorization: Bearer val_op_...` from your backend for profile/status reads and trust operations. Missing, invalid, or revoked credentials return HTTP 401. Keep keys out of browser code and public repositories.

Health and key-identity enrollment remain accessible without an operator key. Enrollment proves control of an agent key; it does not authorize profile reads or protected actions. Human verification uses signed proofs/provider callbacks. The private Icebreaker lookup also accepts a verified agent session for that agent's own address. Manage accounts, keys, and analytics through the website.

## Access and data boundaries

Profile endpoints require operator authentication and return identity and trust summaries. They do not return raw behavioral metrics, stored-evidence links, RPC URLs, internal errors, or verification-provider records. Self and World ID responses return an allowlisted verification summary; nullifiers, credential subjects, and provider storage references are private.

Sandbox runs require an operator API key. Enriched profiles, the trust-gated proxy, and webhook registration require a Pro operator API key. Webhook deliveries are scoped to the operator that initiated the evaluation and the selected chain. Legacy global evaluation history and platform statistics are restricted to Valiron administrators; view your own account analytics in the dashboard.

The gate also requires agent challenge-response headers (`x-agent-address` plus a valid `x-agent-session`, or a signed fresh challenge). Operator credentials do not replace agent identity. See [authentication](https://www.valiron.co/auth.md).

## Monthly request allowance

Free includes **100,000 metered API requests per account per UTC calendar month**.
Request 100,000 is allowed; subsequent requests return HTTP 429 with
`code: "MONTHLY_REQUEST_LIMIT_EXCEEDED"`, `error: "upgrade_required"`, `limit`,
`used`, `resetsAt`, and `upgradeUrl`. Upgrade to Pro or wait until the first of
the next month at 00:00 UTC. Pro ($149/month) and Enterprise have no monthly
request cap; existing feature gates, per-endpoint rate limits and traffic
protections still apply. Crossing the limit never automatically subscribes or
charges an account.

The shared account allowance counts admitted calls to:

- `POST /operator/gate/:agentId`
- `POST /operator/identity/verify`
- `POST /operator/trigger-sandbox/:agentId` and `/operator/trigger-sandbox-key/:agentAddress`
- `POST /proxy/:agentId` (still Pro-only)
- Any configured `/wrap/:operatorId/*` request, charged to the endpoint owner.

Direct metered calls require `Authorization: Bearer val_op_...`. Gate/proxy agent identity requirements still apply.
Wrappers resolve the account from the stored endpoint; an internal trust check
is included in the wrapper request, not counted again. Each attempt admitted
by the monthly counter counts, even if payment, trust or upstream work later
fails. Requests rejected by authentication or the monthly limit do not count.
Summary profile/discovery reads, identity challenges, health, account management,
checkout, and analytics are outside this allowance.

Responses include `X-Valiron-Monthly-Used` and `X-Valiron-Monthly-Reset`.
Free responses also include `X-Valiron-Monthly-Limit` and
`X-Valiron-Monthly-Remaining`. A quota rejection includes `Retry-After`.
If persistent usage storage is unavailable, metered calls return HTTP 503;
there is no process-local fallback that could bypass the allowance.

## Trust Evaluation Endpoints

### POST /operator/identity/verify

Normalize and verify a provider-backed agent identity proof. This endpoint is
provider-independent. SDK 1.3 exposes it as `verifyAgentIdentity()` and provides
dedicated middleware for `x-valiron-identity-*` proof headers. The ANS adapter
and provider credentials run inside Valiron's hosted service.

An empty body returns `identityStatus: "anonymous"`. Supplying an agent ID with
an incomplete or failed proof returns HTTP 200 with `identityStatus: "claimed"`
and a machine-readable `failureReason`. Only a validated authority binding,
fresh signature, and unused nonce return `identityStatus: "verified"`.

#### Request body

```json
{
  "provider": "ans",
  "agentId": "ans://v1.0.0.sales-agent.acme.com",
  "signature": "BASE64URL_OR_0xHEX_SIGNATURE",
  "timestamp": "2026-09-04T12:00:00.000Z",
  "nonce": "nonce-0123456789abcdef",
  "requestDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "keyId": "optional-provider-key-id",
  "policy": {
    "anonymous": "challenge",
    "claimed": "block",
    "verified": "allow",
    "minReputationScore": 65,
    "belowMinimumScore": "limit",
    "mediumRisk": "limit",
    "highRisk": "block"
  }
}
```

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | for a claimed identity | Registered resolver name. `ans` is implemented; DNS, DID, and API-key adapters are future integrations |
| `agentId` | string | no | Provider identity. Omit it to classify the request as anonymous |
| `signature` | string | for verification | Base64/base64url or `0x`-hex signature unless the resolver defines a provider-specific proof |
| `timestamp` | ISO timestamp | for verification | Signed time; default acceptance window is five minutes |
| `nonce` | string | for verification | 16–256 URL-safe characters; atomically claimed to prevent replay |
| `requestDigest` | string | for verification | `sha256:` plus 64 hexadecimal characters for the protected request bytes |
| `keyId` | string | no | Selects one provider-resolved verification key |
| `policy` | object | no | Per-status and per-risk actions. Every action must be `allow`, `limit`, `challenge`, or `block` |

The signature covers the exact canonical payload documented in
[PROVIDER-IDENTITY.md](./PROVIDER-IDENTITY.md#low-level-verification-request).
SDK identity gates calculate `requestDigest` from the exact received request
bytes rather than trusting a digest header.

#### Response — verified

```json
{
  "agentId": "ans://v1.0.0.sales-agent.acme.com",
  "provider": "ans",
  "organization": "Acme Corp",
  "identityStatus": "verified",
  "humanIdentified": false,
  "stableIdentityId": "identity:ans:<sha256>",
  "credentialId": "7b93c61c-e261-488c-89a3-f948119be0a0",
  "credentialVersion": "1.0.0",
  "verifiedAt": "2026-09-04T12:00:00.000Z",
  "reputationScore": 82,
  "riskLevel": "low",
  "policyDecision": {
    "action": "allow",
    "reason": "identity_verified"
  }
}
```

For ANS, `stableIdentityId` is derived from `agentHost`, so reputation and
activity remain continuous across versioned registrations. `credentialId` is
the Registry Authority UUID and `credentialVersion` is the resolved version.

#### Response — claimed, resolver unavailable

```json
{
  "agentId": "ans://v1.0.0.sales-agent.acme.com",
  "provider": "ans",
  "organization": null,
  "identityStatus": "claimed",
  "humanIdentified": false,
  "stableIdentityId": null,
  "verifiedAt": null,
  "failureReason": "resolver_unavailable",
  "reputationScore": null,
  "riskLevel": "unknown",
  "policyDecision": {
    "action": "challenge",
    "reason": "resolver_unavailable"
  }
}
```

This response occurs when the requested provider is not registered. For ANS it
also occurs when the deployment does not have the required ANS credentials and
trusted CA configuration.

#### Error responses

| Status | Error | Meaning |
| --- | --- | --- |
| 400 | `invalid_identity_policy` | A policy is not an object, an action is unsupported, or `minReputationScore` is outside 0–100 |
| 503 | `identity_verification_unavailable` | Valiron could not safely resolve identity or atomically claim replay state |

See [Provider-Backed Identity Errors](./ERRORS.md#provider-backed-identity-errors)
for all `failureReason` values and retry guidance.

---

### GET /operator/agent/:agentId

Retrieve the complete trust profile for an agent.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | ERC-8004 token ID |
| `chain` | query | string | no | Network override (default: ethereum) |

### Response — 200 OK

```json
{
  "agentId": "25459",
  "identity": {
    "agentId": "25459",
    "wallet": "0x52ce...",
    "tokenUri": "data:application/json;base64,...",
    "name": "Agent Name",
    "image": "https://...",
    "description": "Agent description",
    "endpoints": {
      "agentWallet": "eip155:1:0x...",
      "api": "https://api.example.com"
    },
    "trustModels": ["reputation_on_chain", "behavioral_sandbox"]
  },
  "onchainReputation": {
    "feedbackCount": 12,
    "averageScore": 92.5
  },
  "routing": {
    "finalRoute": "prod",
    "meetsThreshold": true
  },
  "chain": {
    "name": "ethereum",
    "chainId": 1
  },
  "timestamp": "2026-03-23T12:00:00.000Z"
}
```

### Error Responses

| Status | Meaning |
|--------|---------|
| 404 | Agent not found in ERC-8004 registry |
| 500 | Internal server error |

---

## GET /operator/wallet/:wallet

Reverse-lookup a wallet address to get its trust profile.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `wallet` | path | string | yes | Ethereum address (0x...) or Solana pubkey (base-58, with `chain=solana`) |
| `chain` | query | string | no | Network override |

### Response — 200 OK

Same structure as `GET /operator/agent/:agentId`.

---

## GET /operator/wallet-risk/:wallet (Pro)

Return an explainable wallet-history assessment. Requires a Pro or Enterprise operator API key in `Authorization: Bearer val_op_...`.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `wallet` | path | string | yes | EVM address or Solana public key |
| `chain` | query | string | no | `ethereum`, `base`, `arbitrum`, `optimism`, `polygon`, or `solana` |

### Response — 200 OK

```json
{
  "available": true,
  "wallet": "0x52ce...",
  "network": "base",
  "provider": "alchemy",
  "score": 78,
  "rawScore": 85,
  "risk": 22,
  "confidence": 0.81,
  "riskLevel": "LOW",
  "reasons": [
    "Wallet has at least one year of history",
    "Score is based on a bounded transaction sample"
  ],
  "hardFlags": [],
  "features": {
    "transactionCount": 146,
    "activeDays": 41,
    "walletAgeDays": 620,
    "uniqueCounterparties": 77,
    "historyTruncated": true
  },
  "observedAt": "2026-07-20T12:00:00.000Z",
  "expiresAt": "2026-07-20T18:00:00.000Z"
}
```

`score` is trust-oriented: higher is better. `risk` is `100 - score`. `confidence` dampens sparse assessments toward neutral. `historyTruncated: true` means the score uses a bounded sample rather than complete transaction history.

Provider failures return HTTP 200 with `available: false`, `provider: "none"`, and an `error` explaining why the signal was unavailable. Gate/profile endpoints exclude unavailable wallet intelligence from composite scoring.

### Error Responses

| Status | Meaning |
|--------|---------|
| 400 | Invalid EVM or Solana wallet address |
| 403 | Missing operator key or plan does not include enriched profiles |
| 500 | Unexpected wallet-risk route failure |

---

## GET /operator/resolve-wallet/:wallet

Lightweight wallet → agentId resolution. Returns just the agent ID and how it was resolved, without the full trust profile.

Wallet resolution returns the associated agent ID when available.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `wallet` | path | string | yes | Ethereum address (0x...) or Solana pubkey (base-58, with `chain=solana`) |
| `chain` | query | string | no | Network override (default: ethereum) |

### Response — 200 OK

```json
{
  "wallet": "0x52ce...",
  "agentId": "25459",
  "source": "subgraph",
  "chainId": 1,
  "agentName": "MyAgent",
  "timestamp": "2024-01-01T00:00:00.000Z"
}
```

---

## POST /operator/trigger-sandbox/:agentId

Execute real-time sandbox tests against an agent and compute a trust evaluation.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | ERC-8004 token ID |
| `chain` | query | string | no | Network override |

### Response — 200 OK

```json
{
  "ok": true,
  "agentId": "25459",
  "wallet": "0x52ce...",
  "tier": "AAA",
  "riskLevel": "GREEN",
  "meetsThreshold": true,
  "testSummary": {},
  "chain": {
    "name": "ethereum",
    "chainId": 1
  },
  "message": "Sandbox evaluation complete"
}
```

> **Note:** The `testSummary` object contains opaque test metrics. Its internal structure is proprietary and may change without notice.

---

## POST /operator/gate/:agentId

Trust gate — combined on-chain reputation + sandbox check. Returns an allow/deny decision. Designed for protecting payment endpoints (x402, etc.).

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | ERC-8004 token ID |

### Request Body

```json
{
  "minScore": 65,
  "trustSignals": ["8004", "sandbox", "wallet"],
  "ttlMs": 86400000
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `minScore` | number | 65 | Minimum composite trust score required to allow |
| `trustSignals` | string[] | automatic | Selected signals. `wallet`, `world`, `self`, and `icebreaker` require Pro |
| `ttlMs` | number | 86400000 | Cache TTL in milliseconds (default 24 hours) |

### Response — 200 OK

```json
{
  "allow": true,
  "tier": "AAA",
  "riskLevel": "GREEN",
  "meetsThreshold": true,
  "route": "prod",
  "agentId": "25459",
  "wallet": "0x52ce...",
  "chain": {
    "name": "ethereum",
    "chainId": 1
  },
  "sandboxRan": false,
  "cached": true,
  "walletRisk": {
    "available": true,
    "score": 78,
    "risk": 22,
    "riskLevel": "LOW",
    "confidence": 0.81,
    "hardFlags": []
  }
}
```

### Decision Logic

1. If the agent meets the trust threshold → `allow: true`
2. If the agent does not meet the threshold → `allow: false`
3. Cached sandbox results are reused within the `ttlMs` window
4. If no cached result exists, sandbox tests run automatically
5. If `wallet` is selected and available, its confidence-damped score is included in the composite result
6. Unavailable wallet history is excluded; any populated wallet hard flag forces `sandbox_only`

---

## GET /operator/agent/:agentId/snapshot

Get the latest behavioral snapshot hash for an agent. Returns an opaque hash suitable for on-chain commitment systems.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | ERC-8004 token ID |
| `chain` | query | string | no | Network override |

### Response — 200 OK

```json
{
  "agentId": "25459",
  "snapshotHash": "0x3a7f2b...",
  "previousHash": "0x0",
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### Error Responses

| Status | Meaning |
|--------|---------|
| 400 | Invalid agentId |
| 404 | Agent not found or no snapshot available (trigger a sandbox evaluation first) |
| 500 | Internal server error |

---

## POST /operator/webhooks/register

Register a public HTTPS webhook with a Pro operator API key. Events are limited to evaluations initiated by that operator on the selected `chain`; registrations cannot subscribe to other operators. Existing registrations must be recreated after the privacy update. Set `?chain=<network>` when registering; use `?chain=key` for key-based evaluations.

### Request Body

```json
{
  "event": "evaluation_complete",
  "url": "https://your-endpoint.com/hooks/valiron",
  "agentIds": [42, 43]
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | yes | Must be `"evaluation_complete"` |
| `url` | string | yes | HTTPS endpoint to receive webhook POST requests |
| `agentIds` | number[] | no | Filter to specific agent IDs. Omit for your own evaluations on the selected chain. |

### Response — 201 Created

```json
{
  "id": "a1b2c3d4-...",
  "event": "evaluation_complete",
  "url": "https://your-endpoint.com/hooks/valiron",
  "agentIds": [42, 43],
  "createdAt": "2026-04-01T12:00:00.000Z"
}
```

### Webhook Payload

When an evaluation completes, Valiron POSTs the following to your registered URL:

```json
{
  "event": "evaluation_complete",
  "agentId": "25459",
  "tier": "AAA",
  "riskLevel": "GREEN",
  "route": "prod",
  "meetsThreshold": true,
  "snapshotHash": "0x3a7f2b...",
  "previousHash": "0x8b2c1a...",
  "encryptedDataUri": null,
  "timestamp": "2026-04-01T12:05:00.000Z",
  "interactionCount": 16
}
```

#### Webhook Payload Fields

| Field | Type | Description |
|-------|------|-------------|
| `event` | string | Always `"evaluation_complete"` |
| `agentId` | string | The evaluated agent ID |
| `tier` | string | Moody's-style trust tier (AAA–C) |
| `riskLevel` | string | GREEN / YELLOW / RED |
| `route` | string | Route decision (`prod`, `prod_throttled`, `sandbox`, `sandbox_only`) |
| `meetsThreshold` | boolean | Whether the agent passed the trust gate |
| `snapshotHash` | string | Deterministic hash of the behavioral evaluation |
| `previousHash` | string | Hash from the prior evaluation |
| `encryptedDataUri` | string\|null | IPFS CID of encrypted snapshot data |
| `timestamp` | string | ISO 8601 timestamp |
| `interactionCount` | number | Total interactions in the evaluation window |

#### Webhook Limitations

- **Maximum registrations:** 1,000 per operator
- **Delivery:** Fire-and-forget — no retries on failure
- **Timeout:** 10 seconds — your endpoint must respond within 10s
- **Signatures:** Webhooks are not signed — verify via IP allowlisting or shared secrets if needed
- **Events:** Only `evaluation_complete` is currently supported

---

## POST /proxy/:agentId (Pro)

Forward a request through Valiron's edge proxy with automatic trust gating, logging, and SSRF protection.

### Parameters

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | Agent to gate |

### Request Body

```json
{
  "targetUrl": "https://your-api.com/data",
  "method": "POST",
  "headers": { "Content-Type": "application/json" },
  "body": "{\"query\": \"example\"}"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `targetUrl` | string | yes | Your origin URL to forward to |
| `method` | string | no | HTTP method (default: `GET`) |
| `headers` | object | no | Headers to forward |
| `body` | string | no | Request body |

### Response — 200 OK

```json
{
  "statusCode": 200,
  "responseHeaders": {},
  "responseBody": "...",
  "responseMs": 145,
  "costCharged": "0.0500",
  "route": "prod",
  "tierResolved": "AA"
}
```

> **SSRF Protection:** The proxy blocks requests to private IPs (10.x, 172.16-31.x, 192.168.x), localhost, link-local addresses, and cloud metadata endpoints (169.254.169.254).

---

## Key-Based Agent Endpoints

For Web2 agents that don't have on-chain identities, Valiron supports key-based authentication using EIP-191 challenge-response.

### POST /operator/key/:agentAddress/challenge

Get a challenge nonce for key-based authentication.

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentAddress` | path | string | yes | Ethereum address (0x...) |

#### Response — 200 OK

```json
{
  "challenge": "valiron-challenge-abc123...",
  "expiresAt": "2026-04-01T12:05:00.000Z",
  "agentAddress": "0x..."
}
```

### POST /operator/key/verify

Verify a signed challenge to authenticate a key-based agent.

#### Request Body

```json
{
  "agentAddress": "0x...",
  "challenge": "valiron-challenge-abc123...",
  "signature": "0x..."
}
```

#### Response — 200 OK

```json
{
  "verified": true,
  "agentAddress": "0x...",
  "score": null,
  "tier": null,
  "riskLevel": null,
  "route": null,
  "icebreaker": null,
  "reasons": [],
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### GET /operator/key/:agentAddress

Get the summary profile of a key-based agent using your operator API key. Icebreaker context and reasons are
redacted from this response.

#### Response — 200 OK

```json
{
  "agentAddress": "0x...",
  "verified": true,
  "score": 82,
  "tier": "A",
  "riskLevel": "GREEN",
  "route": "prod",
  "icebreaker": null,
  "reasons": [],
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### GET /operator/key/:agentAddress/icebreaker

Get the Icebreaker owner context for a verified key-based agent. Supply a Pro
operator API key as `Authorization: Bearer val_op_...`. The agent may instead
authenticate with its Valiron `x-agent-address` and `x-agent-session` headers.
The route returns `401` for a missing agent session and `403` when the caller
is neither that agent nor a Pro operator.

```typescript
const valiron = new ValironSDK({ apiKey: process.env.VALIRON_API_KEY });
const { icebreaker } = await valiron.getKeyAgentIcebreaker(agentAddress);
```

```json
{
  "agentAddress": "0x...",
  "icebreaker": {
    "attested": true,
    "uid": "0x...",
    "owner": "Jane Doe",
    "verifiedHandles": [{ "source": "github", "handle": "janedoe" }],
    "organization": "Acme",
    "profileUrl": "https://app.icebreaker.xyz/profiles/...",
    "credentialUrl": "https://app.icebreaker.xyz/credentials/..."
  }
}
```

When no matching credential exists, `icebreaker` is `{ "attested": false }`.
These are verified profile handles, not Icebreaker connections or mutuals.
Valiron checks the off-chain EAS signature, UID, signer, schema, recipient,
credential name, and expiry before returning `attested: true`. The lookup uses
Icebreaker's profile API and does not independently check off-chain revocation.
The Web2 middleware's behavioral score does not change when this attestation
appears; the API seller must enforce any policy that uses it.

---

## World ID Endpoints

Verify agent-human linkage via Worldcoin's zero-knowledge proof system.

### POST /operator/world-id/verify/:agentId

Submit a World ID proof for an on-chain agent. `verification_level` is required and must be `orb`, `device`, or `phone`.

```json
{
  "merkle_root": "0x...",
  "nullifier_hash": "0x...",
  "proof": "0x...",
  "verification_level": "orb"
}
```

#### Response — 200 OK

```json
{
  "ok": true,
  "agentId": "25459",
  "worldId": { "verified": true, "verificationLevel": "orb" },
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### GET /operator/world-id/status/:agentId

Read verification status with your operator API key.

```json
{
  "agentId": "25459",
  "worldId": { "verified": true, "verificationLevel": "orb" },
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### GET /operator/world-id/profile/:agentId

Requires a Pro operator key. Returns `agentId`, the same allowlisted `worldId` summary, `identity`, `icebreaker`, `humanTrust`, `reasons`, and `timestamp`. `identity` can be `null`; `icebreaker` is `{ "attested": false }` when no attestation is found. The `humanTrust` object contains `hasHumanLink`, `hasBackground`, and `verificationLevel`.

---

## Self Endpoints

Create Self Enterprise verification sessions, receive signed Self webhooks, and read Self eligible-human verification plus optional Self Agent ID binding. Use the `self` trust signal when an endpoint should consider Self proof during Valiron scoring.

### POST /operator/self/session/:agentId

Create a Self Enterprise verification session for an agent.

| Parameter | Location | Type | Required | Description |
|-----------|----------|------|----------|-------------|
| `agentId` | path | string | yes | ERC-8004 token ID |

#### Request Body

```json
{
  "selfAgentId": "self-agent-...",
  "selfAgentRegistry": "0x...",
  "successUrl": "https://example.com/verified",
  "failureUrl": "https://example.com/failed",
  "expiresInSeconds": 900,
  "metadata": {}
}
```

#### Response — 200 OK

```json
{
  "ok": true,
  "agentId": "25459",
  "self": {
    "sessionId": "sess_...",
    "externalUuid": "00000000-0000-0000-0000-000000000000",
    "verificationUrl": "https://verify.self.xyz/s/...",
    "status": "pending",
    "expiresAt": "2026-04-01T12:15:00.000Z"
  },
  "timestamp": "2026-04-01T12:00:00.000Z"
}
```

### GET /operator/self/status/:agentId

Check if an agent has a verified Self eligible-human link.

### GET /operator/self/profile/:agentId

Requires a Pro operator key. Returns `self` eligibility and agent-binding predicates, `identity`, `humanTrust`, `reasons`, and `timestamp`. Provider identifiers are omitted from `self`.

---

## GET /operator/health

Health check endpoint.

### Response — 200 OK

```json
{
  "status": "ok",
  "supportedChains": ["ethereum", "monad", "arbitrum", "base", ...],
  "defaultChain": "ethereum"
}
```

---

## Solana Support

All `/operator/*` endpoints support Solana agents when `chain=solana` is passed as a query parameter or `x-chain: solana` header.

Solana agent identity and reputation data is provided by [QuantuLabs 8004-solana](https://8004.qnt.sh/), while EVM chains use the 8004 team's registry contracts. The two registries have different schemas — this is by design.

### Key Differences from EVM

| Area | EVM | Solana |
|------|-----|--------|
| **Agent ID format** | Numeric token ID (e.g. `25459`) | Base-58 Metaplex Core asset pubkey (e.g. `GL4k...`) or sequential ID (e.g. `1`, `42`) |
| **Wallet format** | `0x`-prefixed hex address | Base-58 public key |
| **Identity source** | ERC-8004 `ownerOf()` on-chain call | QuantuLabs `loadAgent()` SDK call |
| **Reputation source** | ERC-8004 `getSummary()` | QuantuLabs ATOM engine (`getEnrichedSummary()`) |
| **Extra reputation fields** | — | `solana.trustTier`, `solana.qualityScore`, `solana.confidence`, `solana.riskScore`, `solana.uniqueCallers` |
| **Wallet → Agent resolution** | Supported EVM registries | Supported Solana registry |
| **Liveness check** | — | `isItAlive()` endpoint-by-endpoint health probe |
| **Feedback write-back** | — | Valiron scores written on-chain via `giveFeedback()` when enabled by Valiron |

### Sequential Agent IDs

Solana agents are primarily identified by their base-58 asset pubkey, but the QuantuLabs indexer also assigns sequential integer IDs (1, 2, 3, …). You can use either format:

```bash
# By asset pubkey (primary)
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/agent/GL4k...?chain=solana"

# By sequential ID (convenience)
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/agent/42?chain=solana"
```

When a sequential ID is used, the response includes a `sequentialId` field mapping back to the numeric ID.

### Liveness Check

`GET /operator/agent/:agentId/liveness?chain=solana`

Pings each service endpoint from the agent's on-chain metadata and returns a health report. Only available for Solana agents.

**Response:**
```json
{
  "agentId": "GL4k...",
  "chain": { "network": "solana", "cluster": "mainnet-beta" },
  "liveness": {
    "status": "live",
    "okCount": 3,
    "totalPinged": 3,
    "skippedCount": 0,
    "results": [
      { "type": "rest", "endpoint": "https://...", "ok": true, "latencyMs": 120 }
    ]
  }
}
```

The `trigger-sandbox` endpoint also includes a `liveness` summary in its response for Solana agents.

### Feedback Write-Back

When feedback write-back is enabled, Valiron automatically writes evaluation scores back to the Solana reputation registry after sandbox testing and gate evaluations. This closes the trust loop — other consumers of the 8004-solana registry can see Valiron's scores.

Feedback is submitted as fire-and-forget using the `starred` tag with `tag2: "valiron"` for attribution.

### Solana-Specific Response Fields

When querying a Solana agent, the `onchainReputation` object may include an additional `solana` block with ATOM engine metrics:

```json
{
  "onchainReputation": {
    "count": "42",
    "averageScore": 88.5,
    "feedbackEntries": [],
    "totalFeedback": 42,
    "solana": {
      "trustTier": "trusted",
      "qualityScore": 92.1,
      "confidence": 0.87,
      "riskScore": 0.08,
      "uniqueCallers": 15
    }
  }
}
```

### Example Requests

```bash
# Get Solana agent profile
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/agent/GL4k...?chain=solana"

# Get Solana agent by sequential ID
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/agent/42?chain=solana"

# Gate a Solana agent
curl -H "Authorization: Bearer $VALIRON_API_KEY" -X POST "https://valiron-edge-proxy.onrender.com/operator/gate/GL4k...?chain=solana"

# Check liveness
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/agent/GL4k.../liveness?chain=solana"

# Look up by Solana wallet
curl -H "Authorization: Bearer $VALIRON_API_KEY" "https://valiron-edge-proxy.onrender.com/operator/wallet/7xKX...?chain=solana"

# Trigger sandbox for Solana agent
curl -H "Authorization: Bearer $VALIRON_API_KEY" -X POST "https://valiron-edge-proxy.onrender.com/operator/trigger-sandbox/GL4k...?chain=solana"
```


## Agent-Ready Wrapper Endpoint

### ALL /wrap/:operatorId/*

Public agent-facing wrapper URL. This endpoint is created by `POST /operator/endpoints` or the **Make API Agent-Ready** dashboard flow.

```text
https://valiron-edge-proxy.onrender.com/wrap/{operatorId}/{path}
```

The wrapper matches the operator ID, path, and HTTP method to an active endpoint config. It can enforce payment, optional trust checks, rate limits, SSRF protection, upstream auth injection, and request forwarding. These controls apply only to traffic sent to this wrapper URL. Protect a public upstream with `hmac` auth and reject direct, unsigned origin traffic. See [API Scaffolding](./AGENT-READY-APIS.md#recommended-production-pattern-hmac-origin-verification).

#### Caller Headers

| Header | Required | Description |
|--------|----------|-------------|
| `X-PAYMENT` | paid x402 retry | x402 payment payload returned by an x402-capable client. |
| `Authorization: Payment ...` | paid MPP retry | MPP payment authorization header. |
| `x-agent-id` | if trust enabled | ERC-8004 agent ID. |
| `x-agent-address` | not supported by hosted trust wrappers | Use SDK middleware in your own backend when you need key/address identity support. |

#### Free Wrapper Response

If `pricePerCall` is `0`, the wrapper forwards directly to the upstream API:

```bash
curl https://valiron-edge-proxy.onrender.com/wrap/{operatorId}/status
```

#### x402 Paid Wrapper Response

If `paymentProtocol` is `x402` and no valid payment is attached, the wrapper returns:

```http
HTTP/1.1 402 Payment Required
X-PAYMENT-RESPONSE: ...
Content-Type: application/json
```

The caller should retry with a valid `X-PAYMENT` header. See [AGENT-READY-APIS.md](./AGENT-READY-APIS.md#paid-x402-client) for a complete TypeScript client.

#### MPP Paid Wrapper Response

If `paymentProtocol` is `mpp` and no valid payment is attached, the wrapper returns:

```http
HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment ...
Content-Type: application/json
```

The caller should retry with `Authorization: Payment ...`. For command-line testing:

```bash
pnpm exec mppx https://valiron-edge-proxy.onrender.com/wrap/{operatorId}/research
```

#### Error Responses

| Status | Code | Meaning |
|--------|------|---------|
| 402 | `payment_required` | Paid wrapper needs valid x402 or MPP payment. |
| 403 | `trust_denied` | Trust checks are enabled and the agent did not pass. |
| 404 | `wrapper_not_found` | No active wrapper matched operator ID, path, and method. |
| 413 | `payload_too_large` | Request body exceeds wrapper limit. |
| 429 | `rate_limit_exceeded` | Caller exceeded wrapper rate limit. |
| 502 | `wrapper_request_failed` | Upstream request failed or returned an invalid response. |

---
