iOS SDK

Swift / iOS

Integrate Meridian chat completions into your native iOS app using URLSession and Codable models. Zero external dependencies — just Foundation.

Quickstart

import Foundation

// 1. Define request/response models
struct ChatMessage: Codable {
    let role: String
    let content: String
}

struct ChatRequest: Codable {
    let model: String
    let messages: [ChatMessage]
    let stream: Bool
}

struct Choice: Codable {
    let message: ChatMessage
}

struct ChatResponse: Codable {
    let choices: [Choice]
}

// 2. Build and send the request
func complete(apiKey: String, prompt: String) async throws -> String {
    let url = URL(string: "https://api.getnimbus.net/v1/chat/completions")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

    let body = ChatRequest(
        model: "meridian-1",
        messages: [ChatMessage(role: "user", content: prompt)],
        stream: false
    )
    request.httpBody = try JSONEncoder().encode(body)

    let (data, _) = try await URLSession.shared.data(for: request)
    let decoded = try JSONDecoder().decode(ChatResponse.self, from: data)
    return decoded.choices.first?.message.content ?? ""
}

Streaming

For real-time token delivery, set stream: true and consume the SSE response line-by-line with URLSession.bytes.

func streamComplete(apiKey: String, prompt: String) async throws {
    let url = URL(string: "https://api.getnimbus.net/v1/chat/completions")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")

    let body = ChatRequest(
        model: "meridian-1",
        messages: [ChatMessage(role: "user", content: prompt)],
        stream: true
    )
    request.httpBody = try JSONEncoder().encode(body)

    let (bytes, _) = try await URLSession.shared.bytes(for: request)
    for try await line in bytes.lines {
        guard line.hasPrefix("data: ") else { continue }
        let json = line.dropFirst(6)
        if json == "[DONE]" { break }
        if let data = json.data(using: .utf8),
           let chunk = try? JSONDecoder().decode(ChatResponse.self, from: data),
           let content = chunk.choices.first?.message.content {
            print(content, terminator: "")
        }
    }
}

Error Handling

struct APIError: Codable {
    let error: ErrorDetail
    struct ErrorDetail: Codable {
        let message: String
        let code: String
    }
}

func safeComplete(apiKey: String, prompt: String) async -> Result<String, Error> {
    do {
        let result = try await complete(apiKey: apiKey, prompt: prompt)
        return .success(result)
    } catch {
        // URLSession errors, decoding failures, and non-2xx
        // responses all surface here. Inspect the status code
        // from the HTTPURLResponse for rate-limit (429) or
        // auth failures (401).
        return .failure(error)
    }
}