MeterCall Oracle
Pay-per-query oracle feeds. Signed reports your smart contract can verify on-chain. 99% cheaper than Chainlink.
Quickstart
One fetch. Every response is a signed report.
const r = await fetch('https://metercall.ai/v1/oracle/price/ETH-USD'); const report = await r.json(); // { // feed_id: "price/ETH-USD", // feed_id_hash: "0x...", // value: 2847.33, // timestamp: 1713312451200, // digest: "0x...", // signature: "0x...", // signer: "0x..." // }
Or use the SDK:
const { MeterCallOracle } = require('metercall-oracle'); const oracle = new MeterCallOracle({ key: 'mc_live_...' }); const r = await oracle.price('ETH-USD');
Pricing
| Feed class | MeterCall | Chainlink |
|---|---|---|
| Crypto price | $0.0001 / query | ~$30/mo/feed |
| Stablecoin peg | $0.0001 / query | ~$30/mo/feed |
| Gas price | $0.0001 / query | ~$15/mo/feed |
| Forex | $0.0001 / query | ~$50/mo/feed |
| TVL | $0.0002 / query | custom only |
| Weather | $0.0002 / query | custom only |
| Commodity / Stock | $0.0003 / query | $50–75/mo/feed |
| NFT floor | $0.0005 / query | $100+/mo/feed |
| Sports | $0.001 / query | custom only |
GET /v1/oracle/feeds
Returns the catalog plus the current signer and EIP-712 domain so contracts can compare on-chain.
// Response { "feeds": [ { "id": "price", "example": "/v1/oracle/price/ETH-USD", ... } ], "custom_count": 18, "signer": "0xA1B2....", "domain": { "name": "MeterCallOracle", "version": "1", "chainId": 1, ... } }
GET/v1/oracle/price/:pair
Supported pairs use BASE-QUOTE or BASE/QUOTE. Examples: ETH-USD, BTC-USD, SOL-USDC, XAU-USD, SPX-USD.
GET/v1/oracle/gas/:chain
Current gas price in gwei. Supported chains: ethereum. More chains rolling out via the ETH_RPC environment expansion.
GET/v1/oracle/tvl/:protocol
Total Value Locked in USD. Backed by DefiLlama. Protocol slugs: aave, uniswap, curve, lido, etc.
GET/v1/oracle/nft/:collection/floor
NFT floor price in USD. Collection slugs match CoinGecko NFT IDs (cryptopunks, bored-ape-yacht-club, pudgy-penguins).
GET/v1/oracle/sport/:league/:event
Live scores and event outcomes. Populated by MeterCall's sports harvester bots.
GET/v1/oracle/weather/:lat/:lon
Current weather (temperature °C, wind km/h, precipitation mm) for coordinates. Backed by Open-Meteo.
GET/v1/oracle/fx/:from-:to
Forex rate. Example: /v1/oracle/fx/USD-EUR.
GET/v1/oracle/custom/:id
Reads a previously registered custom feed. Same signed-report shape as the built-ins.
POST/v1/oracle/custom
Register a new custom feed. Requires header x-admin-key.
// Request body { "id": "uni-v3-eth-usdc-tick", "description": "Uniswap v3 ETH/USDC current tick", "source_url": "https://example.com/api/tick", "json_path": "data.tick" }
After registration, any query to /v1/oracle/custom/uni-v3-eth-usdc-tick fetches the source, extracts the path, and returns a signed report.
Response shape
{
"feed_id": "price/ETH-USD",
"feed_id_hash": "0xd3...", // sha256(feed_id)
"value": 2847.33,
"timestamp": 1713312451200, // unix ms
"digest": "0x...",
"signature": "0x...", // 65-byte ECDSA
"signer": "0xA1B2...",
"domain": {
"name": "MeterCallOracle",
"version": "1",
"chainId": 1,
"verifyingContract": "0x..."
}
}
Solidity verifier
Drop OracleConsumer.sol into your project. Inherit and call verifyMeterCall(report) before consuming any value.
import "./OracleConsumer.sol"; contract Vault is OracleConsumer { constructor(address signer) OracleConsumer(signer, 1, address(this)) {} function liquidate(Report calldata r) external { verifyFeed(r, "price/ETH-USD"); require(block.timestamp - (r.timestamp / 1000) < 60, "stale"); // r.value is int256 scaled 1e8 — safe to use } }
JavaScript SDK
oracle.js is dependency-free and works in browsers and Node 18+.
const oracle = new MeterCallOracle({ key: MC_KEY }); await oracle.price('BTC-USD'); await oracle.gas('ethereum'); await oracle.tvl('aave'); await oracle.nftFloor('cryptopunks'); await oracle.fx('USD', 'EUR'); await oracle.weather(40.71, -74.00); // Convert to on-chain shape const r = await oracle.price('ETH-USD'); const onchain = oracle.toOnchainReport(r);
Caching & freshness
- Prices: 5 second TTL (matches Chainlink's 0.5% heartbeat cadence).
- Gas: 8 seconds.
- TVL: 60 seconds.
- NFT floor: 30 seconds.
- Weather: 5 minutes.
- Sport: 15 seconds (push-updated by harvester bots).
The timestamp field is always the moment of harvest, not the moment of HTTP response. Enforce your own freshness budget on-chain via maxReportAge in OracleConsumer.
Error codes
| HTTP | error | Meaning |
|---|---|---|
| 400 | bad_pair | Pair isn't in BASE-QUOTE form. |
| 400 | bad_coords | lat/lon not a number. |
| 400 | bad_id | Custom feed id has invalid characters. |
| 401 | unauthorized | Missing or wrong x-admin-key. |
| 404 | feed_not_found | Custom id not registered. |
| 502 | no_data | Upstream returned nothing for the key. |
| 502 | upstream_* | Upstream returned a non-2xx; status code embedded. |