Swift 6.4 URLSession: poll a Sume job with async/await

Swift 6.4 shipped on 15 September 2026. An async URLSession loop for GET /v1/jobs/:id/status that honors next_poll_after_seconds and a 20-minute deadline.

5 min readSume
All posts

Short answer

Decode the status envelope into a small Decodable, call try await URLSession.shared.data(for:) in a loop bounded by a deadline, and sleep for next_poll_after_seconds until terminal is true. The Swift blog announced Swift 6.4 on 15 September 2026, describing it as deepening support across apps, servers, systems code, embedded devices and the browser.

The contract is Sume's jobs and results guide: every submit returns a job id, and the status endpoint tells the client when to look again. Nothing here needs an SDK; the only Sume SDK the docs describe is the TypeScript one.

What the blog post says

The visible excerpt of the announcement is short. It does not list API-level changes to URLSession, so the sample uses only long-standing async APIs and compiles on recent toolchains.

Swift 6.4 facts from the announcement (read 2026-10-03)
ItemDetail
Release date15 September 2026
Positioningapps, servers, systems code, embedded devices and the browser
Related notemodule tracking in debug info began in Swift 6.3 and continues in 6.4

The loop

Save the file as main.swift and run it with SUME_API_KEY=... swift main.swift job_123. Top-level await is allowed in main.swift. A request timeout of 20 seconds bounds one read; the 20-minute deadline bounds the whole wait and is yours, not Sume's.

import Foundation

struct Status: Decodable {
    struct Body: Decodable {
        let terminal: Bool
        let sume_status: String
        let next_poll_after_seconds: Double?
    }
    let data: Body
}

var req = URLRequest(url: URL(string: "https://api.sume.com/v1/jobs/\(CommandLine.arguments[1])/status")!)
req.timeoutInterval = 20
req.setValue("Bearer " + (ProcessInfo.processInfo.environment["SUME_API_KEY"] ?? ""),
             forHTTPHeaderField: "Authorization")

let deadline = Date().addingTimeInterval(20 * 60)
while Date() < deadline {
    let (data, response) = try await URLSession.shared.data(for: req)
    guard (response as? HTTPURLResponse)?.statusCode == 200 else {
        fatalError(String(decoding: data, as: UTF8.self))
    }
    let s = try JSONDecoder().decode(Status.self, from: data).data
    if s.terminal { print(s.sume_status); exit(0) }
    try await Task.sleep(for: .seconds(s.next_poll_after_seconds ?? 2))
}
print("deadline passed; the job is still running and still billing")

On an iPhone or Mac app

A background app can be suspended mid-wait. Persist the job id at submit time, and on relaunch read GET /v1/jobs/:id/status once to find out where the job is. Do not resubmit: a repeat of the paid request with a new key creates a second paid job. A retry of the same submit with the same Idempotency-Key returns the original.

For push-style delivery to your own backend, use mode: "webhook" and have the backend notify the app; the device never needs to verify the signature.

What Sume does and does not do

Sume keeps the job running regardless of the client, tells the client how long to wait through next_poll_after_seconds, and signs webhook deliveries. It does not push to devices and does not cancel a job when your deadline expires.

Reads draw from a read budget that is 40 times the write budget on every plan, so a two-second poll is cheap.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume