Skip to main content
What you’ll build: A full-stack Cloud App (React frontend + Express/.NET/PHP backend) that authenticates with the JTL platform and runs inside the App Shell.

Prerequisites

Before you start, make sure you have:
1

Account and Access

You need:
  • ✅ A JTL ID (your login to the JTL ecosystem)
  • ✅ Access to an organization (tenant) in the Partner Portal (created automatically on first login if you don’t have one yet)
If you don’t have these yet, follow the step-by-step guide: Create a Developer Account.You’ll also need:
  • ✅ JTL-Wawi installed and running locally
2

Tools Installed

You’ll need the following tools installed on your machine:
  • Node.js v24.16.0 or higher (current LTS, includes npm). Verify with node --version and npm --version
  • For .NET template: .NET SDK. Run dotnet --version to check
  • For PHP template: PHP 8.1 or higher with ext-sodium enabled. Run php --version and php -m | grep sodium to check

1. Create the Project Using Cloud Apps CLI

Follow the prompts to create your app:
  • Ok to proceed? (y): y
  • App name: my-jtl-app
  • Description: My JTL Sample App
  • Frontend: React (Vite + Tailwind + JTL UI)
  • Backend: Node.js or .NET or PHP
Use the Arrow Keys to navigate and Enter to select.
The CLI generates a project that matches your backend choice. The frontend is the same for all three.

2. Install Dependencies

From the project root, install all dependencies:
This installs dependencies for the project.

3. Register your App

The register command signs you in with your JTL ID and lets you select a tenant. It then registers the app and writes the generated credentials to your local environment file. From the project root, run:
The CLI opens a browser tab to sign you in with your JTL ID. After you sign in, return to the terminal. The CLI then walks you through three short prompts:
  • Register the app in which tenant? Pick the tenant you want the app registered under. If your account has access to more than one, the CLI lists them all.
  • Review. The CLI prints a summary of the app it is about to create: App name, Technical name, Version, Description, Tenant, and Action. Verify the values are correct.
  • Create app “<app-name>” in tenant “<tenant>”? Select Create the app and confirm.
Once the app is created, the CLI writes the app’s credentials and environment values to your local files. The backend file carries the credentials your server uses and the endpoints it talks to: The frontend file carries the values the auth provider needs: The CLI also returns a link to the app in JTL Hub.
Don’t commit your environment files. They contain your client secrets. The CLI writes them to paths that the template’s .gitignore already excludes, but verify this before pushing to a shared repository.
If the browser does not open automatically, the CLI prints the sign-in URL in the terminal. Copy it into a browser on a machine that can reach it, complete the sign-in, and return to the terminal to continue.

4. Start the App

Run the following command from the root directory to start the development server:
This starts both the backend and frontend:

5. Open the App

Open http://localhost:3004 in your browser. You should see an instruction page. It’s intentional, as the sample app is designed to run inside the JTL Cloud.

6. Verify the Connection

Your app is now running locally and connected to the JTL platform using your credentials. To verify everything is working:
  1. Open JTL Hub in your browser
  2. Navigate to the Manage apps menu and click the Apps in development tab
  3. You should see the my-jtl-app listed
Discover apps
  1. Click the Install button to install the app. Once the app is installed, you’ll see a success screen with the option to configure the app. Click the Configure app button to proceed to the next step.
Install app on JTL Complete the installation process by clicking the Complete setup button in the installation wizard. Complete setup

7. Fetch Data from JTL-Wawi

Your app is running and connected to the platform, but it’s not pulling real ERP data yet. The template includes a working demo page that queries Wawi through the ERP’s GraphQL API. Let’s walk through how it works.

Open the GraphQL Demo Page

The template ships with a demo page at packages/frontend/src/pages/graphql-demo-page/ that runs several example queries against your JTL-Wawi (items, orders, stock data). To view it, see the Test your App guide.

How it Works

The frontend never talks to the JTL-Wawi API directly. All requests go through your backend, which handles authentication transparently. The backend’s POST /graphql endpoint does five things:
  1. Reads the app token from the Authorization header
  2. Verifies the token and reads the tenant from its claims
  3. Obtains an access token using your app’s client credentials
  4. Forwards the GraphQL request to the JTL-Wawi API with the correct Authorization and X-Tenant-ID headers
  5. Returns the response as-is
