How-to guides
/
Create a custom shop

Create a custom shop

Openship supports shop platforms out of the box like Shopify, WooCommerce, and BigCommerce, but also works with custom shops.

To create a custom shop, you must create 4 endpoints:

Search orders endpoint

1. We'll start with a function that returns an array of orders. You can fetch these orders from a CMS, Google Sheet, or any platform.

Each order in the array will have 13 values:

  • orderId:
    string
    unique order identifier
  • orderName:
    string
    order name
  • link:
    string
    link to order
  • date:
    string
    date of order creation
  • first_name:
    string
    customer's first name
  • last_name:
    string
    customer's last name
  • streetAddress1:
    string
    street address
  • streetAddress2:
    string
    apartment/suite
  • city:
    string
    city
  • state:
    string
    state
  • zip:
    string
    zip code
  • country:
    string
    country
  • lineItems:
    array
    products sold
    • name: product title
    • quantity: quantity of product to ship
    • price: product cost
    • image: link to product image
    • productId: product identifier
    • variantId: product variant identifier
    • lineItemId: unique identifier for line item
api/search-orders.js

export default async (req, res) => {
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
return res
.status(200)
.json({ orders: allOrders });
};


2. Openship will send some attributes to the endpoint:

  • domain: shop domain
  • accessToken: access token to verify the request
  • searchEntry: search orders based on this value

Let's put these values to use.

api/search-orders.js

export default async (req, res) => {
const {
domain,
accessToken,
searchEntry,
} = req.query;
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
return res
.status(200)
.json({ orders: allOrders });
};


3. First, we check this access token against our .env file to make the user has been granted access.

api/search-orders.js

