Generate production-ready client code for integrating with the APRO AI Oracle Ticker API (cryptocurrency price, category, OHLCV endpoints). Supported languages: TypeScript, Python, Go, Rust. Use when a customer needs ticker/crypto integration code. Triggers on mentions of ticker, crypto price, OHLCV, coin category, APRO Oracle, or requests for cryptocurrency data API clients.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Generate production-ready client code for integrating with the APRO AI Oracle Ticker API (cryptocurrency price, category, OHLCV endpoints). Supported languages: TypeScript, Python, Go, Rust. Use when a customer needs ticker/crypto integration code. Triggers on mentions of ticker, crypto price, OHLCV, coin category, APRO Oracle, or requests for cryptocurrency data API clients.
argument-hint
<language> (e.g., typescript, python, go, rust)
allowed-tools
Read, Grep, Glob, Write, Bash
AI Oracle Ticker Integration Code Generator
Generate a complete, production-ready client library for the APRO AI Oracle Ticker API in the requested language.
Arguments
$ARGUMENTS — Target language (e.g., "typescript", "python", "go", "rust")
Supported languages: TypeScript, Python, Go, Rust. If the user requests an unsupported language, inform them of the supported options.
If no language is specified, ask the user which language they want.
Instructions
Read this skill document fully before generating any code
Read the OpenAPI spec at references/ai-oracle-api.yaml — this is the authoritative source for all endpoint paths, parameters, request/response schemas, and field types. All generated type definitions and method signatures must match this spec exactly.
Generate a complete client library following the Mandatory Directory Structure below
Write the output to examples/<language>/ticker/ directory
Run compilation verification — execute the language-appropriate compile/check command (see Compilation Verification section). If it fails, read the error output, fix the source files, and re-run until zero errors. This step is mandatory and the output is not considered complete until compilation passes.
API Quick Reference
The full specification lives in references/ai-oracle-api.yaml. This section is a condensed overview for quick orientation — when in doubt, the YAML is the source of truth.
Base URL: https://api-ai-oracle.apro.com
Auth: Two headers on every request — X-API-KEY and X-API-SECRET
This API uses full currency names (e.g., "Bitcoin", "Ethereum"), NOT ticker symbols.
Common Pattern
This API
symbol=BTC
name=Bitcoin
currency=USD
quotation=USD
interval=1d
interval=daily
start/end (seconds)
start_timestamp/end_timestamp (milliseconds)
category_id=defi
category=defi
Endpoints
Endpoint
Method
Description
/v2/ticker/currencies/list
GET
List all supported currencies (paginated)
/v2/ticker/currency/support
GET
Check if a specific currency is supported
/v2/ticker/currency/price
GET
Current price for a cryptocurrency
/v2/ticker/currency/category/list
GET
List all coin categories
/v2/ticker/currency/category/coins
GET
Coins in a specific category
/v2/ticker/currency/ohlcv
GET
OHLCV candlestick data (start_timestamp required)
Response Data Shapes
Some endpoints return a direct array as data, not a wrapped object:
Endpoint
data field type
/v2/ticker/currencies/list
Direct array: [{name, symbol, ...}, ...]
/v2/ticker/currency/support
Single object: {name, symbol, ...}
/v2/ticker/currency/price
Single object: {name, symbol, price, signature[], prices[], ...}
/v2/ticker/currency/category/list
Direct array: [{name, title, description}, ...]
/v2/ticker/currency/category/coins
Direct array: [{name, symbol}, ...]
/v2/ticker/currency/ohlcv
Single object: {name, symbol, points[], ohlcvs[], signature[], ...}
OHLCV Response Structure
The OHLCV response has TWO sets of data points:
data.points[] — Aggregated OHLCV with open, high, low, close, volume, timestamp (timestamps in seconds)
data.ohlcvs[] — Per-provider data, each with provider_name, direct, and its own points[] (no volume field)
Query parameters start_timestamp/end_timestamp use milliseconds, but response timestamp fields are in seconds.
Key Schema Names (from YAML)
YAML Schema
Maps to Generated Type
ApiStatus
ApiStatus
CurrencyInfo
CurrencyInfo
CurrencySupportResponse
CurrencySupport
TickerPriceData
TickerPrice
CategoryInfo
CategoryInfo
CategoryCoin
CategoryCoin
OHLCVData
OHLCVData
OHLCVEntry
OHLCVEntry
SignatureEntry
SignatureEntry
ProviderPrice
ProviderPrice
Wrapped_*Response
ApiResponse<T> (generic envelope)
ErrorResponse
TickerApiError (error class)
When generating types, read each schema's properties and required fields from the YAML — do not guess or hardcode field names.
Mandatory Directory Structure
Every generated project MUST follow this exact directory layout. This is critical for consistency — do not deviate from this structure regardless of the target language.
examples/<language>/ticker/
├── src/
│ ├── types/ # All type/model definitions
│ │ └── index.<ext> # TickerPrice, CategoryInfo, CategoryCoin, OHLCV, ApiResponse, ApiStatus, etc.
│ ├── client/ # HTTP client and API method implementations
│ │ └── index.<ext> # TickerClient class with all 6 endpoint methods
│ └── utils/ # Shared utilities
│ └── index.<ext> # Error handling, retry logic, response parsing, helpers
├── examples/
│ └── index.<ext> # Runnable usage examples for all 6 endpoints
├── .env.example # Template: APRO_API_KEY=your_api_key_here, APRO_API_SECRET=your_api_secret_here
└── README.md # Setup instructions, API reference, usage guide
File Extension Mapping
Language
<ext>
Notes
TypeScript
.ts
Use tsconfig.json at root if needed
Python
.py
Use __init__.py in each src/ subdirectory
Go
.go
Use go.mod at root; packages = directory names
Rust
.rs
Use Cargo.toml at root; src/ is standard
Language-Specific Adaptations
While the directory structure is fixed, each language should adapt idiomatically:
Python: Add __init__.py files in each src/ subdirectory for proper package imports. Use httpx for async HTTP, dataclasses for models, type hints everywhere. Include requirements.txt at root.
TypeScript: Use interface for types, async/await with fetch. Include package.json, tsconfig.json, and .env.example at root. Critical tsconfig requirements: "lib": ["ES2020", "DOM"] (for fetch/Response/RequestInit/AbortSignal), @types/node in devDependencies (for process/console/setTimeout), "rootDir": ".", "include": ["src/**/*", "examples/**/*"]. Critical .env setup: Add dotenv to dependencies and @types/node to devDependencies. In example files, call import 'dotenv/config' at the top (or import dotenv from 'dotenv'; dotenv.config()) so process.env.APRO_API_KEY / process.env.APRO_API_SECRET are loaded from .env. Generate a .env.example file containing APRO_API_KEY=your_api_key_here and APRO_API_SECRET=your_api_secret_here. The tsconfig.json must set "resolveJsonModule": true and "esModuleInterop": true.
Go: Use Go modules. Struct tags for JSON. Package names match directory names. Include go.mod at root. All exported functions must have doc comments.
Rust: Use reqwest (with json feature) for HTTP, serde/serde_json for serialization, tokio for async runtime. Include Cargo.toml at root.
Code Generation Rules
These rules ensure every generated client is production-quality and structurally consistent. Type definitions and method signatures must be derived from the OpenAPI YAML — not invented.
1. Type Definitions (src/types/)
Read the components/schemas section of the YAML and generate types for ALL of the following:
Use the language's idiomatic type system (interfaces, structs, dataclasses, etc.). All fields must have explicit types — no any or interface{}. Field types (string, number, integer, etc.) should match the YAML's type and format attributes.
2. Client Class (src/client/)
Read the paths section of the YAML. Each path maps to exactly one client method:
Note: startTimestamp is required for OHLCV. The API returns error 400 if not provided.
Method parameters must match the YAML's parameters (name, type, required). Adapt naming to language conventions (e.g., get_price in Python, GetPrice in Go), but the set of 6 methods must always be present.
CRITICAL: Parameters use name (full crypto name like "Bitcoin"), NOT symbol. The quotation param is the quote currency, NOT currency. OHLCV intervals are "hourly"/"daily", NOT "1h"/"1d". OHLCV timestamps are in milliseconds, NOT seconds.
Custom error class with fields: statusCode, message, timestamp (derived from YAML's ErrorResponse schema)
Retry logic: exponential backoff on 429 and 5xx, up to maxRetries
Response parser: unwrap the { status, data } envelope (the Wrapped_* pattern in YAML), throw on non-200 status codes. CRITICAL: The data field has different shapes per endpoint — it can be a direct array (for currencies/list, category/list, category/coins) or a single object (for support, price, ohlcv). The parser must handle both: when data is an array, return the array directly; when it's an object, return the object. Never assume data is always one shape.
Provide a single runnable example file that demonstrates ALL 6 endpoints:
List supported currencies (first page)
Check if "Bitcoin" is supported
Fetch Bitcoin price (in USD, median)
List all categories
Get coins in a specific category
Fetch Bitcoin OHLCV data (daily)
Each example call must include inline comments explaining what it does. The example must be copy-paste runnable. For TypeScript/Node.js, read credentials from process.env (loaded via dotenv) — the user only needs to copy .env.example to .env and fill in their keys. For Python, use os.environ (with python-dotenv). For other languages, use idiomatic env-var loading.
CRITICAL — Example robustness rules (these prevent runtime errors in generated examples):
Always guard array operations: Before calling .length, .slice(), .map(), .forEach(), or any array method on API results, check that the value is defined and is an array. Use Array.isArray(result) (TypeScript) or equivalent.
Log the right properties per endpoint: Each endpoint returns different fields. For category/list, log name/title. For category/coins, log name/symbol/price. For currencies/list, log name/symbol. Do NOT assume all array responses have the same shape.
Wrap each endpoint demo in its own try/catch: One failing endpoint must NOT crash the entire example. Catch errors per-call and log them, then continue to the next endpoint.
OHLCV timestamps: When constructing start_timestamp for OHLCV, always use Date.now() - 7 * 24 * 60 * 60 * 1000 (7 days ago in ms). Do NOT hardcode dates that will expire.
Never use .slice() or index access without a guard: if (data && data.length > 0) { console.log(data.slice(0, 5)); } — not console.log(data.slice(0, 5)) directly.
For category/coins: Always use a known category like "Memes". The category name must exactly match a value from category/list — it is case-sensitive.
5. README.md
Must contain these exact sections in order:
Installation — Dependencies and setup steps
Quick Start — Minimal code to get a price quote
API Reference — Table of all 6 methods with params and return types
Error Handling — How errors are structured and how to catch them
Examples — Reference to the examples directory
Security
Never hardcode credentials — Generated code must read API_KEY and API_SECRET from environment variables or .env files. No credential values may appear in source code.
.env must be gitignored — Every generated project must include a .gitignore (or append to an existing one) with .env listed. Only .env.example (containing placeholder values) should be committed.
HTTPS only — The base URL must always use https://. The client must not allow downgrading to HTTP.
No credentials in logs — Generated example code and error handling must never log, print, or expose API key/secret values. Error messages should omit request headers.
Dependency security — Use well-maintained, widely-adopted HTTP libraries (fetch, httpx, net/http, reqwest). Do not introduce unnecessary dependencies that expand the attack surface.
Input validation — Client methods should validate parameters before sending requests (e.g., reject empty name, invalid interval values) to prevent injection via query string manipulation.
Pre-Generation Checklist
Before writing any file, verify mentally:
Have I read references/ai-oracle-api.yaml?
Target directory is examples/<language>/ticker/
All 4 directories exist: src/types/, src/client/, src/utils/, examples/
All type definitions will be generated (matching YAML schemas)
All 6 client methods will be generated (matching YAML paths)
Ask user to install Rust via curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh or from https://rustup.rs/
If the check command fails, stop and tell the user what to install before proceeding. Do not attempt code generation or compilation without a working toolchain.
Step 1: Install Dependencies
cd into the generated project root (examples/<language>/ticker/) and install dependencies:
Language
Install Command
TypeScript
npm install
Python
pip install -r requirements.txt --break-system-packages (if httpx not available)
If compilation fails, follow this loop — up to 3 iterations maximum:
for each attempt (1 to 3):
1. Read the FULL error output from the compilation command
2. Identify the root cause of EVERY error (not just the first one)
3. Fix all errors in the source files
4. Re-run the compilation command from Step 2
5. If exit code is 0 → done, proceed to delivery
6. If still failing → next attempt
After 3 failed attempts, report the remaining errors to the user and ask for guidance.
Important: Fix the root cause, not the symptom. For example, if fetch is not found in TypeScript, don't add declare function fetch(...) — instead fix tsconfig.json to include the DOM lib.
Common Pitfalls by Language
TypeScript (most common source of example.ts errors):
Cannot find name 'fetch'/'Response'/'RequestInit'/'AbortSignal' → Add "DOM" to tsconfig.jsonlib array
Cannot find name 'process'/'console'/'setTimeout' → Add @types/node to devDependencies and run npm install
File 'examples/index.ts' is not under 'rootDir' → Set "rootDir": "." (not "./src") and add "examples/**/*" to include
Cannot find module '../types/index' → Check relative import paths match actual directory structure
Cannot find module 'dotenv/config' → Add dotenv to dependencies (not just devDependencies) and @types/node to devDependencies, then npm install
Type 'string | undefined' is not assignable to type 'string' → When reading process.env, always provide a fallback or assert: process.env.APRO_API_KEY || '' or use a guard that throws if missing
Top-level await error → Do NOT use top-level await in examples. Always wrap example code in an async function main() and call main().catch(console.error) at the bottom
esModuleInterop errors with import dotenv from 'dotenv' → Use import 'dotenv/config' (side-effect import) instead, which works without esModuleInterop; OR ensure "esModuleInterop": true is in tsconfig
Required TypeScript tsconfig.json template — always generate exactly this (adjust target/module only if necessary):
ModuleNotFoundError → Ensure __init__.py exists in every src/ subdirectory
Circular imports → Move shared types to src/types/, import from there in both client and utils
httpx not installed → Include in requirements.txt, install before verification
KeyError: 'r' or missing key 'r' on signature → SignatureEntry fields are signer, hash, signature, timestamp (NOT r, s, v). Always derive types from the YAML SignatureEntry schema.
Go:
imported and not used → Remove unused imports or use _ blank identifier
undefined: SomeType → Check package names match directory names, ensure exports are capitalized
go.mod: missing module → Run go mod tidy before go build
Rust:
unresolved import reqwest → Ensure reqwest = { version = "0.11", features = ["json"] } in Cargo.toml
the trait bound 'X: Deserialize' is not satisfied → Add #[derive(Deserialize)] and use serde::Deserialize
tokio runtime → Ensure tokio = { version = "1", features = ["full"] } in Cargo.toml
missing field 'r' on deserialization → SignatureEntry fields are signer, hash, signature, timestamp (NOT r, s, v). The struct must match the YAML schema exactly. Use #[serde(rename_all = "snake_case")] if needed.