Building a Product Discovery App

Learn how to develop and test your own product discovery app using Relay and the Best Buy product catalog. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

The Orders API expands what Stripe users can do beyond processing charges:

  • Sellers can represent a product catalog in Stripe and accept orders.
  • App Developers can render products from and submit orders to sellers, acting as new sales channels for them.

Through Relay, otherwise complex processes–accessing product feeds, selling products for other businesses, and accepting payments–are reduced to simple and direct API calls.

The following steps walk through the development of a product-discovery application that provides a “Buy Button” experience. With a quick and obvious user workflow, an HTML link–embedded on a web page, shared through social media, or shown within a mobile app–can be the foundation of a complete ordering process.

In a normal workflow, as described in the Relay API for Apps guide, an app developer creates a platform using Stripe Connect and is then granted access to other Stripe accounts through an OAuth flow. To make it easy to get started building Relay-powered apps, Best Buy makes their product inventory accessible to app developers in test mode.

Connect to Best Buy

With a live application, you would invite sellers to connect their Stripe accounts to your platform. Doing so allows you to access their product catalog and place orders for them directly from your app. For the purpose of this recipe, we automated the connection process using the Best Buy Demo account. The connection gives you the following permissions:

  • Read-only access to Products and SKUs
  • Write access to create and pay for Orders

Please note that the connection is created in test mode only (no live orders can be processed), webhooks are disabled, and access is limited to the Relay API endpoints. In order to start creating live mode orders, you will need Best Buy to authenticate your app. Please reach out to relay-app+bestbuy@stripe.com to request a connection.

After automatically connecting, you should be all set to retrieve and use the Relay Demo product catalog as described in the following sections.

If you’ve used Connect before, you may have noticed no API key was returned as part of the connection process. Instead, you can use the Stripe-Account header to make requests on behalf of the Relay Demo account, whose ID is acct_16TZFyGRAn672XBM. Using the Stripe-Account header is described in more detail in Authentication with Connect.

Retrieve products and SKUs

After connecting to the Relay Demo account, the next step is to discover the products they’ve made available for sale. Do so by hitting the “list all products” endpoint, passing along a value of true for the active parameter. (Sellers can make products inactive to make them unavailable for purchase.)

The “list all products” endpoint uses the standard Stripe pagination:

curl https://api.stripe.com/v1/products?active=true \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: acct_16TZFyGRAn672XBM"

You’ll find available products in the data property of the API response.

{
  "object": "list",
  "has_more": true,
  "url": "/v1/products",
  "data": [
   {
     "id": "4397400",
     "livemode": false,
     "created": 1445541476,
     "updated": 1446082438,
     "object": "product",
     "active": true,
     "name": "Google - Chromecast (2015 Model) - Black",
     "caption": "Allows you to stream shows, movies, music, sports and games to your TV; compatible with most Apple® iOS and Android phones and tablets, Mac and Windows laptops and Chromebooks",
     "description": "Google Chromecast (2015 Model): Enjoy a world of entertainment with Google Chromecast (2015). Just connect to your HDTV's HDMI interface and your home Wi-Fi network to get started. You can stream your favorite apps from your compatible phone, tablet or laptop, plus use your phone as a remote to search, play and pause content.\nWhat's included:\n- Chromecast (2015 Model)\n- Power cable, power adapter\n",
     "url": "http://www.bestbuy.com/site/google-chromecast-2015-model-black/4397400.p?id=1219757973565&skuId=4397400&cmp=RMX&ky=1uW6SrOhtsDwV32tCtCxtuDpj7SNO9ptQ",
     "attributes": [],
     "shippable": true,
     "package_dimensions": null,
     "metadata": {
       "best_buy.product_id": "1219757973565"
     },
     "images": [
       "http://img.bbystatic.com/BestBuy_US/images/products/4397/4397400_sb.jpg",
       "http://img.bbystatic.com/BestBuy_US/images/products/4397/4397400_sa.jpg",
       "http://img.bbystatic.com/BestBuy_US/images/products/4397/4397400fp.gif",
       "http://img.bbystatic.com/BestBuy_US/images/products/4397/4397400_sc.jpg"
     ],
     "skus": {
       "url": "/v1/skus?product=4397400&active=true",
       "total_count": 1,
       "has_more": false,
       "data": [
         {
           "updated": 1445541476,
           "product": "4397400",
           "price": 3500,
           "package_dimensions": null,
           "metadata": null,
           "livemode": false,
           "inventory": {
             "value": "in_stock",
             "type": "bucket",
             "quantity": null
           },
           "image": null,
           "currency": "usd",
           "created": 1445541476,
           "attributes": null,
           "active": true,
           "object": "sku",
           "id": "4397400"
         }
       ],
       "object": "list"
     },
     ...
   }
  ]
}

