Skip to main content
Oct 25–28SuiteWorld 2026 — Meet our team
Category
NetSuite
Published
Updated
Reading time
12 min read

NetSuite REST API: Complete Developer Guide (2026)

Guide to the NetSuite REST API — OAuth 2.0, CRUD operations, SuiteQL queries, the metadata catalog, concurrency limits, and the SOAP and TBA end-of-life dates.

Contents11 sections ↓

What is the NetSuite REST API?

The NetSuite REST API — officially named SuiteTalk REST Web Services — is Oracle NetSuite's HTTP/JSON interface for reading and writing records programmatically. It uses standard REST conventions: GET to read, POST to create, PATCH to update, and DELETE to remove records. SuiteQL, NetSuite's SQL-92-based query language, is exposed through the same REST web services, which makes it the single integration surface for most use cases.

NetSuite has offered two web services APIs: SOAP web services and REST web services. Oracle has now put end dates on SOAP, so REST is the only one to build new integrations on.

TL;DR: The NetSuite REST API provides CRUD operations on the record types Oracle lists as supported (custom records included; custom sublists and legacy tax features are not), SuiteQL for queries, and JSON payloads. Authenticate with OAuth 2.0 — from NetSuite 2027.1 you can't create new token-based authentication (TBA) integrations. Your account's metadata catalog at /services/rest/record/v1/metadata-catalog describes every exposed record and field, including your customizations. Concurrency is one pool per account, shared by SOAP, REST and RESTlets: 5, 15 or 20 requests depending on service tier, plus 10 for each SuiteCloud Plus license.


SOAP and TBA end-of-life dates

Oracle has published a timeline for retiring SOAP web services and token-based authentication:

ReleaseWhat changes
2025.2The last planned SOAP web services endpoint.
2026.1New integrations should use REST web services with OAuth 2.0.
2027.1No new SOAP integrations, and no new TBA integrations for SOAP, REST or RESTlets.
2028.2All SOAP web services endpoints are disabled. Support for existing TBA integrations tentatively ends.

If you maintain a SOAP integration or an integration that signs requests with TBA, plan the move to REST web services and OAuth 2.0 now rather than in 2028.


Authentication

OAuth 2.0 is Oracle's preferred authentication method for REST web services and RESTlets. It isn't supported for SOAP web services.

  1. Enable the features: REST Web Services and OAuth 2.0 (Setup > Company > Enable Features > SuiteCloud).
  2. Create an integration record with OAuth 2.0 enabled and the grant type you need.
  3. Give the integration a role with the "REST Web Services" and "Log in using OAuth 2.0 Access Tokens" permissions. Oracle advises against using the Administrator role for integrations.
  4. Pick the flow:
    • Authorization code grant — a user signs in to NetSuite and approves access. Use it when a person is behind the integration.
    • Client credentials (machine-to-machine) — no user interaction; the integration authenticates with a certificate you upload to NetSuite. Use it for server-to-server integrations.
  5. Send the access token in the Authorization header as a Bearer token. Access tokens are valid for 60 minutes.

Token-Based Authentication (TBA) — legacy

TBA signs each request with OAuth 1.0 using a consumer key and secret (from the integration record) plus a token ID and secret (from an access token tied to a user and role). Existing TBA integrations keep working for now, but from NetSuite 2027.1 you can't create new TBA integrations, and support for existing ones tentatively ends in 2028.2. Don't start new work on TBA.


Need a custom NetSuite integration built?

REST web services, RESTlets, SuiteQL and OAuth 2.0 setup, or moving an existing SOAP or TBA integration before the cutoff. NetSuite-only since 2017.

Scope my integration

Making 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/123

Returns JSON with the fields the role can access.

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 changes only the fields you send; any omitted field is left unchanged.

Upsert a record by external ID (PUT):

PUT is used for one thing in REST web services: the upsert operation, when the request URL carries an external ID. If a record with that external ID exists it's updated, otherwise it's created.

Example: upsert a customer by external ID

PUT /services/rest/record/v1/customer/eid:CID002
Content-Type: application/json
 
