> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
title: "Sell Anything API"
description: "In this tutorial, you'll understand how to use Rye's Sell Anything API to create a cart, add products to it, and submit it for checkout."
---

### Requirements

* You have created a [Rye Developer Account](https://console.rye.com/account).
* You have access to your API key [(Follow these steps if not)](/quick-start#1-grab-your-api-key).

***

### Let's begin!

<Steps>
  <Step title="Initialize GQL client with your API key">
    Use your API Key to initialize authorization headers for your GQL client.

    ```javascript
    import { GraphQLClient, gql } from 'graphql-request'

    const endpoint = 'https://graphql.api.rye.com/v1/query'
    const client = new GraphQLClient(endpoint)
    const headers = {
      // Tip: You can get these from the Rye Console, under the "Account" tab.
      'Authorization': 'Basic <API Key Here>',
      'Rye-Shopper-IP': 'xxx.xxx.xxx.xxx',
    }
    ```
  </Step>

  <Step title="Add external product to Rye inventory">
    Adding product data to inventory may take a few seconds, but the product ID will be returned immediately. You can then use this product ID to fetch product data in the next step.
    You can also do this via the Rye Console, under the "Requests" tab.

    ```javascript
    async function requestProduct() {
      const variables = {
        "input": {
          "url": "https://www.amazon.com/Verity-Colleen-Hoover-ebook/dp/B09H6T8LTR"
        }
      };
      const query = gql`
        mutation RequestAmazonProductByURL(
          $input: RequestAmazonProductByURLInput!
        ) {
          requestAmazonProductByURL(input: $input) {
            productId
          }
        }
      `;
      const data = await client.request(query, variables, headers)
      console.log(JSON.stringify(data, undefined, 2))
    }

    await requestProduct();
    ```
  </Step>

  <Step title="Fetch product data from Rye inventory">
    The product ID can be found in the response to the [`requestAmazonProductByURL`](/api-reference/requestamazonproductbyurl) mutation's response.

    ```javascript
    async function fetchProduct() {
      const variables = {
        "input": {
          "id": "B09H6T8LTR",
          "marketplace": "AMAZON"
        }
      };

      const query = gql`
        query DemoAmazonProductFetch($input: ProductByIDInput!) {
          product: productByID(input: $input) {
            title
            vendor
            url
            isAvailable
            images {
              url
            }
            price {
              displayValue
            }
            ... on AmazonProduct {
              ASIN
            }
          }
        }
      `;

      const data = await client.request(query, variables, headers)
      console.log(JSON.stringify(data, undefined, 2))
    }

    await fetchProduct();
    ```
  </Step>

  <Step title="Create a cart">
    We can create a cart containing the Amazon product we just requested.

    ```javascript
    const CREATE_CART_QUERY = gql`
      mutation createCart($input: CartCreateInput!) {
        createCart(input: $input) {
          cart {
            id
            stores {
              ... on AmazonStore {
                store
                cartLines {
                  quantity
                  product {
                    id
                  }
                }
                offer {
                  subtotal {
                    value
                    currency
                    displayValue
                  }
                  margin {
                    value
                    currency
                    displayValue
                  }
                  notAvailableIds
                  shippingMethods {
                    id
                    label
                    taxes {
                      value
                      currency
                      displayValue
                    }
                    price {
                      value
                      currency
                      displayValue
                    }
                    total {
                      value
                      currency
                      displayValue
                    }
                  }
                }
              }
            }
          }
          errors {
            code
            message
          }
        }
      }
    `;

    const createCartWithProducts = (product) => {
      const input = {
        items: {}
      };

      if (product.marketplace === 'AMAZON') {
        input.items.amazonCartItemsInput = [
          { productId: product.id, quantity: 1 },
        ];
      }

      if (product.marketplace === 'SHOPIFY') {
        input.items.shopifyCartItemsInput = [
          { variantId: product.id, quantity: 1 },
        ];
      }

      input.buyerIdentity = {
        city: 'city',
        countryCode: 'countryCode',
        provinceCode: 'provinceCode',
        postalCode: 'postalCode',
      };

      const response = await client.request(
        CREATE_CART_QUERY,
        variables,
        headers,
      );
      return response.data!.createCart.cart!;
    }

    const cart = await createCartWithProducts({
      id: 'B09H6T8LTR',
      marketplace: 'AMAZON',
    })
    ```
  </Step>

  <Step title="Use a fragment">
    In the previous step our GraphQL document was extremely long. We can cut down on duplication by extracting our selected fields out as a reusable fragment, like so:

    ```javascript
    const CartFragment = gql`
      fragment CartFragment on Cart {
        id
        stores {
          ... on AmazonStore {
            store
            cartLines {
              quantity
              product {
                id
              }
            }
            offer {
              subtotal {
                value
                currency
                displayValue
              }
              margin {
                value
                currency
                displayValue
              }
              notAvailableIds
              shippingMethods {
                id
                label
                taxes {
                  value
                  currency
                  displayValue
                }
                price {
                  value
                  currency
                  displayValue
                }
                total {
                  value
                  currency
                  displayValue
                }
              }
            }
          }
        }
      }
    `;

    // Use `CartFragment` to keep `CREATE_CART_QUERY` lean
    const CREATE_CART_QUERY = gql`
      ${CartFragment}

      mutation createCart($input: CartCreateInput!) {
        createCart(input: $input) {
          cart {
            ...CartFragment
          }
          errors {
            code
            message
          }
        }
      }
    `;

    // ...
    ```
  </Step>

  <Step title="Add more products to your cart">
    Add more products to your cart with the product IDs and the cart ID of the desired cart, using the [`addCartItems`](/api-reference/addcartitems) mutation.

    ```javascript
    const ADD_CART_ITEMS_QUERY = gql`
      ${CartFragment}

      mutation addCartItems($input: CartItemsAddInput!) {
        cart {
          ...CartFragment
        }
        errors {
          code
          message
        }
      }
    `;

    const addProductsToCart = (cartId, product) => {
      const input = {
        id: cartId,
        items: {},
      };

      if (product.marketplace === 'AMAZON') {
        input.items.amazonCartItemsInput = [
          { productId: product.id, quantity: 1 },
        ];
      }

      if (product.marketplace === 'SHOPIFY') {
        input.items.shopifyCartItemsInput = [
          { variantId: product.id, quantity: 1 },
        ];
      }

      const variables = { input };

      await client.request(
        ADD_CART_ITEMS_QUERY,
        variables,
        headers,
      );
    }

    await addProductsToCart(
      // We returned the `cart` object from the `createCartWithProducts` function
      // in the previous step.
      cart.id,
      'B01ANEHLXG',
    );
    ```
  </Step>

  <Step title="Fetch cart shipping methods and cost">
    Check if your cart looks good, and fetch the estimated checkout cost and available shipping methods for the cart.

    ```javascript
    const GET_CART_QUERY = gql`
      ${CartFragment}

      query cart($id: ID!) {
        getCart(id: $id) {
          ...CartFragment
        }
      }
    `;

    // Fetch latest cart
    const updatedCart = await client.request(GET_CART_QUERY, { id: cart.id }, headers);

    // Use `latestCart`
    ```
  </Step>

  <Step title="Update buyer identity">
    Update buyer identity information if it was not provided during cart creation as it is required to be able to submit the cart.

    ```javascript
    export const UPDATE_CART_BUYER_IDENTITY_QUERY = gql`
      ${CartFragment}

      mutation updateCartBuyerIdentity($input: CartBuyerIdentityUpdateInput!) {
        updateCartBuyerIdentity(input: $input) {
          cart {
            ...CartFragment
          }
          errors {
            code
            message
          }
        }
      }
    `;

    const input = {
      id: cartId,
      buyerIdentity: {
        city,
        address1,
        address2,
        firstName,
        lastName,
        email,
        phone,
        postalCode,
        provinceCode,
        countryCode,
      },
    };

    await client.request(
      UPDATE_CART_BUYER_IDENTITY_QUERY,
      { input },
      headers,
    );
    ```
  </Step>

  <Step title="Submit your cart">
    ```javascript
    const SUBMIT_CART_MUTATION = gql`
      mutation submitCart($input: SubmitCartInput!) {
        submitCart(input: $input) {
          cart {
            id
            stores {
              store
              isSubmitted
              orderId
              errors {
                code
                message
              }
            }
          }
          errors {
            code
            message
          }
        }
      }
    `;

    const submitCart = async (cartId) => {
      const input = {
        id: cartId,  // IMPORTANT! Make sure the cartId is valid
      };

      const variables = { input };

      const { submitCart: submitCartResult } = await client.request(
        SUBMIT_CART_MUTATION,
        variables,
        headers,
      );

      if (submitCartResult?.errors?.length) {
        throw new Error(
          `Cart submission failed: ${JSON.stringify(submitCartResult.errors)}`,
        );
      }

      return submitCartResult.cart;
    };

    // Example usage
    const submittedCart = await submitCart("your-cart-id-here");
    console.log("Submitted cart:", submittedCart);
    ```
  </Step>

  <Step title="Display the results of the transaction">
    ```javascript
    const CHECKOUT_BY_CART_ID_QUERY = gql`
      query checkoutByCartID($cartID: ID!) {
        checkoutByCartID(cartID: $cartID) {
          cart {
            id
          }
          status
          orders {
            id
            status
          }
        }
      }
    `;

    const TERMINAL_STATUSES = [
      "SUCCEEDED",
      "FAILED",
      "CANCELLED",
      "PARTIALLY_SUCCEEDED",
      "MIXED",
    ];

    const pollCheckoutStatus = async (cartID, intervalMs = 5000, timeoutMs = 60000) => {
      const start = Date.now();

      while (Date.now() - start < timeoutMs) {
        const variables = { cartID };

        try {
          const response = await client.request(CHECKOUT_BY_CART_ID_QUERY, variables, headers);
          const checkout = response.checkoutByCartID;

          if (!checkout) {
            throw new Error("No checkout data returned.");
          }

          console.log("Current checkout status:", checkout.status);

          if (TERMINAL_STATUSES.includes(checkout.status)) {
            return checkout;
          }
        } catch (err) {
          console.error("Error polling checkout:", err.message);
          throw err;
        }

        await new Promise((resolve) => setTimeout(resolve, intervalMs));
      }

      throw new Error("Polling timed out before checkout reached a terminal state.");
    };

    // Example usage
    const cartID = "your-cart-id-here";

    try {
      const checkout = await pollCheckoutStatus(cartID);
      console.log("Final checkout data:", checkout);
    } catch (error) {
      console.error("Checkout polling failed:", error);
    }
    ```

    After submitting your cart, you can either poll the `checkoutByCartID` endpoint, or listen for Rye's order update webhooks. In some cases there may have been some errors during the submission of the cart, and these can be inspected on the `result` object.

    Errors can occur on the Cart level and the Store level:

    * For the cart level: `result.errors` will provide an array of errors related to submitting the cart with appropriate error messages and codes
    * For the store level: `result.cart.stores[idx].errors` will provide an array of errors related to submitting the order to the store with appropriate error messages and codes

    It is important to remember that **submitting a cart is an async operation**. It is possible for errors to occur *after* you have submitted the cart. Read more about checkout lifecycle [here](/payments-and-ordering/payment-flows).
  </Step>

  <Step title="Cart management">
    * To update the number of existing products in the cart, use the [`updateCartItems`](/api-reference/updatecartitems) mutation.
    * To remove existing products from the cart, use the [`deleteCartItems`](/api-reference/deletecartitems) mutation.
    * To remove the entire cart, use the [`removeCart`](/api-reference/removecart) mutation.
  </Step>
</Steps>

## Next steps

***

* We looked at [`requestAmazonProductByURL`](/api-reference/requestamazonproductbyurl) in this guide, but [`requestShopifyProductByURL`](/api-reference/requestshopifyproductbyurl) and [`requestStoreByURL`](/api-reference/requeststorebyurl) can also be used to add products to our product data catalog.
* Check out our "[starting an integration](/get-started/adding-products/overview)" guide to get started with building out your real API integration.
* Experiment with our API using one of the following playgrounds:
  * [Rye Console sandbox](https://console.rye.com/graphql)
  * [Postman workspace](https://www.postman.com/rye-team/workspace/rye/overview)
  <Warning>
    Before you can make GraphQL requests, you will need to set the correct HTTP headers. Check out our [Authorization guide](/authorization-headers) for details.
  </Warning>


---

*Powered by [holocron.so](https://holocron.so)*