export default async (req, res) => {
const {
domain,
accessToken,
searchEntry,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
return res
.status(200)
.json({ orders: allOrders });
};


4. Next, let's check if the search entry parameter exists and if so, filter our orders based on that value.

api/search-orders.js

export default async (req, res) => {
const {
domain,
accessToken,
searchEntry,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
if (searchEntry) {
const orders = allOrders.filter((order) =>
order.orderName.includes(searchEntry)
);
return res.status(200).json({ orders });
}
return res
.status(200)
.json({ orders: allOrders });
};


5. And, if search entry doesn't exist, we return all the orders.

api/search-orders.js

export default async (req, res) => {
const {
domain,
accessToken,
searchEntry,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
if (searchEntry) {
const orders = allOrders.filter((order) =>
order.orderName.includes(searchEntry)
);
return res.status(200).json({ orders });
}
return res
.status(200)
.json({ orders: allOrders });
};

Search orders endpoint

1. We'll start with a function that returns an array of orders. You can fetch these orders from a CMS, Google Sheet, or any platform.

Each order in the array will have 13 values:

  • orderId:
    string
    unique order identifier
  • orderName:
    string
    order name
  • link:
    string
    link to order
  • date:
    string
    date of order creation
  • first_name:
    string
    customer's first name
  • last_name:
    string
    customer's last name
  • streetAddress1:
    string
    street address
  • streetAddress2:
    string
    apartment/suite
  • city:
    string
    city
  • state:
    string
    state
  • zip:
    string
    zip code
  • country:
    string
    country
  • lineItems:
    array
    products sold
    • name: product title
    • quantity: quantity of product to ship
    • price: product cost
    • image: link to product image
    • productId: product identifier
    • variantId: product variant identifier
    • lineItemId: unique identifier for line item

2. Openship will send some attributes to the endpoint:

  • domain: shop domain
  • accessToken: access token to verify the request
  • searchEntry: search orders based on this value

Let's put these values to use.


3. First, we check this access token against our .env file to make the user has been granted access.


4. Next, let's check if the search entry parameter exists and if so, filter our orders based on that value.


5. And, if search entry doesn't exist, we return all the orders.

api/search-orders.js
ExpandClose

export default async (req, res) => {
const allOrders = [
{
orderId: "210983908",
orderName: "SC-1221",
link: "https://sc.com/order/210983908",
date: Intl.DateTimeFormat("en-US").format(
Date.now()
),
first_name: "Jared",
last_name: "Dunn",
streetAddress1: "3593 Sycamore Street",
streetAddress2: "STE. 113",
city: "San Francisco",
state: "CA",
zip: "94103",
country: "US",
lineItems: [
{
name: "Road Bike",
quantity: 1,
price: "499",
image: "https://example.com/road-bike",
productId: "32849038290",
variantId: "0",
lineItemId: "2313613213",
},
],
},
];
return res
.status(200)
.json({ orders: allOrders });
};

Search products endpoint

2. Let's start with a function that returns an array of products. You can fetch these products from a CMS, Google Sheet, or any platform. Each product in the array will have 5 values:

  • image:
    string
    product image
  • title:
    string
    product title
  • productId:
    string
    product identifier
  • variantId:
    string
    variant product identifier, if none send 0
  • price:
    string
    product price
  • availableForSale:
    boolean
    true if item is available
api/search-products.js

export default async (req, res) => {
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
return res
.status(200)
.json({ products: allProducts });
}


2. Openship will send some attributes to the endpoint:

  • accessToken: access token to verify the request
  • searchEntry: search products based on this value
  • productId: product identifier
  • variantId: product variant identifier

Let's put these values to use.

api/search-products.js

export default async (req, res) => {
const {
accessToken,
searchEntry,
productId,
variantId,
} = req.query;
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
return res
.status(200)
.json({ products: allProducts });
}


3. First, we check this access token against our .env file to make the user has been granted access.

api/search-products.js

export default async (req, res) => {
const {
accessToken,
searchEntry,
productId,
variantId,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
return res
.status(200)
.json({ products: allProducts });
};


4. Next, let's check if the search entry parameter exists and if so, filter our products based on that value.

api/search-products.js

export default async (req, res) => {
const {
accessToken,
searchEntry,
productId,
variantId,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
if (searchEntry) {
const products = allProducts.filter((product) =>
product.title.includes(searchEntry)
);
return res.status(200).json({ products });
}
return res
.status(200)
.json({ products: allProducts });
};


5. Next, let's check if the productId and variantId exist. If so, filter allProducts based on these values. If no products are found after filtering, return an error.

api/search-products.js

export default async function handler(req, res) {
const {
accessToken,
searchEntry,
productId,
variantId,
} = req.query;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
if (searchEntry) {
const products = allProducts.filter((product) =>
product.title.includes(searchEntry)
);
return res.status(200).json({ products });
}
if (productId && variantId) {
const products = allProducts.filter(
(product) =>
product.productId === productId &&
product.variantId === variantId
);
if (products.length > 0) {
return res.status(200).json({ products });
}
return res
.status(400)
.json({ error: "Not found" });
}
return res
.status(200)
.json({ products: allProducts });
}

Search products endpoint

2. Let's start with a function that returns an array of products. You can fetch these products from a CMS, Google Sheet, or any platform. Each product in the array will have 5 values:

  • image:
    string
    product image
  • title:
    string
    product title
  • productId:
    string
    product identifier
  • variantId:
    string
    variant product identifier, if none send 0
  • price:
    string
    product price
  • availableForSale:
    boolean
    true if item is available

2. Openship will send some attributes to the endpoint:

  • accessToken: access token to verify the request
  • searchEntry: search products based on this value
  • productId: product identifier
  • variantId: product variant identifier

Let's put these values to use.


3. First, we check this access token against our .env file to make the user has been granted access.


4. Next, let's check if the search entry parameter exists and if so, filter our products based on that value.


5. Next, let's check if the productId and variantId exist. If so, filter allProducts based on these values. If no products are found after filtering, return an error.

api/search-products.js
ExpandClose

export default async (req, res) => {
const allProducts = [
{
image: "https://example.com/book.jpeg",
title: "Pocket Book",
productId: "887262",
variantId: "0",
price: "9.99",
availableForSale: true,
},
];
return res
.status(200)
.json({ products: allProducts });
}

Create order endpoint

To create orders for this shop on Openship, we'll be using the API and will need a key. On Openship, you'll see the key icon on the left sidebar.

After generating a key, add this to your .env file as OPENSHIP_KEY. Since we'll be using Openship's GraphQL API, we'll also add OPENSHIP_DOMAIN to the .env file.

This is how the .env file looks so far:

  • ACCESS_TOKEN: access token to verify the request
  • OPENSHIP_DOMAIN: domain where your Openship API can be accessed (normally ends in /api/graphql)
  • OPENSHIP_KEY: API key created on your Openship instance
.env

ACCESS_TOKEN=supersecretpassword
OPENSHIP_DOMAIN=https://myshop.myopenship.com/api/graphql
OPENSHIP_KEY=bc5394008c83802e



1. Let's start creating our create-order function. First, we'll get these 14 values from the request body:

  • shopId:
    string
    Openship shop ID
  • orderId:
    string
    unique order identifier
  • orderName:
    string
    order name
  • email:
    string
    customer email
  • first_name:
    string
    customer's first name
  • last_name:
    string
    customer's last name
  • streetAddress1:
    string
    street address
  • streetAddress2:
    string
    apartment/suite
  • city:
    string
    city
  • state:
    string
    state
  • zip:
    string
    zip code
  • country:
    string
    country
  • lineItems:
    array
    products sold
    • name: product title
    • quantity: quantity of product to ship
    • price: product cost
    • image: link to product image
    • productId: product identifier
    • variantId: product variant identifier
    • lineItemId: unique identifier for line item
api/create-order.js

export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
};


2. First, we'll check the accessToken against ACCESS_TOKEN variable that's in our .env file.

api/create-order.js

export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
};


3. To make requests to Openship's GraphQL API, we'll use the gql and request imports from the graphql-request package.

We'll use OPENSHIP_DOMAIN as the url and pass OPENSHIP_KEY a header named x-api-key.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
});
} catch {
}
};