A Product is a representation of something you sell. Each variant of a product is called a SKUs (pronounced “skew”, short for Stock Keeping Unit). SKUs are what customers actually puchase. As an example a product is a pair of “Nike Free 5.0”, and the SKUs are the different sizes and colors. To process orders on behalf of sellers (such as Best Buy, in this example), you’ll need to know not just the available products, but also the available SKUs.

As a convenience, SKU objects are automatically expanded in the product objects returned by the API. For each acceptable product attribute–size, color, etc., SKUs have specified values–small/medium, tan/blue, etc. SKUs also contain inventory and price information. When you create an order, you order a specific SKU and not just a product

Depending on your app discovery mechanism, you may cache the products and SKUs in your app or database to present them to yours users, but make sure to get up-to-date information from the Relay API as products and SKUs availability may change regularly.

Order workflow

Now that you have access to and knowledge of the Relay Demo product catalog, you can create orders through your app. There are a few steps in the process; each will be explained in detail.

  • Present products for purchase: Render product information (price, availability) and a Buy option to users.
  • Allow user to choose between variants (SKUs), if need be: If the product has been identified but not the precise SKU (e.g., size, color, and so forth) a dialog should be presented to the user to select a specific SKU or list of SKUs to purchase.
  • Create customers in Stripe: For ease of repeat purchases, we encourage you to create customer records in Stripe and then use these records as the basis of orders. As the Relay Demo products are shippable, the customer’s shipping information should be attached to his profile.
  • Create the order: Create the order in Stripe by providing the items to be purchased and the customer information. Order creation returns computed tax and shipping information that can be presented back to the user for confirmation.
  • Collect payment information: Collect the customer’s payment details. You can do so at any time prior to paying for the order.
  • Pay for the order: Using the collected payment information.

Present products for purchase

With the product and SKU information in hand, you can present individual items or a catalog to your users for consideration. Products can have multiple images, short captions, long-form descriptions, and associated URLs. Combine these as you see fit in ways that match your app’s feel and intent.

Through clickable buttons, images, or links, your users can indicate a desire to purchase an item. If a product comes in multiple variations (i.e., has multiple SKUs), additional interface elements can be used to identify the specific variant to buy. Once a specific SKU is identified, an order can be created. (If a product only comes in one variant, then you’ll already know the SKU to use, but orders are always made using SKU IDs, not product IDs.)

Create a customer in Stripe

Creating reusable customer profiles is central to having a seamless e-commerce experience in your app. By creating customer profiles, repeat purchases can be made with a simple button click and a confirmation; no additional information need be provided.

The Relay endpoints work harmoniously with our Customer objects. An app like yours can create customers in Stripe, and use these customer objects on behalf of the seller (Relay Demo here) to create and pay orders. These customer profiles should be created on your account and they belong to your platform only (here Relay Demo would not have access to them).

After you’ve collected the customer’s email and shipping information but before creating the order, create the customer in your Stripe account:

curl https://api.stripe.com/v1/customers \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -d email="jenny@ros.en" \
   -d shipping[name]="Jenny Rosen" \
   -d shipping[address][line1]="1234 Main Street" \
   -d shipping[address][city]="San Francisco" \
   -d shipping[address][state]=CA \
   -d shipping[address][postal_code]=12345 \
   -d shipping[address][country]=US \
   -d shipping[phone]=8008675309

Notice that the request does not include the Stripe-Account header (as in the product fetching request), as this API call is made on behalf of your own account.

Create an order

Creating an order consists of providing one or more SKUs and the customer’s information. All of these details will be made available to the seller so they may fulfill the order. Given that the Relay Demo products are shippable, a shipping address should also be passed at order creation so the shipping rates can be computed. For this reason, the customer’s shipping information was stored as part of the customer profile above, and the customer profile can be used directly for order creation.

As the order is created in the seller’s Stripe account, you’ll again identify the seller in the request using the Stripe-Account header while using one of your own customer ID.

