Rust SDK
High-performance async Rust SDK for the Linkit API — fluent builders, zero-cost abstractions, serde models, and built-in resilience.
Rust SDK
The Linkit Rust SDK provides a fully async, type-safe client for the Linkit e-commerce API. Built with reqwest, serde, and tokio, it delivers zero-cost abstractions with fluent builder APIs identical to the C# SDK architecture.
Async First
All operations are async and return Result<T, LinkitError>. The SDK integrates retry, circuit breaker, and rate limiting transparently.
Installation
# Cargo.toml
[dependencies]
linkit-sdk = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }# Download from Linkit docs downloads
tar xf linkit-sdk-0.1.0.crate
cd linkit-sdk-0.1.0
# Add as path dependency
[dependencies]
linkit-sdk = { path = "./linkit-sdk-0.1.0" }[dependencies]
linkit-sdk = { git = "https://github.com/theHamdiz/linkit", branch = "main" }Quick Start
use linkit_sdk::{LinkitClient, LinkitConfig};
#[tokio::main]
async fn main() -> linkit_sdk::Result<()> {
// Create client with custom config
let client = LinkitClient::with_config(
LinkitConfig::builder()
.base_url("https://linkit.works/api/v1")
.timeout_secs(30)
.build()?,
)?
.with_auth("your-jwt-token")
.await?;
// Health check
let health = client.health().check().await?;
println!("API status: {}", health.status);
// Create a product
let product = client.products().create()
.iv_id("PROD-001")
.name("Premium Coffee", "قهوة ممتازة")
.price(29.99)
.enabled(true)
.send()
.await?;
println!("Created: {}", product.data.iv_id);
Ok(())
}Configuration
Presets
// Default — balanced settings
let client = LinkitClient::new()?;
// High throughput — 50 concurrent, 5 retries
let client = LinkitClient::with_config(LinkitConfig::high_throughput())?;
// Development — long timeout, minimal retries
let client = LinkitClient::with_config(LinkitConfig::development())?;Custom Builder
use linkit_sdk::{LinkitConfig, RetryPolicy};
use std::time::Duration;
let config = LinkitConfig::builder()
.base_url("https://api.yourcompany.com/v1")
.timeout(Duration::from_secs(45))
.max_concurrent_requests(30)
.user_agent("my-app/1.0")
.retry_policy(RetryPolicy {
max_retries: 5,
initial_delay: Duration::from_millis(100),
backoff_multiplier: 2.0,
max_delay: Duration::from_secs(30),
})
.default_header("X-Custom-Header", "value")
.build()?;Products
Create
let product = client.products().create()
.iv_id("PROD-001")
.name("Premium Coffee", "قهوة ممتازة")
.description("Single origin beans", "حبوب أحادية المصدر")
.price(29.99)
.price_after_vat(34.49)
.vat(15.0)
.category_id("beverages")
.brand_id("brand-01")
.barcode("6281234567890")
.enabled(true)
.fast_moving(true)
.quick_commerce(true)
.shippable(true)
.refrigerated(false)
.hero_image("https://cdn.example.com/coffee.jpg")
.buffer(10.0)
.send()
.await?;List with Filters
let products = client.products().list()
.page(1)
.limit(50)
.enabled(true)
.category("beverages")
.brand("brand-01")
.search("coffee")
.fast_moving(true)
.send()
.await?;
for p in &products.data {
println!("{}: {}", p.iv_id, p.name_en.as_deref().unwrap_or(""));
}
println!("Total: {} | Has next: {}", products.total_count, products.has_next);Get / Update / Delete
// Get
let product = client.products().get("PROD-001").await?;
// Update
let updated = client.products().update("PROD-001")
.price(24.99)
.enabled(false)
.send()
.await?;
// Delete
let result = client.products().delete("PROD-001").await?;Branches
Create
let branch = client.branches().create()
.iv_id("BR-RYD-001")
.name("Riyadh Central", "الرياض سنتر")
.location(24.7136, 46.6753)
.active(true)
.email("riyadh@example.com")
.google_maps_id("ChIJ...")
.send()
.await?;List with Proximity Search
let nearby = client.branches().list()
.near(24.7136, 46.6753, 5.0) // 5km radius
.active(true)
.sort("-created")
.send()
.await?;SKUs
Create & Update Stock
// Create SKU
let sku = client.skus().create()
.iv_id("SKU-001")
.branch_iv_id("BR-RYD-001")
.product_iv_id("PROD-001")
.price(29.99)
.qty(1000.0)
.max_qty(5000.0)
.available(true)
.barcode("6281234567890")
.amazon_sku("AMZN-001")
.salla_id("SL-001")
.send()
.await?;
// Update stock
let stock = client.skus().update_stock("SKU-001", "BR-RYD-001")
.qty(950.0)
.available(true)
.send()
.await?;Customers
// Create
let customer = client.customers().create()
.first_name("Ahmad")
.last_name("Hamdi")
.email("ahmad@example.com")
.phone("+966500000000")
.customer_type("individual")
.send()
.await?;
// Lookup
let found = client.customers().find_by_email("ahmad@example.com").await?;
println!("Customer: {} (active: {})", found.full_name(), found.is_active());Brands
// Create
let brand = client.brands().create()
.brand_code("BRD-01")
.name("Acme Corp", "أكمي")
.logo_url("https://cdn.example.com/acme.png")
.send()
.await?;
// List
let brands = client.brands().list()
.page(1).limit(25).search("Acme")
.send().await?;
for b in &brands.data {
println!("{}: {}", b.brand_code, b.name_en.as_deref().unwrap_or(""));
}
// Update / Delete
let updated = client.brands().update("BRD-01").name("Acme Inc", "أكمي إنك").send().await?;
client.brands().delete("BRD-01").await?;Categories
// Create with parent hierarchy
let category = client.categories().create()
.code("CAT-BEV")
.name("Beverages", "مشروبات")
.parent("CAT-ROOT")
.sort_order(1)
.send()
.await?;
// List with parent filter
let children = client.categories().list()
.parent("CAT-ROOT")
.page(1).limit(50)
.send().await?;
for c in &children.data {
println!("{}: {} (depth: {})", c.code, c.name_en.as_deref().unwrap_or(""), c.depth);
}Orders
// List with filters
let orders = client.orders().list()
.status("confirmed")
.payment_status("completed")
.from("2026-01-01")
.to("2026-03-26")
.currency("SAR")
.sort("-created")
.page(1).limit(20)
.send()
.await?;
for order in &orders.data {
println!("Order {} — {} {} ({})",
order.id,
order.total_amount.unwrap_or(0.0),
order.currency.as_deref().unwrap_or("SAR"),
order.order_status.as_deref().unwrap_or("unknown"),
);
}
// Update status
let updated = client.orders().update_status("ORD-001")
.order_status("shipped")
.fulfillment_status("shipped")
.notes("Dispatched via Aramex")
.send()
.await?;Offers
// Create a direct discount offer
let offer = client.offers().create()
.name("Weekend 15%")
.offer_type("direct_discount")
.status("active")
.target_scope("product")
.target_iv_id("PRD-1001")
.discount_type("percentage")
.discount_value(15.0)
.start_at("2026-03-25T00:00:00Z")
.end_at("2026-03-31T23:59:59Z")
.send()
.await?;
println!("Created offer: {}", offer.data.id);
// List with filters
let offers = client.offers().list()
.status("active")
.offer_type("direct_discount")
.is_active(true)
.page(1).limit(20)
.sort("-created")
.send()
.await?;
for o in &offers.data {
println!("{}: {} ({})", o.id, o.name, o.offer_type);
}
// Update status
client.offers().update_status("ofr_123")
.status("paused")
.active(false)
.send()
.await?;
// Bulk upsert
use linkit_sdk::models::offer::OfferRequest;
let bulk = client.offers().bulk_upsert(vec![
OfferRequest { name: "BOGO".into(), offer_type: "bogo".into(), buy_qty: 1, get_qty: 1, ..Default::default() },
OfferRequest { name: "Bundle".into(), offer_type: "bundle_deal".into(), ..Default::default() },
]).await?;
println!("Processed: {}, Failed: {}", bulk.data.processed, bulk.data.failed);
// Delete
client.offers().delete("ofr_123").await?;Generics
// Create
let generic = client.generics().create()
.generic_code("GEN-PARA")
.name("Paracetamol", "باراسيتامول")
.send()
.await?;
// List
let generics = client.generics().list()
.page(1).limit(50).search("para")
.send().await?;Integrations
// List all integrations
let integrations = client.integrations().list().await?;
for i in &integrations {
println!("{}: {} (enabled: {})", i.slug.as_deref().unwrap_or(""), i.name.as_deref().unwrap_or(""), i.enabled);
}
// Get config, enable, execute
let config = client.integrations().get_config("hungerstation").await?;
client.integrations().enable("hungerstation").await?;
let result = client.integrations().execute("hungerstation").await?;
println!("Execution: {} ({})", result.message, if result.success { "✓" } else { "✗" });
client.integrations().disable("hungerstation").await?;Error Handling
use linkit_sdk::LinkitError;
match client.products().get("PROD-XXX").await {
Ok(product) => println!("Found: {}", product.iv_id),
Err(LinkitError::Api { status: 404, .. }) => println!("Product not found"),
Err(LinkitError::Api { status, message, .. }) => {
eprintln!("API error {status}: {message}");
}
Err(LinkitError::CircuitOpen) => {
eprintln!("Service temporarily unavailable");
}
Err(LinkitError::Timeout { elapsed_ms }) => {
eprintln!("Timed out after {elapsed_ms}ms");
}
Err(e) => eprintln!("Unexpected: {e}"),
}Resilience Pipeline
Every request automatically flows through a 3-layer resilience pipeline:
| Layer | Default | Description |
|---|---|---|
| Rate Limiter | 10 concurrent | Token-bucket semaphore via tokio::sync::Semaphore |
| Circuit Breaker | 5 failures / 60s reset | Lock-free atomics, half-open recovery |
| Retry | 3 attempts, 200ms initial | Exponential backoff with capped delay |
All transient errors (5xx, 429, timeouts, connection errors) are automatically retried. Non-transient errors (4xx, validation) propagate immediately.
Performance
The SDK is optimised for maximum throughput:
- Release profile: LTO (fat), single codegen unit, stripped symbols, abort on panic
- Zero-copy serde:
#[serde(skip_serializing_if)]minimises payload size - Connection pooling:
reqwestconnection reuse with configurable pool size - Lock-free circuit breaker: Uses
AtomicU32/AtomicU64— no mutex contention - Token-bucket rate limiter:
tokio::Semaphorefor backpressure without blocking