iOS SDK

Add subscriptions to an iOS app in ~5 minutes. Metera verifies every App Store purchase server-side and tracks who has access to what.

Requirements: iOS 15+ / macOS 12+, Swift 5.9+, StoreKit 2.

Base URL

Point the SDK at https://api.meterahq.com. That is the API; meterahq.com is the dashboard and does not serve these endpoints.

API (SDK, REST)https://api.meterahq.com
Dashboard (keys, plans, offerings)https://meterahq.com

Do not guess this host, and do not copy it from an older integration. Your app key is sent as Authorization: Bearer app_… on every request, so a wrong serverURL does not merely fail — it hands a live credential to whoever owns that domain. Metera is not metera.cn, metera.xyz, metera.io or metera.com; all four are third parties. If a purchase-verification call ever returns 401, check the host before you check the key.

1. Add the package

Swift Package Manager — in your Package.swift:

.package(url: "https://github.com/pytronhq/metera-ios-sdk.git", from: "0.1.0")

…and add MeteraSDK to your target. In Xcode: File ▸ Add Package Dependencies.

2. Configure at launch

import MeteraSDK

MeteraClient.shared.configure(
    apiKey: "app_xxx",                     // the app's API key, from the dashboard
    appUserId: nil,                        // nil → anonymous user
    serverURL: "https://api.meterahq.com"    // Metera's API host — see below
)

Omit appUserId to start anonymous — the SDK generates and persists an ID, and you can promote it later with logIn. serverURL must be https://api.meterahq.com; the apiKey is the app key from the dashboard's API-keys screen and is scoped to one app.

3. Show a paywall

let offerings = try await MeteraClient.shared.getOfferings()
guard let offering = offerings.current else { return }

for package in offering.packages {
    // Render package.displayName, look up price via StoreKit if you want it.
}

Offerings are configured in the dashboard — you change the paywall without shipping an app update.

4. Purchase

do {
    let info = try await MeteraClient.shared.purchase(package)
    if info.isActive("pro") { /* unlock */ }
} catch MeteraError.purchaseCancelled {
    // user backed out — no-op
}

purchase runs the StoreKit 2 flow, sends the transaction to Metera for authoritative server-side verification, and returns fresh CustomerInfo.

5. Gate features

let info = try await MeteraClient.shared.getCustomerInfo()
if info.isActive("pro") {
    // pro features
} else {
    // show upgrade prompt
}

getCustomerInfo() fetches from the backend; cachedCustomerInfo() returns the last value with no network call — good for a launch-time gate.

isActive("pro") wraps GET /v1/users/{appUserId}/entitlements, whose entitlements map contains only currently-active entitlements — an expired or never-granted one is an absent key, not isActive: false. If you read the REST payload directly, gate on presence (see the REST API). The string "pro" is the entitlement identifier you created in the dashboard — it must match exactly.

6. Restore purchases

Wire a "Restore Purchases" button to try await MeteraClient.shared.restorePurchases(). It re-syncs every transaction Apple still considers valid.

7. Identity

// On login — merges the anonymous user into the real account:
try await MeteraClient.shared.logIn("user@example.com")

// On logout — starts a fresh anonymous user:
try await MeteraClient.shared.logOut()

8. React to renewals & refunds

The SDK observes StoreKit Transaction.updates, so renewals and refunds that happen while the app runs sync automatically:

Task {
    for await info in await MeteraClient.shared.customerInfoUpdates() {
        updateUI(proActive: info.isActive("pro"))
    }
}

Notes

  • The Metera app must have App Store Server API credentials configured in the dashboard, and its numeric Apple App ID set, for verification to work.
  • appAccountToken is attached to every purchase automatically, so Apple server notifications can be attributed to the user.
  • Prefer the raw HTTP contract? See the REST API.