Deploy your first customer portal →
SuitePortal/NetSuite ORM

Mutations

Create, update, delete, and upsert NetSuite records using the REST Record API.

SuitePortal supports mutations — create, update, delete, and upsert — via the NetSuite REST Record API.

create

Create a new record:

const customer = await ns.customer.create({
  data: {
    companyname: 'Acme Corp',
    email: 'hello@acme.com',
  },
});
// Returns the created record with its id
console.log(customer.id); // '123'
POST /services/rest/record/v1/customer
Body: { "companyname": "Acme Corp", "email": "hello@acme.com" }

update

Update an existing record by ID:

const updated = await ns.customer.update({
  where: { id: { equals: 123 } },
  data: { email: 'new@acme.com' },
});
PATCH /services/rest/record/v1/customer/123
Body: { "email": "new@acme.com" }

The where clause must specify a single record by id. Bulk updates are not supported.

delete

Delete a record by ID:

await ns.customer.delete({
  where: { id: { equals: 123 } },
});
DELETE /services/rest/record/v1/customer/123
→ 204 No Content

Returns void — no response body.

upsert

Create or update a record by externalId. If a record with the given external ID exists, it is updated; otherwise a new record is created.

const customer = await ns.customer.upsert({
  where: { externalId: 'EXT-001' },
  data: {
    companyname: 'Acme Corp',
    email: 'hello@acme.com',
  },
});
PUT /services/rest/record/v1/customer/eid:EXT-001
Body: { "companyname": "Acme Corp", "email": "hello@acme.com" }

Upsert is the most common mutation pattern for NetSuite integrations — it matches on externalId so you don't need to track internal IDs.

Sublists (Line Items)

Transaction records like sales orders, invoices, and purchase orders have sublists — nested arrays of line items. Pass them in the data object using the sublist ID:

const order = await ns.salesorder.create({
  data: {
    entity: 42,
    tranid: 'SO-001',
    item: {
      items: [
        { item: 100, quantity: 5, rate: 19.99 },
        { item: 200, quantity: 2, rate: 49.99 },
      ],
    },
  },
});

Sublists also work with update and upsert:

await ns.salesorder.upsert({
  where: { externalId: 'SO-EXT-001' },
  data: {
    entity: 42,
    item: {
      items: [
        { item: 100, quantity: 10 },
      ],
    },
  },
});

Sublist types are auto-generated from the schema. For example, a salesorder with an item sublist generates a SalesorderItemItem interface in your typed client.

Mutations vs Queries

QueriesMutations
APISuiteQL (POST /suiteql)REST Record (/record/v1/{type})
MethodsfindMany, findFirst, countcreate, update, delete, upsert
FilteringFull where clauseid (update/delete) or externalId (upsert)
AuthSame OAuth 1.0a signingSame OAuth 1.0a signing

Both queries and mutations use the same authenticated client — no extra setup required.

Error Handling

Mutations throw the same error types as queries:

import { NetSuiteError, AuthError } from 'suiteportal';

try {
  await ns.customer.create({
    data: { companyname: 'Test' },
  });
} catch (error) {
  if (error instanceof AuthError) {
    // 401/403 — check credentials or permissions
  } else if (error instanceof NetSuiteError) {
    // Other API error (validation, not found, etc.)
    console.error(error.message, error.statusCode);
  }
}

On this page