> For the complete documentation index, see [llms.txt](https://developer.esw.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.esw.com/customs-catalog-api/resources/postman-collection/catalog-onboarding-pipeline.md).

# Catalog Onboarding Pipeline

### <img src="/files/3Hzf3CWYWyHDFskuSRKJ" alt="" data-size="line"> What This Collection Does

This Postman collection walks through the complete **Catalog Onboarding Pipeline** — the sequence of API calls required to upload a catalog and get products classified for international shipping.

{% file src="/files/W8QCjkFGrHvJj06KA0VX" %}

{% hint style="info" %}
You need [**Postman**](https://postman.com/) to use this collection&#x20;
{% endhint %}

***

### Import the Collection

{% stepper %}
{% step %}

#### Open Postman&#x20;

{% endstep %}

{% step %}

#### Click the three dots <i class="fa-ellipsis">:ellipsis:</i>

Click **Import** from the three dots in the top left corner
{% endstep %}

{% step %}

#### Upload file <i class="fa-file-code">:file-code:</i>

Drag and drop `ESW_Customs_Catalog_Onboarding.postman_collection.json` into the import window, or click **Upload Files** and select it
{% endstep %}

{% step %}

#### Confirm

Click **Import** to confirm

{% hint style="info" %}
The collection will appear in your left sidebar under **Collections** as:

{% code expandable="true" %}

```ruby
ESW Customs Catalog — Retailer Onboarding Pipeline
```

{% endcode %}

Expand it to see all ten requests listed in step order.
{% endhint %}
{% endstep %}
{% endstepper %}

***

### Set Up Variables

The collection uses four variables. Set them once and every request picks them up automatically.

**To set them:**

1. Click the collection name in the sidebar
2. Click the **Variables** tab at the top of the right panel

<figure><img src="/files/BxAYyK1cWJMHZSnQlmD4" alt=""><figcaption></figcaption></figure>

3. Fill in the column for each variable

| Variable     | What to enter                         | Example                                                       |
| ------------ | ------------------------------------- | ------------------------------------------------------------- |
| `baseUrl`    | The API base URL                      | `https://logistics-customscatalog-api.sandbox.eshopworld.com` |
| `token`      | Your Bearer JWT token                 | `eyJhbGci...`                                                 |
| `tenantCode` | The retailer's eShopWorld tenant code | `ACME`                                                        |
| `brandCode`  | The retailer's 3-letter brand code    | `ACM`                                                         |

4. Click  `Save`&#x20;

{% @code-walkthrough/kbd-shortcut keys="Cmd/Ctrl + S" label="" position="after" %}

***

### Authentication

The collection is configured with **Bearer Token** authentication at the collection level. Every request automatically sends:

```ruby
Authorization: Bearer {{token}}
```

{% hint style="info" %}
You do not need to set auth on individual requests — they all inherit it from the collection.
{% endhint %}

**To confirm it's configured:**

1. Click the collection name
2. Click the **Authorization** tab

<figure><img src="/files/odfr0wJSd0Z4hODyPEO6" alt=""><figcaption></figcaption></figure>

***

### Onboarding Pipeline

The steps are designed to run in sequence. Each one depends on the previous completing successfully.

{% code expandable="true" %}

```ruby
┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  Step 1 — Validate Brand Config                                  │
│  Confirm the brand exists in eShopWorld before uploading data    │
│                           │                                      │
│                           ▼                                      │
│  Step 2 — Upload Product Catalog                                 │
│  Push all product records to the retailer's tenant               │
│                           │                                      │
│                           ▼                                      │
│  Step 3 — Trigger Tenant Import                                  │
│  Start the eShopWorld import processing job                      │
│                           │                                      │
│                           ▼                                      │
│  Step 4 — Bulk Upload Classifications  (skip if not needed)      │
│  Pre-load HS codes from a CSV/XLSX file                          │
│                           │                                      │
│                           ▼                                      │
│  Step 5 — Reload Master Catalog                                  │
│  Index newly uploaded products across the platform               │
│                           │                                      │
│                           ▼                                      │
│  Step 6 — Run Brand Summarization                                │
│  Aggregate classification data across regions                    │
│                           │                                      │
│                           ▼                                      │
│  Step 7a — Health Check: Invalid Products                        │
│  Step 7b — Health Check: Default Classified Products             │
│  Verify the upload succeeded and products are classified         │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘
```

{% endcode %}

{% hint style="info" %}

* Steps 2, 3, 4, and 5 are all **asynchronous** — a success response means the job was *accepted*, not that it's finished. Allow processing time between steps.
* If any step fails, fix the issue and re-run that step. You do not need to restart from Step 1.
* Step 4 is optional — skip it if HS codes are embedded directly in the product records in Step 2.
  {% endhint %}

***

### Utility Requests

The two utility requests at the bottom of the collection are not part of the main pipeline sequence. Use them independently as needed.

#### Fetch Log Files

**Request:** `POST /api/v2/Logs/GetFiles`

**Purpose:** Returns a paginated list of processing log files for the tenant. Use this to audit what happened after Steps 2 and 3, or to diagnose why products failed to process.

```json
{
  "tenantCode": "{{tenantCode}}",
  "status": ["UploadComplete", "Error"],
  "takeCount": 20,
  "continuationToken": null
}
```

**Body fields explained:**

| Field               | Description                                                                                        |
| ------------------- | -------------------------------------------------------------------------------------------------- |
| `tenantCode`        | Pre-filled from your variable — filters logs to this tenant                                        |
| `status`            | Log statuses to include. Options: `Queued`, `UploadInProgress`, `UploadComplete`, `Error`          |
| `takeCount`         | Maximum number of results to return (max 50)                                                       |
| `continuationToken` | Leave `null` for the first page; paste the token from the previous response to fetch the next page |

**Filtering to errors only:**

Change the `status` array to `["Error"]` to see only failed log entries:

```json
{
  "tenantCode": "{{tenantCode}}",
  "status": ["Error"],
  "takeCount": 20,
  "continuationToken": null
}
```

**Console output after running:**

```ruby
✓ No error log entries
```

or if errors exist:

```ruby
⚠ 2 log entries with Error status
```

Run this after Step 3 (Trigger Import) completes if you're unsure whether processing finished successfully. Look for `UploadComplete` entries confirming the catalog was processed, and `Error` entries that need investigation.

#### Upload Catalog (Default Tenant)

**Request:** `POST /api/v2/RetailerCatalog`

**Purpose:** An alternative to Step 2 that uploads the catalog to the **default tenant** rather than a named tenant. Use if you are not operating in a multi-tenant setup.

The request body is identical to Step 2 but scoped to the platform default. The response is the same — `202 Accepted`.

***

### Run the Full Pipeline with Collection Runner

The Collection Runner lets you run all pipeline steps automatically in sequence

1. Hover over the collection name in the sidebar
2. Click the three dots
3. **Run** button appears

**Recommended settings:**

| Setting                         | Value     | Reason                                                                   |
| ------------------------------- | --------- | ------------------------------------------------------------------------ |
| **Iterations**                  | `1`       | One pass per retailer                                                    |
| **Delay**                       | `2000` ms | Gives async jobs time to queue between steps                             |
| **Persist responses**           | ✓ On      | Lets you review each response after the run                              |
| **Stop run if an error occurs** | ✓ On      | Stops the pipeline if a step fails rather than continuing with bad state |

***

### Common Scenarios

#### Onboarding a brand new retailer

1. Set `tenantCode` and `brandCode` variables for the new retailer
2. Run **Step 1** — confirm the brand is provisioned
3. Paste the retailer's product data into **Step 2** and send
4. Run **Step 3** to trigger import, then wait 5 minutes
5. If you have a classifications file, run **Step 4**
6. Run **Step 5** to reload the catalog, wait 2 minutes
7. Run **Step 6** to run summarization, wait 2 minutes
8. Run **Step 7a and 7b** to check health
9. If any invalid products exist, switch to the **Invalid Product Remediation** collection

***

#### Re-onboarding after a product data correction

If a retailer has corrected their product data and you need to re-upload:

1. Skip Step 1 (the brand already exists)
2. Update the product array in Step 2 with the corrected data and re-send
3. Run Steps 3 → 5 → 6 → 7 in sequence
4. You do not need to run Step 4 again unless the classifications file also changed

***

#### The catalog upload succeeded but products aren't appearing

This usually means Step 5 (Reload Master Catalog) hasn't been run or hasn't completed.

1. Check the Utility — Fetch Log Files request to see if the import completed
2. If `UploadComplete` is in the logs, run Step 5
3. Wait 2–3 minutes and run Step 7 again

***

#### Step 5 keeps returning 412 Precondition Failed

The catalog is still processing from Step 3. This is can happen on large catalogs.

1. Run **Utility — Fetch Log Files** and filter to `status: ["UploadInProgress"]`
2. If entries show `UploadInProgress`, the catalog is still being processed
3. Wait 5 minutes and re-run Step 5
4. If it's been more than 30 minutes and still returning 412, contact your eShopWorld account team

***

### Troubleshooting

**`401 Unauthorized` on every request**\
Token has expired. Get a new JWT from the ESW identity service and update the `token` variable.

***

**`404 Not Found` on Step 1**\
The brand code doesn't exist in eShopWorld. Verify the 3-letter code with your account team. Brand provisioning must happen before catalog upload.

***

**`400 Bad Request` on Step 2**\
One or more products have invalid or missing required fields. The error message in the response body will name the specific field. Common causes:

* `productCode` not unique within the batch — remove duplicates
* `countryOfOrigin` not a valid ISO 2-letter code (e.g. `Ireland` instead of `IE`)
* `category` value not in the accepted list — check Section 17
* `hsCodeRegion` provided without `hsCode` — either provide both or neither

***

**`400 Bad Request` on Step 3**\
The `TenantCode` query parameter is missing or wrong. Click the **Params** tab on the request and confirm `TenantCode` has a value. It should be auto-filled from `{{tenantCode}}` — if it's showing literally as `{{tenantCode}}`, the variable isn't set.

***

**`412 Precondition Failed` on Step 5**\
The catalog from Step 3 is still processing. Wait 2–5 minutes and retry. If it persists beyond 20 minutes, check the Utility — Fetch Log Files request for errors.

***

**Step 7a shows a high invalid product count after onboarding**\
Products were uploaded missing required classification fields. The most common culprits are `hsCode`, `countryOfOrigin`, and `material`. Open the **Invalid Product Remediation** collection, run the investigation phase to download an error file, and pass it to the retailer's data team for correction.

***

**Variables showing `{{variableName}}` literally in the request URL or body**\
The variable isn't set. Click the collection name → **Variables** tab and confirm all four **Current Value** fields are filled in, then save. If they're set but still not resolving, check that you're looking at the collection variables and not an environment — variables at environment level take precedence over collection level.

***

**Collection Runner stops at Step 4 with a file error**\
Step 4 requires a file to be attached in the Body tab. When running via the Collection Runner, you cannot attach a file interactively. Either skip Step 4 in the runner and run it manually afterwards, or disable it in the runner's request list.

***

**Can't see console output from Steps 7a and 7b**\
Open the Postman Console before running the requests: **View → Show Postman Console** (`Cmd + Option + C` on Mac, `Alt + Ctrl + C` on Windows/Linux). Output from requests run before the Console was open is not retained.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.esw.com/customs-catalog-api/resources/postman-collection/catalog-onboarding-pipeline.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
