Skill: obcraft/apiosk (version 1.1.0)

# Apiosk - Keyless API Access with USDC Micropayments **Pay-per-request API access for agents. No API keys. No accounts. Just pay and call.** Apiosk enables agents to access production APIs using x402 protocol - USDC micropayments on Base blockchain. Stop managing API keys, start paying per request. --- ## 🎯 What This Skill Does - **Discover APIs** - Browse 9+ production APIs (weather, prices, news, geocoding, etc.) - **Pay per request** - Automatic USDC micropayments ($0.001-0.10 per call) - **No setup** - No API keys, no accounts, no subscriptions - **Instant access** - Call APIs immediately with x402 payment --- ## 📦 Installation ```bash # Via ClawHub clawhub install apiosk # Or clone manually git clone https://github.com/apiosk/apiosk-skill ``` --- ## ⚙️ Configuration ### 1. Set Up Wallet (One-time) ```bash # Generate new wallet (or import existing) ./setup-wallet.sh # This creates ~/.apiosk/wallet.json with: # - Private key (stored locally, chmod 600 for security) # - Public address # - Base mainnet RPC **IMPORTANT:** The private key is stored in plaintext in `~/.apiosk/wallet.json` (with restrictive file permissions). Only fund this wallet with small amounts for testing. For production, use a hardware wallet or external key management. ``` **Important:** Fund your wallet with USDC on Base mainnet (minimum $1-10 recommended). **How to fund:** 1. Bridge USDC to Base via https://bridge.base.org 2. Or buy USDC on Coinbase → withdraw to Base 3. Send to your Apiosk wallet address ### 2. Discover Available APIs ```bash # List all APIs ./list-apis.sh # Output: # weather $0.001/req Get current weather and forecasts # prices $0.002/req Crypto/stock/forex prices # news $0.005/req Global news by topic/country # company $0.01/req Company info, financials, news # geocode $0.001/req Address → Coordinates # ... ``` --- ## 🚀 Usage ### Basic API Call ```bash # Call weather API ./call-api.sh weather --params '{"city": "Amsterdam"}' # Output: # { # "temperature": 12, # "condition": "Cloudy", # "forecast": [...] # } # # ✅ Paid: $0.001 USDC ``` ### From Agent Code (Node.js) ```javascript const { callApiosk } = require('./apiosk-client'); // Call weather API const weather = await callApiosk('weather', { city: 'Amsterdam' }); console.log(`Temperature: ${weather.temperature}°C`); // ✅ Automatically paid $0.001 USDC ``` ### From Agent Code (Python) ```python from apiosk_client import call_apiosk # Call prices API prices = call_apiosk('prices', { 'symbols': ['BTC', 'ETH'] }) print(f"BTC: ${prices['BTC']}") # ✅ Automatically paid $0.002 USDC ``` --- ## 📚 Available APIs | API | Cost/req | Description | Example | |-----|----------|-------------|---------| | **weather** | $0.001 | Weather forecasts | `{"city": "NYC"}` | | **prices** | $0.002 | Crypto/stock prices | `{"symbols": ["BTC"]}` | | **news** | $0.005 | Global news articles | `{"topic": "AI"}` | | **company** | $0.01 | Company data | `{"domain": "apple.com"}` | | **geocode** | $0.001 | Address → Coordinates | `{"address": "Amsterdam"}` | | **code-runner** | $0.05 | Execute code sandbox | `{"lang": "python", "code": "..."}` | | **pdf-generator** | $0.02 | HTML → PDF | `{"html": "<h1>Hi</h1>"}` | | **web-screenshot** | $0.03 | URL → Screenshot | `{"url": "example.com"}` | | **file-converter** | $0.01 | Convert file formats | `{"from": "docx", "to": "pdf"}` | **Full docs:** https://apiosk.com/#docs --- ## 🔧 Helper Scripts ### `list-apis.sh` ```bash #!/bin/bash # List all available APIs with pricing curl -s https://gateway.apiosk.com/v1/apis | jq -r '.apis[] | "\(.id)\t$\(.price_usd)/req\t\(.description)"' ``` ### `call-api.sh` ```bash #!/bin/bash # Call any Apiosk API with automatic payment # Usage: ./call-api.sh <api-id> --params '{"key":"value"}' API_ID=$1 PARAMS=$3 # Load wallet WALLET_ADDRESS=$(jq -r '.address' ~/.apiosk/wallet.json) # Make request (x402 payment happens via on-chain verification) # The gateway validates payment on-chain, no client-side signature needed curl -X POST "https://gateway.apiosk.com/$API_ID" \ -H "Content-Type: application/json" \ -H "X-Wallet-Address: $WALLET_ADDRESS" \ -d "$PARAMS" ``` ### `check-balance.sh` ```bash #!/bin/bash # Check USDC balance in your Apiosk wallet WALLET_ADDRESS=$(jq -r '.address' ~/.apiosk/wallet.json) curl -s "https://gateway.apiosk.com/v1/balance?address=$WALLET_ADDRESS" | jq # Output: {"balance_usdc": 9.87, "spent_today": 0.13} ``` ### `usage-stats.sh` ```bash #!/bin/bash # View your API usage stats WALLET_ADDRESS=$(jq -r '.address' ~/.apiosk/wallet.json) curl -s "https://gateway.apiosk.com/v1/usage?address=$WALLET_ADDRESS" | jq # Output: # { # "total_requests": 142, # "total_spent_usdc": 1.89, # "by_api": { # "weather": {"requests": 87, "spent": 0.087}, # "prices": {"requests": 55, "spent": 0.11} # } # } ``` --- ## 🎓 Examples ### Example 1: Weather Bot ```javascript const { callApiosk } = require('./apiosk-client'); async function getWeatherReport(city) { const weather = await callApiosk('weather', { city }); return `🌤️ Weather in ${city}: Temperature: ${weather.temperature}°C Condition: ${weather.condition} Forecast: ${weather.forecast.map(f => f.summary).join(', ')} 💰 Cost: $0.001 USDC`; } // Usage console.log(await getWeatherReport('Amsterdam')); ``` ### Example 2: Crypto Price Tracker ```python from apiosk_client import call_apiosk import time def track_prices(symbols, interval=60): """Track crypto prices with Apiosk""" while True: prices = call_apiosk('prices', {'symbols': symbols}) for symbol, price in prices.items(): print(f"{symbol}: ${price:,.2f}") print(f"✅ Paid: $0.002 USDC\n") time.sleep(interval) # Track BTC and ETH every minute track_prices(['BTC', 'ETH']) ``` ### Example 3: News Digest Agent ```javascript const { callApiosk } = require('./apiosk-client'); async function getDailyDigest(topics) { const articles = []; for (const topic of topics) { const news = await callApiosk('news', { topic, limit: 3 }); articles.push(...news.articles); } return `📰 Daily Digest (${articles.length} articles) ${articles.map(a => `- ${a.title} (${a.source})`).join('\n')} 💰 Total cost: $${(topics.length * 0.005).toFixed(3)} USDC`; } // Get tech + business news console.log(await getDailyDigest(['technology', 'business'])); ``` --- ## 🔐 How x402 Works **Traditional API:** ``` 1. Sign up for account 2. Get API key 3. Store securely 4. Include in requests 5. Monitor rate limits 6. Pay monthly subscription ``` **Apiosk (x402):** ``` 1. Make request 2. Gateway returns 402 Payment Required 3. Your wallet signs payment proof 4. Gateway verifies on-chain 5. Gateway forwards to API 6. You get response ``` **Time:** Milliseconds. **Cost:** Exact usage. **Setup:** Zero. --- ## 🛠️ Advanced Configuration ### Custom RPC Endpoint ```bash # Edit ~/.apiosk/config.json { "rpc_url": "https://mainnet.base.org", "chain_id": 8453, "usdc_contract": [REDACTED_SECRET] } ``` ### Set Spending Limits ```bash # Set daily spending limit ./set-limit.sh --daily 10.00 # Set per-request max ./set-limit.sh --per-request 0.10 ``` ### Enable Notifications ```bash # Get notified when balance is low ./configure.sh --alert-balance 1.00 --alert-webhook "https://hooks.slack.com/..." ``` --- ## 📊 Monitoring & Analytics ### Check Spending ```bash # Today's spending ./usage-stats.sh --today # This month ./usage-stats.sh --month # Per API breakdown ./usage-stats.sh --by-api ``` ### Export Usage Data ```bash # Export to CSV for accounting ./export-usage.sh --start 2026-01-01 --end 2026-01-31 --format csv > january_usage.csv ``` --- ## 🆘 Troubleshooting ### "Insufficient USDC balance" ```bash # Check balance ./check-balance.sh # If low, fund your wallet: # 1. Bridge USDC to Base: https://bridge.base.org # 2. Send to: [your wallet address] ``` ### "Payment verification failed" ```bash # Verify wallet signature is working ./test-signature.sh # If fails, regenerate wallet: ./setup-wallet.sh --regenerate ``` ### "API not found" ```bash # Refresh API list ./list-apis.sh --refresh # Check if API is available curl https://gateway.apiosk.com/v1/apis | jq '.apis[] | select(.id=="weather")' ``` --- ## 🌐 For Developers: Add Your Own API Want to monetize your API via Apiosk? ```bash # 1. Sign up curl -X POST https://dashboard.apiosk.com/api/register \ -d '{"email":"[REDACTED_SECRET]","api_name":"My API"}' # 2. Add your API endpoint curl -X POST https://dashboard.apiosk.com/api/add \ -H "Authorization: Bearer $TOKEN" \ -d '{ "name": "my-api", "endpoint": "https://my-api.com", "price_usd": 0.01, "description": "My awesome API" }' # 3. Start earning! # Agents call your API via Apiosk gateway # You get 90-95% of revenue, automatically ``` **More:** https://docs.apiosk.com/developers --- ## 📖 Resources - **Website:** https://apiosk.com - **Dashboard:** https://dashboard.apiosk.com - **Docs:** https://docs.apiosk.com - **GitHub:** https://github.com/apiosk - **Support:** [REDACTED_SECRET] - **Moltbook:** @ApioskAgent --- ## 💡 Why Apiosk? **For Agents:** - ✅ No API key management - ✅ Pay only what you use - ✅ Access 9+ APIs instantly - ✅ Transparent pricing - ✅ On-chain payment proofs **For Developers:** - ✅ Monetize any API - ✅ No payment processing - ✅ 90-95% revenue share - ✅ Instant settlement - ✅ Global reach **Network effect:** More APIs → More agents → More revenue → More APIs --- ## 🦞 About Built by the Apiosk team for the agent economy. **x402 protocol:** Keyless API access with crypto micropayments. **Mission:** Make every API instantly accessible to every agent. **"Stop managing API keys. Start paying per request."** --- ## 📝 License MIT - Use freely in your agents! --- ## 🔗 Quick Links ```bash # Install clawhub install apiosk # Setup cd ~/.openclaw/skills/apiosk && ./setup-wallet.sh # Use ./call-api.sh weather --params '{"city": "Amsterdam"}' # Monitor ./usage-stats.sh ``` **Happy building! 🚀**

