A Swift client for the Penpot RPC API with async/await, automatic retry with exponential backoff, and SVG shape reconstruction.
- Penpot RPC API client (get-file, get-profile, get-file-object-thumbnails)
- Automatic retry with exponential backoff (429/5xx)
- SVG reconstruction from shape trees (path, rect, circle, group, frame, bool)
- Component thumbnail downloads via presigned URLs
- Swift 6 strict concurrency
- Linux compatible
- Swift 6.1+
- macOS 13+ / Linux (Ubuntu 22.04+)
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/DesignPipe/swift-penpot-api.git", from: "0.1.0"),
]Then add PenpotAPI to your target dependencies:
.target(
name: "YourTarget",
dependencies: [
.product(name: "PenpotAPI", package: "swift-penpot-api"),
]
)import PenpotAPI
// Create a client
let client = BasePenpotClient(
accessToken: "your-penpot-token",
baseURL: "https://design.penpot.app/"
)
// Fetch a file with colors, typographies, and components
let file = try await client.request(GetFileEndpoint(fileId: "file-uuid"))
// Access colors
for (_, color) in (file.data.colors ?? [:]).sorted(by: { $0.key < $1.key }) {
print("\(color.name): \(color.color ?? "gradient")")
}
// Access typographies
for (_, typo) in (file.data.typographies ?? [:]).sorted(by: { $0.key < $1.key }) {
print("\(typo.name): \(typo.fontFamily) \(typo.fontSize)")
}
// Render component SVG from shape tree
if let page = file.data.pagesIndex?[component.mainInstancePage ?? ""],
let objects = page.objects {
let svg = PenpotShapeRenderer.renderSVG(objects: objects, rootId: component.mainInstanceId ?? "")
}
// Download component thumbnail
let data = try await client.download(path: "assets/by-id/\(thumbnailId)")
// Get current user profile
let profile = try await client.request(GetProfileEndpoint())PenpotEndpointprotocol — RPC-style:POST /api/main/methods/<commandName>PenpotClientprotocol +BasePenpotClient— URLSession, auth, retryPenpotAPIError— LocalizedError with recovery suggestionsPenpotShapeRenderer— SVG reconstruction from Penpot's shape tree
Two equivalent paths exist:
/api/main/methods/<name>— used by this library; works with URLSession against design.penpot.app/api/rpc/command/<name>— official docs path; blocked by Cloudflare JS challenge on design.penpot.app
Self-hosted Penpot instances (without Cloudflare) accept both paths.
MIT