What is the NetSuite REST API?
The NetSuite REST API — officially named SuiteTalk REST Web Services — is Oracle NetSuite's modern HTTP/JSON interface for reading and writing records programmatically. Unlike the legacy SOAP API, it uses standard REST conventions: GET to read, POST to create, PATCH to update, and DELETE to remove records. SuiteQL (a SQL-like query language) is also exposed through the same REST endpoint, making it the single integration surface for most use cases.
NetSuite provides two APIs for external integration: the legacy SOAP-based web services and the newer REST API. The REST API is the recommended approach for new integrations — it's simpler, more performant, and better documented.
TL;DR: The NetSuite REST API provides RESTful CRUD operations on all standard and custom record types, SuiteQL for SQL-like queries, and JSON payloads. Authentication uses OAuth 2.0 (or OAuth 1.0 / Token-Based Authentication for backward compatibility). The REST API browser at https://{accountId}.suitetalk.api.netsuite.com/rest/platform/v1/metadata-catalog provides interactive documentation for all available record types and fields. Rate limits apply — 10 concurrent requests per account for REST API, with additional throttling at high volumes.
Authentication
Token-Based Authentication (TBA)
The most common authentication method for server-to-server integrations:
-
Create an integration record: Setup > Integration > Manage Integrations > New
- Enable Token-Based Authentication
- Record the Consumer Key and Consumer Secret
-
Create a token: Setup > Users/Roles > Access Tokens > New
- Select the application (integration record)
- Select the user and role
- Record the Token ID and Token Secret
-
Sign requests: Use OAuth 1.0 signature with:
- Consumer Key + Consumer Secret (application level)
- Token ID + Token Secret (user level)
- Account ID
- Nonce and timestamp
Each request includes an Authorization header with the OAuth 1.0 signature.
OAuth 2.0
For web applications and scenarios requiring delegated authorization:
- Register the application: Create an integration record with OAuth 2.0 enabled
- Authorization flow: User is redirected to NetSuite login, grants access, and receives an authorization code
- Token exchange: Exchange the authorization code for access and refresh tokens
- API requests: Include the access token in the Authorization header as a Bearer token
- Token refresh: Access tokens expire — use the refresh token to obtain new ones
OAuth 2.0 is preferred for applications where users authenticate interactively, while TBA is preferred for background integrations.
Need a custom NetSuite integration built?
REST API, RESTlets, SuiteTalk, OAuth setup — we've shipped 150+ integrations since 2017. Senior devs, no junior hand-offs.
Scope my integrationMaking API requests
Base URL
Example: base URL pattern for all REST API requests
https://{accountId}.suitetalk.api.netsuite.com/services/rest/Replace {accountId} with your NetSuite account ID (e.g., 1234567 or 1234567_SB1 for sandbox).
Record operations (CRUD)
Create a record (POST):
Example: create a new customer record
POST /services/rest/record/v1/customer
Content-Type: application/json
{
"companyName": "Acme Corp",
"email": "info@acme.com",
"subsidiary": {"id": "1"}
}Read a record (GET):
Example: get a single customer by internal ID
GET /services/rest/record/v1/customer/123Returns JSON with all accessible fields for the record.
Update a record (PATCH):
Example: update specific fields on an existing customer
PATCH /services/rest/record/v1/customer/123
Content-Type: application/json
{
"phone": "555-0123",
"email": "new@acme.com"
}PATCH updates only the specified fields. PUT replaces the entire record.
Delete a record (DELETE):
Example: permanently delete a customer record
DELETE /services/rest/record/v1/customer/123Sublists (line items)
Records with sublists (e.g., sales order lines, vendor bill lines) include nested arrays:
Example: POST body for a sales order with two line items
{
"entity": {"id": "123"},
"item": {
"items": [
{
"item": {"id": "456"},
"quantity": 10,
"rate": 25.00
},
{
"item": {"id": "789"},
"quantity": 5,
"rate": 50.00
}
]
}
}Filtering and querying records
List records with filters:
Example: get all customers whose company name contains "Acme"
GET /services/rest/record/v1/customer?q=companyName CONTAIN "Acme"Pagination:
Example: retrieve the first 100 customer records
GET /services/rest/record/v1/customer?limit=100&offset=0Default page size is 1000 records. Use limit and offset for pagination through large result sets.
SuiteQL
SuiteQL is NetSuite's SQL-like query language, accessible through the REST API. It's the most powerful way to extract data.
Endpoint:
Example: run a SuiteQL query to retrieve customers created in 2026
POST /services/rest/query/v1/suiteql
Content-Type: application/json
Prefer: transient
{
"q": "SELECT id, companyname, email FROM customer WHERE datecreated > '2026-01-01'"
}SuiteQL capabilities
- JOIN across related tables
- Aggregate functions (SUM, COUNT, AVG, MAX, MIN)
- GROUP BY and HAVING
- Subqueries
- Built-in functions (TO_DATE, NVL, CASE)
Example queries
Top 10 customers by revenue:
Example: SuiteQL query — top 10 customers by invoiced revenue in 2026
SELECT
c.companyname,
SUM(tl.netamount) as total_revenue
FROM transaction t
JOIN transactionline tl ON t.id = tl.transaction
JOIN customer c ON t.entity = c.id
WHERE t.type = 'CustInvc'
AND t.trandate >= '2026-01-01'
GROUP BY c.companyname
ORDER BY total_revenue DESC
FETCH FIRST 10 ROWS ONLYOpen purchase orders by vendor:
Example: SuiteQL query — count and total open purchase orders grouped by vendor
SELECT
v.companyname as vendor,
COUNT(t.id) as open_pos,
SUM(t.foreigntotal) as total_amount
FROM transaction t
JOIN vendor v ON t.entity = v.id
WHERE t.type = 'PurchOrd'
AND t.status = 'PurchOrd:B'
GROUP BY v.companyname
ORDER BY total_amount DESCSuiteQL vs. saved searches
SuiteQL is more flexible than saved searches for complex queries:
- JOINs across any tables (saved searches have limited join paths)
- Subqueries and CTEs
- Union queries
- Better performance on large data sets
- Programmatic access through the API
Saved searches are better for:
- Scheduled reports and email alerts
- Dashboard portlets
- User-facing interfaces where non-developers need to modify criteria
REST API Browser
The REST API browser is your interactive documentation:
Example: REST API browser URL for your NetSuite account
https://{accountId}.suitetalk.api.netsuite.com/rest/platform/v1/metadata-catalogFor each record type, it shows:
- All available fields with data types
- Required vs. optional fields
- Sublist structures
- Available operations (GET, POST, PATCH, DELETE)
- Field-level help text
Use the browser to explore record schemas before writing integration code. It's more reliable than documentation sites because it reflects your actual NetSuite configuration, including custom fields and custom record types.
RESTlets vs. REST API
NetSuite has two REST-related features that are often confused:
REST API (SuiteTalk REST): The standard API for CRUD operations on records. No custom code required. Works with any standard or custom record type.
RESTlets: Custom SuiteScript endpoints that you write and deploy. RESTlets are SuiteScript 2.x scripts that handle HTTP requests and can execute any business logic — not just CRUD operations.
When to use REST API: Standard operations — create records, read records, update records, query data with SuiteQL.
When to use RESTlets: Custom business logic — calculate pricing, validate data against custom rules, execute workflows, aggregate data across multiple record types in a single API call, or any operation that doesn't map to a simple CRUD action.
Rate limits and performance
Concurrency limits
- REST API: 10 concurrent requests per account (can be increased with additional licenses)
- RESTlets: Shared concurrency with REST API
- SuiteQL: Counted within REST API concurrency
Request throttling
NetSuite throttles requests when you exceed limits:
- HTTP 429 (Too Many Requests) response
- Retry-After header indicates when to retry
Performance tips
Use SuiteQL for bulk reads. A single SuiteQL query returning 1,000 records is much faster than 1,000 individual GET requests.
Use PATCH, not PUT. PATCH updates only the fields you specify. PUT replaces the entire record, which is slower and riskier.
Batch operations. For creating or updating multiple records, consider the REST API's batch endpoint or process records in parallel (within concurrency limits).
Minimize round trips. Use expandSubResources=true to include sublists in a single GET request instead of fetching the record and then each sublist separately.
Cache the metadata catalog. Don't query the metadata catalog on every request — cache it and refresh periodically.
Common error codes and fixes
Understanding the HTTP status codes returned by the REST API speeds up debugging significantly.
| HTTP status | Meaning | Common cause | Fix |
|---|---|---|---|
| 400 Bad Request | Invalid payload or field value | Wrong field name, missing required field, wrong data type | Check the REST API Browser for required fields and field IDs |
| 401 Unauthorized | Authentication failure | Wrong Consumer Key, Token ID, or OAuth signature | Regenerate tokens; verify account ID in base URL matches the token |
| 403 Forbidden | Permission denied | Role missing permission for the record type or operation | Add the required permission in Setup > Users/Roles > Roles |
| 404 Not Found | Record does not exist | Wrong internal ID or wrong account (sandbox vs. production) | Confirm the record ID and that you're hitting the right account URL |
| 429 Too Many Requests | Rate limit exceeded | More than 10 concurrent requests | Back off and retry after the Retry-After response header value (seconds) |
| 500 Internal Server Error | Server-side error | Malformed SuiteQL query, locked record, scripting conflict | Check the error message body; SuiteQL syntax errors appear as 500s |
Handling 429 errors in code
When you receive a 429, read the Retry-After header before retrying:
Example: retry logic for 429 rate limit responses (Python)
import time
import requests
def request_with_retry(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
time.sleep(retry_after)
continue
response.raise_for_status()
return response
raise Exception("Max retries exceeded")REST API vs. SOAP API
| Feature | REST API | SOAP API |
|---|---|---|
| Protocol | HTTP + JSON | SOAP + XML |
| Authentication | OAuth 1.0 / 2.0 | TBA or OAuth |
| Query language | SuiteQL | Saved search criteria |
| Payload size | Smaller (JSON) | Larger (XML) |
| Documentation | REST API Browser | WSDL + records browser |
| Learning curve | Lower | Higher |
| Custom records | Supported | Supported |
| Bulk operations | SuiteQL, batch | Search, getList |
| Performance | Generally faster | Slower (XML overhead) |
Recommendation: Use the REST API for all new integrations. Use SOAP only if you're maintaining an existing integration that was built on SOAP, or if you need a specific feature only available in SOAP (increasingly rare).
Sources and references
- Oracle NetSuite SuiteTalk REST Web Services Documentation — NetSuite Help Center (login required). Covers record types, field definitions, authentication flows, and the REST API browser.
- Oracle NetSuite SuiteQL Reference — NetSuite Help Center. Documents supported tables, joins, aggregate functions, and built-in functions available through the SuiteQL endpoint.
- Oracle NetSuite SuiteScript 2.x Developer Guide — NetSuite Help Center. Reference for writing RESTlets and other server-side scripts that extend the REST API.
- Oracle NetSuite Token-Based Authentication Guide — NetSuite Help Center. Step-by-step instructions for generating Consumer Key/Secret and Token ID/Secret pairs.
- OAuth 2.0 Authorization Code Flow for NetSuite — NetSuite Help Center. Details the authorization code grant flow, token endpoints, and refresh token handling.
- SuiteCloud Development Framework (SDF) Documentation — NetSuite Help Center. Covers deploying and managing integrations, scripts, and customizations as code.
What clients ask before signing

Joaquin Vigna
Co-Founder & CTO
Co-founder and Chief Technology Officer at BrokenRubik with 12+ years of experience in software architecture and NetSuite development. Leads technical strategy, innovation initiatives, and ensures delivery excellence across all projects.
Related Articles
NetSuite MCP: AI Connector & Model Context Protocol
How NetSuite MCP works — connect Claude, ChatGPT, or any LLM to your ERP. Setup, security, use cases, MCP Standard Tools SuiteApp, and what it means for…
NetSuite API Guide: REST, SOAP & SuiteScript for Developers
Complete guide to NetSuite APIs. Learn about SuiteTalk REST and SOAP APIs, SuiteScript, authentication methods, and best practices for NetSuite integrations.
NetSuite 2026.1 Release Notes: Developers & IT Architects
NetSuite 2026.1 for developers: REST batch operations, SuiteScript 2.1 runtime upgrades, AI coding in VS Code, and the TBA deprecation deadline.
Joaquin Vigna