path: README.md
content: # Apiosk AgentSkill

**Keyless API access with USDC micropayments for OpenClaw agents.**

Pay-per-request for production APIs. No API keys. No accounts. Just pay and call.

---

## 🚀 Quick Start

```bash
# Install via ClawHub
clawhub install apiosk

# Or clone manually
git clone https://github.com/apiosk/apiosk-skill ~/.openclaw/skills/apiosk
cd ~/.openclaw/skills/apiosk

# Setup wallet (one-time)
./setup-wallet.sh

# Fund your wallet with USDC on Base mainnet
# https://bridge.base.org

# List available APIs
./list-apis.sh

# Call an API
./call-api.sh weather --params '{"city": "Amsterdam"}'
```

---

## 📚 Documentation

See [SKILL.md](./SKILL.md) for complete documentation:
- Configuration
- Available APIs
- Usage examples (Node.js, Python, bash)
- Helper scripts
- Troubleshooting

---

## 🔐 Security Notice

**Before using this skill:**

1. **Private key storage:** The wallet's private key is stored in plaintext in `~/.apiosk/wallet.json` (with chmod 600 permissions). This is suitable for testing but NOT for production with large amounts.

2. **Recommended for production:**
   - Use a hardware wallet (Ledger, Trezor)
   - Or use an external key management service
   - Only fund test wallet with small amounts ($1-10)

