Accepting Orders in Your App

The Orders API provides an infrastructure for apps to process orders on behalf of other Stripe users. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

Relay uses the Orders API to let sellers represent a catalog of physical and digital products in their Stripe accounts. Sellers then authorize any number of apps–shopping and social media platforms–to process orders on their behalf. The end result is an API that supports direct sales from anywhere, be it a tweet, a post on social media, or even from within a dedicated app.

As an app, you’ll initially need to:

  1. Set up your platform
  2. Integrate OAuth to connect sellers
  3. Find a seller’s available products and SKUs

Having done that, you can then:

  1. Create orders on behalf of connected sellers.
  2. Accept payment for orders on behalf of connected sellers.
  3. Optionally take an application fee.

To learn more about the Orders API for sellers, see the Orders API overview. To quickly develop and test your own app, walk through the recipe for using the Relay Demo seller account.

Set up your platform

Stripe Connect makes it easy for platforms to interact with other Stripe accounts, accepting money on their behalf, and accessing their data. Thanks to Relay, a platform can now use Connect to process orders as well.

If you have not done so already, you’ll need to register your platform. Make a note of your client_id and redirect_uri, as both are used to authorize connections to your account.

If you have an existing Connect application, you can begin using it with the Orders API immediately, without even updating your API version!

Integrate OAuth to connect sellers

The rest of this guide assumes you have already registered your platform.

As a Connect platform and app, you create an onboarding flow through which merchants authorize your Connect app to act on their behalf. Once a merchant connects to your app, you’ll be able to access their product catalog and create orders against it. Stripe uses a common OAuth process, explained in detail in the Connecting to Standalone Accounts guide.

Relay applications only need to read product and SKU data and create orders on behalf of their connected merchants. When merchants authorize your Connect application to access their data, we therefore suggest that you request the relay scope for the connection. This scope gives you read_only access to products and SKUs as well as read_write access to orders that your application has created.

Find products and SKUs

To process orders, apps must first be aware of the products a merchant has. You may obtain this information in various ways, but the ultimate source for truth is making an API call on the merchant’s behalf.

curl https://api.stripe.com/v1/products?limit=3 \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: {CONNECTED_STRIPE_ACCOUNT_ID}"
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

Stripe::Product.list(
  {:limit => 3},
  :stripe_account => '{CONNECTED_STRIPE_ACCOUNT_ID}'
)
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

stripe.Product.list(
  limit=3,
  stripe_account='{CONNECTED_STRIPE_ACCOUNT_ID}'
)
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

\Stripe\Product::all(
  array("limit" => 3),
  array("stripe_account" => "{CONNECTED_STRIPE_ACCOUNT_ID}")
);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";

Map<String, Object> productParams = new HashMap<String, Object>();
productParams.put("limit", 3);

RequestOptions requestOptions = RequestOptions.builder().setStripeAccount({CONNECTED_STRIPE_ACCOUNT_ID}).build();

Product.list(productParams, requestOptions);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

stripe.products.list(
  {limit: 3},
  {stripe_account: '{CONNECTED_STRIPE_ACCOUNT_ID}'},
  function(err, products) {
  // asynchronously called
});

Notice that you’ll make this request on behalf of the connected user, by passing their account ID as explained in Authentication with Connect. The API call returns the available product IDs, as well as the product’s descriptions, images, and so on: anything the merchant has provided that will be compelling to your users. You’ll find available products in the data property of the API response.

Products are umbrellas for what merchants sell, but orders are composed of SKUs: specific variants of a product. When you fetch the seller’s products, we’ll automatically return related SKUs, too.