curl https://api.stripe.com/v1/orders \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: acct_16TZFyGRAn672XBM" \
   -d items[][type]=sku \
   -d items[][parent]=4397400 \
   -d items[][quantity]=1 \
   -d currency=usd \
   -d customer=cus_BkUHfRcX1T238f

When the create order request is made, Stripe will compute and factor in appropriate shipping and tax costs, and return an Order object to you. At this point, you can present the total to the customer as well as shipping options.

{
  "id": "or_17ZqJVGRAn672XBM7eOtn9kX",
  "object": "order",
  "amount": 3780,
  "application": null,
  "application_fee": null,
  "charge": null,
  "created": 1454366309,
  "currency": "usd",
  "customer": "cus_7pVJlGxBibLVuJ",
  "email": "jenny@ros.en",
  "updated": 1454366312,
  "status": "created",
  "shipping_methods": [
    {
      "description": "Standard shipping",
      "currency": "usd",
      "amount": 0,
      "id": "Standard",
      "delivery_estimate": {
        "type": "exact",
        "date": "2016-10-02"
      }
    },
    {
      "description": "Expedited shipping",
      "currency": "usd",
      "amount": 1199,
      "id": "Expedited",
      "delivery_estimate": {
        "type": "exact",
        "date": "2016-09-30"
      }
    },
    {
      "description": "Express shipping",
      "currency": "usd",
      "amount": 1998,
      "id": "Express",
      "delivery_estimate": {
        "type": "exact",
        "date": "2016-09-28"
      }
    }
  ],
  "shipping": {
    "phone": "8008675309",
    "name": "Jenny Rosen",
    "address": {
      "state": "CA",
      "postal_code": "12345",
      "line2": null,
      "line1": "1234 Main Street",
      "country": "US",
      "city": "San Francisco"
    }
  },
  "selected_shipping_method": "Standard",
  "metadata": null,
  "livemode": false,
  "items": [
    {
      "type": "sku",
      "quantity": 1,
      "parent": "4397400",
      "description": "Google - Chromecast (2015 Model) - Black",
      "currency": "usd",
      "amount": 3500,
      "object": "order_item"
    },
    {
      "type": "tax",
      "quantity": null,
      "parent": null,
      "description": "Sales Tax",
      "currency": "usd",
      "amount": 280,
      "object": "order_item"
    },
    {
      "type": "shipping",
      "quantity": null,
      "parent": "Standard",
      "description": "Standard shipping",
      "currency": "usd",
      "amount": 0,
      "object": "order_item"
    }
  ]
}

Stripe will automatically notify the seller of the order’s creation.

Collect payment information

At some point before attempting to pay for the order, you’ll want to add a payment method to the customer record. The card information should be securely taken and tokenized–within your app–using our iOS or Android integration. As this recipe only uses Best Buy in test mode, you can simply add a test card directly.

curl https://api.stripe.com/v1/customers/cus_ASiyLhdRTEIjrU \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -d source[object]=card \
   -d source[number]=4242424242424242 \
   -d source[exp_month]=01 \
   -d source[exp_year]=2038

With a stored customer profile and a payment method, you’ll be able to use that customer object to create and pay for orders. Subsequent orders can be processed without needing to ask for billing or payment information again.

In a normal workflow, you may also consider relying on Apple Pay for a seamless payment experience on iOS. Using Apple Pay, you would be able to attach the retrieved token to the customer and specify it as the source to use while paying the order.

Pay for the order

The final step is to accept a payment method from the customer–if you haven’t already–and pay for the order. If you’re storing customers in Stripe, the payment method will have already been stored as well (per the above), and you can just provide the Stripe customer ID in the pay request. Also if you already specified a customer with valid payment information while creating the order, you must specify the same customer here or simply omit it.

curl https://api.stripe.com/v1/orders/or_WPdWgqaBQxzzNSJ4korWoslS/pay \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: acct_16TZFyGRAn672XBM" \
   -d customer=cus_qG7kjtVBxzm9ma

Stripe will automatically notify the seller that the order was paid for. You should notify the customer that the order was placed and that he should expect a receipt from the seller.

Get in touch

If you notice anything surprising, or have feedback or more importantly questions, please [get in touch!](mailto:relay@stripe.com)

More about Relay

Looking to learn more about Relay? Check out these other guides: