# Query NetSuite with SuiteAnalytics Connect

## When to use this

You want SQL over NetSuite's records: `transaction`, `customer`, `item`, the
NetSuite2.com data source that SuiteAnalytics Connect exposes, rather than the
REST record API. NetSuite ships a JDBC driver for it. This article sets it up
as a [JDBC source](/docs/sources/jdbc) so an agent or a scheduled job queries
it under a concurrency limit, with the login held by swarmvia.

For REST under a limit see [Proxy NetSuite](/docs/knowledge-base/netsuite-rest);
for queued writes see [Async NetSuite writes](/docs/knowledge-base/async-netsuite-writes).

## Setup

### 1. Get the driver

In NetSuite: **Setup → Analytics → Connect Driver Download**, JDBC tab. Download
the driver for Linux (the runtime is Linux x86-64) and keep the jar from the
bundle, `NQjc.jar`. NetSuite does not publish it to Maven Central.

**Drivers → Upload a jar**, name it `NetSuite Connect`.
swarmvia confirms it declares `com.netsuite.jdbc.openaccess.OpenAccessDriver`.

### 2. Pick a role

Connect as a role with the **SuiteAnalytics Connect** permission and read
access to the records you mean to query. Role 57, Data Warehouse Integrator,
is the role NetSuite created for exactly this; a custom role is better when
you want less. The role's record and field permissions are the boundary.
NetSuite does not enforce a read-only connection; the driver reports
`readOnly: false` on Test connection, and that is expected.

### 3. Create the source

**Sources → New source → JDBC data source → NetSuite SuiteAnalytics Connect.**

| Placeholder | Where it comes from |
|---|---|
| Connect host | The Connect Driver page: `{account}.connect.api.netsuite.com` |
| Account ID | Setup → Company → Company Information, e.g. `1234567` or `1234567_SB1` |
| Role ID | The role from step 2 |

The preset writes the URL:

```
jdbc:ns://1234567.connect.api.netsuite.com:1708;ServerDataSource=NetSuite2.com;Encrypted=1;NegotiateSSLClose=false;CustomProperties=(AccountID=1234567;RoleID=57)
```

### 4. Create the credential

Two ways in; both are a `jdbc_login` credential.

**Password** (token-based authentication is not what the JDBC driver uses):
the public property `user` (the login email) on the source and the secret
property `password` on the credential. If the account enforces two-factor
authentication for the role, use OAuth 2.0 instead.

**OAuth 2.0 client credentials**: register an integration record in NetSuite
with the client credentials (machine-to-machine) flow and a certificate.
On the credential, choose *OAuth 2.0 client credentials*, token URL
`https://{account}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token`,
your client id, the private key, scope `suite_analytics`, and the token
property `OAuth2Token`. swarmvia mints the token and hands it to the driver on
every connection.

### 5. Test and query

**Test connection** should report product `NetSuite`. Then:

```bash
curl https://netsuite.swarmvia.cloud \
  -H "X-Swarmvia-Key: $SWARMVIA_KEY" \
  -H "content-type: application/json" \
  -d '{"queries":[{"sql":"SELECT id, tranid, trandate, foreigntotal FROM transaction WHERE type = ? AND trandate >= ? FETCH FIRST 50 ROWS ONLY","params":["SalesOrd","2026-01-01"]}]}'
```

Placeholders are `?`. NetSuite2.com speaks an Oracle-flavoured SQL: `FETCH
FIRST n ROWS ONLY` for limits, `BUILTIN.DF()` for display values.

## Tips

- NetSuite counts every Connect query against the account's concurrency
  governance. Set the source's concurrency limit low (2 to 4) so a burst of
  agents never trips it.
- `source_schema` lists NetSuite2.com's thousands of tables. Scope it by
  schema and table rather than listing everything into an agent's context.
- Long analytical queries belong in jobs: send `waitMs: 0` or
  `Prefer: respond-async` and poll, or let the source promote them.

## See also

- [JDBC sources](/docs/sources/jdbc)
- [Database sources](/docs/sources/database)
- [Async](/docs/sources/async)
