MacPaw/OpenAI: the Swift package for calling the OpenAI API
Swift community driven package for OpenAI public API
At a glance
- What is it?
- MacPaw/OpenAI is a community Swift implementation of the OpenAI REST API, distributed through Swift Package Manager. It covers chat, responses, images, audio, embeddings and the Assistants beta, and its Configuration type is what lets it point at other OpenAI-compatible providers.
- Who is it for?
- Adopt MacPaw/OpenAI if you are shipping a Swift or Objective-C app and want typed request and response models instead of hand-rolled JSON, and if you accept that your API key belongs behind a backend proxy. Do not adopt it as a server-side gateway for many languages, and do not expect it to abstract away OpenAI-specific request shapes.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What MacPaw/OpenAI solves for Swift developers
If you write a Mac, iOS or server-side Swift app and want to call the OpenAI HTTP API, your options are to hand-write URLSession calls and Codable models for every endpoint, or to depend on a package that already did that. MacPaw/OpenAI is the second option. The README describes it as a "Swift community-maintained implementation over OpenAI public API", and the repository is organised around that claim: Sources/ holds the library, Tests/ holds the test target, Demo/ holds an Xcode demo app, and openapi.yaml sits at the top level as the specification the types are generated from. The intended reader is an app developer who wants to write `openAI.chats(query:)` and get a typed result back, not someone assembling raw JSON by hand. It is not a general-purpose HTTP client, and it is not a proxy: the README states plainly that production requests must be routed through your own backend server where the key can be loaded from an environment variable or key management service.
How the package is generated and how requests flow
The mechanism is worth understanding before you adopt it, because it shapes what the package can and cannot do. The top-level openapi.yaml is the OpenAI API specification, and openapi-generator-config.yaml plus the Makefile drive code generation from it. The Makefile is explicit that generation requires a local fork of swift-openapi-generator checked out as a sibling directory named swift-openapi-generator, and it lists three changes the fork must contain that the official generator did not have at the time of writing: handling OpenAPI 3.1 nullable schemas expressed as `anyOf: [<schema>, { type: null }]`, matching string enum values for oneOf discriminators that have no explicit mapping (the OpenAI spec uses runtime values such as `input_text` that do not match schema names such as `InputTextContent`), and falling back to structural decoding when inferred discriminator values collide, as they do for `message` across InputMessage and OutputMessage. That is a real dependency on a patched generator, not a cosmetic build detail. At runtime the flow is conventional: you construct an `OpenAI` instance, call a method, and the library issues the request and decodes the response. `OpenAI.Configuration` carries `host`, `basePath`, `port`, `scheme` and `customHeaders`, which is the hook that makes non-OpenAI endpoints possible.
Installing MacPaw/OpenAI with Swift Package Manager
The README gives two install paths. In Xcode you go to File > Add Package Dependencies, enter `https://github.com/MacPaw/OpenAI.git`, and choose a dependency rule such as "Up to Next Major Version". The README's Package.swift example instead pins the main branch, which is a different maintenance commitment: a branch rule tracks every push, while an up-to-next-major rule follows tagged releases such as 0.5.1 from 2026-07-21. Pick deliberately.
dependencies: [
.package(url: "https://github.com/MacPaw/OpenAI.git", branch: "main")
]After the dependency resolves, the entry point is the `OpenAI` class. The simplest form takes the token directly, and the README's own warning sits right next to it: do not expose the key in client-side code. For anything you ship, use the configuration initialiser and supply the token from a backend or a key management service.
let configuration = OpenAI.Configuration(token: "YOUR_TOKEN_HERE", organizationIdentifier: "YOUR_ORGANIZATION_ID_HERE", timeoutInterval: 60.0)
let openAI = OpenAI(configuration: configuration)With an instance in hand you can make a call. The README's cancellation example shows the shape of a chat request through Swift Concurrency, and the same example is where you see that a task cancellation propagates to the underlying URLSessionDataTask automatically.
let task = Task {
do {
let chatResult = try await openAIClient.chats(query: .init(messages: [], model: "asd"))
} catch {
// Handle cancellation or error
}
}
task.cancel()The `model: "asd"` string in that snippet is the README's own placeholder, not a valid model name; substitute a real one. If you use the closure-based methods instead of async/await, the call returns a discardable `CancellableRequest`, and you must hold that reference to cancel later. Combine users cancel by discarding the subscription or calling `cancel()` on it.
The relaxed parsing mode and what it buys you
The package is built for the OpenAI Platform, but the README states it also works with other providers that support an OpenAI-compatible API. The switch is a `.relaxed` parsing option on Configuration. This is the most interesting design decision in the package, because strict decoding against a generated spec is exactly what breaks when a third-party endpoint returns a slightly different shape or omits a field the spec marks required. Relaxed parsing trades type-level guarantees for tolerance. The trade-off is real in both directions: you get to point `host` and `basePath` at DeepSeek, Perplexity, OpenRouter, Gemini or a self-hosted gateway, and you accept that a malformed response may decode into a model with missing values rather than throwing. The README does not document which fields relaxed mode can leave absent, so if you depend on a specific field from a non-OpenAI provider, test that path yourself rather than assuming the option covers it.
Where the package stops being the right tool
Three limits stand out. First, the API key model. The README is unambiguous that keys can access and manipulate billing, usage and organisational data, and that client-side exposure is a significant risk. A Swift package that lives inside a shipped app bundle is client-side code. You can use this library in a server-side Swift service, and the Configuration type supports that, but if your architecture has no backend you are fighting the library's own guidance. Second, the generator fork. The Makefile requires a sibling checkout of a patched swift-openapi-generator to regenerate types, and it notes that the required changes were not in the official generator at the time of writing. If you only consume tagged releases this does not affect you, but anyone regenerating from a newer openapi.yaml inherits that setup. Third, coverage is bounded by the spec and by what the maintainers have wired up. The README's table of contents lists Assistants as Beta, and it documents no rollback or retry policy for failed requests. If you need automatic retries with backoff, or a provider-agnostic abstraction across several vendors, this package does not claim to give you either.
MacPaw/OpenAI compared with the official openai-python client
The obvious alternative for many teams is the official Python client, and the difference is not quality but environment. openai-python is a first-party library for a language whose install story is a package manager command, and it is the natural choice for scripts, notebooks, backend services and anything that is not a compiled Apple-platform binary. MacPaw/OpenAI exists because that client is not usable from Swift. If your product is a Mac app, an iOS app or a Swift server, the Python client is not an alternative at all; it is a second service you would have to run and call over HTTP. The reverse also holds: if your stack is Python, adopting a Swift package means introducing a separate binary or service boundary for no benefit. The honest framing is that these two libraries serve disjoint consumers, and the choice is made by your language, not by feature comparison. Within Swift, the meaningful decision is whether you want generated, spec-aligned types or a thinner hand-written wrapper, and the Makefile's generator notes are the clearest evidence that this project chose the generated route and pays its costs.
Licence, maintenance and the cost of upgrading
The licence is MIT, which permits commercial and closed-source use and requires preserving the copyright notice and permission text. That is a permissive arrangement, but it says nothing about the OpenAI API terms, the data you send, or the terms of any third-party provider you point the client at; those are separate agreements and this article is not legal advice. On maintenance, the repository is not archived and the last push was on 2026-09-14, three days before this writing, with releases 0.5.1 on 2026-07-21, 0.5.0 on 2026-06-05 and 0.4.9 on 2026-04-30. That cadence matters for upgrade planning because the package tracks a moving specification: when openapi.yaml changes, generated types can change with it, and a pinned branch rule will pick those changes up without a version bump. Pinning an up-to-next-major rule against tagged releases gives you a review point. There is also a maintenance obligation specific to this project: if you regenerate types, you need the forked generator as a sibling directory, so your build tooling has to track that fork rather than only the upstream project.
Editorial conclusion
Adopt MacPaw/OpenAI if you are shipping a Swift or Objective-C app and want typed request and response models instead of hand-rolled JSON, and if you accept that your API key belongs behind a backend proxy. Do not adopt it as a server-side gateway for many languages, and do not expect it to abstract away OpenAI-specific request shapes. Before you commit, verify the branch or version rule you pin in Package.swift, confirm the Configuration keys for any non-OpenAI host you plan to call, and read the Makefile note about the forked swift-openapi-generator, because that fork is what the generated types depend on.
Frequently asked questions
How do I install MacPaw/OpenAI in an Xcode project?
Go to File > Add Package Dependencies, enter https://github.com/MacPaw/OpenAI.git, and choose a dependency rule such as Up to Next Major Version. The README also shows adding the package directly to Package.swift, though its example pins the main branch rather than a release.
How do I use the OpenAI API key with MacPaw/OpenAI?
You initialise the OpenAI class with the token, or pass it through OpenAI.Configuration along with an optional organizationIdentifier and timeoutInterval. The README warns that the key is a secret and that production requests should go through your own backend server rather than shipping the key inside a client app.
How do I use the OpenAI API from Swift with MacPaw/OpenAI?
After adding the package and creating an OpenAI instance, you call methods on it such as chats(query:) and await the typed result, or use the closure-based variants that return a CancellableRequest. For Swift Concurrency calls, cancelling the calling task also cancels the underlying URLSessionDataTask.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/macpaw-openai)