3. **Foundry installation:** This skill requires Foundry (cast command). Install it manually:
   ```bash
   curl -L https://foundry.paradigm.xyz | bash
   foundryup
   ```

4. **Gateway verification:** All payments are verified on-chain by the gateway. Your private key is NEVER sent to the gateway.

5. **Test first:** Try with a small API call before funding with larger amounts.

---

## 🔧 Gateway Changes Needed

See [GATEWAY_CHANGES_NEEDED.md](./GATEWAY_CHANGES_NEEDED.md) for:
- Required API endpoints
- Database migrations
- Implementation guide

**TL;DR:** Gateway needs 3 new endpoints:
1. `GET /v1/apis` - List available APIs
2. `GET /v1/balance` - Check wallet balance
3. `GET /v1/usage` - Usage statistics

---

## 📦 Files

```
apiosk-skill/
├── SKILL.md                    # Main documentation
├── README.md                   # This file
├── GATEWAY_CHANGES_NEEDED.md   # Implementation guide
├── package.json                # NPM metadata
├── setup-wallet.sh             # Wallet setup (one-time)
├── list-apis.sh                # List available APIs
├── call-api.sh                 # Call any API
├── check-balance.sh            # Check USDC balance
├── usage-stats.sh              # View usage stats
├── apiosk-client.js            # Node.js wrapper
└── apiosk_client.py            # Python wrapper
```

