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

# NetSuite Create Sales Order

> Creates a sales order in Oracle NetSuite from a customer id and line items, with per-agent defaults for form, subsidiary and custom fields.

Creates one sales order in the workspace's own NetSuite account with a single `POST /services/rest/record/v1/salesOrder` and returns the new order's internal id, document number and a link to open it. Display name **"NetSuite Create Sales Order"**. Off by default.

The tool is generic: everything that differs between NetSuite accounts — custom form, subsidiary, currency, location, custom `custbody_*` / `custcol_*` fields — is a value the admin pins on the configured tool, never code. The agent supplies only what changes per order and takes every id from [NetSuite Lookup](/docs/tools/netsuite_lookup).

## Authentication and enablement

Configured tool bound to a **NetSuite** integration (account id, token id/secret, consumer key/secret — see NetSuite Lookup for where each value comes from). The role behind the token needs permission to create sales orders. REST record writes require **SuiteTax**; accounts on legacy tax get NetSuite's error back.

## Inputs

Per order (agent):

* `customer_id` — **required.** NetSuite internal id of the customer (`match_identifier` from a lookup on `customer`). Never the name.
* `line_items` — **required**, max 500. Each: `item_id` (required, internal id from a lookup on `item`), `quantity` (required, > 0), `rate` (unit price; omit to use the item's price level), `amount`, `description`, `price_level_id`, `units_id`, `location_id`, `department_id`, `class_id`, `tax_code_id`, `custom_fields` (`custcol_*`). Flat `custcol_*` keys on a line are accepted too.
* `tran_date`, `ship_date` — `YYYY-MM-DD`; empty `tran_date` means today.
* `other_ref_num` — the customer's PO number (NetSuite "PO #"); also the duplicate-check key.
* `memo`.
* Ship-to, one of: `shipping_address` (`addressee, attention, addr1, addr2, addr3, city, state, zip, country, phone` — a one-off address on this order, the customer's address book is untouched), `ship_address_text` (free text when the block cannot be split), or `ship_address_list_id` (one of the customer's saved addresses). Giving two is a validation error.
* Bill-to, optional: `billing_address` or `bill_address_text`. NetSuite defaults it from the customer.
* `custom_fields` — header `custbody_*` values for this order: plain value for text/number/date/checkbox, `{"id": "…"}` for list fields. Overrides the configured defaults key by key. Flat `custbody*` / `cseg*` keys at the top level are accepted too; an explicit `custom_fields` entry wins over a flat key with the same name, and a flat key set to `null` means "unset" and is dropped.

Fixed defaults (group **Fixed defaults**; pin per agent so the model cannot contradict them):

* `custom_form_id` (Customization → Forms → Transaction Forms; the form decides invoice / cash sale / progress billing), `subsidiary_id`, `currency_id`, `location_id`, `department_id`, `class_id`, `terms_id`, `sales_rep_id`, `ship_method_id`.
* `order_status` — `A` Pending Approval (default) or `B` Pending Fulfillment.

Configuration only:

* `custom_fields_defaults` — JSON object of `custbody_*` values applied to every order, e.g. `{"custbody_order_source": {"id": "3"}}`.
* `line_custom_fields_defaults` — JSON object of `custcol_*` values applied to every line.
* `duplicate_check` — `none` (default) or `other_ref_num`: before creating, look for a sales order with the same customer and PO number and refuse if one exists, naming it. Recommended for email and upload triggers. With the check on, `other_ref_num` is required — a check that cannot run is refused, not skipped. Runs of this tool for the same account, customer and PO number are serialised with a Postgres advisory lock (the platform's shared write-lock repository) held across check and create, so two Agents runs for one PO cannot both create; the check runs again after the create and reports in `warnings` any other order for that PO entered outside Agents in the same moment. Any existing sales order counts, including cancelled or closed ones — cancel and re-create a PO in NetSuite, or use a new PO number, if a closed order must be replaced.
* `location_mode` — where a resolved `location_id` goes: `header` (default, NetSuite's own behaviour), `lines` (on every line that has no location of its own, header left empty — use when fulfilment reads the line location, as a per-line warehouse export does), or `both`. A line's own `location_id` always wins.

## Output

Flat structured result: `sales_order_id`, `tran_id` (document number, e.g. `SO-10432`), `status`, `total`, `customer_id`, `tran_date`, `other_ref_num`, `order_status`, `line_item_count`, `line_items[]`, `custom_fields`, `netsuite_url`, `warnings[]`, `completed_at`. The markdown summary lists the lines and links to the order. `tran_id`, `status` and `total` come from a best-effort read-back after the create; if that read fails the order still exists, the fields are empty and `warnings` says so.

A refused duplicate returns an error result whose structured content carries `status: "limitation"`, `limitation_type: "duplicate"`, `tool_name`, `duplicate: true`, `existing_sales_order_id`, `existing_tran_id`, `customer_id`, `other_ref_num` and `netsuite_url`. The `limitation` status tells the platform not to retry: the agent gets the existing order at once and decides what to do.

## Limits and side effects

* Creates exactly one sales order per successful call; never updates, cancels or fulfils one.
* Every reference id is validated as digits and every custom-field key as a `custbody*`, `custcol*` or `cseg*` script id before the payload is built.
* Item groups cannot have member lines set on create (NetSuite limitation); attachments are out of scope.
* Logs record line count, order id, status and timing — never the payload or addresses.

## Expected errors

* `NetSuite integration not configured…`, missing consumer pair, invalid account id — configuration.
* `validation error: …` — a missing `customer_id` / `line_items`, a name where an id is expected, a bad date, an unknown custom-field key, two ship-to modes at once, or no `other_ref_num` while `duplicate_check` is on.
* `Another run is creating a sales order for customer … with PO number "…" right now` — another run holds the PO lock; nothing created, retry.
* `A sales order for customer … with PO number "…" already exists: SO-… (id …)` — duplicate check hit; nothing created.
* `Could not check for an existing sales order before creating: …` — the duplicate query failed; nothing created.
* `NetSuite refused the sales order: create sales order returned HTTP 400: …` — NetSuite's own detail (e.g. "Please enter value(s) for: Subsidiary", an item not valid for the subsidiary, SuiteTax not enabled); nothing created.

Which of these the platform retries: configuration and validation errors, the duplicate refusal and any NetSuite `4xx` are limitations (`status: "limitation"`) and go straight back to the agent — the same call would fail the same way. The lock being busy, a failed lock, network failures and NetSuite `5xx` responses are ordinary errors and are retried.