The template’s /graphql proxy verifies the app token’s signature, issuer, expiry, and audience, which is enough to get started. Before deploying to production, add an authorization layer that checks the tenant and user against your own application data. See App Token Authentication for the full verification pattern.

The Query Code

The demo page lives at packages/frontend/src/pages/graphql-demo-page/GraphqlDemoPage.tsx. It keeps a QUERIES object with one entry per example query and runs whichever entry you click. topItems and stockOverview both query QueryItems. recentOrders queries QuerySalesOrders, which returns different fields.

Calling the API Without a Backend

The template also ships a serverless demo at packages/frontend/src/pages/serverless-graphql-page/ServerlessGraphqlPage.tsx. It runs the same queries as the backend example, but calls the JTL-Wawi GraphQL API directly from the browser using an app token.
The endpoint is the JTL API rather than your backend’s proxy, and the tenant is bound into the token, so no tenant header is sent. The two demos differ in what governs the call. A request proxied through your backend carries an app token. The backend verifies the token to identify the app and tenant, then obtains an access token and uses it to make the API request when the app token is valid for the app. A serverless request uses the same app token directly from the browser. The request goes straight to the JTL Cloud API, which validates the app token and applies the signed-in merchant’s permissions. A sample response looks like this:
This demo runs a minimal query to verify the connection. The GraphQL API supports filtering, sorting, pagination, and mutations. Explore the full schema interactively in the GraphQL Playground, or read the Using Platform APIs guide for more patterns.

What Just Happened?

Here’s what’s running under the hood:
  • The React frontend renders your app’s UI (running on port 3004)
  • The Express/.NET/PHP backend handles authentication and API calls (running on port 3005)
  • The backend uses your client ID and secret to authenticate with JTL via OAuth 2.0
  • Once authenticated, it can call the JTL-Wawi API to read and write data

Project Structure

Here’s what’s inside my-jtl-app/:
Working with an AI coding tool? Connect the JTL docs MCP server, then paste the prompt below to explore the project and extend it.
AI Assistant Prompt

Common Issues

The template requires Node.js v24.16.0 or higher (current LTS). Node 18 and earlier are known to fail during install or at runtime. Check your version with node --version. If you need to upgrade, use nvm or download the current LTS from nodejs.org.
The CLI tries to open your default browser to start the JTL ID sign-in. If your environment blocks that, the CLI prints the sign-in URL to the terminal instead. Copy the URL into a browser on a machine that can reach it. After you complete the sign-in, the CLI continues with the tenant selection and review steps.
If you registered the app under the wrong tenant, the simplest path is to remove the app from the Partner Portal and rerun npm run register. The CLI prompts you to pick a tenant each time, so you can pick the correct one on the next pass.
Another process is using the port. Find and stop it:
This usually means the credentials in your local environment file do not match the app registered in the Partner Portal. The fastest way to fix it is to rerun npm run register, which regenerates credentials and rewrites the local file. If the problem persists, regenerate the credentials manually in the Partner Portal under your app’s client credentials, then update the file yourself.
The app token failed verification, or the backend’s own request to the JTL API was rejected. App tokens are valid for about an hour, so request a fresh one with getAppToken rather than reusing one captured earlier. If the token is current, confirm the backend is sending Authorization: Bearer <accessToken> and X-Tenant-ID on its call to the JTL API.
If you get { "data": null } or empty results:
  • Verify the tenantId is correct (check the urn:jtl:tenant_id claim in your app token)
  • Confirm you have data in your Wawi for the query you are making
  • Check that your GraphQL query syntax is valid (no missing brackets or commas)

What’s Next?

Your app is running. Here’s where to go from here:

Test your App

Use the cloud environment to test your app with real (test) data.

Using Platform APIs

Use the JTL-Wawi REST and GraphQL APIs, handle responses, and work with tenant-scoped data.

GraphQL Playground

Try queries and mutations interactively against your ERP instance.

Build from Scratch

Want to understand every piece? Build a Cloud App step by step.

Submit your App

Publish to the App Store, or share your app privately with activation codes.

App Shell & UI

Integrate deeper with the JTL UI using AppBridge and Platform UI components.