Skip to content

The Swift SDK

Everything in the CareersOrbit Swift package for iOS, macOS, tvOS and watchOS apps and server-side Swift, from setup and every method to applications, the candidate portal, errors and tests.

Reference5 min read

The Swift SDK, CareersOrbit, shows live jobs from the delivery API, takes applications with a CV and runs the candidate portal in iOS, iPadOS, macOS, tvOS and watchOS apps, and in server-side Swift. It does what the client in the JavaScript Careers SDK does, with the same errors. It is open source under the MIT licence.

  • async/await on URLSession, with no dependencies
  • Safe under Swift 6 strict concurrency: the clients and every model are Sendable
  • Codable models for every answer, with a JSONValue for a job's JobPosting data
  • Retries, timeouts and typed errors

It needs Swift 5.9 or later, and iOS 15, macOS 12, tvOS 15 or watchOS 8 or later.

Install

In Xcode, choose File › Add Package Dependencies… and enter https://github.com/bifrost-orbit/careers-sdk-swift, then add the CareersOrbit product.

In Package.swift:

Swift
dependencies: [    .package(url: "https://github.com/bifrost-orbit/careers-sdk-swift", from: "0.1.0"),],targets: [    .target(name: "App", dependencies: [.product(name: "CareersOrbit", package: "careers-sdk-swift")]),]

Set up

Create a public key under API keys. It can only read live jobs and send applications, so it is safe to ship in an app.

Swift
import CareersOrbitlet careers = try CareersOrbitClient(publicKey: "careers_pk_...", locale: "de")let list = try await careers.jobs(.init(remote: "hybrid", query: "guide"))for job in list.items {    print(job.title, job.locations.first?.city ?? "")}
publicKey
What it does
A public key, careers_pk_…. Required. Anything else is refused with CareersOrbitError.invalidPublicKey.
environment
What it does
.production (https://api.bifrostorbit.com/careers/v1, the default), .staging (https://api-stage.bifrostorbit.com/careers/v1) or .custom(url)
baseURL
What it does
Overrides the environment's address
locale
What it does
Used when a call names no language, such as de. Without it, the career site's main language answers.
timeout
What it does
Seconds per attempt. 5 by default.
retries
What it does
Extra attempts at a read after a failed connection or a 5xx answer. 2 by default. Applications are sent once.
session
What it does
The URLSession to use

Methods

jobs(CareersJobQuery)
Answers with
Live jobs, filtered by department, location, remote, type and query, with page and perPage
job(_:locale:)
Answers with
One job with its description, form, privacy notice and JobPosting data. Throws .notFound when it is closed or gone.
findJob(_:locale:)
Answers with
The same, or nil
filters(locale:)
Answers with
Departments, locations, job types and workplaces that have live jobs, with counts
site(locale:)
Answers with
The career site's name, introduction, logo, colours, languages and current privacy notice
sitemap()
Answers with
Every live job with its address in each language
apply(to:_:files:)
Answers with
Sends an application. A second one to the same job from the same email updates the first.
joinTalentPool(_:)
Answers with
Keeps someone's details for future jobs
trackJob(_:kind:source:utmSource:)
Answers with
Counts a view or an apply start for the reports. Never throws.
applicationURL(slug:)
Answers with
Where applications for the job are sent

Applications

Swift
let job = try await careers.job("mountain-guide-lofoten")let application = CareersApplication(    firstName: "Kari",    lastName: "Nordmann",    email: "kari@northwilds.com",    phone: "+47 912 34 567",    answers: ["q-years": 6, "q-areas": ["lofoten", "lyngen"], "q-first-aid": .yesNo(true)],    privacyVersion: job.privacy.version,    privacyAccepted: true,    source: "northwilds-app")let files = CareersApplicationFiles(cv: CareersFile(name: "kari-nordmann.pdf", data: cvData))let result = try await careers.apply(to: job.slug, application, files: files)

Send the standard fields job.form asks for (job.form.asks("phone")) and an answer for each question, keyed by its id. Choice answers are option ids. privacyAccepted must be true; the client refuses the application before sending it otherwise. Files are PDF or Word documents up to 10 MB.

Candidate portal

CareersPortalClient lets candidates sign in with an emailed code and follow their applications in your app. Keep the session token somewhere safe, such as the Keychain, by implementing CareersSessionStore; CareersMemorySession keeps it in memory.

Swift
let portal = try CareersPortalClient(publicKey: "careers_pk_...", locale: "de", session: KeychainSession())try await portal.requestCode(email: "solveig@northwilds.com")try await portal.signIn(email: "solveig@northwilds.com", code: "123456")if let me = try await portal.me(), let offer = me.offers.first(where: { $0.status == "open" }) {    _ = try await portal.openOffers()    _ = try await portal.acceptOffer(offer.id, acceptance: CareersOfferAcceptance(name: "Solveig Haugen", consent: true, documentHash: offer.documentHash ?? ""))}
requestCode(email:), signIn(email:code:), signOut()
What it does
Sign-in with a six-digit code. The session lasts two hours.
me()
What it does
Applications, offers, talent pool and requests, or nil when signed out
withdraw(applicationId:reason:), addDocument(applicationId:file:)
What it does
Change an open application
openOffers(), acceptOffer(_:acceptance:), declineOffer(_:reason:), offerPDF(_:)
What it does
Read, sign or decline an offer, and download it
exportData(), askToCorrect(_:), askToErase()
What it does
The candidate's data and data requests
stayInTalentPool(), leaveTalentPool()
What it does
Talent pool consent
stopTexts(_:)
What it does
Stops text messages on sms or whatsapp

Calls that change something answer with the whole CareersPortal again. A 401 throws .signedOut and clears the session store. Leave out publicKey when baseURL is your own server, which adds the key.

Errors

Everything throws CareersOrbitError, apart from CancellationError when the calling task is cancelled.

.notFound(message:)
When
404: no such job, or it isn't live
.unauthorized(message:)
When
401: the key was refused, revoked or has expired
.signedOut(message:)
When
401 from the portal: the candidate's session is missing or has expired
.rateLimited(retryAfter:message:)
When
429: wait retryAfter seconds
.subscriptionInactive
When
402: the organisation's Careers Orbit trial or plan has ended, so the career site is paused. Not retried. Check error.isSubscriptionInactive and show a calm "temporarily unavailable" message instead of the jobs.
.http(status:code:message:)
When
Any other 4xx, such as 422 invalid for a missing field
.server(status:message:)
When
5xx, after the retries
.unavailable(message:)
When
Careers Orbit could not be reached or did not answer in time, after the retries
.decoding(_:)
When
The answer did not match the type asked for
.invalidPublicKey, .invalidURL, .invalidInput
When
The client was set up wrongly, or an application was refused before it was sent

Messages are written for candidates, in the language of the request. See Troubleshooting.

Testing your app

Pass a URLSession whose configuration has your own URLProtocol in protocolClasses, and answer requests with JSON shaped like the delivery API. The SDK's own tests do this in Tests/CareersOrbitTests/StubProtocol.swift.

Was this page helpful?

Read next