{
  "firstName": "John",
  "lastName": "Smith"
}

Delete a record (DELETE):

Example: permanently delete a customer record

DELETE /services/rest/record/v1/customer/123

Sublists (line items)

Records with sublists (e.g., sales order lines, vendor bill lines) include nested arrays. Custom sublists aren't available through REST web services.

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"

Collection queries return record IDs and links, not field values. To get the fields, read each record or use SuiteQL.

Pagination:

Example: retrieve the first 100 customer records

GET /services/rest/record/v1/customer?limit=100&offset=0

Use limit and offset to page through large result sets. The offset must be a multiple of the limit.

Catch misspelled field names

By default, a field name REST web services doesn't recognize only produces a warning. Send the X-NetSuite-PropertyNameValidation: error header so a typo fails the request instead of being silently ignored.


SuiteQL

SuiteQL is NetSuite's query language, based on SQL-92, and it's available through REST web services, the SuiteScript N/query module and SuiteAnalytics Connect. It enforces the same role-based access restrictions as SuiteAnalytics Workbook.

Endpoint:

Example: run a SuiteQL query to retrieve customers created in 2026

POST /services/rest/query/v1/suiteql?limit=1000&offset=0
Content-Type: application/json
Prefer: transient
 
{
  "q": "SELECT id, companyname, email FROM customer WHERE datecreated >= TO_DATE('2026-01-01', 'YYYY-MM-DD')"
}

The Prefer: transient header is required. Results come back 1,000 rows per page by default, up to 100,000 results per query; for larger extracts, Oracle points to SuiteAnalytics Connect.

SuiteQL capabilities

  • Joins across related tables
  • Aggregate functions (SUM, COUNT, AVG, MAX, MIN)
  • GROUP BY and HAVING
  • Subqueries and UNION
  • Built-in functions (TO_DATE, NVL, CASE)

Two rules that catch people: WITH clauses aren't supported, and dates must be wrapped in TO_DATE() rather than compared as plain strings.

Example queries

Top 10 customers by revenue:

Example: SuiteQL query — top 10 customers by invoiced revenue in 2026

SELECT TOP 10
  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 >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
GROUP BY c.companyname
ORDER BY total_revenue DESC

Open 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 DESC

SuiteQL vs. saved searches

SuiteQL is the better fit when you need:

  • Joins the saved search interface doesn't offer
  • Subqueries or UNION
  • Several levels of aggregation
  • Programmatic access for an integration or a large export

Saved searches are better for:

  • Scheduled emails and alerts when records change
  • Dashboard portlets
  • Reports that business users build and adjust themselves

The metadata catalog and the REST API Browser

Your account's metadata catalog is the reference to read before you write integration code:

Example: metadata catalog URL for your NetSuite account

https://{accountId}.suitetalk.api.netsuite.com/services/rest/record/v1/metadata-catalog

Request it with Accept: application/swagger+json to get an OpenAPI 3.0 description. It includes user- and company-specific metadata, so it reflects your account's custom fields and custom records. For each record type it shows the fields with their data types, the sublists, and the operations available.

The REST API Browser is a separate, Oracle-hosted reference for the standard record schema. It's useful for exploring, but it doesn't reflect any one account's customizations — the metadata catalog does.


RESTlets vs. REST API

NetSuite has two REST-related features that are often confused:

REST API (SuiteTalk REST web services): The standard API for CRUD operations on records. No custom code required. Works with the record types Oracle lists as supported, including custom records.

RESTlets: Custom SuiteScript endpoints that you write and deploy. RESTlets handle HTTP requests and can run 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, aggregate data across several record types in a single call, or any operation that doesn't map to a simple CRUD action.


Rate limits and performance

Concurrency limits

  • One pool per account: the concurrency limit applies to the combined total of SOAP web services, REST web services and RESTlet requests.
  • Size: 5 for Standard, 15 for Premium, 20 for Enterprise and Ultimate service tiers, increased by 10 for each SuiteCloud Plus license.
  • SuiteQL requests count against the same pool.

