# Products (https://eulabel.eu/docs/api-reference/endpoints/products)

Create, update, list, and retrieve products.


> Fetch the complete documentation index at: https://eulabel.eu/docs/llms.txt
> Use this file to discover all available pages before exploring further.
> Full content: https://eulabel.eu/docs/llms-full.txt
> Append .md to any page URL for markdown, or send Accept: text/markdown.

> **Note**
> All endpoints require an API key (Bearer token). Base URL: `https://api.eulabel.eu/v1`

- [Authentication](https://eulabel.eu/docs/documentation/get-started/authentication) — API keys, scopes, and session-based dashboard auth
- [Error handling](https://eulabel.eu/docs/knowledge-base/guides/error-handling) — Structured errors, retry strategy, and rate limits
- [SDKs](https://eulabel.eu/docs/documentation/sdks) — Typed client libraries for TypeScript and Python

## POST /products

Creates a new product with a unique digital identity and a GS1 Digital Link QR code URL.

**Permission:** `products:write`

**Authorization** Bearer token

API key authentication. Pass your key in the `Authorization` header:
`Authorization: Bearer sk_live_...`

### Request Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Product display name. |
| `category` | string | Yes | Product category. Value in: "wine" | "food" | "textile" | "electronics" | "battery" |
| `brand` | string | No | Brand name. |
| `gtin` | string | Yes | Valid GTIN-8, GTIN-13, or GTIN-14. |
| `sku` | string | No | Internal SKU reference. |

### TypeScript Definitions

Use the request body type in TypeScript.

```typescript
interface CreateProductRequest {
  name: string;
  category: string;
  brand?: string;
  gtin: string;
  sku?: string;
}
```

**Example:**

```json
{
  "name": "Quinta do Crasto Douro Red 2021",
  "category": "wine",
  "brand": "Quinta do Crasto",
  "gtin": "5601234567890"
}
```

### Example Request

```bash
curl -X POST "https://api.eulabel.eu/v1/products" \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name":"Quinta do Crasto Douro Red 2021","category":"wine","brand":"Quinta do Crasto","gtin":"5601234567890"}'
```

### Response 201

Product created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `productId` | string | No | Unique product identifier. |
| `qrCodeUrl` | string | No | GS1 Digital Link QR code URL. |
| `createdAt` | string | No |  |

```json
{
  "productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "qrCodeUrl": "https://eulabel.eu/01/05601234567890",
  "createdAt": "2026-03-14T20:00:00.000Z"
}
```

### Response 401

Missing or invalid authentication

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "authentication_error"
  }
}
```

### Response 409

Duplicate GTIN

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "duplicate_error",
    "message": "A product with this GTIN already exists",
    "code": "duplicate_error",
    "param": "gtin"
  }
}
```

### Response 422

Validation error

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "validation_error",
    "message": "gtin is required",
    "code": "validation_error",
    "param": "gtin"
  }
}
```

## GET /products

Returns all products in your organization.

**Permission:** `products:read`

**Authorization** Bearer token

API key authentication. Pass your key in the `Authorization` header:
`Authorization: Bearer sk_live_...`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | integer | No | Maximum number of products to return. |
| `offset` | query | integer | No | Number of products to skip for pagination. |

### Example Request

```bash
curl -X GET "https://api.eulabel.eu/v1/products" \
  -H "Authorization: Bearer sk_live_..."
```

### Response 200

List of products

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `products` | array | No |  |
| `pagination` | object | No |  |

### Response 401

Missing or invalid authentication

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "authentication_error"
  }
}
```

## GET /products/{productId}

Retrieves a single product by ID.

**Permission:** `products:read`

**Authorization** Bearer token

API key authentication. Pass your key in the `Authorization` header:
`Authorization: Bearer sk_live_...`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `productId` | path | string | Yes | Unique product identifier. |

### Example Request

```bash
curl -X GET "https://api.eulabel.eu/v1/products/{productId}" \
  -H "Authorization: Bearer sk_live_..."
```

### Response 200

Product details

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `internalId` | string | No |  |
| `tenantId` | string | No |  |
| `gtin` | string | No | Normalized GTIN-14. |
| `name` | string | No |  |
| `category` | string | No | Value in: "wine" | "food" | "textile" | "electronics" | "battery" |
| `brand` | string | No |  |
| `sku` | string | No |  |
| `links` | array | No |  |
| `createdAt` | string | No |  |
| `updatedAt` | string | No |  |

### Response 401

Missing or invalid authentication

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "authentication_error"
  }
}
```

### Response 404

Resource not found

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "not_found",
    "message": "Resource not found",
    "code": "not_found"
  }
}
```

## PATCH /products/{productId}

Updates an existing product. Only the provided fields are changed; omitted
fields remain unchanged. The GTIN cannot be modified.

This endpoint updates product metadata (name, brand, category, SKU).
To update passport data (ingredients, nutrition, allergens, sustainability
information), create a new passport version via `POST /v1/passports`.

**Permission:** `products:write`

**Authorization** Bearer token

API key authentication. Pass your key in the `Authorization` header:
`Authorization: Bearer sk_live_...`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `productId` | path | string | Yes | Unique product identifier. |

### Request Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | No | Product display name. |
| `category` | string | No | Product category. Value in: "wine" | "food" | "textile" | "electronics" | "battery" |
| `brand` | string | No | Brand name. |
| `sku` | string | No | Internal SKU reference. Set to `null` to clear. |

### TypeScript Definitions

Use the request body type in TypeScript.

```typescript
interface UpdateProductRequest {
  name?: string;
  category?: string;
  brand?: string;
  sku?: string;
}
```

**Example:**

```json
{
  "name": "Quinta do Crasto Douro Red 2022",
  "brand": "Quinta do Crasto"
}
```

### Example Request

```bash
curl -X PATCH "https://api.eulabel.eu/v1/products/{productId}" \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name":"Quinta do Crasto Douro Red 2022","brand":"Quinta do Crasto"}'
```

### Response 200

Product updated

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `product` | object | No |  |

### Response 401

Missing or invalid authentication

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "authentication_error"
  }
}
```

### Response 404

Resource not found

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "not_found",
    "message": "Resource not found",
    "code": "not_found"
  }
}
```

### Response 422

Validation error

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No |  |

```json
{
  "error": {
    "type": "validation_error",
    "message": "gtin is required",
    "code": "validation_error",
    "param": "gtin"
  }
}
```