---

## 🎯 What This Enables

**For Agents:**
- Access 9+ production APIs instantly
- Pay per request ($0.001-0.10)
- No API key management
- Automatic USDC micropayments

**For Developers:**
- Monetize any API via Apiosk
- 90-95% revenue share
- No payment processing
- Instant settlement

**Network effect:** More APIs → More agents → More revenue → More APIs

---

## 🌐 Links

- **Website:** https://apiosk.com
- **Dashboard:** https://dashboard.apiosk.com
- **Docs:** https://docs.apiosk.com
- **ClawHub:** https://clawhub.com/apiosk
- **Moltbook:** @ApioskAgent

---

## 🦞 About

Built by Apiosk for the agent economy.

**Mission:** Make every API instantly accessible to every agent.

---

## 📝 License

MIT


path: SECURITY.md
content: # Security Policy

## Wallet Security

### Private Key Storage

The Apiosk skill stores wallet private keys in `~/.apiosk/wallet.json` with restrictive file permissions (chmod 600). **The private key is stored in plaintext.**

**This is suitable for:**
- Testing and development
- Small amounts ($1-10 USDC)
- Proof-of-concept usage

**This is NOT suitable for:**
- Production use with large amounts
- Shared/multi-user systems
- Long-term key storage

### Recommended Production Setup

For production usage, use one of these alternatives:

1. **Hardware Wallet**
   - Ledger or Trezor
   - Requires modification of skill scripts
   - Contact support for integration guide

2. **External Key Management**
   - AWS KMS, Google Cloud KMS, HashiCorp Vault
   - Requires custom integration
   - Recommended for enterprise deployments

3. **Hot Wallet with Monitoring**
   - Generate wallet with `./setup-wallet.sh`
   - Fund with ONLY the amount you need for immediate use
   - Monitor balance: `./check-balance.sh`
   - Set up alerts for unusual activity

### Payment Verification

- All payments are verified on-chain by the gateway
- Your private key is **NEVER** transmitted to the gateway
- The gateway only receives your wallet address
- Payment proofs are verified against the blockchain

### Dependencies

The skill requires Foundry (cast command) for wallet generation. Install manually:

```bash
curl -L https://foundry.paradigm.xyz | bash
foundryup
```

**Why manual installation is recommended:**
- Allows you to review the installer script before running
- Gives you control over when/how dependencies are installed
- Reduces risk of supply chain attacks

### Network Security

The skill communicates with:
- `https://gateway.apiosk.com` - Apiosk API gateway (HTTPS only)
- Base mainnet RPC - On-chain verification
- No other external services

### Best Practices

1. **Start small:** Test with $1-5 USDC first
2. **Monitor usage:** Run `./usage-stats.sh` regularly
3. **Check balance:** Run `./check-balance.sh` before large operations
4. **Backup wallet:** Keep a secure backup of `~/.apiosk/wallet.json`
5. **Never share:** Don't share your private key with anyone
6. **Use dedicated wallet:** Don't reuse wallets from other services

### Reporting Security Issues

If you discover a security vulnerability, please email:
- **Security contact:** [REDACTED_SECRET]
- **Subject:** [SECURITY] Apiosk Skill Vulnerability

**Please do NOT open public GitHub issues for security vulnerabilities.**

We will respond within 48 hours and work with you to address the issue.

### Security Audit Status

**Current status:** Not audited

This skill has not undergone a professional security audit. Use at your own risk.

If you would like to sponsor a security audit, please contact us.

### License

MIT License - See LICENSE file for details.

**Disclaimer:** This software is provided "as is" without warranty of any kind. Use at your own risk.


path: apiosk-client.js
content: /**
 * Apiosk Node.js Client
 * Easy API calls with automatic x402 payment
 */

const fs = require('fs');
const path = require('path');
const https = require('https');