What happens over the limit

  • REST web services return HTTP 429 with CONCURRENCY_LIMIT_EXCEEDED.
  • RESTlets return HTTP 400 with SSS_REQUEST_LIMIT_EXCEEDED.
  • Requests that run longer than 15 minutes time out.

Oracle doesn't document a Retry-After header. Retry after a delay, and increase the delay on each attempt.

Performance tips

Use SuiteQL for bulk reads. One SuiteQL query that returns 1,000 rows is one request; reading the same records one by one is a thousand requests against a shared concurrency pool.

Use PATCH for updates. PATCH changes only the fields you send. PUT is reserved for upserts by external ID.

Batch and async operations. The batch endpoint accepts up to 100 records per request and runs asynchronously. For long-running single requests, send Prefer: respond-async to get a 202 and a job URL instead of waiting (async isn't supported in the query service).

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 statusMeaningCommon causeFix
400 Bad RequestInvalid payload or field valueWrong field name, missing required field, wrong data typeCheck the metadata catalog for required fields and field IDs
401 UnauthorizedAuthentication failureExpired access token, wrong client ID, or wrong accountRefresh the token; verify the account ID in the base URL matches the integration
403 ForbiddenPermission deniedRole missing permission for the record type or operationAdd the required permission in Setup > Users/Roles > Roles
404 Not FoundRecord does not existWrong internal ID or wrong account (sandbox vs. production)Confirm the record ID and that you're hitting the right account URL
429 Too Many RequestsConcurrency limit exceededMore concurrent requests than the account's pool allowsBack off and retry with increasing delays
5xx Server ErrorServer-side errorLocked record, scripting conflict, platform issueCheck the error message body; 4xx codes point to the request, 5xx to the server

Handling 429 errors in code

Example: retry with exponential backoff on 429 responses (Python)

import time
import requests
 
def request_with_retry(url, headers, max_retries=5):
    delay = 2
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code == 429:
            time.sleep(delay)
            delay *= 2
            continue
        response.raise_for_status()
        return response
    raise Exception("Max retries exceeded")

REST API vs. SOAP API

FeatureREST APISOAP API
ProtocolHTTP + JSONSOAP + XML
AuthenticationOAuth 2.0 (TBA for existing integrations)TBA only — OAuth 2.0 isn't supported
Query languageSuiteQLSaved search criteria
Payload sizeSmaller (JSON)Larger (XML)
Schema referenceMetadata catalog (OpenAPI 3.0)WSDL
Custom recordsSupportedSupported
Bulk operationsSuiteQL, batchSearch, getList
StatusCurrentLast endpoint 2025.2; no new integrations from 2027.1; disabled in 2028.2

Recommendation: Build every new integration on REST web services with OAuth 2.0. If you maintain a SOAP or TBA integration, plan its migration before 2027.1, when new SOAP and TBA integrations can no longer be created.


Sources and references

  • Oracle NetSuite Help Center — SuiteTalk REST Web Services (docs.oracle.com). Record operations, the metadata catalog, SuiteQL through REST, async and batch requests.
  • Oracle NetSuite Help Center — SuiteQL. Supported syntax, joins, functions, and the limits listed above (no WITH clauses, dates in TO_DATE()).
  • Oracle NetSuite Help Center — Web services and RESTlet concurrency governance. Concurrency limits by service tier and SuiteCloud Plus licenses.
  • Oracle NetSuite Help Center — OAuth 2.0. Authorization code grant, client credentials (machine-to-machine) flow, and token lifetimes.
  • Oracle NetSuite Help Center — SOAP web services and TBA end-of-life notices. The 2025.2 / 2027.1 / 2028.2 timeline.

What clients ask before signing

Get your integration scoped

Tell us what systems you need to connect. We'll recommend the right approach and ballpark the cost.

We respond within 24 hours.

Share
Joaquin Vigna

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.

12+ years experienceOracle NetSuite Certified +1
Technical ArchitectureSuiteScript DevelopmentNetSuite CustomizationSystem Integration+2 more

Related