Skip to content
Nuxie
Esc
navigateopen⌘Jpreview
On this page

Features & Entitlements

Check Feature Access and consume server-authoritative usage

Features are the app-facing access contract. Products and Entitlements determine why a Customer has access; app code checks the Feature external ID.

Check access

hasFeature() returns cached state while it is fresh and asks the server otherwise:

// nuxie-doc-fragment: basic-feature-access harness=async-body
let access = try await NuxieSDK.shared.hasFeature("premium_content")
if access.allowed {
    showPremiumContent()
} else {
    showUpgradePrompt()
}

For a fixed quota or credit-backed action, include the amount that the action requires:

// nuxie-doc-fragment: metered-feature-access harness=async-body
let access = try await NuxieSDK.shared.hasFeature(
    "ai_generations",
    requiredBalance: 5,
    entityId: "project-456"
)

if access.allowed {
    // This is presentation state only. Consume usage before the side effect.
    showEnabledGenerateButton()
}

Use the explicit policy when the distinction matters:

// nuxie-doc-fragment: feature-access-policies harness=async-body
let cachedFirst = try await NuxieSDK.shared.hasFeature(
    "premium_content",
    policy: .cacheFirst
)

let authoritative = try await NuxieSDK.shared.hasFeature(
    "premium_content",
    policy: .remote
)

.remote always asks the server. It is the appropriate check for a critical decision that cannot tolerate a cached profile.

Reactive SwiftUI access

features is one stable FeatureInfo observable for the SDK lifetime:

// nuxie-doc-snippet: observable-feature-view
import SwiftUI
import Nuxie

struct PremiumView: View {
    @ObservedObject private var features = NuxieSDK.shared.features

    var body: some View {
        if features.isAllowed("premium_content") {
            PremiumContent()
        } else {
            UpgradePrompt()
        }
    }
}

FeatureInfo provides synchronous reads of authenticated cached state:

Method or property Meaning
all All cached access values keyed by Feature external ID.
isAllowed(_:) Whether the cached Feature allows access.
hasBalance(_:) Whether access is unlimited or has positive balance.
balance(_:) Cached metered balance, when present.
feature(_:) Full cached FeatureAccess, when present.

Server-authoritative quotas and credits

Boolean Features and unlimited metered Features can become available immediately from authenticated local purchase state. Fixed quotas and credits are always server-authoritative. The SDK never invents, decrements, or exposes a temporary local balance as authority.

Call useFeatureAndWait() before the protected side effect:

// nuxie-doc-fragment: consume-feature-and-wait harness=async-body
let result = try await NuxieSDK.shared.useFeatureAndWait(
    "ai_generations",
    amount: 1,
    entityId: "project-456"
)

guard result.success else { return }

let remaining = result.authoritativeAccess?.balance
    ?? result.usage?.remaining
proceedWithGeneration(remaining: remaining)

Immediately after a native App Store purchase, this command may attach the one safely matching protected transaction. The server verifies the purchase, grants the allowance, and consumes the requested amount as one idempotent operation. A timeout retains the protected evidence and reuses the same idempotency identity on retry.

If no unique transaction matches, the SDK submits an ordinary authoritative usage command without exposing receipt material. This includes provider-owned checkout, Test Store purchases, another Customer’s transaction, and ambiguous pending transactions. RevenueCat, Superwall, and custom-provider balances arrive through the reviewed Connector synchronization path.

Fire-and-forget reporting

useFeature() starts the same authoritative request in a background task and logs any failure:

// nuxie-doc-fragment: enqueue-feature-usage harness=sync-body
NuxieSDK.shared.useFeature(
    "analytics_event",
    amount: 1,
    metadata: ["source": "settings"]
)

Use it only when the protected side effect does not depend on the result. It cannot authorize quota- or credit-backed work because the caller cannot observe whether the server accepted the deduction.

Change notifications

Set NuxieSDK.shared.delegate to receive featureAccessDidChange after a profile, Feature check, identity change, or purchase synchronization updates cached state:

// nuxie-doc-snippet: feature-access-observer
import Nuxie

@MainActor
final class FeatureObserver: NuxieDelegate {
    func featureAccessDidChange(
        _ featureId: String,
        from oldValue: FeatureAccess?,
        to newValue: FeatureAccess
    ) {
        print("Feature \(featureId) allowed: \(newValue.allowed)")
    }
}

Next steps

Last updated on August 20, 2026

Was this page helpful?