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

# NetSuite

> Oracle NetSuite ERP: customers, sales orders, invoices, item fulfillments, SuiteQL, and raw REST access.

The NetSuite connector lets your workflows read and write NetSuite records through the [SuiteTalk REST Web Services API](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/book_1559132836.html). It exposes curated tools for the most common records (customers, sales orders, invoices, items, item fulfillments), a powerful `run-suiteql` tool for SQL-like reads, and a `raw-request` passthrough for any other REST endpoint.

<Note>
  Spojit authenticates to NetSuite using **Token-Based Authentication (TBA)**. Per Oracle's release notes, **no new TBA authorizations can be created from NetSuite 2027.1 onward**, but existing credentials continue to work. OAuth 2.0 support is coming as an additional connection option.
</Note>

<Snippet file="connection-note.mdx" />

## Finding record types, fields, and SuiteQL tables

NetSuite accounts are heavily customizable, so record and field names vary between accounts. Use these Oracle-maintained references when writing queries or record payloads:

* **[Records Browser](https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2024_2/script/index.html)**: every record type, its fields, and sublists.
* **[Analytics Data Source Schema Browser](https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2024_2/analytics/index.html)**: the tables and columns available to SuiteQL.
* **[SuiteQL reference](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_158394344595.html)**: SuiteQL language syntax and supported functions.

You can also call `list-record-types` and `get-record-metadata` from a workflow to discover what the current NetSuite account exposes.

## Connection setup

<Steps>
  <Step title="Enable TBA in NetSuite">
    In NetSuite go to **Setup → Company → Enable Features → SuiteCloud**. Under *Manage Authentication*, enable **Token-Based Authentication** and **REST Web Services**.
  </Step>

  <Step title="Create an integration record">
    Go to **Setup → Integration → Manage Integrations → New**. Give it a name (e.g. "Spojit"), enable **Token-Based Authentication**, leave **TBA: Authorization Flow** disabled, and save. Copy the **Consumer Key** and **Consumer Secret** that appear at the bottom of the page. They are shown only once.
  </Step>

  <Step title="Create an access token">
    Go to **Setup → Users/Roles → Access Tokens → New**. Select your integration, a user, and a role with the necessary permissions (commonly *SuiteAnalytics Workbook*, *REST Web Services*, and record-type-specific permissions). Save and copy the **Token ID** and **Token Secret**. These are also shown only once.
  </Step>

  <Step title="Note your Account ID">
    Find your account ID at **Setup → Company → Company Information**. Sandboxes have a `_SB` suffix (e.g. `1234567_SB1`).
  </Step>

  <Step title="Add the connection in Spojit">
    Go to **Connections** in Spojit, click **Add Connection**, select **NetSuite**, and enter the five values: **Account ID**, **Consumer Key**, **Consumer Secret**, **Token ID**, **Token Secret**.
  </Step>
</Steps>

## Tools

### Utility