4. Let's create the mutation which will create the order on Openship. We'll pass the mutation under document and pass the values from the request body as variables.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($data: OrderCreateInput!) {
createOrder(data: $data) {
id
}
}
`,
});
} catch {
}
};


5. Now, let's create pass the values from the request body as variables.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($data: OrderCreateInput!) {
createOrder(data: $data) {
id
}
}
`,
variables: {
data: {
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems: { create: lineItems },
shop: { connect: { id: shopId } },
},
},
});
} catch {
}
};


6. We can also pass some extra variables when creating the order:

  • linkOrder:
    boolean
    if true, Openship will check if the order shop has a linked channel and create cart items accordingly
  • matchOrder:
    boolean
    if true, Openship will check if line items have any matches and create cart items accordingly
  • processOrder:
    boolean
    if true and linking the order or matching the order didn't create any errors, Openship will process the order and create purchases based on the cart items
  • status:
    string
    order status

We'll pass in true for linkOrder, matchOrder, and processOrder. Since the order will be in processing as soon as it is created, we'll mark the status as INPROCESS. Otherwise, we would mark the status as PENDING.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($data: OrderCreateInput!) {
createOrder(data: $data) {
id
}
}
`,
variables: {
data: {
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems: { create: lineItems },
shop: { connect: { id: shopId } },
linkOrder: true,
matchOrder: true,
processOrder: true,
status: "INPROCESS",
},
},
});
} catch {
}
};


7. Lastly, if order creation is successful, we'll return the order information.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($data: OrderCreateInput!) {
createOrder(data: $data) {
id
}
}
`,
variables: {
data: {
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems: { create: lineItems },
shop: { connect: { id: shopId } },
linkOrder: true,
matchOrder: true,
processOrder: true,
status: "INPROCESS",
},
},
});
return res
.status(200)
.json({ orderDetails });
} catch {
}
};


8. We'll also catch any errors if creating the order fails.

