n8n-nodes-netsuite-v2
v0.3.0
Published
n8n community node for Oracle NetSuite by SolutionLab - REST API, SuiteQL, Restlets, and Polling Triggers with OAuth 2.0 Client Credentials (M2M/JWT/PS256)
Maintainers
Readme
n8n-nodes-netsuite-v2
A production-grade n8n community node for Oracle NetSuite, built by SolutionLab (Avishai Asaf). Connects to the NetSuite REST API using OAuth 2.0 Client Credentials with Certificate (Machine-to-Machine / JWT PS256) - the most secure, fully automated authentication method available for server-to-server integrations.
3 resources. 11 operations. Polling triggers. SuiteQL templates. Zero user interaction required for authentication.
Why This Node?
Standard NetSuite integrations in n8n rely on OAuth 2.0 Authorization Code flow, which requires a browser-based login, manual token refresh, and session management. This creates fragile automations that break when tokens expire or when running in headless environments.
This node was built by SolutionLab to solve three specific production bottlenecks:
Fully Automated M2M Authentication
OAuth 2.0 Client Credentials with Certificate eliminates all user interaction. The node constructs a JWT, signs it with PS256 (RSASSA-PSS + SHA-256), and exchanges it for an access token - entirely in the background. Tokens are cached per credential and automatically refreshed with a 5-minute safety buffer before expiry. No browser sessions. No token expiry surprises. No manual intervention.
Robust Certificate Handling
Real-world NetSuite certificate integrations frequently fail on PEM format edge cases - especially when private keys are pasted through web UIs, environment variables, or secret managers. This node normalizes every variant automatically:
- Standard multi-line PEM with proper 64-character line breaks
- Single-line keys with escaped
\ncharacters - Raw base64 content without BEGIN/END headers
- Keys with
PRIVATE KEY,RSA PRIVATE KEY, orEC PRIVATE KEYheaders
Enterprise API Coverage with Automatic Pagination
SuiteQL queries and REST Record listings automatically paginate through all results when "Return All" is enabled. NetSuite's structured error responses (o:errorDetails, o:errorCode) are parsed and surfaced as readable messages instead of raw HTTP errors.
Enterprise Features
REST Record Operations
Full CRUD operations on any NetSuite record type via the SuiteTalk REST API.
| Operation | Method | Description | |-----------|--------|-------------| | Create | POST | Create a record with a JSON body | | Get | GET | Retrieve a single record by internal ID | | Get Many | GET | List records with filtering, field selection, and sub-resource expansion | | Update | PATCH | Partial update - only the fields you include are modified | | Upsert | PUT | Create or update a record by external ID - ideal for syncing data from external systems | | Delete | DELETE | Remove a record by internal ID |
Dynamic Record Types - The record type dropdown is populated automatically from NetSuite's metadata catalog (/services/rest/record/v1/metadata-catalog). If the catalog is unavailable, the node falls back to 20 common record types including Customer, Contact, Invoice, Sales Order, Purchase Order, Journal Entry, and more.
Get Many Pagination - Enable "Return All" to automatically follow NetSuite's rel:next pagination links until all records are retrieved. When disabled, a single page of results is returned up to the configured limit.
Additional Options:
| Option | Available On | Type | Description | |--------|-------------|------|-------------| | Fields | Get | String | Comma-separated list of field names to return (reduces payload size) | | Expand Sub-Resources | Get | Boolean | Include sublists and line items in the response |
Tip: Need to filter records or select specific fields? Use the SuiteQL resource — it supports full SQL-like queries with WHERE clauses, JOINs, and field selection.
SuiteQL
Execute SQL-like queries against your NetSuite data using Oracle's SuiteQL syntax.
- Query Templates - Start with built-in templates for common queries (Active Customers, Recent Sales Orders, Open Invoices, Inventory Levels, Employee Directory, Vendor Bills) or write your own
- Automatic Pagination - When "Return All" is enabled, the node paginates through results using NetSuite's
hasMoreflag and offset-based pagination - Configurable Limit - When "Return All" is disabled, returns up to the specified limit (default: 1000)
- Transient Preferences - Requests include the
Prefer: transientheader for optimized response handling
Restlet Operations
Call custom SuiteScript Restlet deployments with full HTTP method support.
| Method | Body | Use Case | |--------|------|----------| | GET | No | Retrieve data from a custom endpoint | | POST | JSON | Submit data or trigger server-side logic | | PUT | JSON | Update resources via a custom endpoint | | DELETE | No | Remove resources via a custom endpoint |
Each request requires a Script ID and Deploy ID. Additional query string parameters can be passed as key-value pairs. The Restlet URL is constructed as:
https://{accountId}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script={scriptId}&deploy={deployId}Platform Capabilities
- Token Caching - Access tokens are cached per
accountId:consumerKeypair in a module-level store. Tokens are reused across workflow executions within the same n8n process and refreshed automatically 5 minutes before expiry. - PEM Normalization - Handles four input variants (multi-line, escaped newlines, single-line, raw base64) and rebuilds the key with proper 64-character line formatting.
- Structured Error Parsing - NetSuite REST API error responses are parsed to extract
o:errorDetailsando:errorCodefields, providing specific error codes and messages instead of generic HTTP status text. - Native Token Exchange - The JWT-to-token exchange uses Node.js native
httpsinstead of n8n's HTTP request helper, avoiding URL encoding issues with theclient_assertionparameter.
Polling Triggers
The NetSuite Trigger node monitors your NetSuite data for changes and starts workflows automatically. It uses SuiteQL to poll for records that have been created or modified since the last check.
| Event | Behavior |
|-------|----------|
| Record Created | Triggers when new records are created (uses datecreated field) |
| Record Updated | Triggers when existing records are modified, excluding newly created records |
| Record Created or Updated | Triggers on any change (uses lastmodifieddate field) |
Key capabilities:
- Dynamic record type dropdown - Same metadata catalog integration as the main node
- Configurable date fields - Override
datecreatedandlastmodifieddatefor custom records that use different field names - Additional filters - Narrow polling scope with SuiteQL WHERE clause fragments (e.g.,
AND subsidiary = 1) - Field selection - Return only the fields you need instead of
SELECT * - Automatic pagination - Handles large result sets across multiple pages
- Structured error handling - NetSuite error codes are parsed and surfaced clearly
Polling interval: Configured in the n8n workflow settings (default: every minute). The trigger establishes a baseline on first activation and only fires for records changed after that point.
Installation
Community Nodes (Recommended)
- In n8n, go to Settings > Community Nodes
- Enter
n8n-nodes-netsuite-v2 - Click Install
- Restart n8n if prompted
Manual Installation
cd ~/.n8n/custom
npm install n8n-nodes-netsuite-v2Then restart n8n.
Compatibility: Requires n8n with
n8n-workflow>= 2.12.0.
Quick Start
- Install the node via Settings > Community Nodes >
n8n-nodes-netsuite-v2 - Configure credentials — follow the NetSuite Setup below to create an M2M integration and certificate
- Create your first workflow — drag the NetSuite node onto the canvas, select Resource: SuiteQL, pick "Active Customers" template, and execute
That's it — you'll see your NetSuite customer list in under 5 minutes.
NetSuite Setup - Prerequisites
Before configuring the node in n8n, complete the following steps in your NetSuite account. Administrator access is required for initial setup.
Step 1: Create an Integration Record
Navigate to Setup > Integration > Manage Integrations > New.
| Setting | Value | |---------|-------| | Name | e.g., "n8n Automation" | | Client Credentials (M2M) Grant | Enabled | | Authorization Code Grant | Disable (not used) | | Token-Based Authentication | Not required |
Click Save, then copy the Consumer Key. The Consumer Secret is not used in the M2M flow.
Step 2: Generate a Certificate Key Pair
Generate an RSA key pair using OpenSSL (4096-bit recommended):
# Generate private key
openssl genrsa -out private.pem 4096
# Generate public certificate (valid for 365 days)
openssl req -new -x509 -key private.pem -out public.pem -days 365Security: Keep
private.pemsecure. Its contents will be pasted into the n8n credential form. Never commit private keys to version control.
Step 3: Configure OAuth 2.0 Client Credentials Mapping
Navigate to Setup > Integration > OAuth 2.0 Client Credentials (M2M) Setup and click Create New.
| Field | Description | |-------|-------------| | Entity | The user or employee associated with API calls | | Role | The role that determines API permissions (see Step 4) | | Integration | The integration record created in Step 1 |
Upload the public certificate (public.pem) from Step 2, then click Save.
Copy the Certificate ID - this is the kid value used in the JWT header for token signing.
Step 4: Configure Role Permissions
The role selected in Step 3 must have the following permissions based on which resources you plan to use:
| Resource | Required Permission | Navigation Path | |----------|---------------------|-----------------| | REST Records (SuiteTalk) | REST Web Services | Setup > REST Web Services | | SuiteQL | SuiteAnalytics Workbook | Reports > SuiteAnalytics Workbook | | Restlets | SuiteScript | Setup > SuiteScript | | All Resources | Log in using Access Tokens | Setup > Log in using Access Tokens |
Tip: For initial testing, use the Administrator role. For production, create a custom role with only the minimum required permissions.
Step 5: Find Your Account ID
Navigate to Setup > Company > Company Information. Your Account ID is displayed at the top of the page.
- Production accounts:
1234567 - Sandbox accounts:
1234567_SB1
The node automatically normalizes the Account ID for API URLs (converts to lowercase and replaces underscores with hyphens).
Credential Configuration
When creating a new NetSuite Client Credentials (Certificate) credential in n8n, fill in the following fields:
| Field | Description | Where to Find |
|-------|-------------|---------------|
| Account ID | Your NetSuite Account ID | Setup > Company > Company Information |
| Consumer Key | Integration consumer key | Integration Record (Step 1) |
| Certificate ID | Certificate ID (JWT kid claim) | M2M Setup page (Step 3) |
| Certificate Private Key (PEM) | Full contents of your private key file | private.pem from Step 2 |
Private Key Format
Paste the entire contents of your private.pem file, including the -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- lines.
The node handles multiple formats automatically:
- Standard multi-line PEM
- Single-line with escaped
\ncharacters - Raw base64 without headers
- Keys with
PRIVATE KEY,RSA PRIVATE KEY, orEC PRIVATE KEYheaders
Testing the Connection
Click Test in the n8n credential form to verify the connection. The test performs a full authentication cycle (JWT creation, token exchange) and calls GET /services/rest/record/v1/metadata-catalog with the Prefer: transient header. If the test passes, all four credential fields are valid and the certificate is correctly mapped in NetSuite.
Usage
Record Operations
Select Resource: Record to perform CRUD operations on NetSuite records.
Create a Record
Select Operation: Create, choose the record type, and provide a JSON body:
{
"companyname": "Acme Corp",
"email": "[email protected]",
"subsidiary": { "id": "1" }
}Get a Record
Select Operation: Get, choose the record type, and enter the Record ID (internal ID).
Use Additional Options to control the response:
- Fields:
companyname,email,phone- return only specific fields - Expand Sub-Resources: include sublists and line items in the response
Get Many Records
Select Operation: Get Many and choose the record type.
- Enable Return All to automatically paginate through all matching records
- Set a Limit when Return All is disabled to control the page size
- For filtering or field selection, use the SuiteQL resource which supports full SQL-like WHERE clauses
Update a Record
Select Operation: Update, choose the record type, enter the Record ID, and provide the fields to update:
{
"email": "[email protected]",
"phone": "555-0100"
}The update uses HTTP PATCH - only the fields you include will be modified.
Delete a Record
Select Operation: Delete, choose the record type, and enter the Record ID.
SuiteQL Queries
Select Resource: SuiteQL and Operation: Execute.
Enter your query using SuiteQL syntax:
SELECT id, companyname, email
FROM customer
WHERE isinactive = 'F'SuiteQL supports JOIN operations for cross-table queries:
SELECT t.tranid, t.trandate, c.companyname
FROM transaction t
JOIN customer c ON t.entity = c.id
WHERE t.type = 'SalesOrd'Options:
- Return All - When enabled, automatically paginates through all results using offset-based pagination. When disabled, returns up to the specified Limit.
- Limit - Maximum number of results per page (default: 1000). Only visible when Return All is disabled.
Restlet Operations
Select Resource: Restlet to call custom SuiteScript Restlet deployments.
| Field | Description |
|-------|-------------|
| Script ID | The numeric script ID of the Restlet deployment |
| Deploy ID | The deployment ID (default: 1) |
| Operation | HTTP method: GET, POST, PUT, or DELETE |
| Body (JSON) | Request body for POST and PUT operations |
| Additional Parameters | Extra query string parameters (key-value pairs) |
Example POST body for a custom Restlet:
{
"action": "createRecord",
"recordType": "customrecord_project",
"values": {
"name": "New Project",
"custrecord_status": "1"
}
}Trigger Setup
Add a NetSuite Trigger node as the first node in your workflow.
- Select the Record Type to monitor (e.g., Customer, Sales Order, Invoice)
- Choose the Event type: Created, Updated, or Created or Updated
- Optionally specify Return Fields (e.g.,
id, companyname, email) to reduce payload size - Optionally add Additional Filters to narrow the scope (e.g.,
AND subsidiary = 1)
The trigger polls NetSuite at the interval configured in your workflow settings. On first activation, it records the current timestamp as a baseline - only records changed after activation will trigger the workflow.
Upsert a Record
Select Operation: Upsert, choose the record type, specify the External ID Field (default: externalid) and its Value, then provide the fields:
{
"companyname": "Acme Corp",
"email": "[email protected]",
"subsidiary": { "id": "1" }
}If a record with the given external ID exists, it will be updated. Otherwise, a new record is created. This is ideal for syncing data from external systems.
Common Workflow Examples
These are popular workflows built with this connector. For implementation help, contact SolutionLab.
NetSuite → Google Sheets Daily Sync Schedule a daily SuiteQL query (e.g., open invoices) and write results to a Google Sheet for reporting.
Shopify Order → NetSuite Sales Order Use a Shopify trigger to capture new orders, then create NetSuite sales orders with customer lookup and item mapping.
Daily Invoice Aging Report via Email Run "Open Invoices" SuiteQL template on a schedule, format as HTML table, and send via email to your finance team.
CRM Contact Sync Use the polling trigger to detect new NetSuite customers, then sync to HubSpot, Salesforce, or your CRM of choice.
Inventory Alerts Poll inventory levels with SuiteQL and send Slack alerts when stock falls below threshold.
Professional Services & Support
This node is developed and maintained by SolutionLab, a team that specializes in NetSuite integrations, SuiteScript development, and n8n workflow automation.
Free vs Professional
| Capability | Free (this connector) | Professional (SolutionLab) | |---|---|---| | Record CRUD + Upsert | Included | — | | SuiteQL queries with templates | Included | — | | Restlet invocation (all HTTP methods) | Included | — | | Polling triggers | Included | — | | Real-time webhook triggers | — | Custom SuiteScript User Event Script deployment | | Bulk create/update/delete | — | Custom Restlet scripts for batch operations | | Line item manipulation | — | Complex transaction workflows (invoices, sales orders with lines) | | Multi-subsidiary configuration | — | NetSuite role, permission, and subsidiary setup | | Custom field mapping & data transformation | — | Integration consulting and architecture |
What We Build
- NetSuite ↔ E-commerce sync - Real-time inventory, order, and customer sync with Shopify, WooCommerce, and custom platforms
- Automated invoicing & payment processing - End-to-end order-to-cash automation with GL journal entries
- Multi-system ERP integration - NetSuite as the hub connecting CRM, warehouse, and logistics systems
- Custom SuiteScript Restlets - Purpose-built API endpoints for complex business logic that REST API can't handle
- Real-time NetSuite triggers - User Event Scripts that push events to n8n webhooks in sub-second latency
Contact
Book a consultation | [email protected] | LinkedIn
How Authentication Works
This section details the OAuth 2.0 Client Credentials with Certificate flow as implemented in this node.
JWT Construction
The node builds a JSON Web Token with the following structure:
Header:
{
"alg": "PS256",
"typ": "JWT",
"kid": "<certificateId>"
}Payload:
{
"iss": "<consumerKey>",
"scope": ["restlets", "rest_webservices"],
"iat": 1710000000,
"exp": 1710003600,
"aud": "https://<accountId>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token"
}| Claim | Description |
|-------|-------------|
| iss | The Consumer Key from the Integration Record |
| scope | Fixed scopes: restlets and rest_webservices |
| iat | Issued-at timestamp (current Unix time in seconds) |
| exp | Expiration timestamp (issued-at + 3600 seconds) |
| aud | The token endpoint URL (also the audience) |
| kid | The Certificate ID from the M2M Setup page |
JWT Signing
The JWT is signed using PS256 (RSASSA-PSS with SHA-256):
- Algorithm:
crypto.sign('sha256', signingInput, { key, padding: RSA_PKCS1_PSS_PADDING, saltLength: RSA_PSS_SALTLEN_DIGEST }) - The signing input is
base64url(header).base64url(payload) - The signature is base64url-encoded and appended:
header.payload.signature
Token Exchange
The signed JWT is exchanged for an access token via HTTP POST:
POST https://<accountId>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<signedJwt>The token exchange uses Node.js native https.request instead of n8n's HTTP helper to avoid URL encoding issues with the client_assertion parameter.
Token Caching
Cache Key: {accountId}:{consumerKey}
Storage: Module-level Map (persists across workflow executions within the same n8n process)
Refresh: 300 seconds (5 minutes) before token expiryWhen a cached token is still valid (more than 5 minutes until expiry), it is reused without making a new token exchange request. This minimizes API calls to the NetSuite token endpoint.
Authentication Hooks
Two hooks ensure the Bearer token is attached to every outgoing request:
- Pre-Authentication - Runs before each
httpRequestWithAuthenticationcall, exchanges credentials for a token, and stores it for the authenticate hook - Authenticate - Injects the
Authorization: Bearer <token>header into the request. Falls back to a direct token exchange if pre-authentication was skipped (e.g., during credential testing)
Troubleshooting
Error Reference
| Error Message | Cause | Solution |
|---------------|-------|----------|
| NetSuite credential error: Account ID is empty | Account ID field not filled in | Enter your Account ID from Setup > Company > Company Information |
| NetSuite credential error: Consumer Key is empty | Consumer Key field not filled in | Enter the Consumer Key from the Integration Record |
| NetSuite credential error: Certificate ID is empty | Certificate ID field not filled in | Enter the Certificate ID from the M2M Setup page |
| NetSuite credential error: Certificate Private Key is empty | Private Key field not filled in | Paste the full contents of your private.pem file |
| JWT signing failed (PS256) | Invalid PEM format or unsupported key type | Verify the key is RSA. Run openssl rsa -check -in private.pem to validate. Ensure the full PEM content including BEGIN/END lines is pasted. |
| Token exchange failed (HTTP 400) | Mismatched credentials or key pair | Verify the Consumer Key matches the Integration Record. Verify the Certificate ID from M2M Setup. Ensure the private key corresponds to the uploaded public certificate. |
| Token exchange failed (HTTP 401) | M2M grant not enabled or mapping inactive | Verify the Integration Record has "Client Credentials (M2M) Grant" enabled. Verify the M2M Setup mapping is active. |
| Token exchange network error | DNS resolution failure or network issue | Check the Account ID format. Verify network connectivity to *.suitetalk.api.netsuite.com. |
| Token response is not valid JSON | Unexpected response from token endpoint | The NetSuite token endpoint may be temporarily unavailable. Retry after a few minutes. |
| Token response missing access_token | Token endpoint returned an unexpected payload | Verify the M2M Setup is complete and active. Check that the Integration Record is not disabled. |
| HTTP 403 on API calls | Insufficient role permissions | Add the required permissions to the role mapped in M2M Setup (see Step 4 in Prerequisites). |
Debugging Steps
Start with the credential test - Click "Test" in the n8n credential form. The error message indicates exactly which step failed: input validation, JWT signing, token exchange, or the API call itself.
Verify the key pair matches - The private key pasted into n8n must correspond to the public certificate uploaded to NetSuite. Both must be generated from the same OpenSSL key pair.
Check the M2M Setup status - Navigate to Setup > Integration > OAuth 2.0 Client Credentials (M2M) Setup in NetSuite and confirm your mapping shows as active.
Sandbox accounts - If using a sandbox, your Account ID includes
_SB1(or similar suffix). The node normalizes this automatically - no manual formatting required.
What's New in v0.3.0
- Polling Triggers — Monitor NetSuite records for creation/modification with the new NetSuite Trigger node
- 6 SuiteQL Templates — Built-in queries for customers, sales orders, invoices, inventory, employees, and vendor bills
- Improved Error Messages — Contextual help for common HTTP errors (400, 401, 403, 404) with troubleshooting guidance
- Input Validation — Record ID and External ID checks prevent cryptic API errors
- Pagination Safety — Maximum iteration limits prevent runaway loops
- AI Agent Support — Use the NetSuite node as a tool in n8n AI Agent workflows
No breaking changes from v0.2.x. See CHANGELOG.md for full details.
Contributing
# Clone the repository
git clone https://github.com/avishaiasaf/n8n-netsuite-node-v2.git
cd n8n-nodes-netsuite-v2
# Install dependencies
npm install
# Build
npm run build
# Lint
npm run lintSubmit issues and pull requests via GitHub.
License
MIT
