All Tutorials

Migrating existing subscription contracts to Shopify

All Tutorials

Migrating existing subscription contracts to Shopify

Migrating existing subscription contracts to Shopify

For merchants that currently process their subscription payments through Stripe, Shopify has built a set of tools to import pay-as-you-go contracts into Shopify without the need to migrate credit cards directly.

The process includes connecting Stripe as a legacy subscription payment gateway and migrating each pay-as-you-go contract to Shopify. After the process is complete, you can use a subscription contract to create subsequent orders like contracts created through Shopify Checkout.

Requirements

This tutorial assumes that you've already completed the preceding tutorial, the Subscriptions API migration guide.

What you'll learn

This tutorial covers the following concepts:

Connect Stripe as a secondary payment gateway

You need to connect Stripe as a secondary payment gateway, using Stripe's Payment Intents API. The process is also compatible with Stripe's Charges API.

To connect the merchant's current Stripe account to Shopify as a secondary gateway:

  1. Redirect the merchant to the following URL: {SHOP_URL}/admin/payments/legacy_subscription. We recommend that you open this link in a new browser window so that merchants can return to your migration page when they complete the process. Merchants are redirected to Stripe and asked to initiate the connection process. After merchants successfully initiate the connection process, they are redirected back to the payment settings page and a banner notifies of a successful connection.

  2. Poll the Shop setting to determine whether Shopify has successfully established a connection with Stripe:

POST /admin/api/2021-01/graphql.json

{
  shop {
    features {
      legacySubscriptionGatewayEnabled
    }
  }
}

View response

JSON response:

{
    "data": {
        "shop": {
            "features": {
                "legacySubscriptionGatewayEnabled": true
            }
        }
    }
}

Determine eligibility to use subscriptions with Shopify

As part of setting up Stripe as a secondary gateway, you need to verify that the primary payment gateway of the store is using Shopify Payments. The following query verifies that the primary payment gateway is Shopify Payments. For stores on a Plus plan, the query verifies that Shopify Checkout can display subscription information.

POST /admin/api/2021-01/graphql.json

{
 shop {
   features {
     eligibleForSubscriptionMigration
   }
 }
}

View response

JSON response:

{
   "data": {
       "shop": {
           "features": {
               "eligibleForSubscriptionMigration": true
           }
       }
   }
}

Import any missing customers

You need to import the customer records to connect them to payment methods and subscription contracts. You can use the customerCreate and customerUpdate mutations to add customers to Shopify.

Create new payment methods for the customers

You can associate Stripe payment methods with the customers that you import into Shopify. To make the association you can use the CustomerPaymentMethodRemoteCreditCardCreate mutation to associate the Shopify customer ID with the Stripe customer ID and payment method ID. If the Stripe payment method ID is not available, then the customer's "default source" is used.

The following example shows a mutation that creates payment methods for customers:

POST /admin/api/2021-01/graphql.json

mutation CreateRemoteCreditCard(
  $customerId: ID!,
  $remoteCustomerId: String!,
  $remotePaymentMethodId: String
) {
  customerPaymentMethodRemoteCreditCardCreate(
    customerId: $customerId,
    stripeCustomerId: $remoteCustomerId,
    stripePaymentMethodId: $remotePaymentMethodId
  ) {
    customerPaymentMethod {
      id
      instrument {
        ... on CustomerCreditCard {
          brand
          lastDigits
        }
      }
    }
  }
}

The mutation returns a URL describing the location of the Admin page, where a merchant can set up a secondary payment gateway on a store.

Import subscription contracts

After you've created or updated Shopify's customer record, you can import the subscription contracts. Subscription contracts include information about the variant, the plan, the payment method, and the billing and shipping addresses.

Importing subscription contracts is a three step process:

  1. Use the SubscriptionContractCreate mutation to create a Subscription Draft.
  2. After the draft is created, you need to add lines to the subscription that represent the variants that are included in the subscription.
  3. After you add lines, perform a mutation to commit the draft, which turns the draft into a live contract.

The following example creates a subscription contract including the customer imported earlier and the payment method from the preceding step:

POST /admin/api/2021-01/graphql.json

mutation {
 subscriptionContractCreate(input:
  {
    customerId: "gid://shopify/Customer/1",
    nextBillingDate: "2020-06-01",
    currencyCode: USD,
    contract: {
      status: ACTIVE,
      paymentMethodId: "gid://shopify/CustomerPaymentMethod/869e7a39",
      billingPolicy: {
        interval: MONTH,
        intervalCount: 1,
        minCycles: 3
      },
      deliveryPolicy: {
        interval: MONTH,
        intervalCount: 1
      },
     deliveryMethod: {
        shipping: {
          address: {
            firstName: "John",
            lastName: "McDonald",
            address1: "33 New Montgomery St",
            address2: "#750",
            city: "San Francisco",
            provinceCode: "CA",
            countryCode: US,
            zip: "94105"
          }
        }
      },
      deliveryPrice: {
        currencyCode: USD,
        amount: 14.99
        }
      }
    }
  )
{
    draft {
      id
    }
    userErrors {
      field
      message
    }
  }
}