api/create-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const orderDetails = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($data: OrderCreateInput!) {
createOrder(data: $data) {
id
}
}
`,
variables: {
data: {
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems: { create: lineItems },
shop: { connect: { id: shopId } },
linkOrder: true,
matchOrder: true,
processOrder: true,
status: "INPROCESS",
},
},
});
return res
.status(200)
.json({ orderDetails });
} catch {
return res.status(400).json({
error: "Order creation failed.",
});
}
};


1. Let's start creating our create-order function. First, we'll get these 14 values from the request body:

  • shopId:
    string
    Openship shop ID
  • orderId:
    string
    unique order identifier
  • orderName:
    string
    order name
  • email:
    string
    customer email
  • first_name:
    string
    customer's first name
  • last_name:
    string
    customer's last name
  • streetAddress1:
    string
    street address
  • streetAddress2:
    string
    apartment/suite
  • city:
    string
    city
  • state:
    string
    state
  • zip:
    string
    zip code
  • country:
    string
    country
  • lineItems:
    array
    products sold
    • name: product title
    • quantity: quantity of product to ship
    • price: product cost
    • image: link to product image
    • productId: product identifier
    • variantId: product variant identifier
    • lineItemId: unique identifier for line item

2. First, we'll check the accessToken against ACCESS_TOKEN variable that's in our .env file.


3. To make requests to Openship's GraphQL API, we'll use the gql and request imports from the graphql-request package.

We'll use OPENSHIP_DOMAIN as the url and pass OPENSHIP_KEY a header named x-api-key.


4. Let's create the mutation which will create the order on Openship. We'll pass the mutation under document and pass the values from the request body as variables.


5. Now, let's create pass the values from the request body as variables.


6. We can also pass some extra variables when creating the order:

  • linkOrder:
    boolean
    if true, Openship will check if the order shop has a linked channel and create cart items accordingly
  • matchOrder:
    boolean
    if true, Openship will check if line items have any matches and create cart items accordingly
  • processOrder:
    boolean
    if true and linking the order or matching the order didn't create any errors, Openship will process the order and create purchases based on the cart items
  • status:
    string
    order status

We'll pass in true for linkOrder, matchOrder, and processOrder. Since the order will be in processing as soon as it is created, we'll mark the status as INPROCESS. Otherwise, we would mark the status as PENDING.


7. Lastly, if order creation is successful, we'll return the order information.


8. We'll also catch any errors if creating the order fails.

api/create-order.js
ExpandClose

export default async (req, res) => {
const {
shopId,
orderId,
orderName,
email,
first_name,
last_name,
streetAddress1,
streetAddress2,
city,
state,
zip,
country,
currency,
lineItems,
} = req.body;
};

Cancel order endpoint

Orders can also be cancelled. This is useful if an item is out of stock, damaged, lost, customer didn't want the order anymore, etc.

1. Let's start creating our cancel-order function. First, we'll get these 2 values from the request body:

  • accessToken:
    string
    access token to verify the request
  • orderId:
    string
    order ID that needs to be cancelled

We'll check the accessToken against ACCESS_TOKEN variable that's in our .env file.

api/cancel-order.js

export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
};


2. We'll use the same function as before to access Openship's GraphQL API.

api/cancel-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const cancelledOrder = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
});
} catch {
}
};


3. This time, we'll call the cancelOrder mutation and pass the orderId as the variable.

api/cancel-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const cancelledOrder = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($orderId: String!) {
cancelOrder(orderId: $orderId) {
id
}
}
`,
variables: { orderId },
});
} catch {
}
};


4. Lastly, if the order cancellation is successful, we'll return the response.

api/cancel-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const cancelledOrder = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($orderId: String!) {
cancelOrder(orderId: $orderId) {
id
}
}
`,
variables: { orderId },
});
return res
.status(200)
.json({ cancelledOrder });
} catch {
}
};


5. We'll also catch any errors if order cancellation fails.

api/cancel-order.js

import { request, gql } from "graphql-request";
export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
try {
const cancelledOrder = await request({
url: process.env.OPENSHIP_DOMAIN,
requestHeaders: {
"x-api-key": process.env.OPENSHIP_KEY,
},
document: gql`
mutation ($orderId: String!) {
cancelOrder(orderId: $orderId) {
id
}
}
`,
variables: { orderId },
});
return res
.status(200)
.json({ cancelledOrder });
} catch {
return res.status(400).json({
error: "Order cancellation failed.",
});
}
};

1. Let's start creating our cancel-order function. First, we'll get these 2 values from the request body:

  • accessToken:
    string
    access token to verify the request
  • orderId:
    string
    order ID that needs to be cancelled

We'll check the accessToken against ACCESS_TOKEN variable that's in our .env file.


2. We'll use the same function as before to access Openship's GraphQL API.


3. This time, we'll call the cancelOrder mutation and pass the orderId as the variable.


4. Lastly, if the order cancellation is successful, we'll return the response.


5. We'll also catch any errors if order cancellation fails.

api/cancel-order.js
ExpandClose

export default async (req, res) => {
const {
accessToken,
orderId,
} = req.body;
if (process.env.ACCESS_TOKEN !== accessToken) {
return res
.status(403)
.json({ error: "Denied" });
}
};

Deploying the shop

Now that we have our functions built, we have to deploy them. We'll keep it simple and add these functions to a Next.js application as API Routes. This is a good starting place when building your own shop. Check out the CodeSandbox below to customize it and make it your own.

When you're finished customizing, you can deploy the application to Vercel, Netlify, or any platform that supports node.js.

We have already deployed the demo shop we just made. To test it, add the shop and choose DEMO under the shop type.

Create Shop

Deploy this shop yourself on Vercel:

Last updated on March 9, 2023