API Walkthrough
Learn the core API and webhook workflow for a managed BoxNCase workspace. This guide assumes basic knowledge of GraphQL.
Communicating with BoxNCase is done via public and private GraphQL APIs and webhooks:
- Public APIs: Used for storefront clients, mobile apps, and other public-facing applications that do not store secret tokens.
- Admin APIs: Used by the BoxNCase Dashboard and by approved server-side apps with explicit permissions.
- Webhooks: Used to notify external systems about events in BoxNCase, such as order creation, order payment, or order fulfillment.
- Synchronous webhooks: Let an approved service participate in selected pricing, shipping, tax, or checkout decisions while a request is in progress.
GraphQL provides many benefits and one of them is tooling that eliminates the needs for dedicated SDKs. To keep this guide universal to any technology stack, we will use GraphQL playground, but you can paste the queries to your preferred language or tool.
Prepare a test workspace
Complete partner onboarding and ask your workspace administrator for test-environment access. Add at least one published product with a variant, price, channel assignment, and inventory.
Example object IDs below are illustrative. Use the IDs returned by your own test workspace.
Open GraphQL playground
Every BoxNCase workspace includes GraphQL access in two ways:
BoxNCase Dashboard: Open the API Playground from your workspace. Queries run with the signed-in user's permissions.
Workspace endpoint: Copy the GraphQL endpoint from your workspace's integration settings. It typically ends in /graphql/. Requests are public only where the storefront schema allows it; privileged fields require a staff or app token.
This tutorial uses the Dashboard playground so credentials do not need to be copied into another tool.
Fetch products
Retrieve a list of 10 products with a minimal price between 10 and 100.
In the result tab, we get a paginated list of products with their names and categories.
Each query also returns the cost of the query.
- GraphQL
- Result
{
products(
first: 10
channel: "default-channel"
where: { minimalPrice: { range: { gte: 10, lte: 100 } } }
) {
edges {
node {
id
name
category {
id
name
}
}
}
}
}
{
"data": {
"products": {
"edges": [
{
"node": {
"id": "UHJvZHVjdDoxMzQ=",
"name": "Monospace Tee",
"category": {
"id": "Q2F0ZWdvcnk6Mzk=",
"name": "T-shirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMzA=",
"name": "Paul's Balance 420",
"category": {
"id": "Q2F0ZWdvcnk6Mjg=",
"name": "Sneakers"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxNDU=",
"name": "Battle-tested at brands like Lush",
"category": {
"id": "Q2F0ZWdvcnk6MjY=",
"name": "Audiobooks"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMzI=",
"name": "Blue Hoodie",
"category": {
"id": "Q2F0ZWdvcnk6Mjk=",
"name": "Sweatshirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMjg=",
"name": "Blue Plimsolls",
"category": {
"id": "Q2F0ZWdvcnk6Mjg=",
"name": "Sneakers"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMzc=",
"name": "Blue Polygon Shirt",
"category": {
"id": "Q2F0ZWdvcnk6Mzk=",
"name": "T-shirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxNjE=",
"name": "Cubes Fountain Tee",
"category": {
"id": "Q2F0ZWdvcnk6Mzk=",
"name": "T-shirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMzY=",
"name": "Darko Polo",
"category": {
"id": "Q2F0ZWdvcnk6NDA=",
"name": "Polo shirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMzg=",
"name": "Dark Polygon Tee",
"category": {
"id": "Q2F0ZWdvcnk6Mzk=",
"name": "T-shirts"
}
}
},
{
"node": {
"id": "UHJvZHVjdDoxMjk=",
"name": "Dash Force",
"category": {
"id": "Q2F0ZWdvcnk6Mjg=",
"name": "Sneakers"
}
}
}
]
}
},
"extensions": {
"cost": {
"requestedQueryCost": 20,
"maximumAvailable": 50000
}
}
}
Get specific product
Retrieve the first product ID from the previous query and fetch the product details.
It is possible to fetch many fields associated with products. To conveniently explore the fields that can be added to the query, use the auto-complete by using cmd+space or ctrl+space on Windows.
Or use the folder icon in the left side panel to explore the fields and interactively add them to the query.
Note that some fields are private and require specific permissions, which we will cover in the later steps.
- GraphQL
- Result
{
product(id: "UHJvZHVjdDoxMzQ=", channel: "default-channel") {
id
seoTitle
seoDescription
availableForPurchaseAt
created
externalReference
isAvailable(address: { country: US })
media(sortBy: { direction: ASC, field: ID }) {
id
alt
}
name
variants {
created
id
media {
alt
}
}
}
}
{
"data": {
"product": {
"id": "UHJvZHVjdDoxMzQ=",
"seoTitle": "",
"seoDescription": "",
"availableForPurchaseAt": "2022-05-13T21:22:42.298000+00:00",
"created": "2023-12-29T09:47:45.467273+00:00",
"externalReference": null,
"isAvailable": true,
"media": [
{
"id": "UHJvZHVjdE1lZGlhOjE3",
"alt": ""
},
{
"id": "UHJvZHVjdE1lZGlhOjE4",
"alt": ""
}
],
"name": "Monospace Tee",
"variants": [
{
"created": "2023-12-29T09:47:45.931645+00:00",
"id": "UHJvZHVjdFZhcmlhbnQ6MzQ4",
"media": [
{
"alt": ""
}
]
},
{
"created": "2023-12-29T09:47:45.942318+00:00",
"id": "UHJvZHVjdFZhcmlhbnQ6MzQ5",
"media": [
{
"alt": ""
}
]
},
{
"created": "2023-12-29T09:47:45.952070+00:00",
"id": "UHJvZHVjdFZhcmlhbnQ6MzUw",
"media": [
{
"alt": ""
}
]
},
{
"created": "2023-12-29T09:47:45.961975+00:00",
"id": "UHJvZHVjdFZhcmlhbnQ6MzUx",
"media": [
{
"alt": ""
}
]
},
{
"created": "2023-12-29T09:47:45.971912+00:00",
"id": "UHJvZHVjdFZhcmlhbnQ6MzUy",
"media": [
{
"alt": ""
}
]
}
]
}
},
"extensions": {
"cost": {
"requestedQueryCost": 4,
"maximumAvailable": 50000
}
}
}
Create a checkout
Let's create a checkout with a product variant we fetched in the previous step.
Checkout only accepts the variant ID, not the product, as variants have inventory and pricing information.
- GraphQL
- Result
mutation {
checkoutCreate(
input: {
channel: "default-channel"
lines: { quantity: 1, variantId: "UHJvZHVjdFZhcmlhbnQ6MzQ4" }
}
) {
checkout {
id
lines {
id
variant {
name
}
}
}
errors {
field
message
}
}
}
{
"data": {
"checkoutCreate": {
"checkout": {
"id": "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1",
"lines": [
{
"id": "Q2hlY2tvdXRMaW5lOjEwMGFkMTUwLWNhZTktNDVlMi1hZDIxLTE3MDVmZDAxZWM3NQ==",
"variant": {
"name": "S"
}
}
]
},
"errors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"maximumAvailable": 50000
}
}
}
Update checkout
Let's add the user and billing addresses to the checkout and assign them to an anonymous user.
Notice that we can add two mutations in a single request. In the last mutation, we updated the email address of the checkout and requested the shipping methods available for the checkout.
- GraphQL
- Result
mutation {
checkoutShippingAddressUpdate(
checkoutId: "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1"
shippingAddress: {
firstName: "First"
lastName: "Last"
streetAddress1: "8066 Madison St."
city: "Brooklyn"
postalCode: "11237"
country: US
countryArea: "NY"
}
) {
errors {
field
message
}
}
checkoutBillingAddressUpdate(
checkoutId: "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1"
billingAddress: {
firstName: "First"
lastName: "Last"
streetAddress1: "8066 Madison St."
city: "Brooklyn"
postalCode: "11237"
country: US
countryArea: "NY"
}
) {
errors {
field
message
}
}
checkoutEmailUpdate(
checkoutId: "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1"
email: "[email protected]"
) {
checkout {
shippingMethods {
id
name
}
}
errors {
field
message
}
}
}
{
"data": {
"checkoutShippingAddressUpdate": {
"errors": []
},
"checkoutBillingAddressUpdate": {
"errors": []
},
"checkoutEmailUpdate": {
"checkout": {
"shippingMethods": [
{
"id": "U2hpcHBpbmdNZXRob2Q6MQ==",
"name": "Default"
},
{
"id": "U2hpcHBpbmdNZXRob2Q6MTU=",
"name": "FedEx"
},
{
"id": "U2hpcHBpbmdNZXRob2Q6MTQ=",
"name": "UPS"
},
{
"id": "U2hpcHBpbmdNZXRob2Q6MTY=",
"name": "EMS"
},
{
"id": "U2hpcHBpbmdNZXRob2Q6MTM=",
"name": "DHL"
}
]
},
"errors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"maximumAvailable": 50000
}
}
}
Select shipping method
Let's select the default shipping method for the checkout retrieved in the previous step.
- GraphQL
- Result
mutation {
checkoutDeliveryMethodUpdate(
id: "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1"
deliveryMethodId: "U2hpcHBpbmdNZXRob2Q6MQ=="
) {
errors {
field
message
}
}
}
{
"data": {
"checkoutDeliveryMethodUpdate": {
"errors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 0,
"maximumAvailable": 50000
}
}
}
Add webhook
Before placing an order, we would like to add a webhook to notify our system about the order so we can dispatch email, create an export to the ERP system, or any other custom action.
For simplicity of the steps, let's do it via the dashboard:
- Open BoxNCase dashboard
- Go to Extentions -> Add Extention -> Provide details manually
- App name
My App - Enable Permissions
HANDLE_CHECKOUTandMANAGE_ORDERS - Copy generated token somewhere safe
- Create a webhook with the following details:
- Name:
Order webhook - Target URL: For simplicity of the test go to
https://webhook.site/and copyYour unique URLvalue - App:
My App - Select Event: Asynchronous ->
ORDER->CREATED
- Name:
- Subscription query
subscription {
event {
... on OrderCreated {
__typename
order {
id
shippingAddress {
streetAddress1
city
cityArea
companyName
countryArea
firstName
country {
country
code
}
id
lastName
postalCode
phone
}
}
}
}
}
Create an order
For simplicity of the steps, we will skip the payment step and create an order directly.
Creating an order without payment requires admin or app permission. Add the app token copied in the previous step to the headers in the playground. If you forgot or lost a token from the previous step, you can create another one in the app settings.
After executing the mutation, you should be able to see the order in the dashboard and a payload in the https://webhook.site/ with the order details provided in the subscription query.
Note: orderCreateFromCheckout mutation requires the App Token. To transform the checkout on behalf of the customer, use checkoutComplete mutation.
- Headers
- Mutation
- Result
{
"authorization": "Bearer YOUR_TOKEN"
}
mutation {
orderCreateFromCheckout(
id: "Q2hlY2tvdXQ6NmUzMzRlMjMtOWJiNS00MWUwLTk1NzYtZDc0NmJmMzQ4NDc1"
) {
order {
id
status
lines {
variantName
quantity
}
}
errors {
field
message
}
}
}
{
"data": {
"orderCreateFromCheckout": {
"order": {
"id": "T3JkZXI6MzYwNWE2MWYtNDc4OC00ZjZlLWJiYzktZjEwMjJhOGFlOGYw",
"status": "UNCONFIRMED",
"lines": [
{
"variantName": "S",
"quantity": 1
}
]
},
"errors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"maximumAvailable": 50000
}
}
}
Marking order as paid
We can mark the order as paid manually in the dashboard, but let's proceed via API, as the main feature of headless API is that we can automate anything via API.
- Mutation
- Result
mutation {
orderMarkAsPaid(
id: "T3JkZXI6MzYwNWE2MWYtNDc4OC00ZjZlLWJiYzktZjEwMjJhOGFlOGYw"
) {
order {
id
totalBalance {
amount
}
}
}
}
{
"data": {
"order": {
"id": "T3JkZXI6MzYwNWE2MWYtNDc4OC00ZjZlLWJiYzktZjEwMjJhOGFlOGYw",
"totalBalance": {
"amount": 0
}
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"maximumAvailable": 50000
}
}
}
Next steps
To learn more about BoxNCase Commerce APIs interactively, you can inspect GraphQL operations using the browser's native network inspector or GraphQL inspector while using the dashboard.
- Explore GraphQL tools
- Learn more about BoxNCase's GraphQL API usage.
Useful resources
Use the workspace API Playground for authenticated exploration and the API reference for the current schema. Generate a client collection from schema introspection when your team uses Postman, Insomnia, or another GraphQL client.