Quickstart
Go from zero to querying NetSuite in 5 minutes.
Video Walkthrough
Initialize
npx suiteportal initThis creates a .env file and suiteportal.config.ts in your project root. Fill in your .env with your NetSuite OAuth credentials:
NETSUITE_ACCOUNT_ID=1234567_SB1
NETSUITE_CONSUMER_KEY=your-consumer-key
NETSUITE_CONSUMER_SECRET=your-consumer-secret
NETSUITE_TOKEN_ID=your-token-id
NETSUITE_TOKEN_SECRET=your-token-secretNever commit your .env file to version control. The init command adds it to .gitignore automatically.
Introspect
Pull your NetSuite schema:
npx suiteportal introspectThis connects to your account, fetches the REST metadata catalog and custom records, and writes:
.suiteportal/
├── schema.json # Normalized schema (records, fields, relations)
├── relations.json # Inferred relationships
└── raw-metadata.json # Raw catalog dataThe introspector discovered 142 record types, 1,229 fields, and 6 relations from a standard NetSuite sandbox. Your results will vary based on customizations.
Generate
Generate TypeScript types and a typed client:
npx suiteportal generateThis reads schema.json and writes:
.suiteportal/client/
├── types.ts # TypeScript interfaces for every record
├── client.ts # Typed SuitePortalClient
└── index.ts # Barrel exportQuery & Mutate
import { createClient } from './.suiteportal/client';
import 'dotenv/config';
const ns = await createClient({
accountId: process.env.NETSUITE_ACCOUNT_ID!,
consumerKey: process.env.NETSUITE_CONSUMER_KEY!,
consumerSecret: process.env.NETSUITE_CONSUMER_SECRET!,
tokenId: process.env.NETSUITE_TOKEN_ID!,
tokenSecret: process.env.NETSUITE_TOKEN_SECRET!,
});
const customers = await ns.customer.findMany({
select: { id: true, companyname: true, email: true },
take: 10,
});
console.table(customers);const activeCustomers = await ns.customer.findMany({
where: {
isinactive: { equals: false },
email: { isNull: false },
},
select: { companyname: true, email: true },
orderBy: { companyname: 'asc' },
take: 50,
});const total = await ns.customer.count();
console.log(`Total customers: ${total}`);
const active = await ns.customer.count({
where: { isinactive: { equals: false } },
});
console.log(`Active customers: ${active}`);const newCustomer = await ns.customer.create({
data: {
companyname: 'Acme Corp',
email: 'hello@acme.com',
},
});
console.log(`Created customer: ${newCustomer.id}`);That's it — you have typed, autocompletable access to your entire NetSuite schema.
What's Next?
Now that you're up and running, explore the full API:
- Querying Guide — All filter operators, select, orderBy, pagination
- Mutations Guide — Create, update, and delete records
- Relations & Include — JOIN related records in queries
- Raw SuiteQL — Escape hatch for aggregations and complex logic
- SuiteQL Gotchas — Common pitfalls and how to avoid them