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

# Dart and Flutter Storefront SDK

> Build typed Flutter storefronts against the public Crave Storefront API.

`crave_storefront_sdk` is the official Dart client for Flutter mobile, web, and desktop storefronts.
It exposes the same reviewed `/api/v1/storefront` contract as
[`@craveup/storefront-sdk`](/getting-started/storefront-sdk), with Dart-native models, cancellation,
timeouts, and typed exceptions. It contains no UI, Flutter, or native runtime dependency.

## Install the exact release

```yaml pubspec.yaml theme={null}
dependencies:
  crave_storefront_sdk: 0.2.0
```

Run `flutter pub get`. Dart-only consumers can run `dart pub get` instead.

## Configure one environment and merchant

```dart theme={null}
import 'package:crave_storefront_sdk/crave_storefront_sdk.dart';

final client = CraveStorefrontClient(
  baseUri: Uri.parse('https://api.craveup.com'),
  merchantSlug: 'downtown-pizza',
  sessionStore: secureSessionStore,
  customerTokenProvider: () async => currentCustomerJwt,
);
```

Use the exact sandbox API origin provided for your account in sandbox builds. Production and
sandbox are separate deployments with separate environment variables, credentials, and data; do
not add a runtime environment switch to a production app. The client accepts plain HTTP only for
exact loopback hosts during local development.

`StorefrontSessionStore` is application-owned. In production, implement it with encrypted platform
storage and isolate records by the supplied API-origin, merchant, and location scope. The included
`InMemoryStorefrontSessionStore` is only for tests and ephemeral demos. Keep customer JWTs in your
authentication layer, not in the cart session store.

## Check ordering readiness

Check availability before presenting an ordering action. This anonymous GET does not create a cart:

```dart theme={null}
final readiness = await client.locations.getOrderingReadiness(
  locationId,
  fulfillmentMethod: FulfillmentMethod.takeout,
);

switch (readiness) {
  case OrderingReady():
    showStartOrder();
  case OrderingUnavailable(:final reason):
    showOrderingUnavailable(reason);
}
```

## Handle typed failures

```dart theme={null}
try {
  final menu = await client.menus.getForLocation(locationId, menuOnly: true);
  renderMenu(menu);
} on StorefrontApiException catch (error) {
  reportSafeFailure(error.code, error.status, error.requestId);
} on StorefrontTimeoutException {
  showRetryMessage();
} on StorefrontRequestCancelledException {
  // The owning screen was disposed or the shopper cancelled the action.
}
```

The exception contract excludes resolved URLs, headers, request bodies, customer data, and payment
values. Cart mutations are never retried implicitly. After `CART_CONFLICT`, re-read the cart,
reconcile the new revision, and let the shopper confirm the next mutation.

Close the client when its application-level owner is disposed:

```dart theme={null}
client.close();
```

<Card title="Build a Flutter storefront" icon="smartphone" href="/quickstarts/flutter">
  Install the package, configure secure session storage, load a menu, and start an order.
</Card>