const WALLET_FILE = path.join(process.env.HOME, '.apiosk', 'wallet.json');
const CONFIG_FILE = path.join(process.env.HOME, '.apiosk', 'config.json');

/**
 * Load wallet configuration
 */
function loadWallet() {
  if (!fs.existsSync(WALLET_FILE)) {
    throw new Error('Wallet not found. Run ./setup-wallet.sh first');
  }
  
  const wallet = JSON.parse(fs.readFileSync(WALLET_FILE, 'utf8'));
  const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
  
  return { wallet, config };
}

/**
 * Call an Apiosk API
 * @param {string} apiId - API identifier (e.g., 'weather', 'prices')
 * @param {object} params - API parameters
 * @returns {Promise<object>} API response
 */
async function callApiosk(apiId, params = {}) {
  const { wallet, config } = loadWallet();
  
  const url = new URL(`/${apiId}`, config.gateway_url);
  
  return new Promise((resolve, reject) => {
    const data = JSON.stringify(params);
    
    const options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': data.length,
        'X-Wallet-Address': wallet.address,
      }
    };
    
    const req = https.request(url, options, (res) => {
      let body = '';
      
      res.on('data', (chunk) => {
        body += chunk;
      });
      
      res.on('end', () => {
        try {
          const response = JSON.parse(body);
          
          if (res.statusCode === 200) {
            resolve(response);
          } else if (res.statusCode === 402) {
            reject(new Error(`Payment required: ${response.error || 'Insufficient balance'}`));
          } else {
            reject(new Error(`API error (${res.statusCode}): ${response.error || body}`));
          }
        } catch (e) {
          reject(new Error(`Failed to parse response: ${e.message}`));
        }
      });
    });
    
    req.on('error', (e) => {
      reject(new Error(`Request failed: ${e.message}`));
    });
    
    req.write(data);
    req.end();
  });
}

/**
 * List available APIs
 * @returns {Promise<Array>} List of APIs
 */
async function listAPIs() {
  const { config } = loadWallet();
  const url = new URL('/v1/apis', config.gateway_url);
  
  return new Promise((resolve, reject) => {
    https.get(url, (res) => {
      let body = '';
      
      res.on('data', (chunk) => {
        body += chunk;
      });
      
      res.on('end', () => {
        try {
          const data = JSON.parse(body);
          resolve(data.apis);
        } catch (e) {
          reject(new Error(`Failed to parse response: ${e.message}`));
        }
      });
    }).on('error', (e) => {
      reject(new Error(`Request failed: ${e.message}`));
    });
  });
}

/**
 * Check wallet balance
 * @returns {Promise<object>} Balance info
 */
async function checkBalance() {
  const { wallet, config } = loadWallet();
  const url = new URL(`/v1/balance?address=${wallet.address}`, config.gateway_url);
  
  return new Promise((resolve, reject) => {
    https.get(url, (res) => {
      let body = '';
      
      res.on('data', (chunk) => {
        body += chunk;
      });
      
      res.on('end', () => {
        try {
          const data = JSON.parse(body);
          resolve(data);
        } catch (e) {
          reject(new Error(`Failed to parse response: ${e.message}`));
        }
      });
    }).on('error', (e) => {
      reject(new Error(`Request failed: ${e.message}`));
    });
  });
}

module.exports = {
  callApiosk,
  listAPIs,
  checkBalance,
};

// Example usage
if (require.main === module) {
  (async () => {
    try {
      console.log('🦞 Apiosk Client Example\n');
      
      // List APIs
      console.log('Available APIs:');
      const apis = await listAPIs();
      apis.forEach(api => {
        console.log(`- ${api.id}: $${api.price_usd}/req - ${api.description}`);
      });
      
      console.log('\n');
      
      // Call weather API
      console.log('Calling weather API for Amsterdam...');
      const weather = await callApiosk('weather', { city: 'Amsterdam' });
      console.log(`Temperature: ${weather.temperature}°C`);
      console.log(`Condition: ${weather.condition}`);
      console.log('✅ Paid: $0.001 USDC\n');
      
      // Check balance
      const balance = await checkBalance();
      console.log(`Remaining balance: $${balance.balance_usdc} USDC`);
      
    } catch (error) {
      console.error('❌ Error:', error.message);
      process.exit(1);
    }
  })();
}


path: apiosk_client.py
content: """
Apiosk Python Client
Easy API calls with automatic x402 payment
"""

import os
import json
import requests
from pathlib import Path

