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 ContentReturns 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
| Queries | Mutations | |
|---|---|---|
| API | SuiteQL (POST /suiteql) | REST Record (/record/v1/{type}) |
| Methods | findMany, findFirst, count | create, update, delete, upsert |
| Filtering | Full where clause | id (update/delete) or externalId (upsert) |
| Auth | Same OAuth 1.0a signing | Same 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);
}
}