Integration Strategy
Plan your integration architecture: point-to-point vs. middleware, iPaaS options, patterns, and error handling strategies.
Integration Architecture Overview
Every NetSuite implementation involves integrations—whether connecting to e-commerce platforms, CRM systems, banks, or third-party applications. A well-planned integration strategy prevents data silos, reduces manual work, and ensures system reliability.
INTEGRATION ARCHITECTURE PATTERNS
═══════════════════════════════════════════════════════════════
POINT-TO-POINT
───────────────────────────────────────────────────────────────
┌─────────┐ ┌─────────┐
│ System │────────►│NetSuite │
│ A │◄────────│ │
└─────────┘ └─────────┘
│ │
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ System │────────►│ System │
│ B │ │ C │
└─────────┘ └─────────┘
Pros: Simple, direct, lower initial cost
Cons: Spaghetti architecture, hard to maintain at scale
HUB AND SPOKE (iPaaS/Middleware)
───────────────────────────────────────────────────────────────
┌─────────┐ ┌─────────┐ ┌─────────┐
│ System │ │ System │ │ System │
│ A │ │ B │ │ C │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────────────┼──────────────┘
│
▼
┌───────────────┐
│ iPaaS/ │
│ Middleware │
│ (Celigo, │
│ Boomi, etc.)│
└───────┬───────┘
│
▼
┌───────────────┐
│ NetSuite │
└───────────────┘
Pros: Centralized monitoring, reusable connectors, scalable
Cons: Higher cost, additional system to manage
Integration Method Comparison
| Method | Use Case | Volume | Complexity |
|---|---|---|---|
| CSV Import | Batch data loads, migrations | Low-Medium | Low |
| SuiteTalk SOAP | Legacy systems, complex operations | Medium-High | High |
| SuiteTalk REST | Modern integrations, mobile apps | Medium-High | Medium |
| RESTlets | Custom endpoints, complex logic | Any | Medium-High |
| iPaaS (Celigo, etc.) | Multiple systems, complex flows | Any | Medium |
| SuiteAnalytics Connect | BI tools, reporting extracts | Read-only | Low-Medium |
Integration Patterns
Real-Time vs. Batch
| Pattern | When to Use | Examples |
|---|---|---|
| Real-Time (Synchronous) | Immediate response required | Price checks, inventory availability |
| Near Real-Time (Async) | Quick updates, no immediate response | Order creation, customer updates |
| Batch (Scheduled) | High volume, non-time-sensitive | Daily inventory sync, GL exports |
| Event-Driven | Triggered by specific actions | Order shipped → update e-commerce |
Data Flow Patterns
COMMON DATA FLOW PATTERNS
═══════════════════════════════════════════════════════════════
MASTER DATA SYNC (Bidirectional)
───────────────────────────────────────────────────────────────
E-Commerce ◄────► Customers ◄────► NetSuite
Products
Challenge: Conflict resolution (which system wins?)
Solution: Define system of record per entity type
ONE-WAY PUSH
───────────────────────────────────────────────────────────────
E-Commerce ─────► Orders ─────► NetSuite
Simple, clear ownership, no conflict resolution needed
PULL/POLLING
───────────────────────────────────────────────────────────────
NetSuite ◄───── Polling ◄───── External System
(status) (every 5 min)
External system requests updates on schedule
EVENT-DRIVEN (Webhook)
───────────────────────────────────────────────────────────────
NetSuite ─────► Webhook ─────► External System
(on save) (immediate)
NetSuite pushes immediately when event occurs
Authentication Methods
| Method | Description | Recommendation |
|---|---|---|
| Token-Based Authentication (TBA) | Consumer/Token key pairs | Preferred for server-to-server |
| OAuth 2.0 | Standard OAuth flow | Preferred for user-facing apps |
| User Credentials | Email/Password | Deprecated—avoid |
Error Handling Strategy
ERROR HANDLING FRAMEWORK
═══════════════════════════════════════════════════════════════
ERROR CATEGORIES
───────────────────────────────────────────────────────────────
1. TRANSIENT ERRORS (retry)
- Network timeouts
- Rate limit exceeded
- Temporary service unavailability
→ Strategy: Exponential backoff retry
2. DATA ERRORS (fix and retry)
- Validation failures
- Missing required fields
- Invalid references
→ Strategy: Log, alert, queue for review
3. SYSTEM ERRORS (escalate)
- Authentication failures
- Permission denied
- API changes
→ Strategy: Alert immediately, stop processing
RETRY PATTERN
───────────────────────────────────────────────────────────────
Attempt 1: Immediate
Attempt 2: Wait 1 second
Attempt 3: Wait 5 seconds
Attempt 4: Wait 30 seconds
Attempt 5: Wait 2 minutes
→ After 5 failures: Move to dead letter queue
MONITORING REQUIREMENTS
───────────────────────────────────────────────────────────────
• Success/failure counts by integration
• Average processing time
• Queue depth (pending records)
• Error rate trending
• Alerts for threshold breaches
iPaaS Comparison
| Platform | NetSuite Focus | Strengths |
|---|---|---|
| Celigo | High (NetSuite partner) | Pre-built connectors, integrator.io |
| Dell Boomi | Medium | Enterprise scale, broad connector library |
| Workato | Medium | User-friendly, strong automation |
| MuleSoft | Medium | Enterprise APIs, Salesforce integration |
| Tray.io | Low-Medium | Flexible workflows, developer-friendly |
Start simple. Point-to-point integrations are fine for 2-3 connections. Only move to iPaaS when you have 4+ integrations or need advanced features like data transformation, error handling, and monitoring. The iPaaS monthly cost often exceeds the development savings unless you truly need the capability.
Integration Planning Checklist
SuiteTalk SOAP
SOAP web services for NetSuite integration: authentication, operations, and best practices.
SuiteTalk SOAP Overview
SuiteTalk SOAP is NetSuite's original web services API. While the REST API is now preferred for new integrations, SOAP remains important for legacy systems and complex operations not yet available in REST.
| Feature | SOAP | REST |
|---|---|---|
| Protocol | XML-based SOAP | JSON over HTTP |
| Maturity | 20+ years, fully featured | Newer, growing coverage |
| Learning Curve | Steeper (WSDL, namespaces) | Lower (standard REST) |
| Custom Records | Full support | Full support |
| Saved Searches | Full support | Via SuiteQL |
| Asynchronous | Yes (native) | Limited |
WSDL and Endpoints
SUITETALK SOAP ENDPOINTS
═══════════════════════════════════════════════════════════════
WSDL URL:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/wsdl/v2024_2_0/netsuite.wsdl
ENDPOINT URL:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/NetSuitePort_2024_2
ACCOUNT ID FORMAT:
───────────────────────────────────────────────────────────────
Production: TSTDRV1234567
Sandbox: TSTDRV1234567_SB1
Development: TSTDRV1234567_DEV
FINDING YOUR ACCOUNT ID:
Setup → Company → Company Information → Account ID
Authentication Setup
Token-Based Authentication (TBA)
TBA SETUP PROCESS
═══════════════════════════════════════════════════════════════
1. CREATE INTEGRATION RECORD
Setup → Integration → Manage Integrations → New
├── Name: "My Integration"
├── State: Enabled
├── Token-Based Authentication: Checked
└── → Save → Note Consumer Key & Secret
2. CREATE ACCESS TOKEN
Setup → Users/Roles → Access Tokens → New
├── Application: "My Integration"
├── User: Integration user
├── Role: Integration role
└── → Save → Note Token ID & Secret
SOAP HEADER WITH TBA:
───────────────────────────────────────────────────────────────
<tokenPassport>
<account>TSTDRV1234567</account>
<consumerKey>consumer_key_here</consumerKey>
<token>token_id_here</token>
<nonce>random_string</nonce>
<timestamp>unix_timestamp</timestamp>
<signature algorithm="HMAC-SHA256">signature</signature>
</tokenPassport>
Common Operations
| Operation | Description | Use Case |
|---|---|---|
| get | Retrieve single record by ID | Fetch customer details |
| getList | Retrieve multiple records by IDs | Batch fetch orders |
| add | Create new record | Create sales order |
| update | Modify existing record | Update customer address |
| upsert | Add or update based on external ID | Sync from external system |
| delete | Remove record | Delete draft order |
| search | Query records with criteria | Find open invoices |
| asyncAddList | Bulk add asynchronously | Import 10,000 records |
Search Operations
SOAP SEARCH EXAMPLE
═══════════════════════════════════════════════════════════════
<search>
<searchRecord xsi:type="TransactionSearchBasic">
<type operator="anyOf">
<searchValue>_salesOrder</searchValue>
</type>
<status operator="anyOf">
<searchValue>_salesOrderPendingFulfillment</searchValue>
</status>
<tranDate operator="within">
<searchValue>2025-01-01T00:00:00</searchValue>
<searchValue2>2025-12-31T23:59:59</searchValue2>
</tranDate>
</searchRecord>
</search>
SEARCH TYPES:
───────────────────────────────────────────────────────────────
Basic: Simple criteria on main record
Joined: Include related record criteria
Advanced: Use saved search definition
Governance and Limits
- Concurrent requests: Based on SuiteCloud license tier
- Records per request: 200 for add/update, 1000 for search results
- Request timeout: 15 minutes
- Rate limiting: Requests may be throttled under load
Best Practices
- Use external IDs: Enable upsert operations and avoid duplicate lookups
- Batch operations: Use addList/updateList instead of individual calls
- Async for large volumes: Use asyncAddList for bulk operations
- Handle pagination: Search results may require multiple pages
- Cache WSDL locally: Avoid re-downloading on every request
- Implement retry logic: Handle transient failures gracefully
SOAP is verbose but powerful. For new integrations, prefer REST unless you need features only available in SOAP (like certain async operations or complex saved search execution). When working with legacy SOAP integrations, prioritize moving to TBA authentication if still using user credentials—it's more secure and doesn't count against concurrent user limits.
SuiteTalk REST
Modern REST API for NetSuite: record operations, SuiteQL, OAuth 2.0, and integration patterns.
REST API Overview
SuiteTalk REST provides a modern, JSON-based API for NetSuite integration. It follows REST conventions and is easier to use than SOAP for most common operations.
API Endpoints
REST API BASE URLS
═══════════════════════════════════════════════════════════════
RECORD API:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/record/v1
QUERY API (SuiteQL):
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/query/v1
METADATA:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/record/v1/metadata-catalog
EXAMPLES:
───────────────────────────────────────────────────────────────
GET customer: GET /customer/123
Create customer: POST /customer
Update customer: PATCH /customer/123
Delete customer: DELETE /customer/123
List customers: GET /customer
Authentication
OAuth 2.0 Setup
OAUTH 2.0 FLOW
═══════════════════════════════════════════════════════════════
1. AUTHORIZATION REQUEST
───────────────────────────────────────────────────────────────
GET https://<ACCOUNT_ID>.app.netsuite.com/app/login/oauth2/authorize.nl
?response_type=code
&client_id=<CLIENT_ID>
&redirect_uri=<REDIRECT_URI>
&scope=rest_webservices
&state=<STATE>
2. TOKEN EXCHANGE
───────────────────────────────────────────────────────────────
POST https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=<AUTH_CODE>
&redirect_uri=<REDIRECT_URI>
&client_id=<CLIENT_ID>
&client_secret=<CLIENT_SECRET>
3. API REQUEST WITH TOKEN
───────────────────────────────────────────────────────────────
GET /services/rest/record/v1/customer/123
Authorization: Bearer <ACCESS_TOKEN>
Token-Based Authentication
TBA HEADER FORMAT
═══════════════════════════════════════════════════════════════
Authorization: OAuth
realm="ACCOUNT_ID",
oauth_consumer_key="consumer_key",
oauth_token="token_id",
oauth_signature_method="HMAC-SHA256",
oauth_timestamp="unix_timestamp",
oauth_nonce="random_string",
oauth_version="1.0",
oauth_signature="base64_encoded_signature"
Record Operations
REST RECORD OPERATIONS
═══════════════════════════════════════════════════════════════
CREATE CUSTOMER (POST)
───────────────────────────────────────────────────────────────
POST /services/rest/record/v1/customer
Content-Type: application/json
{
"companyName": "Acme Corporation",
"email": "contact@acme.com",
"subsidiary": {"id": "1"},
"custentity_external_id": "ACME-001"
}
Response: 201 Created
{
"id": "12345",
"links": [...]
}
UPDATE CUSTOMER (PATCH)
───────────────────────────────────────────────────────────────
PATCH /services/rest/record/v1/customer/12345
Content-Type: application/json
{
"phone": "555-1234",
"custentity_credit_limit": 50000
}
Response: 204 No Content
GET WITH SUBLISTS
───────────────────────────────────────────────────────────────
GET /services/rest/record/v1/salesOrder/67890?expandSubResources=true
Returns order with line items, addresses, etc.
SuiteQL Queries
SUITEQL VIA REST API
═══════════════════════════════════════════════════════════════
POST /services/rest/query/v1/suiteql
Content-Type: application/json
Prefer: transient
{
"q": "SELECT id, companyname, email
FROM customer
WHERE isinactive = 'F'
AND datecreated > '2025-01-01'
ORDER BY companyname"
}
RESPONSE:
{
"links": [...],
"count": 150,
"hasMore": true,
"offset": 0,
"totalResults": 1523,
"items": [
{"id": "123", "companyname": "Acme Corp", "email": "..."},
{"id": "124", "companyname": "Beta Inc", "email": "..."},
...
]
}
PAGINATION:
───────────────────────────────────────────────────────────────
Add to query: FETCH NEXT 1000 ROWS ONLY
Add header: Prefer: respond-async
Next page: Follow "next" link in response
Sublist Operations
WORKING WITH SUBLISTS
═══════════════════════════════════════════════════════════════
ADD LINE TO SALES ORDER
───────────────────────────────────────────────────────────────
POST /services/rest/record/v1/salesOrder/67890/item
Content-Type: application/json
{
"item": {"id": "100"},
"quantity": 5,
"rate": 99.99
}
UPDATE LINE
───────────────────────────────────────────────────────────────
PATCH /services/rest/record/v1/salesOrder/67890/item/1
Content-Type: application/json
{
"quantity": 10
}
DELETE LINE
───────────────────────────────────────────────────────────────
DELETE /services/rest/record/v1/salesOrder/67890/item/1
GET ALL LINES
───────────────────────────────────────────────────────────────
GET /services/rest/record/v1/salesOrder/67890/item
Error Handling
REST API ERROR RESPONSES
═══════════════════════════════════════════════════════════════
400 BAD REQUEST
───────────────────────────────────────────────────────────────
{
"type": "https://www.netsuite.com/problems/validation",
"title": "Invalid field value",
"status": 400,
"o:errorDetails": [
{
"detail": "Invalid reference key '999' for field 'subsidiary'",
"o:errorCode": "INVALID_KEY_OR_REF"
}
]
}
429 TOO MANY REQUESTS
───────────────────────────────────────────────────────────────
{
"type": "https://www.netsuite.com/problems/rate-limiting",
"title": "Rate limit exceeded",
"status": 429,
"o:errorDetails": [
{
"detail": "Request rate limit exceeded. Retry after 60 seconds."
}
]
}
- Use SuiteQL for queries: More flexible than record filtering
- Expand sublists selectively: Only request what you need
- Handle pagination: Use offset/limit for large result sets
- Check for async: Large operations may return 202 Accepted
- Use external IDs: Enable idempotent operations
REST is the future of NetSuite integrations. Start new projects with REST unless you specifically need SOAP features. The REST API's JSON format is easier to debug, and OAuth 2.0 is standard across modern applications. SuiteQL via REST gives you SQL-like flexibility that's often easier than building complex search criteria.
RESTlets
Build custom REST endpoints in NetSuite for complex integration logic and specialized operations.
RESTlet Overview
RESTlets are custom SuiteScript endpoints that respond to HTTP requests. They enable you to build custom APIs within NetSuite, perfect for complex business logic that standard APIs don't cover.
| Use RESTlets When | Use Standard API When |
|---|---|
| Complex business logic required | Simple CRUD operations |
| Multiple records in single transaction | Single record operations |
| Custom data transformation | Standard field mapping |
| Aggregate data from multiple sources | Single record type queries |
| Custom authentication/validation | Standard authentication |
RESTlet Structure
RESTLET SCRIPT TEMPLATE (SuiteScript 2.1)
═══════════════════════════════════════════════════════════════
/**
* @NApiVersion 2.1
* @NScriptType Restlet
*/
define(['N/record', 'N/search', 'N/log'], (record, search, log) => {
/**
* GET request handler
* @param {Object} requestParams - URL parameters
* @returns {Object} Response data
*/
const get = (requestParams) => {
try {
const customerId = requestParams.customerId;
if (!customerId) {
return { error: 'customerId is required' };
}
// Load customer record
const customer = record.load({
type: record.Type.CUSTOMER,
id: customerId
});
return {
id: customer.id,
name: customer.getValue('companyname'),
email: customer.getValue('email'),
balance: customer.getValue('balance')
};
} catch (e) {
log.error('GET Error', e.message);
return { error: e.message };
}
};
/**
* POST request handler
* @param {Object} requestBody - Request body (JSON parsed)
* @returns {Object} Response data
*/
const post = (requestBody) => {
try {
const { customerName, email, subsidiary } = requestBody;
// Validation
if (!customerName) {
return { error: 'customerName is required' };
}
// Create customer
const customer = record.create({
type: record.Type.CUSTOMER
});
customer.setValue('companyname', customerName);
customer.setValue('email', email);
customer.setValue('subsidiary', subsidiary || 1);
const customerId = customer.save();
return {
success: true,
customerId: customerId
};
} catch (e) {
log.error('POST Error', e.message);
return { error: e.message };
}
};
/**
* PUT request handler
*/
const put = (requestBody) => {
// Update logic
};
/**
* DELETE request handler
*/
const doDelete = (requestParams) => {
// Delete logic
};
return { get, post, put, delete: doDelete };
});
Deployment
RESTLET DEPLOYMENT
═══════════════════════════════════════════════════════════════
1. CREATE SCRIPT RECORD
Customization → Scripting → Scripts → New
├── Type: RESTlet
├── Script File: restlet_customer_api.js
└── Functions: get, post, put, delete
2. CREATE SCRIPT DEPLOYMENT
├── Status: Released
├── Log Level: Debug (for testing)
├── Execute As Role: Integration role
├── Audience: Roles that should access
└── URL: Generated automatically
RESTLET URL FORMAT:
───────────────────────────────────────────────────────────────
https://<ACCOUNT_ID>.restlets.api.netsuite.com/app/site/hosting/restlet.nl
?script=<SCRIPT_ID>
&deploy=<DEPLOY_ID>
&customerId=123
Or use external URL (if configured)
Authentication
RESTLET AUTHENTICATION
═══════════════════════════════════════════════════════════════
OPTION 1: TOKEN-BASED AUTHENTICATION (TBA)
───────────────────────────────────────────────────────────────
Same OAuth 1.0 header as SuiteTalk REST:
Authorization: OAuth
realm="ACCOUNT_ID",
oauth_consumer_key="...",
oauth_token="...",
oauth_signature_method="HMAC-SHA256",
oauth_timestamp="...",
oauth_nonce="...",
oauth_version="1.0",
oauth_signature="..."
OPTION 2: NLAUTH (Not Recommended)
───────────────────────────────────────────────────────────────
Authorization: NLAuth
nlauth_account=ACCOUNT_ID,
nlauth_email=user@domain.com,
nlauth_signature=password,
nlauth_role=3
Note: NLAuth uses user credentials—prefer TBA for security
Advanced Patterns
RESTLET DESIGN PATTERNS
═══════════════════════════════════════════════════════════════
PATTERN 1: COMPOSITE OPERATIONS
───────────────────────────────────────────────────────────────
// Single API call creates order with items and customer
const post = (requestBody) => {
const { customer, orderLines, shipAddress } = requestBody;
// Create or find customer
let customerId = findCustomerByEmail(customer.email);
if (!customerId) {
customerId = createCustomer(customer);
}
// Create sales order
const order = record.create({ type: 'salesorder' });
order.setValue('entity', customerId);
// Add lines
orderLines.forEach((line, index) => {
order.setSublistValue({
sublistId: 'item',
fieldId: 'item',
line: index,
value: line.itemId
});
order.setSublistValue({
sublistId: 'item',
fieldId: 'quantity',
line: index,
value: line.quantity
});
});
const orderId = order.save();
return { success: true, orderId };
};
PATTERN 2: SEARCH AGGREGATION
───────────────────────────────────────────────────────────────
// Combine data from multiple searches into single response
const get = (requestParams) => {
const customerId = requestParams.customerId;
return {
customer: getCustomerDetails(customerId),
openOrders: getOpenOrders(customerId),
recentInvoices: getRecentInvoices(customerId),
creditLimit: getCreditInfo(customerId)
};
};
PATTERN 3: WEBHOOK RECEIVER
───────────────────────────────────────────────────────────────
// Receive webhooks from external systems
const post = (requestBody) => {
log.audit('Webhook Received', JSON.stringify(requestBody));
// Validate webhook signature
if (!validateSignature(requestBody)) {
return { error: 'Invalid signature', status: 401 };
}
// Queue for processing (avoid timeout)
const queueRecord = record.create({ type: 'customrecord_webhook_queue' });
queueRecord.setValue('custrecord_payload', JSON.stringify(requestBody));
queueRecord.save();
return { success: true, message: 'Queued for processing' };
};
Governance Considerations
- Governance units: RESTlets have standard SuiteScript limits (10,000 units)
- Timeout: 5 minutes for synchronous requests
- Concurrency: Based on account's SuiteCloud license
- Response size: 10MB maximum
For long-running operations, queue work and use scheduled scripts to process.
RESTlets are your escape hatch when standard APIs don't fit. Common use cases: e-commerce order import with custom logic, inventory availability checks across locations, composite operations that would require multiple API calls. Always add logging and error handling—debugging RESTlets in production without good logs is painful.
CSV Import
Batch data loading via CSV: templates, field mapping, scheduling, and best practices.
CSV Import Overview
CSV Import is NetSuite's built-in tool for batch data loading. It's often the simplest integration method for periodic data transfers that don't require real-time processing.
Import Types
| Import Type | Description | Common Use |
|---|---|---|
| Add | Create new records only | Initial data load |
| Update | Modify existing records | Mass updates |
| Add/Update | Upsert based on key field | Ongoing sync |
Import Process Flow
CSV Formatting Rules
CSV FORMATTING REQUIREMENTS
═══════════════════════════════════════════════════════════════
FILE FORMAT
───────────────────────────────────────────────────────────────
• Encoding: UTF-8 (preferred) or Windows-1252
• Delimiter: Comma (,)
• Text qualifier: Double quotes (")
• Line ending: CRLF or LF
• First row: Column headers (required)
FIELD FORMATS
───────────────────────────────────────────────────────────────
Dates: MM/DD/YYYY or YYYY-MM-DD
Booleans: T/F, True/False, Yes/No, 1/0
Numbers: No thousands separator, period decimal
Currency: No currency symbol, no thousands separator
Multi-select: Values separated by pipe (|)
References: Internal ID or External ID
EXAMPLE CSV
───────────────────────────────────────────────────────────────
External ID,Company Name,Email,Subsidiary,Is Inactive
CUST-001,Acme Corporation,sales@acme.com,1,F
CUST-002,Beta Industries,info@beta.com,1,F
CUST-003,"Gamma, LLC",contact@gamma.com,2,F
Note: "Gamma, LLC" quoted because contains comma
Field Mapping
FIELD MAPPING STRATEGIES
═══════════════════════════════════════════════════════════════
REFERENCE FIELDS
───────────────────────────────────────────────────────────────
For fields like Customer, Item, Class, etc.:
Option 1: Internal ID
Column: Customer
Value: 12345
Option 2: Name/Display Value
Column: Customer
Value: Acme Corporation
Option 3: External ID (recommended)
Column: Customer : External ID
Value: CUST-001
SUBLIST IMPORT (Two-File Method)
───────────────────────────────────────────────────────────────
File 1: Header (Sales Order)
External ID,Customer,Order Date,Subsidiary
SO-001,CUST-001,12/01/2025,1
SO-002,CUST-002,12/02/2025,1
File 2: Lines (Sales Order Items)
External ID,Item,Quantity,Rate
SO-001,ITEM-001,10,99.99
SO-001,ITEM-002,5,149.99
SO-002,ITEM-001,20,99.99
Import header first, then lines (linked by External ID)
SINGLE-FILE SUBLIST IMPORT
───────────────────────────────────────────────────────────────
Denormalized format (repeat header data):
External ID,Customer,Item,Quantity,Rate
SO-001,CUST-001,ITEM-001,10,99.99
SO-001,CUST-001,ITEM-002,5,149.99
SO-002,CUST-002,ITEM-001,20,99.99
Saved Import Maps
Save field mappings for repeated imports:
| Setting | Description |
|---|---|
| Import Map Name | Descriptive name for this mapping |
| Record Type | Customer, Item, Sales Order, etc. |
| Field Mappings | CSV column → NetSuite field |
| Import Options | Add, Update, or Add/Update |
| Data Handling | On error: skip record or abort |
Scheduled Imports
AUTOMATED CSV IMPORT
═══════════════════════════════════════════════════════════════
OPTION 1: SCHEDULED IMPORT (Built-in)
───────────────────────────────────────────────────────────────
1. Save import map
2. Go to: Setup → Import/Export → Scheduled CSV Imports
3. Configure:
- Saved import to use
- File source: File Cabinet folder
- Schedule: Daily, Weekly, etc.
- Email notification on completion
OPTION 2: SUITESCRIPT + N/TASK MODULE
───────────────────────────────────────────────────────────────
const task = require('N/task');
const importTask = task.create({
taskType: task.TaskType.CSV_IMPORT,
mappingId: 'custimport_customer_sync',
importFile: 'SuiteScripts/imports/customers.csv'
});
const taskId = importTask.submit();
OPTION 3: EXTERNAL AUTOMATION
───────────────────────────────────────────────────────────────
1. External system uploads CSV to File Cabinet via REST/SOAP
2. Scheduled script triggers import
3. Results logged/emailed
Error Handling
- Invalid reference: Referenced record doesn't exist—check ID or name
- Required field missing: Mandatory field not mapped or empty
- Duplicate key: External ID already exists (for Add imports)
- Invalid date format: Use MM/DD/YYYY or configure format
- Permission denied: Import user lacks record access
- Always preview: Review first 10 rows before full import
- Use external IDs: Enable reliable updates without internal IDs
- Test in sandbox: Validate import maps before production
- Limit batch size: 25,000 records max per import recommended
- Log imports: Keep import files and results for audit
CSV Import is underrated. For daily/weekly batch updates from systems that can export CSV (most can), it's often simpler than building API integrations. Use scheduled imports with File Cabinet as the drop zone—external systems FTP files there, NetSuite picks them up automatically. Just ensure good monitoring so you catch failures.
NetSuite AI Connector (MCP)
AI integration capabilities using the Model Context Protocol (MCP) standard.
NetSuite now supports the Model Context Protocol (MCP), enabling AI systems to interact with NetSuite data and operations through standardized interfaces.
MCP Overview
The Model Context Protocol (MCP) is an open standard for connecting AI systems to external data sources and tools. NetSuite's AI Connector implements MCP, allowing AI assistants and agents to query data, create records, and execute business processes.
MCP ARCHITECTURE
═══════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────┐
│ AI APPLICATION │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ AI Model (Claude, GPT, etc.) ││
│ │ "What were last month's top 10 customers by revenue?" ││
│ └───────────────────────────┬─────────────────────────────┘│
└──────────────────────────────┼──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ MCP CLIENT │
│ Translates natural language to MCP tool calls │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ NETSUITE MCP SERVER │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Query │ │ Record │ │ Workflow │ │
│ │ Tools │ │ Tools │ │ Tools │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ NETSUITE │
│ Records, Transactions, Searches, Workflows │
└─────────────────────────────────────────────────────────────┘
Available MCP Tools
| Tool Category | Capabilities | Example Use |
|---|---|---|
| Query Tools | Run saved searches, SuiteQL queries | "Show me overdue invoices" |
| Record Tools | Create, read, update records | "Create a customer for Acme Corp" |
| Workflow Tools | Trigger workflows, check status | "Approve pending purchase orders" |
| Report Tools | Generate financial reports | "Generate income statement for Q4" |
| Analytics Tools | Access dashboard KPIs | "What's our current DSO?" |
Prerequisites
- NetSuite account: Administrator-level access to configure features, integrations, and roles
- Paid AI accounts: ChatGPT Plus/Enterprise or Claude Pro/Enterprise
- Integration record: Must be created and configured in NetSuite
- Enabled features in NetSuite: Server SuiteScript, OAuth 2.0, REST Web Services
NetSuite Configuration
STEP 1: ENABLE FEATURES
═══════════════════════════════════════════════════════════════
Path: Setup → Company → Enable Features → SuiteCloud subtab
Enable the following features:
✓ Server SuiteScript
✓ OAuth 2.0
✓ REST Web Services
STEP 2: INSTALL SUITEAPP
═══════════════════════════════════════════════════════════════
Location: SuiteApp section (or Customization → SuiteBundler → Search & Install)
Action: Search for "MCP" and install "MCP Standard Tools SuiteApp"
STEP 3: CONFIGURE ROLE
═══════════════════════════════════════════════════════════════
Path: Setup → Users/Roles → Manage Roles
Approach: Clone an existing role (e.g., AP Clerk) or create a new
least-privilege role
Required Permissions:
├── MCP server connection: Full
└── Login using OAuth 2.0 access token: Full
⚠️ IMPORTANT: Administrator role CANNOT be used for AI connections
Integration Record Setup
CREATE INTEGRATION RECORD
═══════════════════════════════════════════════════════════════
Path: Setup → Integrations → Manage Integrations → New
Fields to Configure:
├── Name: "AI Connector – ChatGPT" (or "AI Connector – Claude")
├── State: Enabled
├── Authentication: OAuth 2.0
└── Redirect URI: Callback URL from AI client
Result: NetSuite generates Client ID and Client Secret
(Store these securely - Client Secret shown only once!)
OAuth 2.0 Authorization Flow
| Step | Action | Details |
|---|---|---|
| 1. Authorization Request | AI client redirects user | User logs into NetSuite and grants consent |
| 2. Authorization Code | NetSuite returns code | Code sent to Redirect URI |
| 3. Token Exchange | AI client requests tokens | Sends code, Client ID, Client Secret to token endpoint |
| 4. Tokens Issued | NetSuite returns tokens | Access Token (API calls), Refresh Token (renewal) |
OAUTH 2.0 ENDPOINTS
═══════════════════════════════════════════════════════════════
Replace <ACCOUNT_ID> with your NetSuite account ID
Authorization:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/authorize
Token:
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token
Revoke (to invalidate tokens):
https://<ACCOUNT_ID>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/revoke
Connecting ChatGPT to NetSuite
CHATGPT CONNECTOR SETUP
═══════════════════════════════════════════════════════════════
1. OPEN SETTINGS
Path: Settings → Apps and Connectors
2. ENABLE DEVELOPER MODE
Navigate to Advanced Settings and enable Developer Mode if required
3. CREATE CONNECTOR
Action: Create Connector
Name: "NetSuite Connector"
4. ENTER DETAILS
Account ID: Found at Setup → Company → Company Information
MCP Server URL: Use format from NetSuite AI Connector docs,
inserting your Account ID
5. AUTHENTICATE
Method: OAuth 2.0
Role: Select your custom MCP role (NOT Administrator)
6. TEST CONNECTION
Example prompt: "Show me the most recently created vendor"
Validate results directly in NetSuite
Connecting Claude to NetSuite
CLAUDE CONNECTOR SETUP
═══════════════════════════════════════════════════════════════
1. OPEN SETTINGS
Path: Settings → Connectors
2. CHOOSE CONNECTOR TYPE
Option A: Web → NetSuite AI Connector (pre-built)
Option B: Custom connector (recommended for more control)
3. ENTER DETAILS
MCP Server URL: Same format as ChatGPT, with your Account ID
4. AUTHENTICATE
Method: OAuth 2.0
Role: Select your custom MCP role (NOT Administrator)
5. TEST CONNECTION
Try: "What customers were created this week?"
Verify results match NetSuite data
Use Cases
- Customer Service: "Look up order SO-12345 status"
- Sales Support: "What's the pricing history for this customer?"
- Finance: "Generate AR aging report and email CFO"
- Operations: "What items are below reorder point?"
- Executive: "Compare this month's revenue to last year"
Testing & Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Role not visible during auth | Missing permissions or assignment | Verify MCP permission, role assignment, then re-login |
| Permission errors on create/update | Role has view-only access | Grant Create/Edit permissions for target record types |
| Missing data in results | Subsidiary restrictions | Verify role has access to all required subsidiaries |
| Token expired errors | Access token lifecycle | Implement refresh token logic; re-authenticate if needed |
| Administrator role rejected | Security restriction | Create dedicated least-privilege role for AI connections |
Review AI application settings to opt out of training data usage if required by your organization's data policies. Both ChatGPT and Claude offer enterprise plans with data privacy guarantees.
Security Considerations
- Least-privilege roles: Create dedicated roles with minimum necessary permissions
- Role-based access: AI executes with assigned role permissions only
- Subsidiary scope: Restrict data visibility to assigned subsidiaries
- Audit logging: All AI operations logged for compliance review
- Operation approval: Configure which operations need human approval
- Rate limiting: Prevent excessive AI-initiated operations
- Data filtering: Restrict sensitive fields from AI access
- Token security: Store Client Secret securely; implement token refresh
Community Tools & References
In addition to the official SuiteApp, these resources can help with MCP implementations:
- OpenSuiteMCP: github.com/opensuitemcp/opensuitemcp — Open-source NetSuite MCP client with OAuth 2.0 (PKCE), automatic token refresh, error handling, and LangChain integration
- NetSuite AI Connector Service: Oracle Help Documentation
- NetSuite MCP Server Overview: Product Page
- Model Context Protocol: MCP Getting Started Guide
- OAuth 2.0 Flow: NetSuite OAuth 2.0 Documentation
The MCP integration is transformative for organizations using AI assistants. Start with read-only access (queries and reports) to build trust, then gradually enable write operations with appropriate approval workflows. The biggest value is in repetitive lookup tasks—"What's the status of X?" questions that currently require manual NetSuite navigation. Note that open-source tools like OpenSuiteMCP should be thoroughly vetted before production use.
Common Integrations
Integration patterns for Salesforce, Shopify, Amazon, banking, and payment processors.
E-Commerce Integrations
Shopify Integration
SHOPIFY ↔ NETSUITE DATA FLOWS
═══════════════════════════════════════════════════════════════
PRODUCTS (NetSuite → Shopify)
───────────────────────────────────────────────────────────────
NetSuite Item ─────► Shopify Product
├── Item ID → SKU
├── Display Name → Title
├── Description → Description
├── Base Price → Price
├── Images → Images
└── Quantity → Inventory Level
ORDERS (Shopify → NetSuite)
───────────────────────────────────────────────────────────────
Shopify Order ─────► NetSuite Sales Order
├── Order Number → External ID
├── Customer Email → Customer (lookup/create)
├── Line Items → Item lines
├── Shipping → Shipping item
├── Discounts → Discount items
└── Payment → Payment record (if paid)
FULFILLMENT (NetSuite → Shopify)
───────────────────────────────────────────────────────────────
NetSuite Fulfillment ─────► Shopify Fulfillment
├── Tracking Number → Tracking
├── Carrier → Company
└── Ship Date → Created At
INVENTORY (NetSuite → Shopify)
───────────────────────────────────────────────────────────────
Frequency: Real-time or every 15 minutes
NetSuite Available Qty → Shopify Inventory Level
Amazon Integration
| Data Type | Direction | Frequency |
|---|---|---|
| Product Listings | NetSuite → Amazon | On change |
| Inventory | NetSuite → Amazon | Every 15 min |
| Pricing | NetSuite → Amazon | On change |
| Orders | Amazon → NetSuite | Every 5 min |
| Fulfillment | NetSuite → Amazon | On ship |
| Returns | Amazon → NetSuite | Daily |
CRM Integrations
Salesforce Integration
SALESFORCE ↔ NETSUITE DATA FLOWS
═══════════════════════════════════════════════════════════════
ACCOUNTS/CUSTOMERS (Bidirectional)
───────────────────────────────────────────────────────────────
Decision: Which system is master?
Option A: Salesforce Master (Common)
SF Account ─────► NS Customer
New customers created in Salesforce, synced to NetSuite
Option B: NetSuite Master
NS Customer ─────► SF Account
New customers created in NetSuite, synced to Salesforce
Option C: Bidirectional
Requires conflict resolution rules
Usually based on "last modified wins" or designated fields
OPPORTUNITIES → SALES ORDERS
───────────────────────────────────────────────────────────────
SF Opportunity (Closed Won) ─────► NS Sales Order
├── Account → Customer
├── Products → Items (requires item mapping)
├── Amount → Total
└── Opportunity ID → External ID
INVOICES/PAYMENTS → SALESFORCE
───────────────────────────────────────────────────────────────
NS Invoice ─────► SF Invoice Object (custom)
NS Payment ─────► SF Payment Object (custom)
Banking Integrations
BANK INTEGRATION PATTERNS
═══════════════════════════════════════════════════════════════
BANK FEEDS (Transactions Import)
───────────────────────────────────────────────────────────────
Bank ─────► NetSuite Bank Data
├── Method: Direct bank connection or file import
├── Frequency: Daily or multiple times per day
└── Matching: Auto-match to existing transactions
Supported formats: OFX, QFX, CSV, BAI2
POSITIVE PAY (Fraud Prevention)
───────────────────────────────────────────────────────────────
NetSuite Checks ─────► Bank Positive Pay File
├── Check number
├── Amount
├── Payee name
└── Date
Bank verifies checks against file before clearing
ACH/EFT PAYMENTS
───────────────────────────────────────────────────────────────
NetSuite Vendor Payments ─────► NACHA File ─────► Bank
├── Generate NACHA format file
├── Upload to bank portal (manual or automated)
└── Bank processes ACH transactions
LOCKBOX (Customer Payments)
───────────────────────────────────────────────────────────────
Bank Lockbox ─────► Payment File ─────► NetSuite
├── Bank processes customer checks
├── Generates payment data file
├── NetSuite imports and matches to invoices
Payment Processor Integrations
| Processor | Integration Method | Features |
|---|---|---|
| Stripe | SuiteApp or RESTlet | Cards, ACH, subscriptions |
| PayPal | Native integration | PayPal payments, e-commerce |
| Authorize.net | SuitePayments | Credit card processing |
| Square | iPaaS or custom | POS, online payments |
| Bill.com | SuiteApp | AP automation, vendor payments |
Industry-Specific Integrations
- EDI: SPS Commerce, TrueCommerce for customer/vendor EDI
- PLM: Product Lifecycle Management systems
- MES: Manufacturing Execution Systems for shop floor
- Quality: QMS systems for quality tracking
- POS: Square, Lightspeed, Shopify POS
- Marketplaces: Amazon, eBay, Walmart, Etsy
- Shipping: ShipStation, ShipBob, EasyPost
- Returns: Loop, Returnly, Happy Returns
- Billing: Stripe Billing, Chargebee, Zuora
- CRM: Salesforce, HubSpot
- Support: Zendesk, Intercom, Freshdesk
- Usage: Product analytics for usage-based billing
Before building custom integrations, check the SuiteApp marketplace. Common integrations like Shopify, Salesforce, and major shipping carriers have established connectors that are faster to implement than custom builds. Custom development makes sense when you have unique requirements or need tight control over the integration logic.
E-Invoicing
Electronic invoicing standards, compliance requirements, and NetSuite configuration.
NetSuite now supports e-invoicing for North American markets, expanding beyond existing European and Latin American coverage.
E-Invoicing Overview
E-invoicing (electronic invoicing) is the exchange of invoice documents between trading partners in structured electronic format. Many countries now mandate e-invoicing for B2B and B2G transactions.
Global E-Invoicing Standards
| Region | Standard | Status |
|---|---|---|
| European Union | Peppol, FatturaPA (Italy) | Mandatory (varies by country) |
| Mexico | CFDI 4.0 | Mandatory |
| Brazil | NF-e, NFS-e | Mandatory |
| India | GST E-Invoice | Mandatory above threshold |
| Saudi Arabia | ZATCA E-Invoicing | Mandatory |
| North America | Various (emerging) | Voluntary/Growing |
E-Invoicing Architecture
E-INVOICING FLOW
═══════════════════════════════════════════════════════════════
OUTBOUND (Sending Invoices)
───────────────────────────────────────────────────────────────
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ NetSuite │ │ E-Invoice │ │ Trading │
│ Invoice │────►│ Provider │────►│ Partner │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
Generate Convert to Receive &
XML/JSON standard format validate
INBOUND (Receiving Invoices)
───────────────────────────────────────────────────────────────
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Vendor │────►│ E-Invoice │────►│ NetSuite │
│ │ │ Provider │ │ Vendor Bill│
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
Send e-invoice Validate & Create bill
transform for approval
NetSuite Configuration
Enable E-Invoicing
- Enable Electronic Invoicing
- Configure country-specific settings
E-Invoice Provider Setup
E-INVOICE PROVIDER CONFIGURATION
═══════════════════════════════════════════════════════════════
Setup → Company → Electronic Invoicing → Provider Setup
PROVIDER OPTIONS:
───────────────────────────────────────────────────────────────
• NetSuite E-Invoicing (native)
• Avalara (for supported countries)
• Third-party providers (via integration)
CONFIGURATION:
───────────────────────────────────────────────────────────────
1. Select provider
2. Enter API credentials
3. Map NetSuite fields to e-invoice format
4. Configure document types (invoice, credit memo, etc.)
5. Set up customer/vendor identifiers (VAT, tax ID)
6. Test with sample transactions
Country-Specific Requirements
PEPPOL REQUIREMENTS
───────────────────────────────────────────────────────────────
Required Fields:
• Seller: Name, Address, VAT ID, Peppol ID
• Buyer: Name, Address, VAT ID, Peppol ID
• Invoice: Number, Date, Due Date, Currency
• Lines: Description, Quantity, Unit, Price, VAT
• Totals: Net, VAT, Gross
Peppol ID Format: Country Code : Identifier
Example: DE:991234567890
CFDI 4.0 REQUIREMENTS
───────────────────────────────────────────────────────────────
• RFC (tax ID) for buyer and seller
• Uso de CFDI (invoice purpose code)
• Forma de Pago (payment method)
• Método de Pago (payment timing)
• Producto/Servicio codes (SAT catalog)
• Unidad de Medida codes
• Digital stamp from PAC (authorized provider)
• Timbrado within 72 hours of transaction
Implementation Checklist
E-invoicing compliance is increasingly mandatory globally. Start by understanding which countries require it and by when. For multi-country operations, consider a provider that covers all your jurisdictions to avoid managing multiple integrations. The data quality requirements are strict—clean up customer tax IDs and addresses before going live, as e-invoice rejections create operational headaches.