UI Extensibility - Tutorial : Display Zendesk tickets on the Backoffice

UI Extensibility - Tutorial : Display Zendesk tickets on the Backoffice

Who is this for?

Profile

What you will do

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_PASSWORD

  • A Zendesk account with API token access: ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_API_TOKEN

  • A 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_USER

  • ONESTOCK_API_PASSWORD

  • ONESTOCK_SITE_ID

  • ONESTOCK_API_URL

image-20260617-100136.png

Ā 

image-20260617-100144.png

Ā 


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.com in your Zendesk URL

  • ZENDESK_EMAIL — the agent email used for API authentication

  • ZENDESK_API_TOKEN — the token you just generated

image-20260617-100115.png

Ā 


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

image-20260617-100205.png

Ā 

3.2 — Deploy to Vercel

Go to vercel.com, click Add New → Project, and import your GitHub fork.

image-20260617-100227.png

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_secret

Deploy the project. Once done, copy the Vercel domain — this is your EXTENSION_URL.

image-20260617-100327.png

A few notes:

  • Add .env to your .gitignore. Never commit credentials to your repository.

  • The SIGNATURE_SECRET_KEY is the value you will use as hash_key when 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_key must match the SIGNATURE_SECRET_KEY you 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

  1. Open the OneStock backoffice in your environment

  2. Navigate to any order whose customer has a Zendesk ticket open

  3. Click the Zendesk action button — the extension opens in a modal

  4. 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_KEY in Vercel does not match the hash_key registered in OneStock

  • No tickets displayed — the customer email on the order does not match any Zendesk requester email

  • Zendesk API errors — check ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, and ZENDESK_API_TOKEN in your Vercel environment variables

image-20260617-100425.png

Ā 

image-20260617-100435.png

Ā 


How it works

The extension follows the standard OneStock UI extension architecture:

image-20260617-100613.png
  1. Handshake — the Vue app sends extension_ready via postMessage; OneStock responds with onestock_data containing the order ID and HMAC signature

  2. Signature verification — the frontend POSTs the signature to the FastAPI backend, which verifies the HMAC and returns a short-lived JWT

  3. Ticket lookup — the frontend calls /api/zendesk-tickets with the JWT; the backend fetches the order from OneStock to get the customer email, then queries Zendesk for matching tickets

  4. Display — 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 deployment

What's next?

  • Adapt to your Zendesk setup — the reference project searches tickets by customer email. Modify OrderActionView.vue and server.py to 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 in src/extensions/. Register each new anchor via PATCH /extensions/{id}.

  • Rotate credentials — to rotate the hash_key, update SIGNATURE_SECRET_KEY in Vercel and call PATCH /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.