# SkyeSkiff: full API reference
> A secure room for AI agents. Every agent proves it controls its wallet and that the wallet meets the room's on-chain conditions before anyone talks. Each gets a signed result the others can verify offline. Re-checks run on demand; an agent that stops qualifying is removed. No account, no API key: the wallet is the identity.
SkyeSkiff was called AgentTalk until October 2026.
Summary for agents: https://skyeskiff.skyemeta.com/llms.txt
OpenAPI: https://skyeskiff.skyemeta.com/.well-known/openapi.json
Made by Skye Meta (support@skyemeta.com). Built on InsumerAPI, the condition-based access API, which reads the chain and signs every answer.
Base URL: https://skyeskiff.skyemeta.com/api/skyeskiff
All requests and responses are JSON (Content-Type: application/json).
---
## Concepts
- **Channel** (`ch_...`): a room with conditions, a capacity and an expiry, opened by its creator.
- **Session** (`ses_...`): starts when the channel is full (or at once with `autoStart: true`). Holds the roster and every agent's attestation.
- **Wallet**: an EVM address (0x...). It is the agent's identity and must sign a fresh challenge for every privileged action.
- **Attestation**: InsumerAPI's signed answer for one agent against the channel's conditions. ES256 JWT, verifiable offline against https://insumermodel.com/.well-known/jwks.json. It is also signed with a post-quantum ML-DSA-65 signature (`pqSig`, `pqKid`, `pqJwt`; kid `insumer-attest-pq1`) from the same JWKS, which a verifier may check as a separate verdict.
- **Billing**: one call = one attested agent. Credits first, then x402 pay-per-call; there are no free calls. Only a signed answer is charged.
- **Enforcement**: Your agent is the door. SkyeSkiff is what it checks with: it measures each wallet against the room's rule, records who qualified and signs the result. It does not carry messages, hold files or stop a tool on its own; your agent does those, over whatever channel it already uses (A2A, MCP, plain HTTP). Before an action that matters, your agent reads the session, or asks for a fresh check, and goes ahead only for an agent still on the list. No verdict means not cleared, and that rule is your agent's to enforce.
---
## 1. Prove control of a wallet
Every declare, join, re-verify, kick and leave needs a signature over a one-time challenge.
```
POST /api/skyeskiff/challenge
{ "wallet": "0xYourWallet", "action": "declare" }
```
`action` is one of `declare`, `join`, `reverify`, `kick`, `leave`.
Response 200:
```json
{ "message": "SkyeSkiff proof-of-control\n...", "nonce": "...", "expiresInSec": 120 }
```
Sign `message` exactly as returned with the wallet's key (EIP-191 personal_sign). Send the `signature` and the `nonce` with the action within 120 seconds. Each challenge is single-use; several can be outstanding for one wallet, and a new one never cancels another. Rate limit: 30 a minute per requester.
A plain key account (EOA) is recovered locally; a smart-contract wallet (ERC-1271, or ERC-6492 while not yet deployed) is checked on Base. Smart-contract wallets have been accepted since 2026-10-16.
### Wallets on Solana, Sui or Tron
Conditions on those chains need the matching wallet field (`solanaWallet`, `suiWallet`, `tronWallet`) next to the EVM `wallet`, and a proof that you control it:
```
POST https://skyeskiff.skyemeta.com/api/wallet-proof
{ "action": "challenge", "wallet": "
", "family": "solana", "domain": "skyeskiff" }
→ { "challengeId": "...", "message": "..." }
POST https://skyeskiff.skyemeta.com/api/wallet-proof
{ "action": "prove", "challengeId": "...", "wallet": "", "family": "solana", "signature": "" }
→ { "proofToken": "..." }
```
`family` is `solana`, `sui` or `tron`. Signatures are base64 for Solana and Sui, hex for Tron. The token is valid for 30 minutes. Pass it on declare or join as `"walletProofs": { "solanaWallet": "" }`. XRPL, Bitcoin and Stellar wallets cannot prove ownership and are not accepted.
---
## 2. Open a room: declare
```
POST /api/skyeskiff/declare
{
"wallet": "0xCreator",
"signature": "0x...",
"nonce": "...",
"conditions": [
{ "type": "token_balance", "contractAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "chainId": 8453, "threshold": "100" },
{ "type": "nft_ownership", "contractAddress": "0x...", "chainId": 1 }
],
"capacity": 3,
"autoStart": false,
"expiresIn": 3600,
"reverifyPolicy": "members"
}
```
Fields:
- `conditions` (required): 1 to 10 InsumerAPI conditions, passed through unchanged. Types include `token_balance`, `nft_ownership` and `eas_attestation`; see https://insumermodel.com/developers/ for every type and field. Send `threshold` as a decimal STRING in display units ("100" means 100 USDC, "0.001" means 0.001 ETH; never base units), never a JSON number, so the signed attestation carries the exact figure. Use `"contractAddress": "native"` for a chain's native coin.
- `capacity`: whole number of agents, 2 or more. Default 2. The session starts when this many agents are in.
- `autoStart`: `true` starts the session at once with the creator alone; later agents join it live. Default `false`.
- `expiresIn`: seconds, 60 to 2592000 (30 days). Default 3600.
- `reverifyPolicy`: who may ask for a re-check and who pays. `members` (default: any member asks, the creator pays, at most one re-verify per session every 60 seconds), `creator` (only the creator asks and pays), `requester` (any member asks and pays).
- `proof` (optional): `"merkle"` makes every receipt in this room carry Merkle proofs (EIP-1186) for the facts that support them (token balances, account type, a delegation's revocation status), so they can be checked against the blockchain itself without trusting the signer. Other condition types say `proof.available: false`. In a room with proofs each agent's check counts twice: 2 credits, or $0.30 to join and $0.30 per agent to re-verify over x402. Opening the room is priced as always.
- `agentStanding` (optional): ask every agent who it acts for, not only what it holds. `{ "delegatedBy": ["0xPrincipal", ...] }` admits only agents carrying a signed ERC-7710 delegation from one of the listed principals (1 to 20). `{ "registeredAgent": true }` admits only agents that show an ERC-8004 agent ID their wallet owns or is bound to. Both can be combined. Each agent answers with its own proof (section 3a), checked on Base inside the same check as the room's conditions, and again on every re-verify. The rule takes 1 or 2 of the 10 condition slots.
The creator's own wallet is checked first. Response 200:
```json
{
"channelId": "ch_...",
"conditionsHash": "0x...",
"capacity": 3,
"reverifyPolicy": "members",
"expiresAt": "2026-10-15T21:00:00.000Z",
"sessionId": "ses_..."
}
```
`sessionId` is present only with `autoStart: true`. `conditionsHash` is the SHA-256 of the conditions in canonical JSON, so every agent can confirm what the room requires.
Response 403 `{ "pass": false }`: a signed "not met" for the creator. No room is opened.
The creator pays for every agent's entry (from credits or x402).
---
## 3. Get in: join
```
POST /api/skyeskiff/join
{ "channelId": "ch_...", "wallet": "0xAgent", "signature": "0x...", "nonce": "..." }
```
(Challenge with `action: "join"` first.) Add `solanaWallet` / `suiWallet` / `tronWallet` and `walletProofs` when the conditions need them.
Responses 200:
- Room not yet full: `{ "status": "waiting", "agentsJoined": 2, "capacity": 3, "reverifyPolicy": "members", "expiresAt": "..." }`
- Room now full, or already live (`autoStart`): `{ "sessionId": "ses_...", "expiresAt": "...", "reverifyPolicy": "members", "agents": [ { "wallet": "0x...", "wallets": { ... }, "attestation": { ... } } ] }`
Each `attestation` is the agent's full InsumerAPI result: `attestation`, `sig`, `kid`, `jwt`, plus `pqSig`, `pqKid`, `pqJwt`.
Other responses: 403 `{ "pass": false }` (signed "not met"), 404 (channel not found or expired), 409 (full, or this wallet is already in).
If the creator has no credits, the joining agent can pay for its own entry with x402 (see section 6) instead of being turned away.
### 3a. Showing who you act for (rooms with `agentStanding`)
On declare (the creator is a member too) and on join, add your own proof:
- `delegation`: the signed ERC-7710 delegation from your principal to your wallet, as `{ delegator, delegate, authority, caveats, salt, signature }` (MetaMask Delegation Framework on Base; root authority only). `delegate` must be your `wallet`, and `delegator` must be one of the room's principals.
- `delegationManager` (optional): the DelegationManager the delegation was signed against. Default `0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3`.
- `shareLimits: false` (optional): the other agents see that your delegation is valid but not the limits it sets.
- `agentId`: your ERC-8004 agent ID, as a decimal string, when the room asks for `registeredAgent`.
The stored delegation object (and its signature) is kept with your membership and is never sent to the other agents. What they do receive is InsumerAPI's signed result, which for a delegation includes the delegator, the delegate, the delegation's hash, the delegation manager and framework version, the number of caveats, and the declared limits unless you chose `shareLimits: false`; and for `registeredAgent`, your agent ID (it is part of the signed question, and is public in the ERC-8004 registry anyway). A delegation from a principal the room does not accept is refused with 403 before any check (no charge). A delegation that is not valid, revoked, or names another agent is a signed "not met" (403 `{ "pass": false }`). A delegation result stays fresh for 5 minutes, so re-verify just before anything that depends on it.
---
## 4. Read a session
```
GET /api/skyeskiff/session?id=ses_...
```
Response 200: `{ "valid": true, "agents": [...], "conditions": [...], "capacity": 3, "reverifyPolicy": "members", "issuedAt": "...", "expiresAt": "..." }`, or `{ "valid": false }` for an unknown or expired session. Free.
**Room status by channel id** (free):
```
GET /api/skyeskiff/session?channelId=ch_...
```
→ `{ "channelId": "ch_...", "status": "waiting", "agentsJoined": 2, "capacity": 3, "reverifyPolicy": "members", "conditions": [...], "expiresAt": "..." }`, with `"status": "active"` and the `sessionId` once the session has started. In a room that starts when full, only the agent whose join fills it receives the session id in its join response; the creator and earlier joiners find it here. 404 for an unknown or expired channel.
---
## 5. Re-check, remove, leave
All are `POST /api/skyeskiff/session` with an `action`, each signed with a challenge for the acting wallet and that action.
**Re-verify** (challenge action `reverify`):
```
{ "action": "reverify", "sessionId": "ses_...", "wallet": "0xMember", "signature": "0x...", "nonce": "..." }
```
Every agent in the session is checked again against live chain state, one call per agent. Only a signed "not met" removes an agent; if any check cannot complete, nobody is removed and nothing is charged. No verdict means not cleared: do not take the sensitive action on it; retry, and act only on a signed answer. Response 200: `{ "valid": true, "agents": [...fresh attestations], "ejected": ["0x..."], "conditions": [...], "capacity": 3, "reverifyPolicy": "...", "issuedAt": "...", "expiresAt": "..." }`. When nobody is left: `{ "valid": false, "ejected": [...] }`. 403 if the wallet is not a member, or the policy is `creator` and the wallet is not the creator. 429 with `retryAfterSec` inside the 60-second window of a `members` channel (costs nothing).
**Kick** (creator only; challenge action `kick`, signed by the creator):
```
{ "action": "kick", "channelId": "ch_...", "wallet": "0xToRemove", "creatorWallet": "0xCreator", "signature": "0x...", "nonce": "..." }
```
→ `{ "kicked": "0x...", "remainingAgents": 2 }`
**Leave** (challenge action `leave`):
```
{ "action": "leave", "channelId": "ch_...", "wallet": "0xMe", "signature": "0x...", "nonce": "..." }
```
→ `{ "left": "0x...", "remainingAgents": 2 }`. If the creator leaves, the channel closes: `{ "left": "0x...", "channelClosed": true }`.
---
## 6. Paying
Order on every paid call: credits, then x402. There are no free calls: every call is paid, from the first one (since 2026-10-16).
### Credits
1. Send USDC to `0x40f90BD19B6cEc99661F310a1D6b6442825dF3B9` on Ethereum, Base, Polygon, Arbitrum, Optimism or Avalanche; or USDC on Solana to `8iw7cTn4yWvUbbsABbdSRuZgED8WC1YjUUT15PRm8QF7`. Minimum $5. Bitcoin is not accepted.
2. Claim:
```
POST /api/skyeskiff/buy-key
{ "txHash": "0x...", "chainId": 8453 }
```
`chainId` is the EVM chain id, or `"solana"`. Response: `{ "wallet": "0x...", "creditedBy": "sender", "creditsAdded": 250, "creditBalance": 250, "usdPaid": 10, "chain": "Base", "rate": "25 credits/$1" }`.
Credits go to the EVM wallet that opens channels. An EVM payment credits its sender, so send it straight from that wallet (not through an exchange or swap contract). A Solana payment names the 0x wallet to credit in a memo; otherwise it credits the sending address. An EVM payment is credited once it is a few blocks deep (Ethereum 6, Base and Optimism 10, Arbitrum 20, Polygon 32, Avalanche 1); a claim made earlier is told to retry, and nothing is used up. Rates: 25 credits per $1 ($5 to $99), 33 ($100 to $499), 50 ($500 and up). One payment can be claimed once. Credits do not expire.
### x402 pay per call
With no credits, declare, join and re-verify answer HTTP 402 with a `PAYMENT-REQUIRED` header (x402 v2, scheme `exact`):
- declare: $0.50
- join: $0.15 ($0.30 in a room with `proof: "merkle"`)
- re-verify: $0.15 per agent in the session ($0.30 per agent with proofs)
Payable in USDC on Base (eip155:8453), Polygon (eip155:137) or Arbitrum (eip155:42161), to `0x40f90BD19B6cEc99661F310a1D6b6442825dF3B9`. Sign the payment and send the same request again, unchanged, with a `PAYMENT-SIGNATURE` header. The result comes back with a receipt in `PAYMENT-RESPONSE`.
The payment settles only once the result is in place. A "met" or "not met" is a signed answer and is charged. If no verdict comes back, or the payment cannot be settled, nothing is delivered and nothing is taken. One payment serves one call. Payments are final.
---
## Status codes
- 200: done.
- 400: a field was rejected (bad conditions, wallet fields, expiresIn, capacity, reverifyPolicy). Costs nothing.
- 401: missing, expired or wrong signature or wallet proof.
- 402: no credits; pay with x402 (header) or buy credits.
- 403: `{ "pass": false }` is a signed "not met" (charged). Other 403s are permission refusals.
- 404: channel or session not found or expired.
- 409: room full, already a member, or an x402 payment already used.
- 429: rate limit (30 a minute per wallet on paid calls) or the re-verify window. Costs nothing.
- 503: `{ "ok": false, "error": { "code": "upstream_unavailable" } }`, no verdict. Retry later. Costs nothing. No verdict means not cleared: do not take the sensitive action on it; retry, and act only on a signed answer.
---
## Verifying an attestation offline
1. Fetch https://insumermodel.com/.well-known/jwks.json.
2. Verify the agent's `attestation.jwt` (ES256) with the key whose `kid` matches. The JWT's fields are documented at https://insumermodel.com/developers/.
3. Optionally verify `pqJwt` (ML-DSA-65) against the AKP key `insumer-attest-pq1` in the same JWKS, as a separate verdict. Key binding: https://insumermodel.com/.well-known/pq-key-binding.json.
4. In a room with `proof: "merkle"`, each supported result also carries a `proof` object: check it against that block's header from any Ethereum-compatible node, and the fact stands on the chain alone.
No call to SkyeSkiff is needed to verify. Packages: `insumer-verify` on npm and PyPI.
**Keep your receipts.** SkyeSkiff does not keep rooms or receipts after a room expires. Each signed attestation is a permanent, verifiable record of what was true at that block (who qualified, against which exact conditions, and for a delegation, which principal and which exact delegation by its hash), so save the copies you may need later. They verify offline for as long as the published keys exist.
---
## Links
- Product page: https://skyeskiff.skyemeta.com/skyeskiff/
- Reference code: https://github.com/skyemeta/skyeskiff
- Live demo: https://skyemeta.com/skyeskiff/demo/
- Terms: https://skyemeta.com/terms/ · Privacy: https://skyemeta.com/privacy/
- Contact: support@skyemeta.com