Become a Shipping Provider for the Orders API Deprecated

    Let Stripe users leverage your shipping API when they sell products.

    When a merchant creates an order though the Orders API, Stripe checks their shipping and tax settings to dynamically, and in real-time, sets those costs. Sellers have four choices for shipping settings:

    • free: No additional cost, the default.
    • flat_rate: One or more flat additional costs.
    • dynamic: Determined on the fly per order.
    • provider: Calculated using a third party shipping provider.

    If a user chooses the provider, Stripe will automatically attempt to contact a third party shipping provider with the order details to obtain shipping methods for the order. This guide outlines the steps required to become a provider for shipping calculations in the Orders API as well as the specific API you are expected to implement.

    Authenticating users

    Orders API users choose their shipping calculation strategy in the Stripe Dashboard. When they pick provider, they will be prompted to specify the URL that their provider uses for shipping calculation. To become a provider, you should give your users the ability to obtain this URL from your dashboard, so they can paste it into the Stripe Dashboard.

    The URL must accept HTTP POST requests for /create. If your URL is https://www.example.com/shipping/, your endpoint should be able to respond to:

    • POST https://www.example.com/shipping/create

    The URL will be used as-is by Stripe, which means that you are welcome to include HTTP basic authentication in the URL string. You could, for example, give the user the following URL to let them authenticate as user foo with password bar: POST https://foo:bar@www.example.com/shipping/. The URL is not considered sensitive by Stripe, so we encourage you to use an unguessable identifier as the user’s password instead of the user’s usual password, should you choose to include authentication in the URL.

    The endpoint you need to implement to become a Orders API shipping provider through the reverse API is outlined below:

    Order Creation

    When an order is created, Stripe will issue a POST HTTP request to the specified endpoint with the details of the unpaid, created order. Your endpoint should calculate the shipping rates for the order based upon the SKUs it contains, the customer’s address, and the merchant-defined shipping origin address. The order creation is not a guarantee that the order will eventually get paid. Your endpoint should therefore calculate the shipping rates but not purchase any labels on behalf of the merchant.

    If you support storing merchant-defined identifiers along with your shipments, we strongly encourage you to reuse the identifiers already included in the order. Using the same identifiers will make it easier for the Stripe user to reconcile shipments in your system with their Stripe orders. If your system creates a shipment based on the order below, for example, reusing the identifier "or_15iahK2eZvKYlo2CzKGgMVNl" helps the user link the Stripe order to the shipment you create.

    A couple of things to keep in mind as you calculate shipping rates:

    • The shipping field on the order contains the destination address.
    • The from_address field in the shipping_settings contains the origin address.
    • The package_dimensions specifies weight in ounces and dimensions in inches.

    Sample Request

    The structure of the request will look like a fully expanded Order, not all of which will be relevant to calculating shipping rates for an order. Below is an example of the fields that you should expect to be present and usable for calculating shipping rates.

    {
      "order": {
        "id": "or_15iahK2eZvKYlo2CzKGgMVNl",
        "created": 1426898562,
        "object": "order",
        "shipping": {
          "name": "Bob Rosen",
          "address": {
            "line1": "1234 Main street",
            "line2": null,
            "city": "Anytown",
            "state": "CA",
            "postal_code": "123456",
            "country": "US"
          }
        },
        "items": [
          {
            "object": "order_item",
            "quantity": 1,
    See all 67 lines "type": "sku", "parent": { "id": "sku_h8UvZvy9JA4QXeuR5Wxt", "object": "sku", "package_dimensions": { "width": 10, "length": 10, "height": 10, "weight": 32 }, "metadata": {}, "product": { "id": "prod_6naDTQsFnjCXUqY9ZEph", "object": "product", "package_dimensions": { "width": 5, "length": 5, "height": 5, "weight": 16 }, "metadata": {}, ... }, ... } } ], "amount": 1500, "currency": "usd", ... }, "settings": "shipping": { "from_name": "Jenny Rosen", "from_address": { "line1": "123 Main Street", "line2": "Unit 42", "city": "San Francisco", "state": "CA", "postal_code": "94110", "country": "USA" }, ... } ... } }

    Note that some fields like metadata and package_dimensions can be present both on a product and a SKU. The fields on the product provides fallback values that an individual SKU can override. For example, in the request above, you should calculate shipping on a 10” x 10” x 10” item that weighs 32oz since those are the dimensions specified on the SKU.

    Sample Response

    Your endpoint must return a 200 status code, along with a JSON response. The JSON needs a top-level shipping_update property. This property must contain a shipping_methods array of shipping methods that apply to the order. An example of a valid response is:

    {
      "shipping_update": {
        "shipping_methods": [
          {
            "id": "free_shipping",
            "description": "Free 7-day Shipping",
            "amount": 0,
            "currency": "usd",
            // Optional delivery estimate:
            "delivery_estimate": {
              "type": "exact",
              "date": "2019-11-21"
            },
          }, {
            "id": "priority_shipping",
            "description": "2-day Priority Shipping",
            "amount": 499,
            "currency": "usd",
            // Optional delivery estimate:
            "delivery_estimate": {
              "type": "exact",
              "date": "2019-11-16"
            }
          }
        ]
      }
    }

    Indicating an error

    Any non-200 responses when creating or refunding orders will be considered an error, which results in the order creation or refund being rejected. This also means that if your endpoint is broken (e.g., due to a syntax error), orders cannot be created.

    Your endpoint can respond to the Stripe request with error messages that the API will return to the order creation request. Error codes are represented in the usual Stripe format:

    {
      "error": {
        "type": "action_failed",
        "code": "address_verification_failed",
        "message": "The postal code 94110 does not match the state NY."
      }
    }

    Acceptable values for the error code are:

    • shipping_calculation_failed: the shipping could not be computed
    • address_verification_failed: the address could not be verified

    Stripe supports passing optional extra information, to help merchants and users identify and fix the issue that prevents you from calculating shipping costs. In particular, you can make address validation errors actionable by including a param, as explained in our error handling guide

    Testing Your Integration

    To test your integration first configure your shipping integration in the Dashboard. The Relay settings in the Dashboard will let you specify a custom shipping provider by picking “Change shipping” and selecting “Provider” from the first dropdown. We suggest only sending test request (and thus only using test settings) while you are still developing your endpoint. Be sure to test different shipping addresses, shippable and non-shippable goods, as well as full and partial returns.

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page