# Build a Storefront

> Integrate Infuse-Marketplace apps and algorithms, device selection, Stripe Checkout, purchases, and installs into your own customer site.

Use the Infuse Cloud dashboard to create and manage listings first. Build a custom storefront only when you need to resell embedded apps and algorithms from your own website or application.

Your storefront owns the customer experience: item browsing, customer authentication, device selection, post-checkout status, and install actions. Infuse remains the source of truth for published apps and algorithms, checkout sessions, purchase entitlements, linked Infuse IoT release compatibility, and install access.

## Dashboard Setup

Before integrating a custom storefront:

1. Open **Infuse-Marketplace**.
2. Select the marketplace instance.
3. Open **Provider**.
4. Open **Discover** and choose apps or algorithms to sell.
5. Create listings for those items.
6. Open **Listings** and confirm each listing is active.
7. Open **Purchases** to understand how completed purchases are reviewed.
8. Open **Devices** to understand device state and install actions.

The dashboard is the operational control surface for apps, algorithms, listings, purchases, and installs. **Store Preview** can be useful later as a manual example of listing selection and checkout session creation, but a production storefront should use your own backend boundary so provider credentials never run in the customer browser.

At a high level, your backend reads listed apps and algorithms from Infuse, creates a checkout session for the selected items and devices, redirects the customer to Stripe Checkout, then reads purchase state from Infuse after Stripe confirms payment.

## How the Integration Works

Your storefront should call Infuse APIs from your server. Do not call Infuse-Marketplace APIs directly from customer browsers with provider credentials.

For manual dashboard verification of checkout states, see [Checkout Flow](/docs/marketplace/providers/checkout-flow).

<mermaid :config="config" :toolbar="{"title":"Storefront checkout flow"}" code="---%0Atoolbar%3A%0A%20%20title%3A%20Storefront%20checkout%20flow%0A---%0AsequenceDiagram%0A%20%20%20%20participant%20Customer%20as%20End%20customer%0A%20%20%20%20participant%20Frontend%20as%20Your%20storefront%20frontend%0A%20%20%20%20participant%20Backend%20as%20Your%20backend%0A%20%20%20%20participant%20Infuse%20as%20Infuse-Marketplace%20API%0A%20%20%20%20participant%20Stripe%20as%20Stripe%20Checkout%0A%0A%20%20%20%20Customer-%3E%3EFrontend%3A%20Opens%20storefront%0A%20%20%20%20Frontend-%3E%3EBackend%3A%20Request%20catalogue%0A%20%20%20%20Backend-%3E%3EInfuse%3A%20List%20published%20marketplace%20items%0A%20%20%20%20Infuse--%3E%3EBackend%3A%20Items%2C%20prices%2C%20images%2C%20metadata%0A%20%20%20%20Backend--%3E%3EFrontend%3A%20Storefront%20catalogue%20data%0A%20%20%20%20Frontend--%3E%3ECustomer%3A%20Show%20listed%20apps%20and%20algorithms%0A%20%20%20%20Customer-%3E%3EFrontend%3A%20Select%20items%20and%20devices%0A%20%20%20%20Frontend-%3E%3EBackend%3A%20Start%20checkout%0A%20%20%20%20Backend-%3E%3EInfuse%3A%20Create%20checkout%20session%0A%20%20%20%20Infuse--%3E%3EBackend%3A%20checkoutSessionId%20and%20checkoutUrl%0A%20%20%20%20Backend--%3E%3EFrontend%3A%20checkoutUrl%0A%20%20%20%20Frontend--%3E%3ECustomer%3A%20Redirect%20to%20Stripe%20Checkout%0A%20%20%20%20Customer-%3E%3EStripe%3A%20Complete%20or%20cancel%20payment%0A%20%20%20%20Stripe--%3E%3ECustomer%3A%20Redirect%20to%20your%20success%20or%20cancel%20URL%0A%20%20%20%20Infuse-%3E%3EInfuse%3A%20Validate%20payment%20and%20create%20entitlements%0A%20%20%20%20Frontend-%3E%3EBackend%3A%20Load%20purchase%20status%0A%20%20%20%20Backend-%3E%3EInfuse%3A%20Read%20provider%20purchases%0A%20%20%20%20Infuse--%3E%3EBackend%3A%20Purchase%20and%20entitlement%20state%0A%20%20%20%20Backend--%3E%3EFrontend%3A%20Confirmation%2C%20pending%2C%20or%20error%20state">



