SDK Reference
Swift SDK
Native Swift SDK for the Linkit API — async/await, Codable, URLSession, aligned with OpenAPI v1.
Swift SDK
Requirements
Swift 6.0+ (package tools version 6.0) · macOS 14+ · iOS 17+ · watchOS 10+ · tvOS 17+ · Pure Foundation — zero external dependencies.
Base URL
Pass the origin only (no trailing slash), for example https://linkit.works. All service methods use full paths such as /api/v1/products.
If you still pass https://linkit.works/api/v1, the client automatically strips the /api/v1 suffix so paths are not doubled.
Installation
Swift Package Manager
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/linkit-sa/linkit-swift-sdk", from: "0.2.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",
jwtToken: "your-jwt-token"
)
// Product
let product = try await client.products.create(
ProductRequest(ivId: "P-001", nameEn: "Aspirin 500mg", averagePrice: 12.50)
)
// SKU (quantities use API field `qty`; availability uses `available`)
let sku = try await client.skus.create(
SKURequest(ivId: "S-001", branchIvId: "BR-RYD", productIvId: "P-001",
price: 29.99, qty: 150, available: true)
)
// List SKUs (response uses `items`, exposed also as `data`)
let skuPage = try await client.skus.list(branchIvId: "BR-RYD", enabled: true)
for row in skuPage.data {
print("\(row.ivId): qty=\(row.qty ?? 0)")
}Configuration
let config = LinkitConfiguration(
baseUrl: "https://linkit.works",
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 overview
| Accessor | Highlights |
|---|---|
products | CRUD, list / listAll, bulk, fixMissingSkus() |
skus | Create returns envelope data; get/update/delete optional branchIvId query; updateStock (qty / available); bulk |
branches | List (branches + pagination), create/update (refetch), bulk, updateWorkingHours |
customers | CRUD, lookup, search, addresses, customer-groups |
orders | List (orders + pagination), create, update, updateStatus, bulkCreate (JSON array), bulkDelete, bulkUpdateStatus, analyticsSummary() / export() → Data |
offers | CRUD, status, bulk, analyticsReport(days:) → Data |
brands | CRUD by brand code path, bulk, updateProducts |
categories | CRUD by category code, tree, move, updateProducts, list filters |
generics | CRUD by generic code, bulk, search(body:), clearCache() |
integrations | listApps() (GET /api/v1/apps), getConfig / execute / executeBatch with organizationId + slug |
health | check(), system(), ping(), telemetry() → Data |
Branches & working hours
let branches = try await client.branches.list(page: 1, limit: 20, search: "Riyadh")
for b in branches.data {
print(b.ivId ?? "", b.nameEn ?? "", b.active ?? false)
}
let periods = [WorkingHoursPeriod(weekDay: "Monday", openHour: 9, openMinute: 0, closeHour: 17, closeMinute: 0)]
let body = BranchWorkingHoursBody(workingHours: periods)
let wh = try await client.branches.updateWorkingHours("BR-001", body: body)Integrations (org + slug)
let apps = try await client.integrations.listApps()
let cfg = try await client.integrations.getConfig(organizationId: "org_123", slug: "salla")
let run = try await client.integrations.execute(
organizationId: "org_123",
slug: "salla",
request: IntegrationExecuteRequest(fullSync: true)
)
let batch = try await client.integrations.executeBatch(
organizationId: "org_123",
request: BatchExecuteRequest(slugs: ["salla", "zid"], maxConcurrent: 2)
)Orders (bulk + analytics)
let page = try await client.orders.list(status: "confirmed", sort: "-created")
for o in page.data { print(o.id, o.orderStatus ?? "") }
let created = try await client.orders.create(
OrderRequest(
currency: "SAR",
customerName: "Ahmad Ali",
destination: "BR-RYD",
fulfillmentMethod: "delivery",
fulfillmentStatus: "pending",
orderStatus: "pending",
paymentMethod: "cash",
paymentStatus: "pending",
skus: ["sku_iv_1"],
source: "pos",
sourceTimeStamp: ISO8601DateFormatter().string(from: .now),
sourceTransactionId: "txn-001",
totalAmount: 120.0
)
)
let bulkStatus = try await client.orders.bulkUpdateStatus(
OrderBulkStatusRequest(
orderIds: ["ord_1", "ord_2"],
status: OrderStatusUpdateRequest(orderStatus: "shipped")
)
)
let analyticsJSON = try await client.orders.analyticsSummary(from: "2026-01-01T00:00:00Z", to: "2026-04-01T00:00:00Z")Health & telemetry
let health = try await client.health.check()
let sys = try await client.health.system()
let pong = try await client.health.ping()
let telem = try await client.health.telemetry() // decode JSON in your appError 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
- Codable — JSON with
convertToSnakeCase/convertFromSnakeCaseon the HTTP layer - Actor-based circuit breaker — Thread-safe via Swift concurrency
- Checked continuation rate limiter — Backpressure without GCD
- AsyncStream — Auto-paginating
listAll()on products and customers where supported