{
  "object": "list",
  "has_more": false,
  "url": "/v1/products",
  "data": [
    {
      "id": "prod_6yK3M2RfEUqrkF",
      "created": 1442100452,
      "updated": 1442100452,
      "object": "product",
      "livemode": false,
      "name": "2015 Limited Edition T-shirt",
      "caption": null,
      "description": "Super awesome, one-of-a-kind t-shirt",
      "active": true,
      "attributes": [
        "size",
        "gender",
        "color"
      ],
      "shippable": true,
      "metadata": {},
      "url": null,
      "package_dimensions": null,
      "images": [],
      "skus": {
        "object": "list",
        "total_count": 3,
        "has_more": false,
        "url": "/v1/skus?product=prod_6yK3M2RfEUqrkF\u0026active=true",
        "data": [
          {
            "id": "sku_6yK573OC7bNAX0",
            "created": 1442100560,
            "updated": 1442100560,
            "object": "sku",
            "livemode": false,
            "product": "prod_6yK3M2RfEUqrkF",
            "image": null,
            "active": true,
            "price": 1500,
            "currency": "usd",
            "inventory": {
              "type": "finite",
              "quantity": 500,
              "value": null
            },
            "attributes": {
              "size": "Medium",
              "gender": "Unisex",
              "color": "Cyan"
            },
            "metadata": {},
            "package_dimensions": null
          },
          {
            "id": "sku_6yK5PxwPbswVFB",
            "created": 1442100602,
            "updated": 1442100602,
            "object": "sku",
            "livemode": false,
            "product": "prod_6yK3M2RfEUqrkF",
            "image": null,
            "active": true,
            "price": 1500,
            "currency": "usd",
            "inventory": {
              "type": "finite",
              "quantity": 400,
              "value": null
            },
            "attributes": {
              "size": "Large",
              "gender": "Unisex",
              "color": "Cyan"
            },
            "metadata": {},
            "package_dimensions": null
          }
        ]
      }
    }
  ]
}

If you look at all the SKUs for a product, you’ll see every possible attribute value, for example: size can be “Small”, Medium”, or “Large”; color can be “Cyan” or “Magenta”. Using that information, you can render appropriate dropdown menus or create other interfaces for customers to select what they’re purchasing.

You should also pay attention to each SKU’s inventory, which reflects whether that particular item is currently purchasable. (Attempts to pay for an order that contains an out-of-stock item will result in an error.)

You’ll need to store all of the relevant information to make products and SKUs purchasable in orders. The most important bit of information will be the SKU IDs, which go directly into an Order.

Create orders

Having identified a seller’s available products (more precisely, SKUs), the next step is to make them available for purchase by your users. This can be as simple as providing a link or button users click, or by building up a shopping cart. The ordering process can begin within a website, a mobile app, a social media tool, or by merely displaying a linked image. (For more on the order workflow, see the Building a Product Discovery App recipe.)

Once a user has expressed intent to purchase one or more products, create an order in Stripe by providing:

  • SKUs to be purchased
  • Quantity of each
  • Currency of the order
  • Customer details–email address, shipping information, and so on

Orders are created on the merchant’s Stripe account, using the merchant’s account ID in the request.

curl https://api.stripe.com/v1/orders \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: {CONNECTED_STRIPE_ACCOUNT_ID}" \
   -d currency=usd \
   -d email="jenny@example.com" \
   -d items[][type]=sku \
   -d items[][parent]=sku_6yK573OC7bNAX0 \
   -d items[][quantity]=2 \
   -d shipping[name]="Jenny Rosen" \
   -d shipping[address][line1]="1234 Main Street" \
   -d shipping[address][city]=Anytown \
   -d shipping[address][country]=US \
   -d shipping[address][postal_code]=123456
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

Stripe::Order.create(
  :currency => 'usd',
  :email => 'jenny@example.com',
  :items => [
    {
      :type => 'sku',
      :parent => 'sku_6yK573OC7bNAX0'
    }
  ],
  :shipping => {
    :name => 'Jenny Rosen',
    :address => {
      :line1 => '1234 Main Street',
      :city => 'Anytown',
      :country => 'US',
      :postal_code => '123456'
    }
  },
  {:stripe_account => '{CONNECTED_STRIPE_ACCOUNT_ID}'}
)
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

stripe.Order.create(
  currency = 'usd',
  email = 'jenny@example.com',
  items = [
    {
      "type":'sku',
      "parent":'sku_6yK573OC7bNAX0'
    }
  ],
  shipping = {
    "name":'Jenny Rosen',
    "address":{
      "line1":'1234 Main Street',
      "city":'Anytown',
      "country":'US',
      "postal_code":'123456'
    }
  },
  stripe_account='{CONNECTED_STRIPE_ACCOUNT_ID}'
)
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

