Compute
Use the Swift client
How the released Swift client is shaped, and why it is a different product from the separate application people install to help power approved network tasks.
Package and platform requirements
This page prints no package name and no minimum platform version. Both move with each release, so both are published on the compatibility matrix instead.
Read your row there before you add the dependency. It names the released package, its version, the platforms tested against it, and the protocol release it speaks.
Your base URL and current API version appear in the portal under developer settings, and in the API description you download.
This client is not the provider application
Two Lithi products get confused here, so keep them apart.
This client is for customers. It submits work, reads status, and downloads results, and it is the only one of the two you need to use Compute.
The separate application people install to help power approved network tasks is a different product, with a different audience and a different setup. Installing it changes nothing about what your account can submit, and not installing it costs you nothing.
How accepted work is actually carried out is not something any client configures or exposes. You describe the outcome you want, and you approve a price for it.
Submit work
The client mirrors the API namespaces, so a call site shows the authority it needs.
let quote = try await client.work.quote(taskSpec)
// A quote is non-authorizing. It carries an expiry and a signature.
try await approve(quote)
let job = try await client.work.run(quote)
Your taskSpec carries the same seven objects everywhere: workflow, input, parameters, quality, policy, output and limits.
Approval is always a separate act. Requesting a quote never starts work, and no client can collapse the two steps.
Await a terminal state
Terminal states are SUCCEEDED, PARTIAL, FAILED and CANCELLED. Everything else means keep waiting.
let status = try await client.work.status(jobID: job.id)
switch status.state {
case .succeeded, .partial: return try await readResult(job.id)
case .failed, .cancelled: return report(status.nextAction)
default: return try await poll(until: status.validUntil)
}
Take the exact type names from your release. Poll on the validUntil the response carries, not on an interval you chose.
Handle refusals and verify the result
Every operation carries its own generated error_schema, and every refusal carries a safe reason with a non-empty next action. Keep EDGE_ABUSE_LIMITED, CANONICAL_ADMISSION_LIMITED, CANONICAL_BUDGET_EXHAUSTED and CELL_CAPACITY_UNAVAILABLE in separate branches.
Read result-manifest.json before any part file. It is written last, and it is the only complete-bundle marker.
Then check the digests in provenance.json against what you submitted, and keep receipt.json with your own record. Read your row on the compatibility matrix and how to download and verify a result.