> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wisepim.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WISEPIM Public API

> The WISEPIM REST API: base URL, authentication with project API keys, paging, error format, rate limits and the OpenAPI spec you can load into any client.

The WISEPIM Public API lets your own systems read and update a project's catalog: an ERP that pushes prices, a storefront that reads enriched content, or a sync job that keeps another PIM in step. Everything the API does, it does on **one project**, the project the API key is bound to.

| | |
| - | - |
| **Base URL** | `https://wisepim.com/api/public/v1` |
| **Authentication** | `Authorization: Bearer wpk_...` ([project API key](https://docs.wisepim.com/en/api-reference/authentication.md)) |
| **Format** | JSON requests and responses, UTF-8, HTTPS only |
| **OpenAPI spec** | [docs.wisepim.com/openapi.json](https://docs.wisepim.com/openapi.json) (OpenAPI 3.1) |
| **Version** | v1, versioned by path. Breaking changes get a new mount. |

> [!NOTE]
>
> The API covers products, categories and attributes. Enrichment, imports, exports and automations are not in v1; run those in the app or with an [automation](https://docs.wisepim.com/en/automations/overview.md). To let an AI assistant work with your catalog, use [Connected Apps](https://docs.wisepim.com/en/settings/connected-apps.md) instead of an API key.

## Quickstart

**1. Create an API key**

In the WISEPIM app, open **Settings > API Access** and click **Create API key**. Pick a name and the permissions the integration needs. The full key is shown once; store it in a secrets manager. See [API Access](https://docs.wisepim.com/en/settings/api.md) for who can create keys and the limits.

**2. Check the key**

`GET /me` needs no scope and tells you which project the key is bound to and which scopes it carries.

```bash theme={null}
curl https://wisepim.com/api/public/v1/me \
  -H "Authorization: Bearer $WISEPIM_API_KEY"
```

**3. Page through your products**

Lists are keyset-paged. Pass `next_cursor` back as `cursor` until `has_more` is `false`.

```bash theme={null}
curl "https://wisepim.com/api/public/v1/products?limit=100" \
  -H "Authorization: Bearer $WISEPIM_API_KEY"
```

**4. Write back**

Update one product with `PATCH /products/{product_id}`, or send up to 200 products at once to `POST /products/batch`, keyed by SKU. Both need the `products:write` scope.

## Endpoints

| Endpoint | Scope | What it does |
| - | - | - |
| [`GET /me`](https://docs.wisepim.com/en/api-reference/key/me) | none | Describe the calling key and its project |
| [`GET /project`](https://docs.wisepim.com/en/api-reference/key/project) | `project:read` | Project identity, locales, industry, product count |
| [`GET /products`](https://docs.wisepim.com/en/api-reference/products/list) | `products:read` | List products, bulk lookup by `ids` or `skus`, incremental sync with `updated_since` |
| [`POST /products`](https://docs.wisepim.com/en/api-reference/products/create) | `products:write` | Create one product |
| [`GET /products/{product_id}`](https://docs.wisepim.com/en/api-reference/products/get) | `products:read` | One product with attribute values and category ids |
| [`PATCH /products/{product_id}`](https://docs.wisepim.com/en/api-reference/products/update) | `products:write` | Partial update of one product |
| [`POST /products/batch`](https://docs.wisepim.com/en/api-reference/products/batch) | `products:write` | Create or update up to 200 products by SKU, atomically |
| [`GET /categories`](https://docs.wisepim.com/en/api-reference/categories/list) | `categories:read` | Flat category list with `parent_id` and `level` |
| [`GET /categories/{category_id}`](https://docs.wisepim.com/en/api-reference/categories/get) | `categories:read` | One category |
| [`GET /attributes`](https://docs.wisepim.com/en/api-reference/attributes/list) | `attributes:read` | Attribute definitions, filter by `codes` or `group_id` |
| [`GET /attributes/{attribute_id}`](https://docs.wisepim.com/en/api-reference/attributes/get) | `attributes:read` | One attribute definition |

## Paging

Every list returns the same envelope and is ordered by id ascending:

```json theme={null}
{ "data": [ ... ], "next_cursor": "aWQ6NDIx", "has_more": true }
```

* `limit` defaults to 50 and is capped at 200.
* The cursor is opaque. A malformed cursor is a `422 invalid_cursor`, never a silent restart from the top.
* There is no total count. Drain the list until `has_more` is `false`.
* Keyset paging visits every pre-existing row exactly once, even while products are being inserted.

For incremental sync, call `GET /products?updated_since=<ISO-8601>` on a schedule, page to the end, then store the highest `updated_at` you saw as the next `updated_since`.

## Errors

Every error is JSON with the same envelope. `code` is a stable machine-readable string; branch on it rather than on `error`.

```json theme={null}
{ "error": "Scope products:write is required", "code": "insufficient_scope", "request_id": "3f9a1c2b", "required_scopes": ["products:write"], "missing_scopes": ["products:write"] }
```

| Status | Codes | Meaning |
| - | - | - |
| `401` | `api_key_required` | Missing, unknown, revoked or expired key |
| `403` | `insufficient_scope`, `issuer_cannot_write`, `product_limit_exceeded` | Key lacks the scope, the person who created the key can no longer edit the project, or the plan has no room for another product |
| `404` | `not_found` | Unknown id, or an id that belongs to another project (never a 403) |
| `409` | `sku_conflict`, `idempotency_conflict` | A product with that SKU already exists in the project, or an `Idempotency-Key` was reused for a different request |
| `422` | `invalid_cursor`, `invalid_limit`, `invalid_filter`, `invalid_sku`, `invalid_price`, `invalid_status`, `unknown_category`, `unknown_attribute`, `invalid_attribute_value`, `batch_invalid`, `invalid_idempotency_key` | Bad paging or filter input, or a write that failed validation. Schema validation errors carry a per-field `detail` array. `batch_invalid` lists one entry per offending item in `errors` and nothing was written |
| `429` | `rate_limited` | Over the per-key limit. `retry_after` in the body and a `Retry-After` header say how long to wait |

Quote the `request_id` when you [contact support](https://wisepim.com/contact) about a failed call.

## Rate limits

Each key has its own limit, **600 requests per minute** by default, counted in a fixed 60-second window. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (seconds until the window resets). A request that fails a scope check still counts. Support can raise a key's limit when a sync needs it; `GET /me` shows the limit the key currently has.

## Retries and idempotency

Networks fail mid-request, and a client that retries a `POST` after a timeout cannot know whether the first attempt was applied. Send an **`Idempotency-Key`** header on every write (`POST /products`, `PATCH /products/{product_id}`, `POST /products/batch`) and reuse the same key for every retry of that write.

```bash theme={null}
curl -X POST https://wisepim.com/api/public/v1/products \
  -H "Authorization: Bearer $WISEPIM_API_KEY" \
  -H "Idempotency-Key: order-sync-2026-10-29-sku-8841" \
  -H "Content-Type: application/json" \
  -d '{"sku": "8841", "name": "Oak sideboard"}'
```

* The key is any string of 1 to 128 printable ASCII characters without whitespace. A UUID per logical operation works well.
* A retry with the same key, method, path, query and JSON body returns the **original status and body** and applies nothing again. The order of keys in the JSON body does not matter.
* Keys are scoped to the API key that sent them and are kept until that API key is deleted. Rotating a key starts a fresh scope.
* The same key with a different request is a `409 idempotency_conflict`; a malformed key is a `422 invalid_idempotency_key`. A write that fails leaves no record, so the next attempt with the same key runs normally.
* A replayed response describes the product as it was when the write ran. Use `GET /products/{product_id}` for the current state.
* `GET` requests need no key. `POST /products/batch` is keyed by SKU, so a retried batch without a header is also safe, but a header gives you the original `results` and `summary` back instead of a second run.

The API does not retry anything on your behalf. Retry `5xx` responses and timeouts with the same key; honour `Retry-After` on a `429` before retrying.

## Test safely

There is no separate sandbox host. Test against a **separate project** instead: [create a project](https://docs.wisepim.com/en/essentials/managing-projects.md), fill it with a copy or a sample of your catalog, and create a key bound to that project. Keys cannot reach any other project, so a bug in your integration never touches the catalog your live channels read from. [Compare Projects](https://docs.wisepim.com/en/essentials/managing-projects.md) shows the differences between the test project and the live one before you point the integration at production.

## Related

> **[Authentication and scopes](https://docs.wisepim.com/en/api-reference/authentication.md)**
>
> How keys work, which scopes exist, and how to rotate a key you think has leaked.

> **[API Access settings](https://docs.wisepim.com/en/settings/api.md)**
>
> Create, rename and revoke keys in the app, and the limits per project and per person.

> **[Developer portal](https://docs.wisepim.com/developers)**
>
> Every developer resource in one place: spec, MCP server, llms.txt, guides.

> **[Connected Apps](https://docs.wisepim.com/en/settings/connected-apps.md)**
>
> Let ChatGPT or Codex work with your catalog through a scoped, revocable connection.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.