I built CartQL to scratch my own itch.
I wanted a shopping cart API that I could use anywhere. On personal projects, side hustles, landing pages — without needing to bring my own inventory system. I wanted to sell things I sourced from other APIs, markdown files, CMSs, existing commerce platforms, even spreadsheets. And I didn’t want to rewire cart logic every time I built something new.
So I built CartQL, a flexible GraphQL shopping cart API that plugs into any stack, doesn’t assume where your products come from, and handles carts, items, and checkout in a predictable way.
Here’s how it works:
metadata field to store custom item data like variants, notes, or shipping info.Manage cart items, checkout and pay for orders with a simple declarative GraphQL API. The API is completely open and free to use.
Use this endpoint: https://api.cartql.com
query {
  cart(id: "ck5r8d5b500003f5o2aif0v2b", currency: { code: GBP }) {
    ...CartWithItems
  }
}
fragment CartWithItems on Cart {
  ...CartInfo
  items {
    ...ItemInfo
  }
}
fragment CartInfo on Cart {
  id
  email
  isEmpty
  abandoned
  totalItems
  totalUniqueItems
  currency {
    code
    symbol
  }
  subTotal {
    amount
    formatted
  }
  shippingTotal {
    amount
    formatted
  }
  taxTotal {
    amount
    formatted
  }
  grandTotal {
    amount
    formatted
  }
  metadata
  notes
  createdAt
  updatedAt
}
fragment ItemInfo on CartItem {
  id
  name
  description
  images
  quantity
  metadata
  unitTotal {
    amount
    formatted
  }
  lineTotal {
    amount
    formatted
  }
  createdAt
  updatedAt
}mutation {
  addItem(
    input: {
      cartId: "ck5r8d5b500003f5o2aif0v2b"
      id: "5e3293a3462051"
      name: "Full Logo Tee"
      description: "Purple Triblend / L"
      images: ["full-logo-tee.png"]
      price: 2000
    }
  ) {
    id
    totalItems
    subTotal {
      formatted
    }
  }
}mutation {
  updateItem(
    input: {
      cartId: "ck5r8d5b500003f5o2aif0v2b"
      id: "5e3293a3462051"
      price: 2500
      quantity: 2
    }
  ) {
    id
    totalItems
    subTotal {
      formatted
    }
  }
}mutation {
  removeItem(
    input: { cartId: "ck5r8d5b500003f5o2aif0v2b", id: "5e3293a3462051" }
  ) {
    id
    totalItems
    subTotal {
      formatted
    }
  }
}metadatamutation {
  updateItem(
    input: {
      cartId: "ck5r8d5b500003f5o2aif0v2b",
      id: "5e3293a3462051",
      metadata: {
        "engraving": "Jamie"
      }
    }
  ) {
    id
    metadata
  }
}mutation {
  updateCart(
    input: { id: "ck5r8d5b500003f5o2aif0v2b", currency: { code: GBP } }
  ) {
    id
    currency {
      code
      symbol
      thousandsSeparator
      decimalSeparator
      decimalDigits
    }
  }
}mutation {
  checkout(
    input: {
      cartId: "ck5r8d5b500003f5o2aif0v2b"
      email: "jamie@cartql.com"
      shipping: {
        name: "Jamie Barton"
        line1: "123 Cart Lane"
        city: "Newcastle upon Tyne"
        postalCode: "NE14 CQL"
        country: "England"
      }
    }
  ) {
    id
    grandTotal {
      formatted
    }
  }
}const Stripe = require("stripe");
const { request, gql } = require("graphql-request");
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const query = gql`
  query getCart($cartId: ID!) {
    cart(id: $cartId) {
      items {
        name
        description
        unitTotal {
          amount
          currency {
            code
          }
        }
        quantity
      }
    }
  }
`;
async function handler(event) {
  const { cartId } = JSON.parse(event.body);
  const { cart } = await request("https://api.cartql.com", query, {
    cartId,
  });
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    success_url: `${process.env.URL}/thankyou`,
    cancel_url: `${process.env.URL}/cart`,
    line_items: cart.items.map(
      ({ name, description, unitTotal, quantity }) => ({
        price_data: {
          currency: unitTotal.currency.code,
          unit_amount: unitTotal.amount,
          product_data: {
            name,
            description,
          },
        },
        quantity,
      }),
    ),
  });
  return {
    statusCode: 201,
    body: JSON.stringify(session),
  };
}There are even more mutations:
setItemsincrementItemQuantitydecrementItemQuantityemptyCartdeleteCartCheck out the gatsby-cartql-starter repo to see it in action.
If you ever wanted to sell something online without needing a whole commerce platform — CartQL might scratch that itch too.