</mermaid>

## Before You Start

You need:

- An Infuse organisation with access to the marketplace instance you want to sell from.
- Server-side API credentials for that organisation.
- Permissions for published catalogue reads, checkout session creation, provider devices, provider purchases, and install access if your site will trigger installs.
- The `marketplaceInstanceId` for the marketplace instance your storefront should display.
- Absolute `successUrl` and `cancelUrl` routes hosted by your site.
- A way to map signed-in customers in your system to one or more Infuse device IDs.

Keep API credentials on your backend. Your frontend should receive only the item, device, checkout, and purchase data needed to render the customer experience.

## Recommended Backend Boundary

Expose your own customer-facing routes and keep Infuse authentication behind them. For example:

<table>
<thead>
  <tr>
    <th>
      Your route
    </th>
    
    <th>
      Infuse API used by your backend
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        GET /storefront/items
      </code>
    </td>
    
    <td>
      <code>
        GET /marketplace/marketplace-items
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        GET /storefront/items/:id
      </code>
    </td>
    
    <td>
      <code>
        GET /marketplace/marketplace-items/{id}
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        GET /storefront/devices
      </code>
    </td>
    
    <td>
      Your device system or <code>
        GET /marketplace/providers/devices
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        POST /storefront/checkout
      </code>
    </td>
    
    <td>
      <code>
        POST /marketplace/checkout/session
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        GET /storefront/purchases
      </code>
    </td>
    
    <td>
      <code>
        GET /marketplace/providers/purchases
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        POST /storefront/devices/:deviceId/items/:itemId/install
      </code>
    </td>
    
    <td>
      <code>
        POST /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/install
      </code>
    </td>
  </tr>
</tbody>
</table>

This boundary lets you enforce your own customer authentication, hide provider credentials, validate selected devices belong to the signed-in customer, and store local audit records such as the returned `checkoutSessionId`.

## 1. Load Listed Apps and Algorithms

Use the public marketplace item APIs to build your catalogue and item detail pages.

```http
GET /marketplace/marketplace-items?marketplaceInstanceId={marketplaceInstanceId}&page=1&pageSize=24
Authorization: Bearer {provider_access_token}
```

Common query fields:

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th align="right">
      Required
    </th>
    
    <th>
      Use
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        marketplaceInstanceId
      </code>
    </td>
    
    <td align="right">
      Yes
    </td>
    
    <td>
      Selects the marketplace instance to display.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        page
      </code>
    </td>
    
    <td align="right">
      No
    </td>
    
    <td>
      Page number for pagination.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pageSize
      </code>
    </td>
    
    <td align="right">
      No
    </td>
    
    <td>
      Number of items per page.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search
      </code>
    </td>
    
    <td align="right">
      No
    </td>
    
    <td>
      Text search for storefront search boxes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type
      </code>
    </td>
    
    <td align="right">
      No
    </td>
    
    <td>
      Filters by marketplace item type when your UI separates apps, algorithms, or other item categories.
    </td>
  </tr>
</tbody>
</table>

For an item detail page, fetch the current listed item before showing price or allowing checkout.

```http
GET /marketplace/marketplace-items/{id}?marketplaceInstanceId={marketplaceInstanceId}
Authorization: Bearer {provider_access_token}
```

Use Infuse as the source of truth for marketplace item IDs, listing visibility, price, currency, linked release metadata, icons, images, and developer-provided descriptions. If you cache catalogue data, refresh it before checkout so you do not sell an item that has changed price or visibility.

## 2. Resolve Customer Devices

Checkout sessions are created for one or more target devices. Your storefront must know which devices the customer can buy for before creating checkout.

Most providers resolve this through their own account system:

1. Authenticate the customer in your site.
2. Load the customer-owned devices from your system.
3. Map each selectable device to the corresponding Infuse `deviceId`.
4. Send only valid selected `deviceIds` to your checkout route.