\Stripe\Order::create(array(
  "currency" => "usd",
  "email" => "jenny@example.com",
  "items" => array(
    array(
      "type" => "sku",
      "parent" => "sku_6yK573OC7bNAX0"
    )
  ),
  "shipping" => array(
    "name" => "Jenny Rosen",
    "address" => array(
      "line1" => "1234 Main Street",
      "city" => "Anytown",
      "country" => "US",
      "postal_code" => "123456"
    )
  ),
  array("stripe_account" => "{CONNECTED_STRIPE_ACCOUNT_ID}")
);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";

Map<String, Object> orderParams = new HashMap<String, Object>();
orderParams.put("currency", "usd");
orderParams.put("email", "jenny@example.com");
List<Object> itemsParams = new LinkedList<Object>();
Map<String, String> item1 = new HashMap<String, String>();
item1.put("type", "sku");
item1.put("parent", "sku_6yK573OC7bNAX0");
itemsParams.add(item1);
orderParams.put("items", itemsParams);
Map<String, Object> shippingParams = new HashMap<String, Object>();
shippingParams.put("name", "Jenny Rosen");
Map<String, Object> addressParams = new HashMap<String, Object>();
addressParams.put("line1", "1234 Main Street");
addressParams.put("city", "Anytown");
addressParams.put("country", "US");
addressParams.put("postal_code", "123456");
shippingParams.put("address", addressParams);
orderParams.put("shipping", shippingParams);

RequestOptions requestOptions = RequestOptions.builder().setStripeAccount({CONNECTED_STRIPE_ACCOUNT_ID}).build();

Order.create(orderParams, requestOptions);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

stripe.orders.create({
  currency: 'usd',
  email: 'jenny@example.com',
  items: [
    {
      type: 'sku',
      parent: 'sku_6yK573OC7bNAX0'
    }
  ],
  shipping: {
    name: 'Jenny Rosen',
    address: {
      line1: '1234 Main Street',
      city: 'Anytown',
      country: 'US',
      postal_code: '123456'
    }
  }
}, {
  stripe_account: '{CONNECTED_STRIPE_ACCOUNT_ID}'
}, function(err, order) {
  // asynchronously called
});

Order creations are synchronous requests. You’ll get an Order object as the response, or an error if a problem occurred.

{
  "id": "or_6yLD5jBXsLYNcr",
  "created": 1442104773,
  "updated": 1442104773,
  "object": "order",
  "livemode": false,
  "status": "created",
  "metadata": {},
  "customer": null,
  "shipping": {
    "name": "Jenny Rosen",
    "address": {
      "line1": "1234 Main Street",
      "line2": null,
      "city": "Anytown",
      "state": null,
      "postal_code": "12356",
      "country": "US"
    },
    "phone": null
  },
  "email": null,
  "items": [
    {
      "parent": "sku_6yK573OC7bNAX0",
      "object": "order_item",
      "type": "sku",
      "description": "2015 Limited Edition T-shirt",
      "amount": 1500,
      "currency": "usd",
      "quantity": 1
    },
    {
      "parent": null,
      "object": "order_item",
      "type": "tax",
      "description": "Taxes (included)",
      "amount": 0,
      "currency": "usd",
      "quantity": null
    },
    {
      "parent": "ship_free-shipping",
      "object": "order_item",
      "type": "shipping",
      "description": "Free shipping",
      "amount": 0,
      "currency": "usd",
      "quantity": null
    }
  ],
  "shipping_methods": [
    {
      "id": "ship_free-shipping",
      "description": "Free shipping",
      "amount": 0,
      "currency": "usd",
      "delivery_estimate": {
        "type": "exact",
        "date": "2016-12-17"
      }
    }
  ],
  "selected_shipping_method": "ship_free-shipping",
  "amount": 1500,
  "currency": "usd",
  "charge": null
}

As you can see in the response, Stripe automatically plugs in the appropriate shipping and tax costs, per the seller’s settings. You can use these values in the returned Order object to present a final total to your user for payment.

Behind the scenes, Stripe will notify the seller of the order’s creation by email or webhook notification, depending upon the seller’s settings. (You will also receive webhook notifications at your Connect app’s endpoint.)

Accept payment for orders

The final step for the app is to collect payment for the order. Orders are paid for similar to any other charge in Stripe, using either a credit card or an existing Customer object from a Stripe account (with a previously stored source). A simple and common option is to have the customer pay using a credit card, tokenized via Stripe.js or Checkout.

You’ll most likely want to save card details in a Customer object on your own Stripe account, so users of your app have their payment credentials saved for re-use across whichever merchants they want to purchase from in the future.

Provide the payment source in the pay order call, and the customer will be charged.

curl https://api.stripe.com/v1/orders/or_19P4Ee2eZvKYlo2C3kA3J2hO/pay \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -d source="{TOKEN}"
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

# Get the credit card details submitted by the form
token = params[:stripeToken]

order = Stripe::Order.retrieve('or_19P4Ee2eZvKYlo2C3kA3J2hO')

order.pay(:source => token)
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

# Get the credit card details submitted by the form
token = request.POST['stripeToken']

order = stripe.Order.retrieve('or_19P4Ee2eZvKYlo2C3kA3J2hO')

order.pay(source=token)
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

// Get the credit card details submitted by the form
$token = $_POST['stripeToken'];

$order = \Stripe\Order::retrieve("or_19P4Ee2eZvKYlo2C3kA3J2hO");

$order->pay(array("source" => $token));
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";

// Get the credit card details submitted by the form
String token = request.getParameter("stripeToken");

Order order = Order.retrieve("or_19P4Ee2eZvKYlo2C3kA3J2hO", null);

Map<String, Object> orderParams = new HashMap<String, Object>();
orderParams.put("source", token);

order.pay(orderParams);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

// Get the credit card details submitted by the form
var token = request.body.stripeToken; // Using Express

stripe.orders.pay("or_19P4Ee2eZvKYlo2C3kA3J2hO", {
  source: token
}, function(err, order) {
  // called asynchronously
});

Note that all of the order creation and payment activity occurs on the seller’s account, on whose behalf you’re operating. The customer’s funds will flow directly to the seller’s Stripe account, and they will be all set to fulfill the order.

Upon payment, the Order object’s status will be changed to paid, and order.payment_succeed events will be sent to all applicable webhook endpoints.

Take an application fee

Apps also have the option to apply an application fee when accepting payment for an order. No Stripe fees are taken from the application fee; the only Stripe fees are on the charge itself, and those come from the amount going to the seller. You must make it clear to your connected sellers that you charge an application fee.

For example, on an order of $100 (USD), if you take an application fee of $1.00 (USD), you will receive $1.00 (USD) in your Stripe account. The seller will receive $95.80 (USD) in their Stripe account: $100, less the $3.20 Stripe fee (2.9% + 30 cents), less your application fee.

To charge an application fee, pass in the optional application_fee parameter in the pay order call. The application_fee parameter must be a positive integer (e.g., an amount in cents), representing a flat amount, not a percentage.

curl https://api.stripe.com/v1/orders/or_6yLD5jBXsLYNcr/pay \
   -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
   -H "Stripe-Account: {CONNECTED_STRIPE_ACCOUNT_ID}" \
   -d source=tok_16glHpJrQulZCT9iNFY21k34 \
   -d application_fee=100
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

order = Stripe::Order.retrieve('or_6yLD5jBXsLYNcr',
  :stripe_account => '{CONNECTED_STRIPE_ACCOUNT_ID}')

order.pay(
  :application_fee => 100,
  :source => 'tok_16glHpJrQulZCT9iNFY21k34'
  # Obtained with Stripe.js ^^^
)
# Set your secret key: remember to change this to your live secret key in production
# See your keys here: https://dashboard.stripe.com/account/apikeys
stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"

order = stripe.Order.retrieve('or_6yLD5jBXsLYNcr',
  stripe_account='{CONNECTED_STRIPE_ACCOUNT_ID}')

order.pay(
  application_fee=100,
  source='tok_16glHpJrQulZCT9iNFY21k34'
  # Obtained with Stripe.js ^^^
)
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

$order = \Stripe\Order::retrieve("or_6yLD5jBXsLYNcr",
  array("stripe_account" => "{CONNECTED_STRIPE_ACCOUNT_ID}")
);

$order.pay(array(
  "application_fee" => 100,
  "source" => "tok_16glHpJrQulZCT9iNFY21k34"
  # Obtained with Stripe.js ^^^
));
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";

RequestOptions requestOptions = RequestOptions.builder().setStripeAccount({CONNECTED_STRIPE_ACCOUNT_ID}).build();

Order order = Order.retrieve("or_6yLD5jBXsLYNcr", requestOptions);

Map<String, Object> orderParams = new HashMap<String, Object>();
orderParams.put("application_fee", 100);
orderParams.put("source", "tok_16glHpJrQulZCT9iNFY21k34");
// Obtained with Stripe.js ^^^

order.pay(orderParams);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

stripe.orders.retrieve("or_6yLD5jBXsLYNcr", {
  stripe_account: '{CONNECTED_STRIPE_ACCOUNT_ID}'
}, function(err, order) {
    if !err {
      order.pay({
        application_fee: 100,
        source: "tok_16glHpJrQulZCT9iNFY21k34"
        // Obtained with Stripe.js ^^^
      })
    }
});

Graceful error handling

Creating and paying for orders can fail in a number of ways. To deliver the best possible user experience, you should should display clear, actionable errors whenever something goes wrong. To help you learn about possible errors and thoroughly test your error handling flows, check out our advanced error handling guide.

Next steps

Congrats! You've gone through how to use the Orders API's products, SKUs and orders features. Some things you might want to see next: