SuiteBilling Audit Logs
Streams the NetSuite SystemNote audit trail scoped to SuiteBilling record types — subscriptions, billing accounts, invoices, price plans, and related billing records. Each event captures who changed which field, the old and new values, and the context in which the change was made, making it well suited for finance/SOX audit of billing data.
Sync Type: Incremental
Overview
NetSuite records every field-level change to a record as a System Note. This input queries the SystemNote table via SuiteQL, filtered to the NetSuite record types that make up the SuiteBilling module, and streams new changes in ascending date order. The connector tracks the timestamp of the last processed change and resumes from there on each subsequent sync, so no events are missed and none are duplicated.
Authentication
This integration uses NetSuite's OAuth 2.0 Client Credentials (machine-to-machine) flow with a signed JWT client assertion. Rather than a shared client secret, the connector signs a short-lived JWT with an RSA private key (PS256); NetSuite verifies the signature against the public certificate you upload during setup. The signed assertion is exchanged for a one-hour bearer token at the per-account token endpoint (https://<account>.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token), which is then used for all SuiteQL requests.
Prerequisites
1. SuiteAnalytics / SuiteQL enabled
The integration role must be able to run SuiteQL queries. Ensure SuiteAnalytics Workbook is enabled for your account and granted to the role used by this integration.
2. Permissions
The role mapped to the integration needs:
- REST Web Services and Log in using OAuth 2.0 Access Tokens permissions
- SuiteAnalytics Workbook permission (SuiteQL runs under workbook role restrictions)
- View access to System Notes and to the SuiteBilling record types in scope (Subscriptions, Billing Accounts, Invoices, Price Plans, etc.)
Setup
1. Enable required features
In NetSuite, go to Setup > Company > Enable Features > SuiteCloud and enable REST Web Services and OAuth 2.0.
2. Create an Integration Record
Go to Setup > Integration > Manage Integrations > New.
- Give it a name (e.g.
Monad SuiteBilling Audit). - Under OAuth 2.0, check Client Credentials (Machine to Machine) Grant and the REST Web Services scope.
- Save. Copy the generated Client ID (Consumer Key) — this is your Client ID.
3. Generate an RSA key pair
Generate a 2048-bit (or larger) RSA key pair. Keep the private key for the connector; you will upload the public certificate to NetSuite.
Code
4. Map the certificate (OAuth 2.0 Client Credentials Setup)
Go to Setup > Integration > OAuth 2.0 Client Credentials (M2M) Setup > Create New.
- Entity: the user the integration acts as.
- Role: a role with the permissions listed above.
- Application (Integration): the Integration Record from step 2.
- Certificate: upload
monad-netsuite-public.pem. - Save. Copy the generated Certificate ID — this is your Certificate ID.
5. Identify your SuiteBilling record type IDs
This input filters SystemNote by numeric record-type internal IDs. Determine the internal IDs for the SuiteBilling record types you want to audit (e.g. Subscription, Subscription Line, Billing Account, Billing Schedule, Invoice, Price Plan). You can confirm these in your account by running a SuiteQL query such as SELECT DISTINCT recordtypeid, BUILTIN.DF(recordtypeid) FROM systemnote, or by inspecting the record types in Customization > Lists, Records, & Fields.
Details
The connector executes a SuiteQL query against the SystemNote table filtered to the configured record types, ordered by change date ascending. Results are paginated using limit/offset (1000 rows per page) and streamed as individual audit events. The cursor advances on the date of the most recent change processed.
Timezone note: the SuiteQL date filter is evaluated in the NetSuite account's timezone, while the connector formats its cursor in UTC. For exact incremental boundaries, the NetSuite account should be configured to UTC.
Configuration
The following configuration defines the input parameters. Each field's specifications, such as type, requirements, and descriptions, are detailed below.
Settings
| Setting | Type | Required | Description |
|---|---|---|---|
| Account ID | string | Yes | NetSuite account ID / realm, e.g. 1234567 or 1234567_SB1 for a sandbox. Used to build the per-account SuiteTalk host. |
| Certificate ID | string | Yes | ID of the public certificate uploaded to NetSuite for this integration. Sent as the JWT kid header. |
| Record Type IDs | array of strings | Yes | Numeric NetSuite record-type internal IDs to scope the audit trail to SuiteBilling records (e.g. Subscription, Billing Account, Invoice, Price Plan). At least one is required. |
| Backfill Start Time | string | No | The date to start fetching data from, in RFC 3339 format. If not specified, the first sync starts from now and all subsequent syncs are incremental. |
Secrets
| Secret | Type | Required | Description |
|---|---|---|---|
| Client ID | string | Yes | OAuth 2.0 client ID (the consumer key of the NetSuite Integration Record). Used as the iss claim of the signed JWT client assertion. |
| Private Key | string | Yes | PEM-encoded RSA private key used to sign the JWT client assertion (PS256). Its public certificate must be registered in NetSuite. |
Connector Limitations
-
Record-type scoping is explicit. The connector filters
SystemNoteby numeric record-type internal IDs you provide. These IDs must be confirmed against your own account; there is no auto-discovery. -
System Notes (v1) only. The connector reads the SuiteQL-queryable
SystemNotetable. System Notes v2 (available only through SuiteAnalytics Workbook) is not used. -
SuiteQL result limits. A single SuiteQL query returns at most ~100,000 rows; the connector paginates within that and windows by date across runs. Concurrency is governed by your account's SuiteCloud tier.
-
RSA certificate required. The connector signs assertions with PS256, so the certificate uploaded to NetSuite must be an RSA certificate.
Troubleshooting
Common Issues
-
Authentication Errors (401 /
INVALID_LOGIN)- Confirm the Client ID is the consumer key of the Integration Record, with no leading/trailing whitespace.
- Verify the Private Key is the RSA private key that matches the public certificate uploaded to NetSuite. A mismatched key pair causes signature verification to fail.
- Confirm the Certificate ID matches the certificate in OAuth 2.0 Client Credentials (M2M) Setup, and that the certificate is mapped to the same Integration Record, entity, and role.
- Ensure the uploaded certificate is an RSA certificate (the connector signs with PS256); an EC certificate will be rejected.
- Check that the certificate has not passed its expiration date — regenerate and re-upload if it has.
- Verify the mapped role has the Log in using OAuth 2.0 Access Tokens and REST Web Services permissions.
-
Connection / DNS Errors
- The Account ID must be your realm, e.g.
1234567(production) or1234567_SB1(sandbox). The connector lowercases it and converts_to-to build the hosthttps://<account>.suitetalk.api.netsuite.com. - A wrong Account ID typically surfaces as a DNS resolution failure or a 404. For sandboxes, use the full sandbox ID (e.g.
1234567_SB1), not the base account number.
- The Account ID must be your realm, e.g.
-
INSUFFICIENT_PERMISSIONor Feature Errors on SuiteQL- SuiteQL requires the SuiteAnalytics Workbook feature to be enabled and granted to the integration role.
- The REST Web Services feature must be enabled under Setup > Company > Enable Features > SuiteCloud.
-
No Records / Empty Syncs
- Verify the Record Type IDs are the correct numeric internal IDs for the SuiteBilling record types in your account. Incorrect IDs return zero rows. Confirm them with
SELECT DISTINCT recordtypeid, BUILTIN.DF(recordtypeid) FROM systemnote. - If Backfill Start Time is not set, the first sync starts from now, so only changes made after the connection is created are captured. Set a backfill time to pull historical changes.
- The cursor advances on the change date; if no billing records changed since the last run, emitting no records is expected behavior.
- Verify the Record Type IDs are the correct numeric internal IDs for the SuiteBilling record types in your account. Incorrect IDs return zero rows. Confirm them with
-
Records Missing Near the Time Boundary (Timezone)
- The SuiteQL date filter is evaluated in the NetSuite account's timezone, while the connector formats its cursor in UTC. If the account is not on UTC, changes near the boundary can appear shifted. Set the NetSuite account timezone to UTC for exact incremental boundaries.
-
Rate Limiting /
SSS_REQUEST_LIMIT_EXCEEDED(429)- SuiteQL concurrency is governed by your account's SuiteCloud tier. The connector rate-limits itself, but running many integrations against the same account concurrently can still hit limits. Reduce concurrent usage or upgrade to SuiteCloud Plus.
Related Articles
- NetSuite SystemNote / System Notes Overview
- NetSuite SuiteQL
- OAuth 2.0 Client Credentials (M2M) Flow
Sample Record
Code
Sync frequency
By default this input polls approximately every 10 seconds, with each sync beginning after the previous one completes. A cron schedule configured on the pipeline overrides this cadence. See Input Sync Frequency for details.