WALLET_FILE = Path.home() / '.apiosk' / 'wallet.json'
CONFIG_FILE = Path.home() / '.apiosk' / 'config.json'


def load_wallet():
    """Load wallet configuration"""
    if not WALLET_FILE.exists():
        raise FileNotFoundError('Wallet not found. Run ./setup-wallet.sh first')
    
    with open(WALLET_FILE) as f:
        wallet = json.load(f)
    
    with open(CONFIG_FILE) as f:
        config = json.load(f)
    
    return wallet, config


def call_apiosk(api_id: str, params: dict = None) -> dict:
    """
    Call an Apiosk API
    
    Args:
        api_id: API identifier (e.g., 'weather', 'prices')
        params: API parameters
    
    Returns:
        API response as dictionary
    
    Raises:
        requests.HTTPError: If API call fails
        ValueError: If payment fails
    """
    wallet, config = load_wallet()
    params = params or {}
    
    url = f"{config['gateway_url']}/{api_id}"
    headers = {
        'Content-Type': 'application/json',
        'X-Wallet-Address': wallet['address'],
    }
    
    response = requests.post(url, json=params, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    elif response.status_code == 402:
        error = response.json().get('error', 'Insufficient balance')
        raise ValueError(f'Payment required: {error}')
    else:
        response.raise_for_status()


def list_apis() -> list:
    """
    List available APIs
    
    Returns:
        List of API dictionaries
    """
    _, config = load_wallet()
    
    url = f"{config['gateway_url']}/v1/apis"
    response = requests.get(url)
    response.raise_for_status()
    
    return response.json()['apis']


def check_balance() -> dict:
    """
    Check wallet balance
    
    Returns:
        Balance information dictionary
    """
    wallet, config = load_wallet()
    
    url = f"{config['gateway_url']}/v1/balance"
    params = {'address': wallet['address']}
    
    response = requests.get(url, params=params)
    response.raise_for_status()
    
    return response.json()


def usage_stats(period: str = 'all') -> dict:
    """
    Get usage statistics
    
    Args:
        period: 'all', 'today', 'week', or 'month'
    
    Returns:
        Usage statistics dictionary
    """
    wallet, config = load_wallet()
    
    url = f"{config['gateway_url']}/v1/usage"
    params = {
        'address': wallet['address'],
        'period': period,
    }
    
    response = requests.get(url, params=params)
    response.raise_for_status()
    
    return response.json()


# Example usage
if __name__ == '__main__':
    print('🦞 Apiosk Client Example\n')
    
    try:
        # List APIs
        print('Available APIs:')
        apis = list_apis()
        for api in apis:
            print(f"- {api['id']}: ${api['price_usd']}/req - {api['description']}")
        
        print('\n')
        
        # Call weather API
        print('Calling weather API for Amsterdam...')
        weather = call_apiosk('weather', {'city': 'Amsterdam'})
        print(f"Temperature: {weather['temperature']}°C")
        print(f"Condition: {weather['condition']}")
        print('✅ Paid: $0.001 USDC\n')
        
        # Check balance
        balance = check_balance()
        print(f"Remaining balance: ${balance['balance_usdc']} USDC")
        
    except Exception as e:
        print(f'❌ Error: {e}')
        exit(1)


path: call-api.sh
content: #!/bin/bash
# Call any Apiosk API with automatic x402 payment
# Usage: ./call-api.sh <api-id> --params '{"key":"value"}'

set -e

WALLET_FILE="$HOME/.apiosk/wallet.json"
CONFIG_FILE="$HOME/.apiosk/config.json"

# Check arguments
if [ $# -lt 3 ]; then
  echo "Usage: ./call-api.sh <api-id> --params '{\"key\":\"value\"}'"
  echo ""
  echo "Example: ./call-api.sh weather --params '{\"city\":\"Amsterdam\"}'"
  exit 1
fi

API_ID=$1
shift
if [ "$1" != "--params" ]; then
  echo "❌ Expected --params flag"
  exit 1
fi
shift
PARAMS=$1

# Load wallet
if [ ! -f "$WALLET_FILE" ]; then
  echo "❌ Wallet not found. Run ./setup-wallet.sh first"
  exit 1
fi

WALLET_ADDRESS=$(jq -r '.address' "$WALLET_FILE")
WALLET_KEY=$(jq -r '.private_key' "$WALLET_FILE")
GATEWAY_URL=$(jq -r '.gateway_url' "$CONFIG_FILE")

# Make request
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$GATEWAY_URL/$API_ID" \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: $WALLET_ADDRESS" \
  -d "$PARAMS")

HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')

if [ "$HTTP_CODE" == "200" ]; then
  echo "$BODY" | jq
  
  # Extract price from response header (if available)
  PRICE=$(echo "$BODY" | jq -r '.meta.price_paid_usdc // 0.001')
  echo ""
  echo "✅ Paid: \$$PRICE USDC"
elif [ "$HTTP_CODE" == "402" ]; then
  echo "❌ Payment required but failed"
  echo "$BODY" | jq
  echo ""
  echo "Check your USDC balance: ./check-balance.sh"
elif [ "$HTTP_CODE" == "404" ]; then
  echo "❌ API not found: $API_ID"
  echo ""
  echo "Available APIs:"
  ./list-apis.sh
else
  echo "❌ Request failed (HTTP $HTTP_CODE)"
  echo "$BODY" | jq
fi


path: check-balance.sh
content: #!/bin/bash
# Check USDC balance in your Apiosk wallet

WALLET_FILE="$HOME/.apiosk/wallet.json"
CONFIG_FILE="$HOME/.apiosk/config.json"

if [ ! -f "$WALLET_FILE" ]; then
  echo "❌ Wallet not found. Run ./setup-wallet.sh first"
  exit 1
fi

WALLET_ADDRESS=$(jq -r '.address' "$WALLET_FILE")
RPC_URL=$(jq -r '.rpc_url' "$CONFIG_FILE")
USDC_CONTRACT=$(jq -r '.usdc_contract' "$CONFIG_FILE")
GATEWAY_URL=$(jq -r '.gateway_url' "$CONFIG_FILE")

echo "🦞 Apiosk Wallet Balance"
echo ""
echo "Address: $WALLET_ADDRESS"
echo ""

# Check USDC balance on-chain
if command -v cast &> /dev/null; then
  BALANCE_WEI=$(cast call "$USDC_CONTRACT" "balanceOf(address)(uint256)" "$WALLET_ADDRESS" --rpc-url "$RPC_URL")
  BALANCE_USDC=$(echo "scale=2; $BALANCE_WEI / 1000000" | bc)
  echo "💰 USDC Balance: $BALANCE_USDC USDC"
else
  echo "⚠️  Install Foundry to check on-chain balance: curl -L https://foundry.paradigm.xyz | bash"
fi

# Check usage via Apiosk gateway
USAGE=$(curl -s "$GATEWAY_URL/v1/balance?address=$WALLET_ADDRESS")

if [ $? -eq 0 ]; then
  echo ""
  echo "📊 Apiosk Usage:"
  echo "$USAGE" | jq
else
  echo ""
  echo "⚠️  Could not fetch usage stats from gateway"
fi

echo ""
echo "Top up at: https://bridge.base.org"
echo ""


path: list-apis.sh
content: #!/bin/bash
# List all available Apiosk APIs with pricing

GATEWAY_URL="https://gateway.apiosk.com"

echo "🦞 Available Apiosk APIs"
echo ""

# Fetch API list
APIS=$(curl -s "$GATEWAY_URL/v1/apis")

if [ $? -ne 0 ]; then
  echo "❌ Failed to fetch APIs from $GATEWAY_URL"
  exit 1
fi

# Parse and display
echo "$APIS" | jq -r '.apis[] | "\(.id)\t$\(.price_usd)/req\t\(.description)"' | column -t -s $'\t'

echo ""
echo "Total APIs: $(echo "$APIS" | jq '.apis | length')"
echo ""
echo "Usage: ./call-api.sh <api-id> --params '{\"key\":\"value\"}'"
echo "Docs: https://apiosk.com/#docs"
echo ""


path: package.json
content: {
  "name": "apiosk-skill",
  "version": "1.0.1",
  "description": "Keyless API access with USDC micropayments for OpenClaw agents",
  "main": "apiosk-client.js",
  "scripts": {
    "setup": "./setup-wallet.sh",
    "list": "./list-apis.sh",
    "balance": "./check-balance.sh",
    "stats": "./usage-stats.sh"
  },
  "keywords": [
    "apiosk",
    "x402",
    "api",
    "payment",
    "usdc",
    "agent",
    "openclaw"
  ],
  "author": "Apiosk Team",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/olivierbrinkman/apiosk-skill"
  },
  "homepage": "https://apiosk.com",
  "bugs": {
    "url": "https://github.com/olivierbrinkman/apiosk-skill/issues"
  },
  "dependencies": {}
}


