wf-market
A Rust client library for the warframe.market API.
Features
- Type-safe API - Compile-time guarantees prevent common mistakes like updating orders you don't own
- Automatic item loading - Items are fetched on client construction; orders have direct item access via
get_item() - Async/await - Built on Tokio for efficient async operations
- Session persistence - Save and restore login sessions with serde-compatible credentials
- Rate limiting - Built-in rate limiter to prevent API throttling
- Caching - Optional caching for slowly-changing data (items, rivens)
- WebSocket support - Real-time order updates (optional feature)
Installation
Add to your Cargo.toml:
[]
= "0.2"
# With WebSocket support
= { = "0.2", = ["websocket"] }
Quick Start
use ;
async
Authentication
Login with Credentials
use ;
let creds = new;
let client = builder.build.await?.login.await?;
Session Persistence
Save and restore sessions to avoid re-authenticating:
use ;
// After login, export the session
let session = client.export_session;
let json = to_string?;
write?;
// Later: restore session
let saved: Credentials = from_str?;
// Validate before using (recommended)
if validate_credentials.await?
Working with Orders
Fetching Orders
// Get orders with user info
let orders = client.get_orders.await?;
// Orders have direct item access
for order in &orders
// Get just order data (lighter response)
let listings = client.get_listings.await?;
// Get top buy/sell prices
let top = client.get_top_orders.await?;
println!;
println!;
Managing Your Orders
use ;
// Get your orders
let my_orders = client.my_orders.await?;
// Create a sell order
let order = client.create_order.await?;
// Update order price
client.update_order.await?;
// Delete order
client.delete_order.await?;
// Close order (record a sale)
let transaction = client.close_order.await?;
Type-Safe Order IDs
The OwnedOrderId type ensures you can only update/delete orders you own:
// This compiles - my_orders() returns OwnedOrder with OwnedOrderId
let orders = client.my_orders.await?;
client.delete_order.await?;
// This won't compile - get_orders() returns OrderListing with String id
let orders = client.get_orders.await?;
// client.delete_order(&orders[0].order.id); // Error!
Item Index
Items are automatically fetched when building a client. This enables O(1) item lookups and automatic item access from orders:
// Items loaded automatically on build()
let client = builder.build.await?;
// Access items directly
println!;
// O(1) lookups by ID or slug
if let Some = client.get_item_by_slug
// Orders have direct item access
let orders = client.get_orders.await?;
for order in &orders
Standalone Item Fetching
Fetch items without creating a client using ItemIndex::fetch(). This is useful for pre-loading items or building a client synchronously:
use ;
// Fetch items independently (no client needed)
let index = fetch.await?;
println!;
// Build client synchronously with pre-fetched items
let client = builder.build_with_items;
// With custom platform/language settings
let index = fetch_with_config.await?;
Caching Items
For applications that restart frequently, use build_with_cache() to avoid re-fetching items:
use ApiCache;
let mut cache = new;
// First build fetches from API, subsequent builds use cache (if < 1 day old)
let client = builder.build_with_cache.await?;
// Cache is serializable for persistence across restarts
let json = to_string?;
Long-Running Applications
For long-running applications, refresh the item index periodically:
// Refresh items (new orders will use updated index)
client.revalidate_items.await?;
Caching
Use ApiCache for other endpoints that rarely change:
use ApiCache;
use Duration;
let mut cache = new;
// First call fetches from API
let items = client.get_items.await?;
// Subsequent calls use cache (instant)
let items = client.get_items.await?;
// With TTL - refresh if older than 24 hours
let items = client.get_items_with_ttl.await?;
// Cache is serializable for persistence
let serializable = cache.to_serializable;
let json = to_string?;
WebSocket (Real-time Updates)
Enable the websocket feature for real-time order updates:
[]
= { = "0.2", = ["websocket"] }
use ;
let ws = client.websocket
.on_event
.subscribe
.auto_reconnect
.connect
.await?;
// Subscribe to specific items
ws.subscribe.await?;
// Set your status
ws.set_status.await?;
Item Types
Items can be categorized using type-checking methods:
let items = client.items;
for item in items.iter
Mods
// Create mod order with rank
let order = sell
.with_mod_rank;
Ayatan Sculptures
if let Some = item.as_sculpture
Configuration
use ;
let config = ClientConfig ;
let client = builder
.config
.build
.await?;
Feature Flags
| Feature | Default | Description |
|---|---|---|
rustls-tls |
Yes | Use rustls for TLS |
native-tls |
No | Use native TLS instead of rustls |
websocket |
No | Enable WebSocket support for real-time updates |
v1-api |
No | Enable deprecated V1 API endpoints (statistics) |
V1 API Endpoints (Deprecated)
Some endpoints are only available in the legacy V1 API. Enable them with the v1-api feature:
[]
= { = "0.3", = ["v1-api"] }
Warning: V1 endpoints are deprecated and will be removed when V2 equivalents become available.
Item Statistics
Get historical price and volume statistics for an item:
use Client;
let client = builder.build.await?;
let stats = client.get_item_statistics.await?;
// Get recent average price from closed trades
if let Some = stats.recent_avg_price
// Analyze 48-hour trend (hourly data)
for entry in &stats.statistics_closed.hours_48
// Check 90-day statistics
let total_volume = stats.statistics_closed.total_volume_90d;
let has_data = stats.has_sufficient_data;
println!;
Examples
Run the examples with:
# Basic usage (no auth required)
# Authenticated examples (set WFM_EMAIL and WFM_PASSWORD)
# Generate JWT token for testing (saves to .env)
Development
Running Tests
Unit tests run without credentials:
Integration Tests
Integration tests require warframe.market credentials:
# 1. Set up credentials
# Edit .env with your email and password
# 2. Generate a JWT token (avoids rate limiting)
# 3. Run integration tests (serially - server allows one WS connection)
Troubleshooting:
- "Rate limited": Wait 10-15 minutes, then run
cargo run --example update_token - "JWT token expired": Run
cargo run --example update_tokento refresh - "Unknown error" on WebSocket: Use
--test-threads=1to run tests serially
Minimum Supported Rust Version
This crate requires Rust 1.85 or later (2024 edition).
License
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.