Published on

Upsert by external ID

PUT to eid:<your key> creates the record if the external ID is new, and updates it otherwise. Safe to retry.

upsert.js
export async function upsertByExternalId({ host, token, recordType, externalId, body, replace }) {
const qs = replace ? `?replace=${encodeURIComponent(replace)}` : ''
const url = `https://${host}.suitetalk.api.netsuite.com/services/rest/record/v1/${recordType}/eid:${encodeURIComponent(externalId)}${qs}`
const res = await fetch(url, {
method: 'PUT',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (res.status !== 204) throw new Error(`Upsert ${res.status}: ${await res.text()}`)
// NetSuite answers 204 with the record URL in Location
return res.headers.get('location')?.split('/').pop()
}

Usage:

const id = await upsertByExternalId({
host: '1234567-sb1',
token,
recordType: 'salesOrder',
externalId: `SHOPIFY-${order.id}`,
replace: 'item', // replace item lines on update instead of appending
body: {
entity: { id: customerId },
otherRefNum: order.name,
item: { items: order.lines.map((l) => ({ item: { id: l.nsItemId }, quantity: l.qty, rate: l.price })) },
},
})

Use a key from the source system, never one generated at request time. Why this matters: the retry that creates a duplicate order.