> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encorekit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# placement()

> Create and present Encore offers with a fluent API

## Purpose

Create and present Encore offers using a fluent API that fits naturally in SwiftUI and UIKit. Purchase handling and passthrough logic are managed by app-level handlers — see [onPurchaseRequest()](./on-purchase-request) and [onPassthrough()](./on-passthrough).

## Signature

```swift theme={null}
public func placement(_ id: String? = nil) -> any PlacementBuilderProtocol
```

`placement(_:)` returns a value conforming to `PlacementBuilderProtocol`. Build it from any thread, then call `show()`:

```swift theme={null}
public protocol PlacementBuilderProtocol {
    var id: String { get }

    /// Presents the offer sheet and returns the outcome. Throws on transport/SDK errors.
    func show() async throws -> PresentationResult

    /// Fire-and-forget presentation (wraps the async form in a Task).
    func show()
}
```

<Note>
  `Encore.shared.placement(_:)` and the static `Encore.placement(_:)` are equivalent — the static form just forwards to the shared instance.
</Note>

## Methods

| Method                | Parameters    | Description                                                                                                                                                                                              |
| --------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `placement(_:)`       | `id: String?` | Creates a placement builder with an optional identifier. If omitted, a unique ID is auto-generated.                                                                                                      |
| `show() async throws` | None          | Presents the offer sheet and returns a [`PresentationResult`](./presentation-result). Throws an [`EncoreError`](./errors) on transport / SDK failure. Presentation runs on the main actor automatically. |
| `show()`              | None          | Fire-and-forget variant — presents the sheet and discards the result/errors. Use the `async throws` form when you need the outcome.                                                                      |

## Usage Patterns

### Cancellation Flow (fire-and-forget)

```swift theme={null}
Button("Cancel Subscription") {
    Encore.shared.placement("cancellation_flow").show()
}
```

<Tip>
  Provide a placement ID to identify this specific placement in analytics and in your `onPassthrough` handler.
</Tip>

### Async/Await Pattern

```swift theme={null}
Button("Cancel Subscription") {
    Task {
        do {
            let result = try await Encore.shared.placement("cancellation_flow").show()
            switch result {
            case .granted(let entitlement):
                print("User accepted: \(entitlement)")
            case .notGranted(let reason):
                proceedWithCancellation(reason: reason)
            }
        } catch let error as EncoreError {
            // Transport / SDK failure — never block the user.
            print("Encore error: \(error.errorDescription ?? "")")
            proceedWithCancellation(reason: nil)
        }
    }
}
```

<Info>
  `show()` is `@MainActor`-driven — presentation always happens on the main thread. From a synchronous SwiftUI `Button` or UIKit `@IBAction`, wrap the `await` call in a `Task { }`.
</Info>
