> For the complete documentation index, see [llms.txt](https://learn.moselle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://learn.moselle.io/getting-started/onboarding/setup-integrations/netsuite.md).

# NetSuite

Connect NetSuite to Moselle to automatically sync your sales orders, purchase orders, inventory, and product catalog daily for accurate demand forecasting.

### Overview

The NetSuite integration connects your NetSuite account to Moselle so your planning always runs on up-to-date ERP data. Once connected, Moselle automatically syncs every day:

* **Sales orders** — your sales history, routed to the right sales channels, used to forecast demand
* **Purchase orders** — open and incoming orders from your suppliers, so replenishment plans account for stock already on the way
* **Inventory levels** — on-hand and available stock for each NetSuite location, mapped to your Moselle warehouses
* **Product catalog** — your NetSuite items, linked to Moselle items by SKU

This removes manual exports and keeps your forecasts, replenishment recommendations, and reports aligned with NetSuite.

NetSuite is an **assisted integration**: you create the credentials, and the Moselle team handles the connection, data checks, and channel mapping with you.

***

### Connect NetSuite

**Time Required:** About 30 minutes **Who should do this:** A NetSuite Administrator

#### Step 1: Create Web Services Role in NetSuite

1. In NetSuite, navigate to **Setup → Users/Roles → Manage Roles**
2. Click **New** to create a new role
3. Name the role (e.g., "Moselle Web Services")
4. Under **Authentication**, tick **Web Services Only Role**
5. Leave the **Center** field unset
6. Under **Permissions**, add the following:
   * **Setup Tab**:
     * Log in using Access Tokens
     * REST Web Services
     * SuiteAnalytics Workbook
   * **Lists Tab**:
     * Items
     * Locations
     * Customers
     * Vendors
     * Classes
     * Departments
     * Subsidiaries
     * Any custom records you want to sync
   * **Transactions Tab**:
     * Find Transactions
     * Sales Orders
     * Purchase Orders
7. Save the role

{% hint style="info" %}
**View** access is enough on every permission above — Moselle only reads your data.

Classes, Departments and Subsidiaries are used to work out which Moselle sales channel each order belongs to. Without them we can see the values on your orders but not what they are called, which turns channel mapping into a round of emails.
{% endhint %}

{% hint style="danger" %}
**Do not use the Administrator role, and do not give this role administrator privileges or a Center.**

NetSuite blocks token-based logins for admin-level roles, and the failure gives you nothing to go on: the login fails with `Invalid login attempt` while the user, the role and the token all still show as **Active**. This is the most common reason a NetSuite connection fails and it has cost customers several days each. Create a dedicated role with only the permissions above.
{% endhint %}

{% hint style="warning" %}
**Can't find SuiteAnalytics Workbook in the list?** The feature has to be switched on before the permission appears. Go to **Setup → Company → Enable Features → Analytics**, tick **SuiteAnalytics Workbook**, save, then return to the role.

This permission is required. Moselle reads your data with SuiteQL, which does not work without it.
{% endhint %}

#### Step 2: Create Integration Record

1. Navigate to **Setup → Integration → Manage Integrations**
2. Click **New**
3. Name the integration (e.g., "Moselle Integration")
4. Under the **Authentication** tab:
   * Enable **Token-Based Authentication**
   * **Turn off** TBA: ISSUETOKEN Endpoint
   * **Turn off** TBA: Authorization Flow
   * Under the **OAuth 2.0** section, ensure everything is **turned off**
5. Save the integration
6. **Record the Consumer Key and Consumer Secret** — you will need these for authentication

{% hint style="warning" %}
NetSuite only shows the Consumer Secret once, right after you save. Copy it before leaving the page.
{% endhint %}

#### Step 3: Generate Access Tokens

1. Navigate to **Setup → Users/Roles → Access Tokens → New**
2. Select the **Application** (integration record from Step 2)
3. Select your **User**
4. Select the **Role** (web services role from Step 1)
5. Save the access token
6. **Record the Token ID and Token Secret** — you will need these for authentication

{% hint style="success" %}
**Best practice: use a dedicated integration user.** Create the token for a NetSuite user that is used only for Moselle and has the Moselle role assigned. Tokens tied to a personal login — especially one already connected to other apps — are the most common reason a connection can't read any records.
{% endhint %}

#### Step 4: Get Your Account ID

Your NetSuite Account ID is found in your NetSuite URL:

* If your URL is `https://1234567.app.netsuite.com`, your Account ID is `1234567`
* For a sandbox, send the ID in its underscore form — `1234567_SB1`, not `1234567-sb1`. The hyphenated version appears in the URL, but the underscore form is what authentication expects, and sending the wrong one fails as `Invalid login attempt` with no further explanation.

{% hint style="info" %}
Connect your **production** account, not a sandbox. Sandbox accounts (IDs ending in `-sb1`, `-sb2`, etc.) use separate credentials and usually hold test data.
{% endhint %}

#### Step 5: Add Your Credentials Securely in Moselle

1. Log in to Moselle and go to **Settings → Integrations → NetSuite**, or open this link directly: [app.moselle.io/settings/integrations?integration=netsuite](https://app.moselle.io/settings/integrations?integration=netsuite)
2. Click **Connect** on the NetSuite card
3. In the **Credentials** box, paste the following:
   * **Account ID**
   * **Consumer Key**
   * **Consumer Secret**
   * **Token ID**
   * **Token Secret**
4. Click **Send securely**

**Expected Result:** You'll see a **"NetSuite credentials sent"** confirmation. Our team takes it from there and will be in touch once the connection is live.

{% hint style="warning" %}
**Never share NetSuite credentials over email, Slack, or chat.** The Settings form encrypts your credentials as soon as they reach us, and they are never shown again — so keep your own secure copy in case you need to re-create or rotate them.
{% endhint %}

{% hint style="info" %}
The NetSuite card won't switch to **Connected** on its own — our team confirms with you directly once your first sync is verified.
{% endhint %}

#### Step 6: Internal Review and Connection Test

Once your credentials are submitted, the Moselle team reviews them internally and runs a test sync to confirm we can read your items, locations, inventory, sales orders, and purchase orders.

If anything needs adjusting — most often a role permission, or a token created for the wrong user or role — we'll contact you with the specific change needed.

**Expected Result:** We confirm your NetSuite data is syncing into Moselle.

#### Step 7: Data Review and Channel Mapping

After your data syncs, we review how your sales and inventory are organized in NetSuite — for example, which **customers**, **classes**, **departments**, or **locations** represent each sales channel, and which locations hold sellable stock.

We then schedule a session with you to confirm:

* Which NetSuite customers or fields roll up into each Moselle sales channel
* Which NetSuite locations should appear as Moselle warehouses (and which to exclude)
* Which inventory figure to plan from (for example, **Available** vs. **On Hand**)
* Which date to use for purchase orders (for example, expected receipt vs. ship date)

{% hint style="info" %}
You don't need to prepare a channel mapping in advance. We review your data first and bring a proposed mapping to the session.
{% endhint %}

#### Step 8: Validate Your Data

We compare Moselle's sales and inventory against a report or export from your NetSuite account and resolve any differences before you start planning. From here, your data syncs automatically every day.

***

### Optional: Share Saved Searches (After Your Data Syncs)

Saved searches are **not required** to connect NetSuite. Once your core data is syncing, you can optionally share saved searches if you'd like Moselle to pick up extra data or custom fields beyond the standard sync. Your Moselle team will let you know if a saved search would help.

To create one:

1. Navigate to **Lists → Search → Saved Searches → New**
2. Select the record type (e.g., Transaction, Item, Customer)
3. Add the fields you want to include in Moselle
4. Set search criteria if needed
5. Make the search **Public** or share it with the integration user
6. Save the search with a descriptive name, then send the name to your Moselle team

**Saved search limitations:**

* Formula fields within saved searches will not be returned
* Saved searches with summary results are not supported
* Related objects return only internal IDs — add joined fields (e.g., customer name) if you need the details

***

### Data Sync Details

**Sync Frequency** — NetSuite data syncs daily. If your team pulls NetSuite reports at a set time each morning, let us know and we can align the sync timing.

**What syncs** — Items, locations, inventory levels by location, sales orders, and purchase orders.

**SKU Matching** — NetSuite items automatically link to Moselle items when SKUs match exactly. Non-matching SKUs require manual linking, and sales for unlinked items won't appear until they're linked.

***

### Supported Record Types

The NetSuite integration supports pulling data from:

* **Transactions** — Sales orders and purchase orders
* **List Objects** — Items, locations, customers, vendors
* **Custom Records and Reports** — Available on request via saved searches

***

### Data Mapping & Routing

We configure channel and warehouse mapping for you after reviewing your data, and confirm it with you before go-live (see Step 7).

#### Sales Channel Routing

Sales orders from NetSuite are routed to specific Sales Channels in Moselle (e.g., Wholesale, Ecommerce, Retail).

* **Common Method (Entity/Customer):** Most often, we route orders based on the **Customer** on the sales order. For example, all orders from your wholesale customers go to your "Wholesale" channel.
* **Alternative Methods:** We can also route by **Class**, **Department**, **Location**, or a **custom field** on the sales order — whichever best reflects how you plan.

#### Warehouse Mapping (Location Linking)

Your NetSuite **Locations** are read into Moselle and then linked to Moselle **Warehouses** as a deliberate step, not automatically.

* **Nothing is created without your say-so.** A NetSuite location that has no Moselle warehouse is listed as available to link, and stays unlinked until someone links it. Most NetSuite accounts carry locations that have no place in planning — contract manufacturers, in-transit and adjustment locations, offices — and creating a warehouse for each of those would clutter your planning for no benefit.
* **You choose what counts.** During onboarding we will send you the full list of your NetSuite locations and ask which should drive planning in Moselle. Inventory syncs for the ones you link.

**Tip:** Matching names make the mapping obvious, but they are not required — tell us the pairs and we will link them.

***

### Sales Order Fields Moselle Uses

Moselle reads the following fields from your NetSuite sales orders. You don't need to configure these — they're listed so you know what to check if numbers look off.

| Field        | Description      | Notes                                                                                                                 |
| ------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------- |
| **trandate** | Transaction Date | Used to assign sales to calendar months. The integration user's date format should be `M/D/YYYY` (e.g., `1/28/2026`). |
| **tranid**   | Transaction ID   | The unique identifier for the order (e.g., `SO-12345`).                                                               |
| **item**     | Item             | The item sold.                                                                                                        |
| **quantity** | Quantity         | Numeric value.                                                                                                        |
| **amount**   | Total Amount     | Numeric value.                                                                                                        |
| **rate**     | Unit Price       | Numeric value. Used to calculate amount if total is zero.                                                             |

***

### Troubleshooting

| Issue                                            | Cause                                                                                       | Solution                                                                                                         |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `Invalid login attempt`                          | The role is the Administrator role, has admin-level privileges, or has a Center assigned    | Create a dedicated role as in Step 1 and issue a fresh token against it. See *Diagnosing a failed login* below   |
| `Invalid login attempt`, everything looks Active | The user or role behind the token has been disabled or un-assigned since the token was made | Check the Login Audit Trail Detail column; `EntityOrRoleDisabled` confirms it                                    |
| `Invalid login attempt` immediately after setup  | The new role and token have not propagated yet                                              | Wait a few minutes and retry before changing anything                                                            |
| `Invalid or unsupported search`                  | A date was sent in a format your account does not use                                       | Tell us — this is ours to fix, not yours                                                                         |
| `Record 'X' was not found`                       | The role lacks permission for that record type, or the feature is not enabled               | Add the permission from Step 1; if it isn't listed, the underlying feature needs enabling first                  |
| Credentials rejected                             | A value was mis-copied, or the pairs were crossed                                           | Resend each value labelled individually. Consumer Key/Secret and Token ID/Secret look alike and are easy to swap |
| Inventory missing for some items                 | Stock recorded with no location, or item inactive in NetSuite                               | Assign a location and confirm the item is active                                                                 |
| Items not linking automatically                  | SKUs don't match between NetSuite and Moselle                                               | Manually link items or update SKUs to match                                                                      |

***

### Diagnosing a failed login

Nearly every NetSuite connection problem produces the same unhelpful message:

```
Invalid login attempt. For more details, see the Login Audit Trail in the
NetSuite UI at Setup > Users/Roles > User Management > View Login Audit Trail.
```

That message is the same whether the credentials are wrong, the role is blocked, the user is disabled, or the token simply hasn't propagated yet. The **Detail** column in the Login Audit Trail is the only thing that tells them apart.

**The Detail column is not shown by default.** On the Login Audit Trail page, open the **Results** subtab, add **Detail** to the columns, and submit. If that subtab isn't available, build it as a saved search instead: **Reports → Saved Searches → New → Login Audit Trail**, add `Detail`, `User`, `Role`, `Status` and the token or application name as result columns, filter `Status = Failure`, and run it.

Then match what it says:

| Detail says            | What it means                                                                                                                                                                          |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EntityOrRoleDisabled` | The user or role behind the token is disabled, un-assigned, **or admin-privileged**. Check all three — the role being admin-level is the usual cause and nothing in the UI looks wrong |
| `InvalidSignature`     | The Consumer Secret or Token Secret is wrong, or the pairs have been crossed                                                                                                           |
| `InvalidAccount`       | The account ID is wrong, often a sandbox account sent without its suffix                                                                                                               |

{% hint style="info" %}
Send us the exact timestamp of a failed attempt and we can tell you which entry to look at. Without it, the audit trail is long and the relevant row is easy to miss.
{% endhint %}

***

### Optimizing NetSuite Data for Forecasting

If you use Moselle's forecasting features, these additional considerations help ensure accurate demand predictions from your NetSuite data.

#### Know What Counts as Demand

Moselle uses your NetSuite **Sales Orders** as the demand signal for forecasting. Transfer orders and purchase orders are internal inventory movement, so they are never counted as demand.

{% hint style="info" %}
If you record some customer demand outside of sales orders (for example, cash sales at point of sale), let your Moselle team know during channel mapping so we can account for it.
{% endhint %}

#### Include Sufficient History

Forecasts work best with at least **12–24 months** of sales history in NetSuite. More history gives Mo better seasonal pattern detection — if you have multiple years of data, let us know and we'll bring it all in.

#### Verify Channel Routing After Sync

After your initial sync:

1. Navigate to **Forecasting** and review demand by channel
2. Confirm that the volume and patterns per channel match your expectations
3. If a channel looks unexpectedly high or low, check whether transactions are being misrouted

#### Fiscal Period Alignment

NetSuite supports custom fiscal calendars, while Moselle forecasts on a standard **calendar month** basis.

| Your NetSuite Setup               | Impact on Moselle Forecasting                 | What to Do                                                              |
| --------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------- |
| **Standard calendar months**      | No issues — dates align directly              | No action needed                                                        |
| **4-4-5 fiscal calendar**         | Fiscal weeks don't align with calendar months | No action needed — Moselle uses `trandate`, not fiscal period           |
| **Non-January fiscal year start** | Fiscal Q1 may not equal calendar Q1           | Be aware when setting quarterly forecast guidelines                     |
| **13-period calendar**            | Periods don't map to 12 calendar months       | No action needed — Moselle uses `trandate` for calendar-month alignment |

{% hint style="info" %}
Moselle uses the **transaction date** (`trandate`) to assign sales to calendar months. As long as your sales orders have accurate transaction dates, data will align correctly — regardless of your NetSuite fiscal calendar configuration.
{% endhint %}

If you use a non-standard fiscal calendar, minor differences between Moselle's monthly totals and NetSuite's fiscal period totals are expected. Quarterly totals should still align closely.

#### Forecasting Data Quality Checklist

Before generating your first forecast with NetSuite data, verify:

* [ ] Connection test passed and your first sync is confirmed by the Moselle team
* [ ] At least 12 months of sales order history is available in NetSuite
* [ ] Channel mapping reviewed and confirmed with your Moselle team
* [ ] Sales by channel match your own NetSuite reports
* [ ] Warehouse names match between NetSuite Locations and Moselle Warehouses
* [ ] Quarantine or holding locations excluded from sellable inventory
* [ ] Items linked between NetSuite and Moselle (no unmatched SKUs)
