The JTL platform exposes two API surfaces, each serving a different purpose:Documentation Index
Fetch the complete documentation index at: https://developer.jtl-software.com/llms.txt
Use this file to discover all available pages before exploring further.
| API | Purpose | Format |
|---|---|---|
| REST API | Authentication, token management, and account operations | Standard REST (JSON over HTTP) |
| GraphQL API | Querying and mutating ERP data (items, categories, customers, orders, stock) | GraphQL (single endpoint) |
Required Headers
Every API request to the JTL Cloud Platform requires a specific set of headers. Missing or incorrect headers result in401 or 400 errors.
| Header | Value | Required | Description |
|---|---|---|---|
Authorization | Bearer <access_token> | Yes | JWT access token from the client credentials flow |
X-Tenant-ID | <tenantId> | Yes | Identifies which merchant’s data to access. Get this from the verified session token. |
Content-Type | application/json | Yes (for POST/mutations) | Request body format |
The
X-Tenant-ID is what scopes your request to a specific merchant. The tenant ID determines whose data you’re reading or writing.C# samples target .NET 8 with implicit usings enabled and use raw string literals (C# 11+). PHP samples target PHP 8.1+ and require the
guzzlehttp/guzzle Composer dependency. TypeScript samples assume a modern Node.js or browser environment with fetch available globally. These examples use raw HTTP requests. If your project already uses HTTP or GraphQL client libraries, the same headers and payload structure apply.REST API
The REST API handles authentication and account-level operations. You already use it to obtain access tokens (see Authentication & Login). It also provides endpoints for account management, JWKS key retrieval, and other platform services.Base URL
REST endpoints use URL-path versioning:/erp/v2/ for new integrations. See Versioning for the full version history.
Example: Token Request
This is the most common REST call your app makes. See Authentication & Login for the full implementation with caching.Example: JWKS Retrieval
Fetch the public keys used to verify session tokens:GraphQL API
All ERP data operations (reading items, creating categories, updating customers, querying orders) go through the GraphQL API. It provides a single endpoint for both queries (reads) and mutations (writes).Endpoint
POST requests to this single URL, regardless of whether you’re reading or writing data.
Making a Request
Every GraphQL request has the same structure: anoperationName, a query string, and optional variables. The shape is identical across languages, only the syntax for sending the HTTP request differs.
data object with the results, or an errors array if something went wrong.
Throughout this guide, GraphQL query and mutation strings are shown in plain GraphQL syntax. The string itself is the same across languages; only how you embed it (a template literal in TypeScript, a verbatim string in C#, a heredoc in PHP) differs. The variables object follows the JSON serialization conventions of your language.
Querying Data
Queries read data from the ERP without modifying it. Use them to fetch items, customers, orders, categories, and other resources. The examples in this section use thequery() / QueryAsync() / JtlGraphQL::query() helper built in Building a Reusable API Client.
The GraphQL operation itself is language-agnostic. Only the variables object differs depending on your language’s JSON syntax and conventions.
Basic Query
Fetch a list of products with their SKU and name:nodes array with each item’s id, sku, and name, plus a totalCount of all matching items.
Example response
Example response
Requesting Specific Fields
One of GraphQL’s key advantages is that you only fetch the fields you need. This reduces payload size and improves performance. A minimal query with just IDs and names:query() helper handles both, only the operation string changes.
Sorting
Control the order of results using theorder variable. Pass an array of sort objects with the field name as the key and ASC or DESC as the value.
In C#, build the variables with
new { first = 20, order = new[] { new { name = "ASC" } } }. In PHP, use ['first' => 20, 'order' => [['name' => 'ASC']]].Filtering
Use thewhere variable to filter results based on field conditions. Filters use a structured input type specific to each query.
contains and eq for strings, gte and lte for numbers, in for enum-like fields. See the GraphQL Playground for the full schema of available operators on each query.
Pagination
The GraphQL API uses cursor-based pagination. Usefirst to set the page size and after to fetch subsequent pages.
Add pageInfo to your query to get pagination metadata:
endCursor as after until hasNextPage is false:
| Field | Description |
|---|---|
hasNextPage | true if more results exist beyond this page |
endCursor | Opaque cursor string to pass as after for the next page |
totalCount | Total number of matching items across all pages |
Mutating Data
Mutations create, update, or delete ERP data. They follow the same request structure as queries but use themutation keyword. Use the same query() helper as it handles both.
Creating a Resource
Create a new category in the ERP:categoryId of the newly created resource. Set parentId to an existing category ID to create a subcategory.
Updating a Resource
Update an existing category:id field is required to identify which resource to update. Only the fields you include in the request are modified; omitted fields remain unchanged. The mutation returns true on success.
Handling Responses
Every GraphQL response has the same top-level structure:Success
A successful response contains thedata object with your requested fields. The errors field is either absent or an empty array.
Errors
GraphQL errors are returned in theerrors array, even when the HTTP status is 200. Always check for errors in the response body, not just the status code.
Building a Reusable API Client
As your app grows, you’ll want a helper that handles headers, authentication, and error checking in one place.Using the Client
What’s Next
GraphQL Playground
Try queries and mutations interactively with autocomplete and schema
docs.
Handling Webhooks
Respond to lifecycle events and AppBridge messages in your app.
Error Handling
Understand error formats, retry strategies, and validation errors.
Rate Limiting
Stay within request limits and handle throttling gracefully.
Best Practices
Production patterns for API usage, caching, and performance.