UI Extensibility - Tutorial : Display Zendesk tickets on the Backoffice
Who is this for?
Profile | What you will do |
|---|---|
š§ System Integrator (SI) | You deploy a UI extension that surfaces Zendesk tickets inside the OneStock backoffice order detail page, using a fork of the provided reference project. |
āļø Retailer Tech Team | You own the deployed extension post go-live, manage credentials rotation, and can adapt the codebase to your internal Zendesk setup. |
What you will build
A UI extension that appears as an action button on any order detail page in the OneStock backoffice. When clicked, it opens a modal showing all Zendesk tickets linked to the customer's email ā fetched live from Zendesk, secured by OneStock's signature verification.
Why this matters
Customer service agents currently switch between OneStock and Zendesk to handle order issues. This extension removes that context switch: the agent stays in OneStock, sees the customer's open and resolved tickets inline, and can act without leaving the order view.
What you need before starting
A OneStock environment with a Config Manager role ā you need:
site_id,api_url,ONESTOCK_API_USER,ONESTOCK_API_PASSWORDA Zendesk account with API token access:
ZENDESK_SUBDOMAIN,ZENDESK_EMAIL,ZENDESK_API_TOKENA GitHub account to fork the reference project
A Vercel account to deploy the project (free tier sufficient)
Step 1 ā Create an application user in your backoffice
Go to Users ā Application ā Create API access and select External System = API User.
Save the credentials ā you will need them to configure the project:
ONESTOCK_API_USERONESTOCK_API_PASSWORDONESTOCK_SITE_IDONESTOCK_API_URL
Ā
Ā
Step 2 ā Create a Zendesk API token
In your Zendesk Admin Center, go to Apps and integrations ā API tokens ā Add API token.
Save the three values you will need:
ZENDESK_SUBDOMAINā the part before.zendesk.comin your Zendesk URLZENDESK_EMAILā the agent email used for API authenticationZENDESK_API_TOKENā the token you just generated
Ā
Step 3 ā Fork and deploy the project
3.1 ā Fork the reference project
The repository is currently private. Contact product@onestock-retail.com to get access to the repository and share your github username.
Fork the reference project to your GitHub account: https://github.com/jpsaklokham/onestock-ui-extension
Ā
3.2 ā Deploy to Vercel
Go to vercel.com, click Add New ā Project, and import your GitHub fork.
Before deploying, generate two security secrets:
# Generate SIGNATURE_SECRET_KEY
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Generate JWT_SECRET
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"In Vercel ā your project ā Settings ā Environment Variables, add:
# OneStock
ONESTOCK_SITE_ID=your_site_id
ONESTOCK_API_URL=your_onestock_api_url
ONESTOCK_API_USER=your_api_user
ONESTOCK_API_PWD=your_api_password
# Zendesk
ZENDESK_SUBDOMAIN=your_zendesk_subdomain
ZENDESK_EMAIL=agent@yourcompany.com
ZENDESK_API_TOKEN=your_zendesk_api_token
# Security
SIGNATURE_SECRET_KEY=your_generated_secret
JWT_SECRET=your_generated_jwt_secretDeploy the project. Once done, copy the Vercel domain ā this is your EXTENSION_URL.
A few notes:
Add
.envto your.gitignore. Never commit credentials to your repository.The
SIGNATURE_SECRET_KEYis the value you will use ashash_keywhen registering the extension in Step 4.
Step 4 ā Register the extension in OneStock
Use your API credentials to declare the extension and its anchor:
POST {{ONESTOCK_API_URL}}/extensions
Headers: OneStock-User: {{ONESTOCK_API_USER}}, OneStock-Pwd: {{ONESTOCK_API_PASSWORD}}
{
"token": "{{token}}",
"site_id": "{{ONESTOCK_SITE_ID}}",
"extension": {
"name": "Zendesk",
"description": "Zendesk connector",
"hash_key": "{{SIGNATURE_SECRET_KEY}}",
"url": "{{EXTENSION_URL}}",
"test_url": "{{EXTENSION_URL}}",
"injection_points": [
{
"anchor": "bo.order.action",
"name": "Zendesk",
"path": "/order-action",
"rank": 0
}
]
}
}A few notes:
The
hash_keymust match theSIGNATURE_SECRET_KEYyou set in Vercel. OneStock uses it to sign every request to your extension.The
path(/order-action) must match the route defined in the extension's Vue Router.The
anchor: "bo.order.action"makes the extension appear as a button on every order detail page.
Step 5 ā Test the extension
Open the OneStock backoffice in your environment
Navigate to any order whose customer has a Zendesk ticket open
Click the Zendesk action button ā the extension opens in a modal
The extension loads, performs the OneStock handshake, verifies the signature, then displays the customer's open and resolved tickets grouped by status
If the modal stays blank, open your browser devtools (F12) and check the Console for postMessage or fetch errors. Common issues:
403 Invalid signatureāSIGNATURE_SECRET_KEYin Vercel does not match thehash_keyregistered in OneStockNo tickets displayed ā the customer email on the order does not match any Zendesk requester email
Zendesk API errors ā check
ZENDESK_SUBDOMAIN,ZENDESK_EMAIL, andZENDESK_API_TOKENin your Vercel environment variables
Ā
Ā
How it works
The extension follows the standard OneStock UI extension architecture:
Handshake ā the Vue app sends
extension_readyvia postMessage; OneStock responds withonestock_datacontaining the order ID and HMAC signatureSignature verification ā the frontend POSTs the signature to the FastAPI backend, which verifies the HMAC and returns a short-lived JWT
Ticket lookup ā the frontend calls
/api/zendesk-ticketswith the JWT; the backend fetches the order from OneStock to get the customer email, then queries Zendesk for matching ticketsDisplay ā tickets are rendered as a timeline split into Active and Resolved groups
Project structure:
src/
ā
āāā main.ts # App entry point ā mounts Vue, applies locale from URL,
ā # and sends "extension_ready" to the Backoffice parent frame
ā
āāā App.vue # Root component ā runs the handshake once and provides
ā # order data to the whole component tree via provide/inject
ā
āāā onestockHandshake.ts # Handshake composable ā listens for the "onestock_data"
ā # postMessage, verifies the HMAC signature with the server,
ā # and stores the returned JWT for subsequent API calls
ā
āāā onestockApi.ts # HTTP client ā attaches the JWT Bearer token to every
ā # request; exposes callOnestockApi (OneStock proxy) and
ā # callBackendApi (any direct server route)
ā
āāā router.ts # Vue Router ā auto-discovers all extensions by glob-importing
ā # every src/extensions/*/route.ts file at build time
ā
āāā i18n.ts # vue-i18n setup ā defines supported locales, exports
ā # setLocale() used by the handshake and main.ts
ā
āāā style.css # Global base styles
ā
āāā vite-env.d.ts # Vite environment type declarations (VITE_* vars)
ā
āāā assets/
ā āāā icon.jpeg # Extension icon
ā
āāā components/
ā āāā HelloWorld.vue # Placeholder component (not used in production)
ā
āāā locales/ # i18n translation files (one per supported language)
ā āāā en.json
ā āāā fr.json
ā āāā de.json
ā āāā it.json
ā āāā es.json
ā āāā el.json
ā āāā ru.json
ā
āāā extensions/ # One sub-folder per extension ā router picks them up automatically
āāā order-action/
āāā OrderActionView.vue # The Zendesk tickets panel ā fetches tickets by order ID
ā # and renders them as an Active / Resolved timeline
āāā route.ts # Declares the /order-action route and maps it to OrderActionView
server.py # FastAPI server ā verifies HMAC signatures, issues JWTs,
ā # and proxies authenticated calls to OneStock and Zendesk
api/
āāā index.py # Vercel serverless entry point ā wraps server.py for deploymentWhat's next?
Adapt to your Zendesk setup ā the reference project searches tickets by customer email. Modify
OrderActionView.vueandserver.pyto search by order reference or any other Zendesk field.Add more anchors ā the same extension codebase can power additional anchors (
bo.page,bo.orders.action) by adding routes insrc/extensions/. Register each new anchor viaPATCH /extensions/{id}.Rotate credentials ā to rotate the
hash_key, updateSIGNATURE_SECRET_KEYin Vercel and callPATCH /extensions/{id}with the new key. OneStock retains the 3 most recent keys to avoid downtime during rotation.UI Extensibility reference ā full handshake contract, anchor types, and security details are in the UI Extensibility ā How to develop guide.