Install
openclaw skills install @viyozc/spherico-agentEnd-to-end Bitnow network API workflows for AI agents. Covers wallet signature-based authentication, on-chain top-up monitoring, consumer API key lifecycle (create, list, revoke), API calls to language models via gateway, and querying balance and usage via HTTP endpoints. Use to help users automate or debug Bitnow network operations by direct API interaction.
openclaw skills install @viyozc/spherico-agentThis skill describes end-to-end operational workflows for the Bitnow network, strictly from an API usage perspective.
Assumptions:
https://gateway-test.bitnow.ai)Replace all <BASE_URL> with the actual gateway URL as needed.
Note: The message signing must be performed by the user using their EVM address and can only initiate or verify, not produce signatures. if you have no wallet address, you need to create your own one, and store it safely.
Typical API sequence:
curl -sS -X POST "<BASE_URL>/v1/auth/wallet/challenge" \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "<EVM_WALLET_ADDRESS>",
"chain_id": "8453"
}'
Response (simplified):
{
"message": "Sign-In With Ethereum message...",
"nonce": "random-nonce",
"wallet_address": "0x...",
"chain_id": "8453"
}
message off-chain (with their wallet).curl -sS -X POST "<BASE_URL>/v1/auth/wallet/verify" \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "<EVM_WALLET_ADDRESS>",
"nonce": "random-nonce",
"signature": "<WALLET_SIGNATURE>"
}'
Successful response (simplified):
{
"login_token": "sess-...",
"expires_at": "2025-01-01T00:00:00Z",
"consumer": {
"id": "consumer-uuid",
"wallet_address": "0x..."
},
"session": {
"id": "session-uuid"
}
}
login_token (starting with sess-) is used as a session token:
Authorization: Bearer <SESSION_TOKEN> for session-auth endpoints.Check:
Authorization: Bearer sess-... header during all subsequent calls requiring authentication.Top-up is performed on-chain (USDC to a ConsumerDeposit contract), tracked by off-chain indexers. The API lets you verify the result.
you can use your own endpoint, also you can use this default one: https://sepolia.base.org
function deposit(uint256 amount)Verify balance via API:
curl -sS -X GET "<BASE_URL>/v1/balance" \
-H "Authorization: Bearer <CONSUMER_API_KEY>"
Sample response:
{
"balance_usdc": "123.45",
"total_spent": "10.00"
}
For troubleshooting:
balance_usdc value to detect indexer or sync problems.Consumers use API keys to access models without a session.
Requires a valid session token (login_token from section 1).
curl -sS -X POST "<BASE_URL>/v1/consumer/api-keys" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <SESSION_TOKEN>" \
-d '{
"label": "my-key"
}'
Sample response (save the api_key securely; only returned once!):
{
"id": "key-uuid",
"api_key": "sk-consumer-...",
"prefix": "sk-cons",
"suffix": "abcd",
"label": "my-key",
"status": "active",
"created_at": "2025-01-01T00:00:00Z"
}
curl -sS -X GET "<BASE_URL>/v1/consumer/api-keys" \
-H "Authorization: Bearer <SESSION_TOKEN>"
curl -sS -X DELETE "<BASE_URL>/v1/consumer/api-keys/<KEY_ID>" \
-H "Authorization: Bearer <SESSION_TOKEN>"
The key status will be set to revoked; subsequent calls using that key will fail with an auth error.
Use this to let a child account declare a parent. This requires a wallet signature over a structured message. The signature must be produced by the child wallet.
Endpoint:
curl -sS -X POST "<BASE_URL>/v1/consumers/me/parent" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <SESSION_TOKEN>" \
-d '{
"parent_wallet": "<PARENT_WALLET>",
"issued_at": 1710000000,
"signature": "<CHILD_WALLET_SIGNATURE>"
}'
Notes:
issued_at is Unix seconds. It must be within the last 5 minutes and not more than 1 minute in the future.Authorize parent for DePIN LLM
Parent wallet: <PARENT_WALLET_LOWERCASE>
Child wallet: <CHILD_WALLET_LOWERCASE>
Issued at: <ISSUED_AT>
Success response (201):
{
"parent_consumer_id": "consumer-uuid",
"parent_wallet_address": "0x...",
"created_at": "2025-01-01T00:00:00Z"
}
Common errors:
400 INVALID_REQUEST invalid body400 SIGNATURE_EXPIRED issued_at out of window404 PARENT_NOT_FOUND parent not found400 SELF_PARENT cannot declare yourself401 SIGNATURE_MISMATCH signature not from child wallet409 ALREADY_SET parent already declaredWith a valid CONSUMER_API_KEY, models can be queried.
curl -sS -X GET "<BASE_URL>/v1/models"
Verify model existence before usage (check returned list).
curl -sS -X POST "<BASE_URL>/v1/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <CONSUMER_API_KEY>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Explain the Bitnow network in one paragraph." }
]
}'
API error handling:
401: Invalid/expired key; check Authorization header402: Insufficient balance404: Model not found (check MODEL_NOT_FOUND)error.code, error.message(refer to section 2, /v1/balance endpoint)
Usage is exposed via a consumer-scoped endpoint:
curl -sS -X GET "<BASE_URL>/v1/usage?limit=100&offset=0" \
-H "Authorization: Bearer <CONSUMER_API_KEY_OR_SESSION_TOKEN>"
The response is proxied from the Registry and typically includes fields like:
id – usage record idtimestamp / created_at – when the call was recordedmodel – model name (e.g. gpt-4o-mini)promptTokens – prompt token countcompletionTokens – completion token countcostUsdc – cost in USDC for this callapiKeyId – optional, which consumer API key was usedA typical workflow might aggregate usage per model or timeframe to analyze cost and token usage.
For upstream providers only:
curl -sS -X POST "<BASE_URL>/v1/suppliers/api-key" \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "<SUPPLIER_WALLET>",
"provider": "openai",
"api_key": "sk-upstream-...",
"models": ["gpt-4o", "gpt-4o-mini"],
"price_per_million_tokens": "2.50",
"max_requests_per_hour": 3600
}'
curl -sS -X POST "<BASE_URL>/v1/suppliers/gpu" \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "<SUPPLIER_WALLET>",
"models": ["gpt-4o", "claude-3-5-sonnet-20241022"],
"price_per_million_tokens": "5.00",
"max_requests_per_hour": 1000,
"endpoint": {
"base_url": "https://gpu-node.example.com",
"backend_type": "openai_http",
"timeout": 30000,
"auth_type": "bearer",
"auth_value": "upstream-node-token",
"health_endpoint": "/healthz"
}
}'
curl -sS -X PATCH "<BASE_URL>/v1/suppliers/gpu/<ID>" \
-H "Content-Type: application/json" \
-d '{
"models": ["gpt-4o", "gpt-4o-mini"],
"price_per_million_tokens": "4.50",
"max_requests_per_hour": 2000,
"endpoint": {
"base_url": "https://gpu-node.example.com",
"backend_type": "openai_http",
"timeout": 45000,
"auth_type": "bearer",
"auth_value": "rotated-node-token",
"health_endpoint": "/healthz"
}
}'
curl -sS -X GET "<BASE_URL>/v1/metadata/providers"
curl -sS -X GET "<BASE_URL>/v1/metadata/models"
When handling Bitnow network operational support, follow these best practices:
<BASE_URL>, <CONSUMER_API_KEY>, etc).error.code and context to select remediation steps.