SDK Reference
Swift SDK
High-performance native Swift SDK for the Linkit API — async/await, Codable, URLSession, zero dependencies.
Swift SDK
Platform Support
macOS 13+ · iOS 16+ · watchOS 9+ · tvOS 16+ · Swift 5.9+ · Pure Foundation — zero external dependencies.
Installation
Swift Package Manager
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/linkit-sa/linkit-swift-sdk", from: "0.1.0"),
]Or add via Xcode: File → Add Package Dependencies → Enter URL.
Direct Download
Download the release archive from the Downloads page.
Quick Start
import LinkitSDK
let client = try LinkitClient.quickSetup(
baseUrl: "https://linkit.works/api/v1",
jwtToken: "your-jwt-token"
)
// Create a product
let product = try await client.products.create(
ProductRequest(ivId: "P-001", nameEn: "Aspirin 500mg", averagePrice: 12.50)
)
// List SKUs
let skus = try await client.skus.list(branchIvId: "BR-RYD", enabled: true)
for sku in skus.data {
print("\(sku.ivId): \(sku.price ?? 0) SAR")
}Configuration
let config = LinkitConfiguration(
baseUrl: "https://linkit.works/api/v1",
jwtToken: "your-jwt-token",
timeoutSeconds: 45,
maxConcurrentRequests: 20,
maxRetries: 5,
retryBaseDelayMs: 100,
retryMaxDelayMs: 30_000,
circuitBreakerThreshold: 10,
circuitBreakerRecoveryMs: 30_000,
userAgent: "my-pharmacy-app/1.0",
defaultHeaders: ["X-Custom": "value"]
)
let client = try LinkitClient(configuration: config)| Setting | Default | Description |
|---|---|---|
timeoutSeconds | 30 | Request timeout |
maxConcurrentRequests | 10 | Rate limiter permits |
maxRetries | 3 | Retry attempts for 5xx/429 |
retryBaseDelayMs | 200 | Base exponential backoff |
retryMaxDelayMs | 10000 | Max backoff cap |
circuitBreakerThreshold | 5 | Failures before opening |
circuitBreakerRecoveryMs | 60000 | Recovery timeout |
Services Reference (11 Services)
| Service | Methods | Description |
|---|---|---|
client.products | create(), getByIvId(), update(), delete(), list(), listAll() | Product catalog |
client.skus | create(), getByIvId(), update(), delete(), list() | SKU / inventory |
client.branches | create(), getByIvId(), update(), delete(), list() | Physical locations |
client.customers | create(), getById(), update(), delete(), list(), listAll(), lookupByEmail(), lookupByPhone(), search(), getAddresses(), createAddress(), updateAddress(), deleteAddress(), getGroups(), createGroup(), updateGroup(), deleteGroup() | Customer profiles |
client.orders | getById(), list(), updateStatus() | Order management |
client.offers | create(), getById(), update(), updateStatus(), delete(), list(), bulkUpsert() | Promotions & discounts |
client.brands | create(), getById(), update(), delete(), list() | Brand management |
client.categories | create(), getById(), update(), delete(), list() | Product categories |
client.generics | create(), getById(), update(), delete(), list() | Generic medicines |
client.integrations | list(), getById(), getConfig(), execute() | Integration management |
client.health | check(), detailed() | Health checks |
Products
// Create
let product = try await client.products.create(
ProductRequest(
ivId: "P-001",
nameEn: "Aspirin 500mg", nameAr: "أسبرين ٥٠٠ مجم",
averagePrice: 12.50, isEnabled: true, isPom: false
)
)
// List with filters
let products = try await client.products.list(
page: 1, limit: 20, search: "aspirin",
enabled: true, isFastMoving: true
)
// Stream all products (auto-paginates)
for await product in client.products.listAll() {
print(product.nameEn ?? "")
}
// Update
let updated = try await client.products.update("P-001",
request: ProductRequest(ivId: "P-001", averagePrice: 14.00))
// Delete
try await client.products.delete("P-001")SKUs
let sku = try await client.skus.create(
SKURequest(ivId: "S-001", branchIvId: "BR-RYD", productIvId: "P-001",
price: 29.99, stock: 150)
)
let skus = try await client.skus.list(
branchIvId: "BR-RYD", productIvId: "P-001", enabled: true
)Customers
// Create
let customer = try await client.customers.create(
CustomerRequest(firstName: "Ahmad", lastName: "Ali",
email: "ahmad@company.sa", phone: "+966512345678")
)
// Lookup
if let found = try await client.customers.lookupByEmail("ahmad@company.sa") {
print("Found: \(found.id)")
}
// Address management
let address = try await client.customers.createAddress(customer.id,
request: AddressRequest(label: "Home", line1: "123 King Rd", city: "Riyadh", country: "SA"))
// Group management
let group = try await client.customers.createGroup(
CustomerGroupRequest(name: "VIP Customers"))Orders
let orders = try await client.orders.list(
status: "confirmed", paymentStatus: "completed",
from: "2026-01-01", currency: "SAR", sort: "-created"
)
let updated = try await client.orders.updateStatus("ORD-001",
request: OrderStatusUpdateRequest(orderStatus: "shipped", notes: "Via Aramex"))Offers
// Create
let offer = try await client.offers.create(
OfferRequest(name: "Weekend 15%", offerType: "direct_discount",
status: "active", targetScope: "product",
targetIvId: "P-001", discountType: "percentage",
discountValue: 15.0)
)
// List with filters
let offers = try await client.offers.list(
status: "active", offerType: "direct_discount",
isActive: true, sort: "-created"
)
// Update status
try await client.offers.updateStatus(offer.data.id,
request: OfferStatusUpdate(status: "paused", isActive: false))
// Bulk upsert
let bulk = try await client.offers.bulkUpsert([
OfferRequest(name: "BOGO", offerType: "bogo", buyQty: 1, getQty: 1),
OfferRequest(name: "Bundle", offerType: "bundle_deal"),
])
print("Processed: \(bulk.data.processed), Failed: \(bulk.data.failed)")
// Delete
try await client.offers.delete(offer.data.id)Brands / Categories / Generics
// Brand
let brand = try await client.brands.create(
BrandRequest(brandCode: "BRD-001", nameEn: "Panadol", nameAr: "بنادول"))
// Category
let category = try await client.categories.create(
CategoryRequest(categoryCode: "CAT-001", nameEn: "Pain Relief"))
// Generic medicine
let generic = try await client.generics.create(
GenericRequest(genericCode: "GEN-001", nameEn: "Paracetamol", nameAr: "باراسيتامول"))Error Handling
do {
let product = try await client.products.getByIvId("INVALID")
} catch let error as LinkitError {
switch error {
case .notFound(let type, let id):
print("Not found: \(type) \(id ?? "")")
case .authentication(let msg, _):
print("Auth: \(msg)")
case .rateLimited(let retryAfter):
print("Rate limited, retry after \(retryAfter ?? 0)s")
case .circuitOpen(let endpoint):
print("Circuit open: \(endpoint)")
case .validation(let field, let msg):
print("Validation: \(field) — \(msg)")
default:
print(error.description)
}
}Architecture
- URLSession — Native Apple networking, no external dependencies
- Codable — Built-in JSON serialization with
convertToSnakeCase/convertFromSnakeCase - Actor-based circuit breaker — Thread-safe via Swift concurrency
- Checked continuation rate limiter — Backpressure without GCD
- AsyncStream — Auto-paginating
listAll()on Products and Customers - Sendable — All models conform to
Sendablefor safe cross-actor usage