path: setup-wallet.sh
content: #!/bin/bash
# Apiosk Wallet Setup - One-time configuration

set -e

WALLET_DIR="$HOME/.apiosk"
WALLET_FILE="$WALLET_DIR/wallet.json"
CONFIG_FILE="$WALLET_DIR/config.json"

echo "🦞 Apiosk Wallet Setup"
echo ""

# Create directory
mkdir -p "$WALLET_DIR"

# Check if wallet exists
if [ -f "$WALLET_FILE" ] && [ "$1" != "--regenerate" ]; then
  echo "❌ Wallet already exists at $WALLET_FILE"
  echo "Use --regenerate to create a new wallet (WARNING: old wallet will be lost!)"
  exit 1
fi

# Generate wallet using cast (Foundry)
if ! command -v cast &> /dev/null; then
  echo ""
  echo "❌ 'cast' not found. Foundry is required to generate wallets."
  echo ""
  echo "To install Foundry, run:"
  echo "  curl -L https://foundry.paradigm.xyz | bash"
  echo "  foundryup"
  echo ""
  echo "Or visit: https://book.getfoundry.sh/getting-started/installation"
  echo ""
  exit 1
fi

echo "Generating new wallet..."
WALLET_OUTPUT=$(cast wallet new)
ADDRESS=$(echo "$WALLET_OUTPUT" | grep "Address:" | awk '{print $2}')
PRIVATE_KEY=$(echo "$WALLET_OUTPUT" | grep "Private key:" | awk '{print $3}')

