GraphQL Api is enabled by default (defined('GRAPHQL') || define('GRAPHQL', true) in env.php). To disable it, define GRAPHQL as false.

defined('GRAPHQL') || define('GRAPHQL', true);

Install library dependency

The webonyx/graphql-php library is already required in composer.json - from the Vvveb folder run composer install (not composer require).

Authentication

Authentication is done with HTTP Authorization or Bearer tokens using any admin user credentials that has GraphQL role permissions.

curl -i -H 'Content-Type: application/json' -H "Authorization: Bearer mytoken" -X POST -d '{"query":"{ posts { nodes { postId name content } } }"}' 'https://demo.vvveb.com/graphql' 
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' 

Permissions

Permission can be controlled from admin user roles and can be set for both resource and action.

GraphQL IDE

An interactive in-browser GraphQL IDE is provided by the GraphQL plugin https://plugins.vvveb.com/product/graphql


To fetch products effectively via the Vvveb GraphQL API, you should use a query that includes pagination arguments (like page 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: Bearer token or the session ID in the headers to keep the cart "alive" between requests.
  • Error Handling: Always check the errors array 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 errors array 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 cartItemId vs productId: Always use the cartItemId for updates and removals. A productId isn'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 quantity to 0 in the updateCartItem mutation 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 loading to 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%").

Vercel Next.js Commerce

Vercel Next.js Commerce headless store implemented using Vvveb GraphQL API https://github.com/givanz/vercel-vvveb-commerce

Demo vercel-vvveb-commerce.vercel.app