Skills and External API Integration
Skill scripts can call external HTTP APIs just like ordinary Python programs, thereby connecting Claude's capabilities with third-party services.
Basic Pattern for Calling External APIs
Usingrequeststhe library to send HTTP requests is the most common way of calling APIs in Skill scripts.
Example
import requests
import json
import sys
import os
# API key is read from environment variables, not hardcoded into the script
API_KEY = os.environ.get("MY_API_KEY", "")
BASE_URL = "https://api.example.com/v1"
def call_api(endpoint: str, payload: dict, timeout: int = 30) -> dict:
"""
Generic API call wrapper
Parameters:
endpoint: API path, e.g., "/analyze"
payload: Request body (JSON)
timeout: Timeout in seconds, default 30
Returns:
Parsed JSON response, or a dictionary containing error
"""
if not API_KEY:
return {"error": "API key not set, please set the environment variable MY_API_KEY"}
url = BASE_URL + endpoint
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
try:
response = requests.post(url, headers=headers,
json=payload, timeout=timeout)
response.raise_for_status() # Raises an exception on HTTP 4xx/5xx
return response.json()
except requests.Timeout:
return {"error": f"Request timeout (exceeded {timeout} seconds)"}
except requests.HTTPError as e:
return {"error": f"HTTP error {e.response.status_code}: {e.response.text}"}
except requests.ConnectionError:
return {"error": "Unable to connect to API service, please check the network"}
except Exception as e:
return {"error": str(e)}
# Usage example
if __name__ == "__main__":
result = call_api("/analyze", {
"text": "example is a well-known technical learning platform in China",
"lang": "zh"
})
print(json.dumps(result, ensure_ascii=False, indent=2))
Secure Management of API Keys
API keys should not be written directly in script files; they should be passed through environment variables.
Example
export MY_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"
python scripts/api_client.py
# Or set them inline when executing the script
MY_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx" python scripts/api_client.py
In SKILL.md, inform users that they need to configure the key:
## 前置配置 本 Skill 需要外部 API 密钥,首次使用前请完成以下配置: 1. 在 [API 服务商网站] 注册并获取 API 密钥 2. 在终端中设置环境变量: ```bash export MY_API_KEY="你的密钥" ``` 3. 若需要永久生效,将上述命令添加到 ~/.bashrc 或 ~/.zshrc 若未配置,Skill 将提示"未设置 API 密钥"并退出。
Never commit API keys to a Git repository. You can create a .gitignore file in the Skill directory to exclude the .env file from version control.
Handling API Rate Limiting
Most APIs have request frequency limits. When calling APIs in batch, you need to add delays between requests.
Example
import time
import requests
class RateLimitedClient:
"""API client with rate limiting control"""
def __init__(self, base_url: str, api_key: str,
requests_per_minute: int = 60):
self.base_url = base_url
self.api_key = api_key
self.min_interval = 60.0 / requests_per_minute # Minimum interval between requests (seconds)
self.last_request = 0.0
def _wait_if_needed(self):
"""If the time since the last request is not enough, wait for the remaining time"""
elapsed = time.time() - self.last_request
wait = self.min_interval - elapsed
if wait > 0:
time.sleep(wait)
self.last_request = time.time()
def post(self, endpoint: str, payload: dict) -> dict:
self._wait_if_needed()
headers = {"Authorization": f"Bearer {self.api_key}"}
try:
resp = requests.post(
self.base_url + endpoint,
headers=headers, json=payload, timeout=30
)
# Handle 429 Too Many Requests: wait and retry once
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 5))
print(f"Rate limit triggered, waiting {retry_after} seconds before retrying...")
time.sleep(retry_after)
resp = requests.post(
self.base_url + endpoint,
headers=headers, json=payload, timeout=30
)
resp.raise_for_status()
return resp.json()
except Exception as e:
return {"error": str(e)}
Response Caching
For APIs that return the same result for the same input, you can cache the results to local files to avoid duplicate requests, saving money and improving speed.
Example
import hashlib
import json
import os
CACHE_DIR = "/home/claude/.api_cache"
os.makedirs(CACHE_DIR, exist_ok=True)
def _cache_key(endpoint: str, payload: dict) -> str:
"""Generate a cache key based on the request content (MD5 hash)"""
raw = json.dumps({"endpoint": endpoint, "payload": payload},
sort_keys=True)
return hashlib.md5(raw.encode()).hexdigest()
def cached_call(endpoint: str, payload: dict, call_fn) -> dict:
"""
API call with caching
Parameters:
endpoint: API path
payload: Request body
call_fn: The function that actually makes the HTTP request
Returns:
API response (returns the cached result directly when the cache is hit)
"""
key = _cache_key(endpoint, payload)
cache_file = os.path.join(CACHE_DIR, f"{key}.json")
# Cache hit
if os.path.exists(cache_file):
with open(cache_file, "r") as f:
print(f"Cache hit: {key[:8]}...")
return json.load(f)
# Cache miss, make a real request
result = call_fn(endpoint, payload)
# Save to cache (only cache successful results)
if "error" not in result:
with open(cache_file, "w") as f:
json.dump(result, f, ensure_ascii=False)
return result