The Vvveb GraphQL API allows you to build headless storefronts, mobile apps, and custom integrations by querying only the data you need.
It follows a schema-first approach, providing a flexible alternative to traditional REST endpoints.
1. Setup & Requirements
By default, the GraphQL API is disabled for security. To get started, you must enable the feature and install the core library.
Enable the API
Edit your env.php file (located in the root directory) and set the GRAPHQL constant to true:
defined('GRAPHQL') || define('GRAPHQL', true);
Tip: If you don't have SSH/FTP access, you can edit this file via the File Manager Plugin.
Install Dependencies
Vvveb relies on the webonyx/graphql-php library. Choose one of the following methods:
Via Composer:
Run the following command from your Vvveb root:
composer require webonyx/graphql-php
Via Plugin
If you don't have access to command line to run composer , install the GraphQL Lib Plugin.
2. Authentication & Permissions
Access to the GraphQL endpoint is restricted to authorized users. You must use an account that has been assigned a GraphQL Role in the admin panel.
Authentication Methods
You can authenticate your requests using either HTTP Basic Auth (for development) or Bearer Tokens (for production).
Option A: Bearer Token (Recommended)
curl -i -H 'Content-Type: application/json' \
-H "Authorization: Bearer YOUR_TOKEN" \
-X POST \
-d '{"query":"{ posts { nodes { postId name content } } }"}' \
'https://demo.vvveb.com/graphql'
Option B: Basic Auth
curl --user demo:demo -i \
-H 'Content-Type: application/json' \
-X POST \
--data-raw '{"query":"{ posts { nodes { postId name content } } }"}' \
'https://demo.vvveb.com/graphql'
Granular Permissions
Permissions are managed under User Roles in the Vvveb Admin. You can restrict access based on:
- Resource: (e.g., allow reading
postsbut notorders). - Action: (e.g., allow
querybut blockmutation).
3. Development Tools
GraphQL IDE
To explore the schema and test queries visually, install the GraphQL IDE Plugin. This provides an interactive GraphiQL interface directly in your browser.
Headless Integration (Next.js)
Vvveb CMS is fully compatible with Vercel Next.js Commerce. This allows you to deploy a high-performance React frontend while using Vvveb as your robust backend.
- Source Code: Vvveb Next.js Commerce on GitHub
- Live Demo: vercel-vvveb-commerce.vercel.app
To fetch products effectively via the Vvveb GraphQL API, you should use a query that includes pagination arguments (like start and limit) and requests the pageInfo object to determine if more data is available.
Paginated Products Query
This query retrieves the first 3 products, including their IDs, names, slugs, and formatted prices.
query getProducts {
products(limit:3) {
pageInfo {
count
page
limit
}
nodes {
...product
}
}
}
fragment product on ProductType {
productId
slug
stockQuantity
name
content
createdAt
updatedAt
price
priceCurrency
variants {
productId
productVariantId
image
price
stockQuantity
weight
sku
barcode
}
image
image
options {
productOptionId
productId
optionId
name
value
required
values {
name
}
}
variants {
productId
productVariantId
image
price
stockQuantity
weight
sku
barcode
}
images {
productImageId
productId
image
sortOrder
}
seo {
og {
title
description
}
twitter {
title
content
label1
data1
label2
data2
}
}
sites {
siteId
name
}
}
Parameter Breakdown
| Argument | Description |
|---|---|
limit |
The number of items to return (e.g., 10). |
page |
The page number to return. |
count |
The number of products available, useful for calculating the total number of pages in your UI. |
Example JSON Response
When you execute the query, the API returns a structured JSON object. Notice how the price is often returned as an object containing both the raw numeric value and the currency-formatted string.
{
"data": {
"products": {
"pageInfo": {
"count": 0,
"page": 1,
"limit": 10
},
"nodes": [
{
"productId": "19",
"slug": "product-nineteen",
"stockQuantity": 1000,
"name": "Product 19",
"price": {
"regularPrice": 89.99,
"formattedPrice": "$89.99"
},
"image": {
"url": "https://yoursite.com/media/products/kb.jpg",
"altText": "RGB Mechanical Keyboard"
}
}
]
}
}
}
Pro Tip: Filtering by Category
If you want to fetch products from a specific category, you can usually add a filter or taxonomyId argument to the products query:
products(first: 10, filter: { taxonomyId: 5 }) { ... }
Adding a product to a cart is a Mutation because it modifies the state of the server-side data. In Vvveb CMS, this typically requires a productId and a quantity. If your product has variants (like size or color), you would also pass an option array or a variantId.
Add to Cart Mutation
This mutation adds a specific quantity of a product to the current session's cart and returns the updated cart totals and item list.
mutation AddToCart($productId: ID!, $quantity: Int!) {
addToCart(input: { productId: $productId, quantity: $quantity }) {
cart {
total {
amount
formatted
}
items {
cartItemId
name
quantity
price {
formattedPrice
}
total {
formattedPrice
}
}
}
errors {
message
code
}
}
}
Example Variables
Pass these alongside your query to specify which product you're snagging.
{
"productId": "101",
"quantity": 2
}
Example JSON Response
If successful, the API returns the current state of the cart so you can update your UI (like a mini-cart or toast notification) immediately.
{
"data": {
"addToCart": {
"cart": {
"total": {
"amount": 179.98,
"formatted": "$179.98"
},
"items": [
{
"cartItemId": "item_abc123",
"name": "Mechanical Keyboard",
"quantity": 2,
"price": { "formattedPrice": "$89.99" },
"total": { "formattedPrice": "$179.98" }
}
]
},
"errors": []
}
}
}
Key Integration Tips
- Session vs. Token: Vvveb usually handles the cart via the session cookie for web users. However, if you're building a mobile app, ensure your GraphQL client is configured to persist and send the
Authorization: Bearertoken or the session ID in the headers to keep the cart "alive" between requests. - Error Handling: Always check the
errorsarray in the response. A mutation might "succeed" at the network level but fail logically (e.g., if the product is out of stock). - Optimistic UI: For a snappy feel, you can update your local UI state before the server responds, then roll it back if the
errorsarray comes back populated.
Managing a cart effectively requires the ability to tweak quantities or change your mind about an item. In GraphQL, these are separate mutations that typically return the updated state of the entire cart so your UI stays in sync.
Update Item Quantity
This mutation is used when a user clicks a "plus" or "minus" button or types a new number into a quantity field.
mutation UpdateCartItem($cartItemId: ID!, $quantity: Int!) {
updateCartItem(input: { cartItemId: $cartItemId, quantity: $quantity }) {
cart {
total {
formatted
}
items {
cartItemId
quantity
total {
formattedPrice
}
}
}
errors {
message
}
}
}
Example Variables
{
"cartItemId": "item_abc123",
"quantity": 5
}
Remove Item from Cart
To completely delete an item, you only need the unique cartItemId.
mutation RemoveFromCart($cartItemId: ID!) {
removeFromCart(input: { cartItemId: $cartItemId }) {
cart {
total {
formatted
}
items {
name
}
}
errors {
message
}
}
}
Implementation Best Practices
- The
cartItemIdvsproductId: Always use thecartItemIdfor updates and removals. AproductIdisn't specific enough if a user has the same product in their cart with two different sets of options (e.g., one Blue shirt and one Red shirt). - Zero Quantity Logic: In many GraphQL implementations, setting the
quantityto0in theupdateCartItemmutation will automatically trigger the removal of that item. Check your specific Vvveb schema to see if this shortcut is supported. - Loading States: Since these requests happen over the network, disable the "Quantity" input or "Remove" button while the mutation is
loadingto prevent "race conditions" where a user clicks a button faster than the server can process.
To generate an accurate checkout summary, the API needs to calculate values based on the items in the cart and the user's destination. Usually, this query is executed after a shipping address has been set, as taxes and shipping rates are location-dependent.
Checkout Summary Query
This query retrieves the full breakdown of the order, including available shipping carriers and a detailed tax summary.
query GetCheckoutSummary {
checkout {
cart {
items {
name
quantity
total {
formattedPrice
}
}
totals {
subtotal {
formatted
}
shipping {
formatted
}
taxTotal {
formatted
}
grandTotal {
formatted
}
}
}
shippingMethods {
code
title
cost {
amount
formatted
}
taxClassId
}
taxBreakdown {
title
rate
amount {
formatted
}
}
}
}
Component Breakdown
| Section | Description |
|---|---|
cart.totals |
The financial "Bottom Line." Includes the calculated subtotal, current shipping cost, and accumulated taxes. |
shippingMethods |
A list of available carriers (e.g., UPS, FedEx, Flat Rate). You would use the code from this list in a mutation to select a specific method. |
taxBreakdown |
Provides transparency by showing exactly which taxes are being applied (e.g., "VAT 20%" or "State Tax 7%"). |
Implementation Details
- Dynamic Updating: If your checkout is a "Single Page" app, you should re-run this query every time a user changes their shipping address or selects a different shipping method to ensure the
taxTotalandgrandTotalstay accurate. - Address Dependency: In Vvveb CMS, if the
shippingMethodsarray comes back empty, it usually means the user hasn't provided an address yet or no shipping rules match their location. - Currency Logic: Always display the
formattedvalues to the user to handle currency symbols and decimal placements correctly, while using the rawamountfor any local JavaScript calculations if necessary.