View response

JSON response:

{
  "data": {
    "subscriptionContractCreate": {
      "draft": {
        "id": "gid://shopify/SubscriptionDraft/7"
      },
      "userErrors": []
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 10,
      "actualQueryCost": 10,
      "throttleStatus": {
        "maximumAvailable": 1000.0,
        "currentlyAvailable": 990,
        "restoreRate": 50.0
      }
    }
  }
}

Now that the subscription draft has been created, you need add lines to the draft, to tell the subscription which line items should be included in the contract:

POST /admin/api/2021-01/graphql.json

mutation {
  subscriptionDraftLineAdd(
    draftId: "gid://shopify/SubscriptionDraft/7"
    input: {
      productVariantId: "gid://shopify/ProductVariant/2"
      quantity: 20
      currentPrice: 25.00
    }
  ) {
    lineAdded {
      id
      quantity
      productId
      variantId
      variantImage {
        id
      }
      title
      variantTitle
      currentPrice {
        amount
        currencyCode
      }
      requiresShipping
      sku
      taxable
    }
    draft {
      id
    }
    userErrors {
      field
      message
      code
    }
  }
}

View response

JSON response:

{
  "data": {
    "subscriptionDraftLineAdd": {
      "lineAdded": {
        "id": "gid://shopify/SubscriptionLine/818b344f-1e7f-4b0e-9fc2-2b749d4b5494",
        "quantity": 20,
        "productId": "gid://shopify/Product/1",
        "variantId": "gid://shopify/ProductVariant/2",
        "variantImage": {
          "id": "gid://shopify/ImageSource/1474738389014"
        },
        "title": "Aerodynamic Wool Coat",
        "variantTitle": "Rustic Plastic Computer",
        "currentPrice": {
          "amount": "25.0",
          "currencyCode": "USD"
        },
        "requiresShipping": true,
        "sku": "",
        "taxable": true
      },
      "draft": {
        "id": "gid://shopify/SubscriptionDraft/7"
      },
      "userErrors": []
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 11,
      "actualQueryCost": 11,
      "throttleStatus": {
        "maximumAvailable": 1000.0,
        "currentlyAvailable": 989,
        "restoreRate": 50.0
      }
    }
  }
}

To convert the subscription draft into a subscription contract that you can bill against, you need to commit the draft. The following mutation commits the draft, and returns a live subscription contract that accepts billing attempts:

POST /admin/api/2021-01/graphql.json

mutation {
  subscriptionDraftCommit(draftId: "gid://shopify/SubscriptionDraft/22") {
    contract {
      id
    }
    userErrors {
      field
      message
    }
  }
}

View response

JSON response:

{
  "data": {
    "subscriptionDraftCommit": {
      "contract": {
        "id": "gid://shopify/SubscriptionContract/7"
      },
      "userErrors": []
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 10,
      "actualQueryCost": 10,
      "throttleStatus": {
        "maximumAvailable": 1000.0,
        "currentlyAvailable": 990,
        "restoreRate": 50.0
      }
    }
  }
}

Create billing attempts

You need to create billing attempts to trigger the billing schedule of a contract. When billing attempts are successful, Shopify creates an order.

The following mutation makes a billing attempt by specifying the required fields subscriptionContractId and idempotencyKey (a unique key generated by the client to avoid duplicate payments). In response to a successful mutation, the subscription contract is billed against its current status:

 mutation {
  subscriptionBillingAttemptCreate(subscriptionContractId: "gid://shopify/SubscriptionContract/1", subscriptionBillingAttemptInput: {
    idempotencyKey: "abc123",
    test: true
  }) {
    subscriptionBillingAttempt {
    id
    errorMessage
    nextActionUrl
    order {
        id
    }
    ready
    }
  }
}

View response

JSON response:

{
   "data": {
       "subscriptionBillingAttemptCreate": {
           "subscriptionBillingAttempt": {
               "id": "gid://shopify/SubscriptionBillingAttempt/593791910",
               "order": {
                   "id": "gid://shopify/Order/148977776"
               },
               "ready": true,
               "subscriptionContract": {
                   "id": "gid://shopify/SubscriptionContract/1"
               }
           },
           "userErrors": []
       }
   }
}

For more information on creating billing attempts, refer to Create a billing attempt.