# Save wallet
cat > "$WALLET_FILE" << EOF
{
  "address": "$ADDRESS",
  "private_key": "$PRIVATE_KEY",
  "created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
EOF

chmod 600 "$WALLET_FILE"

# Create config
cat > "$CONFIG_FILE" << EOF
{
  "rpc_url": "https://mainnet.base.org",
  "chain_id": 8453,
  "usdc_contract": [REDACTED_SECRET],
  "gateway_url": "https://gateway.apiosk.com",
  "daily_limit_usdc": 100.0,
  "per_request_limit_usdc": 1.0
}
EOF

echo ""
echo "✅ Wallet created successfully!"
echo ""
echo "📍 Address: $ADDRESS"
echo "📂 Saved to: $WALLET_FILE"
echo ""
echo "⚠️  IMPORTANT: Fund your wallet with USDC on Base mainnet"
echo ""
echo "How to fund:"
echo "  1. Bridge USDC to Base: https://bridge.base.org"
echo "  2. Or buy on Coinbase → Withdraw to Base"
echo "  3. Send to: $ADDRESS"
echo ""
echo "Minimum recommended: $1-10 USDC"
echo ""
echo "Check balance: ./check-balance.sh"
echo ""


path: usage-stats.sh
content: #!/bin/bash
# View your API usage statistics

WALLET_FILE="$HOME/.apiosk/wallet.json"
CONFIG_FILE="$HOME/.apiosk/config.json"

if [ ! -f "$WALLET_FILE" ]; then
  echo "❌ Wallet not found. Run ./setup-wallet.sh first"
  exit 1
fi

WALLET_ADDRESS=$(jq -r '.address' "$WALLET_FILE")
GATEWAY_URL=$(jq -r '.gateway_url' "$CONFIG_FILE")

# Parse arguments
PERIOD="all"
if [ "$1" == "--today" ]; then
  PERIOD="today"
elif [ "$1" == "--week" ]; then
  PERIOD="week"
elif [ "$1" == "--month" ]; then
  PERIOD="month"
fi

echo "🦞 Apiosk Usage Stats ($PERIOD)"
echo ""

# Fetch usage
USAGE=$(curl -s "$GATEWAY_URL/v1/usage?address=$WALLET_ADDRESS&period=$PERIOD")

if [ $? -ne 0 ]; then
  echo "❌ Failed to fetch usage stats"
  exit 1
fi

# Display summary
echo "📊 Summary:"
echo "$USAGE" | jq -r '"Total Requests: \(.total_requests)\nTotal Spent: $\(.total_spent_usdc) USDC"'

echo ""
echo "📈 By API:"
echo "$USAGE" | jq -r '.by_api | to_entries[] | "\(.key):\t\(.value.requests) req\t$\(.value.spent) USDC"' | column -t -s $'\t'

echo ""
echo "💡 Tip: Use --today, --week, or --month to filter"
echo ""


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (MEDIUM)