If the devices are registered in your provider Infuse-IoT Cloud organisation, your backend can also read provider devices from Infuse:

```http
GET /marketplace/providers/devices?limit=50&offset=0
Authorization: Bearer {provider_access_token}
```

Before checkout, validate that you have:

- At least one selected `deviceId`.
- At least one selected `marketplaceItemId`.
- A signed-in customer who is allowed to buy for those devices.
- Current item data from Infuse for the selected marketplace items.

## 3. Create a Checkout Session

When the customer confirms their basket, create an Infuse checkout session from your backend.

```http
POST /marketplace/checkout/session
Authorization: Bearer {provider_access_token}
Content-Type: application/json

{
  "deviceIds": ["device_123", "device_456"],
  "marketplaceItemIds": ["mi_abc"],
  "successUrl": "https://example.com/marketplace/checkout/success",
  "cancelUrl": "https://example.com/marketplace/checkout/cancel",
  "livemode": true
}
```

The request includes:

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Use
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        deviceIds
      </code>
    </td>
    
    <td>
      Devices the purchase applies to.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        marketplaceItemIds
      </code>
    </td>
    
    <td>
      Infuse-Marketplace items selected by the customer.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        successUrl
      </code>
    </td>
    
    <td>
      Absolute URL Stripe redirects to after successful checkout.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cancelUrl
      </code>
    </td>
    
    <td>
      Absolute URL Stripe redirects to if the customer cancels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        livemode
      </code>
    </td>
    
    <td>
      Use <code>
        true
      </code>
      
       for production transactions and <code>
        false
      </code>
      
       for test or preview purchases where available.
    </td>
  </tr>
</tbody>
</table>

The response includes:

```json
{
  "checkoutSessionId": "mcs_123",
  "checkoutUrl": "https://checkout.stripe.com/c/session...",
  "livemode": true
}
```

Store the `checkoutSessionId` with your local order, customer action, or audit record if you need reconciliation. Then redirect the customer to `checkoutUrl`.

## 4. Redirect to Stripe Checkout

Infuse creates the Stripe Checkout session. Your integration should not create Stripe catalogue objects, prices, line items, or fulfillment records directly for Infuse-Marketplace purchases.

After the customer pays or cancels, Stripe redirects the browser to the `successUrl` or `cancelUrl` you supplied. Treat this redirect as a browser navigation event, not proof that the purchase is active. Infuse validates successful payment, records purchase state, and creates the relevant entitlements.

## 5. Read Purchase State

After the customer returns to your site, read purchase state from Infuse through your backend.

```http
GET /marketplace/providers/purchases?deviceId={deviceId}&livemode=true&page=1&pageSize=20
Authorization: Bearer {provider_access_token}
```

Useful query fields:

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Use
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        deviceId
      </code>
    </td>
    
    <td>
      Limits results to one device.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        livemode
      </code>
    </td>
    
    <td>
      Separates production purchases from test purchases.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        page
      </code>
      
       and <code>
        pageSize
      </code>
    </td>
    
    <td>
      Paginates purchase history.
    </td>
  </tr>
</tbody>
</table>

Use this endpoint to drive "Your purchases", checkout confirmation, pending payment, and entitlement-aware UI states.

For a device detail page, load the device and purchase context:

```http
GET /marketplace/providers/devices/{deviceId}/details
Authorization: Bearer {provider_access_token}
```

For release and compatibility information for a purchased item on a device:

```http
GET /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/releases
Authorization: Bearer {provider_access_token}
```

Your success page should be able to show a pending state while Infuse confirms the purchase. Poll or refresh purchase state from your backend until the purchase is active, failed, or requires customer support.

## 6. Queue Installs

Payment and installation are separate steps. A successful checkout grants purchase entitlements. Your storefront decides whether to install immediately after purchase or present install controls later.

First, read available releases for the purchased item and device:

```http
GET /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/releases
Authorization: Bearer {provider_access_token}
```

Then queue an install for the selected version:

```http
POST /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/install
Authorization: Bearer {provider_access_token}
Content-Type: application/json

{
  "version": "1.4.2"
}
```

Only show install actions for active purchases and compatible releases. If a release is not compatible with the target device, keep the action disabled and explain the device or version requirement in your UI.

