Tutorial: Stripe Relay Integration

In this tutorial, we'll demonstrate how to use EasyPost with Stripe Relay to fetch rates in real-time, and to fulfill orders after they've been paid for.

Although we'll be using Ruby in these example scripts, this functionality could be integrated into any app written with Python, PHP, Java, and other languages with EasyPost's official client libraries and Stripe’s client libraries.

Before You Start

  1. Sign up for an EasyPost account or log in to an existing account.
  2. Sign up or log in to your Stripe account.
  3. Activate EasyPost in Stripe.
  4. Make sure you have Ruby, the EasyPost Ruby client, and the Stripe Ruby client installed.

Step 1: Get Your Keys

The first thing we need is an API key from EasyPost. This is an example application, so we're going to use the test API key. You can find your test key on the API Keys page.

We'll also need our Stripe API key. Login to Stripe, open Account Settings, and click on the "API Keys" tab. Note your test secret key, that's what we'll be using in our script.

Next, open your favorite code editor and create a new file called easypost_stripe_relay.rb. Load the EasyPost and Stripe client libraries, and set the API keys:

easypost_stripe_relay.rb

require 'stripe'
require 'easypost'

Stripe.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
EasyPost.api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
      

Step 2: Create the Script

Once EasyPost is setup as your Stripe Relay shipping provider you will receive real-time rates whenever a Stripe Order is created.

You or your customer will select a Stripe Order shipping_method, and pay for the Order.

EasyPost can help you fulfill your paid Stripe Orders. We'll purchase the "selected_shipping_method", return a shipping label, and mark the Stripe Order as "fulfilled".

easypost_stripe_relay.rb

def main
  Stripe::Order.list(status: "paid", limit: 10).data.each do |paid_order|
    puts "\nFulfilling #{paid_order.id}..."

    # the Stripe Order.id is automatically sent to EasyPost as a Shipment.reference
    shipment = EasyPost::Shipment.retrieve(paid_order.id)

    selected_rate = select_easypost_rate_for_stripe_order(paid_order, shipment)

    begin
      shipment.buy(selected_rate)
    rescue EasyPost::Error => e
      puts "Unable to fulfill #{paid_order.id}: #{e.message}"
      next
    end

    puts "Tracking code: #{shipment.tracking_code}"
    puts "Shipping label: #{shipment.postage_label.label_url}"

    paid_order.status = "fulfilled"
    paid_order.metadata["shipping_tracking_code"] = shipment.tracking_code
    paid_order.save
  end
end
      

Step 3: Select a Rate

If your Stripe Order already has a "selected_shipping_method", it's simple to purchase that rate. If not, you can implement your own rate shopping logic here - for now we'll default to the lowest rate option.

easypost_stripe_relay.rb

def select_easypost_rate_for_stripe_order(order, shipment)
  if order.selected_shipping_method && order.selected_shipping_method.start_with?("rate_")
    EasyPost::Rate.new(order.selected_shipping_method)
  else
    shipment.lowest_rate("USPS")
  end
end
      

Step 4 (Advanced): Create a New Shipment

By default Stripe will create an EasyPost Shipment for each Relay Order. However, because EasyPost Shipments are immutable, you may wish to create a new Shipment with custom options before purchasing a shipping label.

easypost_stripe_relay.rb

SHIPPING_ORIGIN_ADDRESS = {
  company: "EasyPost",
  street1: "417 Montgomery St",
  street2: "5 FL",
  city: "SAN FRANCISCO",
  state: "CA",
  zip: "94104"
}

def easypost_shipment_from_stripe_order(order)
EasyPost::Shipment.create(
  from_address: SHIPPING_ORIGIN_ADDRESS,
  to_address: easypost_address_from_stripe_shipping(order.shipping),
  parcel: {predefined_package: "PARCEL", weight: stripe_order_weight(order)},
  options: {label_format: "PDF"} # custom options
)
end

def easypost_address_from_stripe_shipping(shipping)
{
  name: shipping.name,
  phone: shipping.phone
  street1: shipping.address.line1,
  street2: shipping.address.line2,
  city: shipping.address.city,
  state: shipping.address.state,
  zip: shipping.address.postal_code,
  country: shipping.address.country,
}
end

def stripe_order_weight(order)
weight = 0
order.items.each do |item|
  next unless item.type == "sku"
  sku = Stripe::SKU.retrieve(id: item.parent, expand: ['product'])
  package_dimensions = sku.package_dimensions || sku.product.package_dimensions || {weight: 0}
  weight += package_dimensions[:weight]
end
weight
end
      

This sample script is a good starting point for thinking about how to automate the fulfillment of your Stripe Relay Orders. Automatic label printing would be a good next step - either using PrintNode, or by sending the label directly to a connected printer.

If you have any trouble please feel free to reach out to support@easypost.com!