<AccordionGroup>
  <Accordion title="verify-connection: Test credentials and account">
    Fetches the REST metadata catalog root and returns success if credentials are valid.

    No parameters required.

    **Example response:**

    ```json theme={null}
    {
      "success": true,
      "status": 200,
      "data": {
        "items": [
          { "name": "customer", "links": [{ "rel": "self", "href": ".../record/v1/metadata-catalog/customer" }] }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="run-suiteql: Execute a SuiteQL query">
    <ParamField body="query" type="string" required>
      SuiteQL query. Example: `SELECT id, companyname FROM customer WHERE isinactive = 'F' FETCH FIRST 10 ROWS ONLY`.
    </ParamField>

    <ParamField body="limit" type="number">Max rows per page (default 100, max 1000).</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>

    **Example request:**

    ```json theme={null}
    {
      "query": "SELECT id, tranid, trandate, entity FROM transaction WHERE type = 'SalesOrd' AND trandate >= '01/01/2025' FETCH FIRST 5 ROWS ONLY"
    }
    ```

    **Example response:**

    ```json theme={null}
    {
      "success": true,
      "status": 200,
      "data": {
        "links": [{ "rel": "self", "href": ".../query/v1/suiteql" }],
        "count": 3,
        "hasMore": false,
        "items": [
          { "id": "4421", "tranid": "SO4421", "trandate": "02/14/2025", "entity": "128" },
          { "id": "4422", "tranid": "SO4422", "trandate": "02/14/2025", "entity": "129" },
          { "id": "4423", "tranid": "SO4423", "trandate": "02/15/2025", "entity": "130" }
        ],
        "offset": 0,
        "totalResults": 3
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Metadata / discovery

<AccordionGroup>
  <Accordion title="list-record-types: List all record types in this account">
    Returns the REST metadata catalog root: every record type the account exposes via REST.

    No parameters required.
  </Accordion>

  <Accordion title="get-record-metadata: Get the schema for one record type">
    <ParamField body="recordType" type="string" required>
      Record type name, e.g. `customer`, `salesOrder`, `invoice`.
    </ParamField>

    **Example request:**

    ```json theme={null}
    { "recordType": "customer" }
    ```

    The response is a JSON-Schema document listing every field, sublist, and enumeration; use it to discover what payload shape the record expects.
  </Accordion>
</AccordionGroup>

### Customers

<AccordionGroup>
  <Accordion title="list-customers: List customers">
    <ParamField body="q" type="string">SuiteTalk query filter (e.g. `companyName START_WITH 'Acme'`).</ParamField>
    <ParamField body="limit" type="number">Page size (default 100, max 1000).</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>

    **Example request:**

    ```json theme={null}
    { "q": "isInactive IS false", "limit": 5 }
    ```

    **Example response:**

    ```json theme={null}
    {
      "success": true,
      "status": 200,
      "data": {
        "links": [{ "rel": "self", "href": ".../customer" }],
        "count": 5,
        "hasMore": true,
        "totalResults": 342,
        "items": [
          { "links": [{ "rel": "self", "href": ".../customer/128" }], "id": "128" },
          { "links": [{ "rel": "self", "href": ".../customer/129" }], "id": "129" }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="get-customer: Fetch a customer by ID">
    <ParamField body="id" type="string" required>Customer internal ID.</ParamField>
    <ParamField body="expandSubResources" type="boolean">Inline sublists (addresses, contacts).</ParamField>

    **Example response:**

    ```json theme={null}
    {
      "success": true,
      "status": 200,
      "data": {
        "id": "128",
        "companyName": "Acme Inc",
        "email": "ap@acme.example",
        "phone": "+1-415-555-0123",
        "isPerson": false,
        "isInactive": false,
        "subsidiary": { "id": "1", "refName": "Parent Company" },
        "terms": { "id": "4", "refName": "Net 30" }
      }
    }
    ```
  </Accordion>

  <Accordion title="create-customer: Create a customer">
    <ParamField body="body" type="object" required>
      Customer payload. Common fields: `companyName`, `email`, `phone`, `subsidiary`, `isPerson`, `firstName`, `lastName`.
    </ParamField>

    **Example request:**

    ```json theme={null}
    {
      "body": {
        "companyName": "Globex Corporation",
        "email": "contact@globex.example",
        "subsidiary": { "id": "1" },
        "isPerson": false
      }
    }
    ```

    **Example response:**

    ```json theme={null}
    { "success": true, "status": 204, "data": null }
    ```

    The new customer's internal ID is returned in the `Location` response header (e.g. `/record/v1/customer/512`).
  </Accordion>

  <Accordion title="update-customer: Patch an existing customer">
    <ParamField body="id" type="string" required>Customer internal ID.</ParamField>
    <ParamField body="body" type="object" required>Fields to update.</ParamField>

    **Example request:**

    ```json theme={null}
    { "id": "128", "body": { "phone": "+1-415-555-9999" } }
    ```
  </Accordion>
</AccordionGroup>

### Sales orders

<AccordionGroup>
  <Accordion title="list-sales-orders: List sales orders">
    <ParamField body="q" type="string">SuiteTalk filter (e.g. `tranDate ON_OR_AFTER '01/01/2025'`).</ParamField>
    <ParamField body="limit" type="number">Page size.</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>
  </Accordion>

  <Accordion title="get-sales-order: Fetch a sales order by ID">
    <ParamField body="id" type="string" required>Sales order internal ID.</ParamField>
    <ParamField body="expandSubResources" type="boolean">Inline line items.</ParamField>

    **Example response (truncated):**

    ```json theme={null}
    {
      "success": true,
      "status": 200,
      "data": {
        "id": "4421",
        "tranId": "SO4421",
        "tranDate": "2025-02-14",
        "entity": { "id": "128", "refName": "Acme Inc" },
        "status": { "id": "B", "refName": "Pending Fulfillment" },
        "total": 1245.50,
        "item": {
          "items": [
            { "line": 1, "item": { "id": "301", "refName": "Widget" }, "quantity": 10, "rate": 120.00, "amount": 1200.00 }
          ]
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Invoices

<AccordionGroup>
  <Accordion title="list-invoices: List invoices">
    <ParamField body="q" type="string">SuiteTalk filter (e.g. `status IS "Invoice:A"` for open invoices).</ParamField>
    <ParamField body="limit" type="number">Page size.</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>
  </Accordion>

  <Accordion title="get-invoice: Fetch an invoice by ID">
    <ParamField body="id" type="string" required>Invoice internal ID.</ParamField>
    <ParamField body="expandSubResources" type="boolean">Inline invoice lines.</ParamField>
  </Accordion>
</AccordionGroup>

### Items

<Note>
  NetSuite has several item subtypes (`inventoryItem`, `assemblyItem`, `nonInventorySaleItem`, `serviceSaleItem`, …). The tools below default to `inventoryItem`. To list across all subtypes, use `run-suiteql` with `SELECT id, itemid, itemtype FROM item`.
</Note>

<AccordionGroup>
  <Accordion title="list-items: List items of a subtype">
    <ParamField body="recordType" type="string" default="inventoryItem">Item record type.</ParamField>
    <ParamField body="q" type="string">SuiteTalk filter.</ParamField>
    <ParamField body="limit" type="number">Page size.</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>
  </Accordion>

  <Accordion title="get-item: Fetch an item by ID">
    <ParamField body="id" type="string" required>Item internal ID.</ParamField>
    <ParamField body="recordType" type="string" default="inventoryItem">Item subtype.</ParamField>
  </Accordion>
</AccordionGroup>

### Item fulfillments

<Note>
  Item fulfillment records in NetSuite are normally created by **transforming** a sales order, not by a bare `POST /record/v1/itemFulfillment`. The `create-item-fulfillment` tool wraps the transform endpoint so the LLM doesn't need to know the URL convention.
</Note>

<AccordionGroup>
  <Accordion title="list-item-fulfillments: List fulfillment records">
    <ParamField body="q" type="string">SuiteTalk filter (e.g. `createdFrom IS 4421`).</ParamField>
    <ParamField body="limit" type="number">Page size.</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>
  </Accordion>

  <Accordion title="get-item-fulfillment: Fetch a fulfillment by ID">
    <ParamField body="id" type="string" required>Item fulfillment internal ID.</ParamField>
    <ParamField body="expandSubResources" type="boolean">Inline fulfilled line items.</ParamField>
  </Accordion>

  <Accordion title="create-item-fulfillment: Fulfill a sales order">
    <ParamField body="salesOrderId" type="string" required>Internal ID of the sales order being fulfilled.</ParamField>

    <ParamField body="body" type="object" required>
      Fulfillment payload. Set `itemReceive: true` and `quantity` on each line you want to ship.
    </ParamField>

    **Example request:**

    ```json theme={null}
    {
      "salesOrderId": "4421",
      "body": {
        "shipStatus": "C",
        "item": {
          "items": [
            { "line": 1, "itemReceive": true, "quantity": 10 }
          ]
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Generic record CRUD

Use these when the record type isn't covered by a domain-specific tool (e.g. `purchaseOrder`, `vendorBill`, `journalEntry`, `employee`).

<AccordionGroup>
  <Accordion title="get-record: Fetch any record by type and ID">
    <ParamField body="recordType" type="string" required>Record type (e.g. `purchaseOrder`).</ParamField>
    <ParamField body="id" type="string" required>Internal ID.</ParamField>
    <ParamField body="expandSubResources" type="boolean">Inline sublists.</ParamField>
    <ParamField body="fields" type="string">Comma-separated list of fields to return.</ParamField>
  </Accordion>

  <Accordion title="list-records: List records of a type">
    <ParamField body="recordType" type="string" required>Record type.</ParamField>
    <ParamField body="q" type="string">SuiteTalk filter.</ParamField>
    <ParamField body="limit" type="number">Page size.</ParamField>
    <ParamField body="offset" type="number">Pagination offset.</ParamField>
  </Accordion>

  <Accordion title="create-record: Create any record">
    <ParamField body="recordType" type="string" required>Record type.</ParamField>
    <ParamField body="body" type="object" required>Record payload.</ParamField>
  </Accordion>

  <Accordion title="update-record: Patch any record">
    <ParamField body="recordType" type="string" required>Record type.</ParamField>
    <ParamField body="id" type="string" required>Internal ID.</ParamField>
    <ParamField body="body" type="object" required>Fields to update.</ParamField>
  </Accordion>

  <Accordion title="delete-record: Delete a record">
    <ParamField body="recordType" type="string" required>Record type.</ParamField>
    <ParamField body="id" type="string" required>Internal ID.</ParamField>
  </Accordion>

  <Accordion title="upsert-record: Create or update by external ID">
    <ParamField body="recordType" type="string" required>Record type.</ParamField>
    <ParamField body="externalId" type="string" required>External ID.</ParamField>
    <ParamField body="body" type="object" required>Record payload.</ParamField>
  </Accordion>
</AccordionGroup>

### Sublists

<AccordionGroup>
  <Accordion title="get-sublist: Fetch a sublist from a record">
    <ParamField body="recordType" type="string" required>Parent record type.</ParamField>
    <ParamField body="id" type="string" required>Parent record ID.</ParamField>
    <ParamField body="sublistId" type="string" required>Sublist name (e.g. `item`, `addressBook`).</ParamField>
  </Accordion>

  <Accordion title="add-sublist-item: Append a line to a sublist">
    <ParamField body="recordType" type="string" required>Parent record type.</ParamField>
    <ParamField body="id" type="string" required>Parent record ID.</ParamField>
    <ParamField body="sublistId" type="string" required>Sublist name.</ParamField>
    <ParamField body="body" type="object" required>Line item payload.</ParamField>
  </Accordion>
</AccordionGroup>

### Advanced

<AccordionGroup>
  <Accordion title="raw-request: Make any signed REST request">
    Execute an arbitrary signed request against the NetSuite REST API. TBA signing is applied automatically. `path` is relative to `/services/rest`.

    <ParamField body="method" type="string" required>HTTP method: `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`.</ParamField>
    <ParamField body="path" type="string" required>Path relative to `/services/rest` (e.g. `/record/v1/vendorBill`).</ParamField>
    <ParamField body="body" type="object">Request body.</ParamField>
    <ParamField body="queryParams" type="object">Query parameters as a key/value map.</ParamField>
    <ParamField body="headers" type="object">Extra headers.</ParamField>

    **Example request:**

    ```json theme={null}
    {
      "method": "GET",
      "path": "/record/v1/purchaseOrder",
      "queryParams": { "limit": "5", "q": "status IS \"PurchOrd:B\"" }
    }
    ```
  </Accordion>
</AccordionGroup>