## Provider Listing APIs

Provider listing APIs are useful for provider administration screens, but customer-facing storefront pages should normally read from the public marketplace item APIs so the storefront reflects what is currently published and visible to customers.

```http
GET /marketplace/providers/listings
Authorization: Bearer {provider_access_token}
```

```http
GET /marketplace/providers/listings/{marketplaceId}
Authorization: Bearer {provider_access_token}
```

Use these APIs when you need to inspect or manage the apps and algorithms your provider organisation lists. Do not use them as the only checkout-time availability check.

## Customer Experience States

Build explicit states into your storefront:

<table>
<thead>
  <tr>
    <th>
      State
    </th>
    
    <th>
      What to show
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Catalogue loading
    </td>
    
    <td>
      Listed apps and algorithms are being loaded from your backend.
    </td>
  </tr>
  
  <tr>
    <td>
      Item unavailable
    </td>
    
    <td>
      The item is no longer published, listed, or valid for the current marketplace instance.
    </td>
  </tr>
  
  <tr>
    <td>
      No eligible devices
    </td>
    
    <td>
      The customer must register or select a compatible device before checkout.
    </td>
  </tr>
  
  <tr>
    <td>
      Checkout redirecting
    </td>
    
    <td>
      The session was created and the customer is being sent to Stripe Checkout.
    </td>
  </tr>
  
  <tr>
    <td>
      Checkout cancelled
    </td>
    
    <td>
      The customer returned from the cancel URL. Keep the basket editable.
    </td>
  </tr>
  
  <tr>
    <td>
      Purchase pending
    </td>
    
    <td>
      The customer returned from success, but Infuse has not finished confirming purchase state.
    </td>
  </tr>
  
  <tr>
    <td>
      Purchase active
    </td>
    
    <td>
      The entitlement exists and install or management actions can be shown.
    </td>
  </tr>
  
  <tr>
    <td>
      Install queued
    </td>
    
    <td>
      An install request has been accepted for the selected device and version.
    </td>
  </tr>
</tbody>
</table>

## Implementation Checklist

- Keep provider API credentials server-side.
- Build around Infuse `marketplaceItemIds`; avoid a separate item ID system unless it maps directly back to Infuse IDs.
- Validate selected devices against your signed-in customer before creating checkout.
- Refresh item details before checkout so price, currency, and visibility are current.
- Use absolute, stable `successUrl` and `cancelUrl` values.
- Store `checkoutSessionId` if you need local order tracking or support diagnostics.
- Treat `successUrl` as a return route, not fulfillment confirmation.
- Read purchase state from `GET /marketplace/providers/purchases`.
- Use `livemode: true` only for real customer transactions.
- Trigger installs only for active purchases and compatible releases.
- Do not call Stripe directly to fulfill Infuse-Marketplace purchases.

## Endpoint Summary

<table>
<thead>
  <tr>
    <th>
      Purpose
    </th>
    
    <th align="right">
      Method
    </th>
    
    <th>
      Endpoint
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      List published storefront items
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/marketplace-items
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Get published item detail
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/marketplace-items/{id}
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      List provider devices
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/devices
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Create checkout session
    </td>
    
    <td align="right">
      POST
    </td>
    
    <td>
      <code>
        /marketplace/checkout/session
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      List provider purchases
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/purchases
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Get provider device details
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/devices/{deviceId}/details
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Get purchased item releases
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/releases
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Queue purchased item install
    </td>
    
    <td align="right">
      POST
    </td>
    
    <td>
      <code>
        /marketplace/providers/devices/{deviceId}/purchases/{marketplaceItemId}/install
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      List provider listings
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/listings
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Get provider listing
    </td>
    
    <td align="right">
      GET
    </td>
    
    <td>
      <code>
        /marketplace/providers/listings/{marketplaceId}
      </code>
    </td>
  </tr>
</tbody>
</table>

## Related Documentation

- [Checkout flow](/docs/marketplace/providers/checkout-flow)
- [Purchases](/docs/marketplace/providers/purchases)
- [Install purchased apps and algorithms](/docs/marketplace/providers/install-purchased-products)
- [Infuse-Marketplace API reference](/api-reference/marketplace)
