Security model
The integration's trust surface is small by design. One outbound HTTPS channel runs from Salesforce to NetSuite. Every request is signed. Credentials stay server-side and never show in the app. A NetSuite role you control scopes what they can do.
Authentication
Two separate identities are used, at different times:
| Identity | Used | Mechanism |
|---|---|---|
| Installer (M2M) | Only while deploying the NetSuite package | OAuth 2.0 client credentials, with a certificate you generate and register against the SuiteCloud Development Integration |
| Runtime (TBA) | Every sync call | Token-Based Authentication, using the consumer key and secret from the Continuous integration record, plus the token id and secret from your integration user and role |
No passwords, session cookies, or interactive logins are involved in either path, and the installer certificate never leaves the admin's workstation.
Request signing
Every runtime call is signed with OAuth 1.0a, HMAC-SHA256. Each request gets a fresh nonce and timestamp. The signature covers the HTTP method, the endpoint URL, and every parameter, including the RESTlet's script and deploy query parameters. It's encoded per RFC 3986 and keyed by the consumer secret and token secret. NetSuite verifies the signature and executes under the token's role. The nonce and timestamp bound replay, and a tampered URL or body fails verification.
Per-call endpoints
Each call can point at a named endpoint: the Continuous entry script, another RESTlet in the same NetSuite account, or an external URL. It can also override the HTTP method and action it sends. That widens the trust surface in two ways, and both are guarded.
- Every host still needs a Remote Site Setting. Salesforce refuses a callout to a host that isn't allow-listed, so an override on a new host fails with "Unauthorized endpoint" until an admin adds it in Setup. The endpoint editor's Check host button runs the probe on demand. Validate turns a missing Remote Site into a blocking error, so it surfaces before Activate rather than during a live run.
- Credentials stay account-bound. The stored token pair is issued by one NetSuite account and signs every request the same way. You can point a call at a host outside that account's own RESTlet domain. That's how a customer routes a call through their own middleware. Validate warns when the host isn't the connected account's, because only a service that forwards to that account can authenticate.
An in-account relay adds no trust surface at all. When a call points at another RESTlet in the same NetSuite account, Salesforce doesn't gain a new destination. It posts to the endpoint it already posts to, signed the same way, and the entry script forwards the payload from inside NetSuite.
No second credential exists, none is asked for, and none could help. Token-based auth is bound to the account, so a script in that account is reachable only from inside it.
The forward runs under the same role as the call that arrived. The NetSuite role stays the ceiling for the target, the same as it is for the packaged writers. If the target's own deployment isn't open to that role, NetSuite refuses the call itself, rather than configuration catching it. No secret passes to the target, no Remote Site entry is added, and no data leaves the account boundary that wasn't already leaving it.
Pointing back at the entry script itself is refused. That would re-enter the dispatcher with the caller's own payload and recurse. Salesforce refuses it at Activate, and NetSuite refuses it again, by name, before anything is sent. A longer loop through other RESTlets is refused too. Every hop adds its own script id to the forwarded payload. A chain that would come back to an endpoint already in it, or run past three relays, is refused before anything is sent. An admin can also narrow where a relay may go at all, with the optional Relay Allowlist on Continuous Revenue Settings.
Two kinds of callout always ignore an override and use the connection's own endpoint. They are the mapping editor's live field lookups, and Validate's NetSuite-side checks, like the record-type describes and the RESTlet version floor. Only the packaged RESTlet answers those.
The single call that does go to the override host is Validate's endpoint probe, whose whole job is proving Salesforce can reach it.
Endpoint overrides are configuration, not a credential. An admin edits them under the Continuous Control Admin permission set. Every run records the URL, method, and action it used, so where a payload went is auditable after the fact.
What a call may ask NetSuite to do
A call carries write instructions: which record type to write, whether a record can be created, which fields can be cleared, which sublist rows get replaced. An admin edits all of it under the Continuous Control Admin permission set, and all of it stays inside three bounds that no configuration can widen.
- The NetSuite role is still the ceiling. A target is legal only if the token's role can create that record type. The check that admits it is a live metadata read made as that role. A record type the role can't touch was never available to point at in the first place.
- Identity fields are never writable, and deletes take two opt-ins. A record's
id, external id, and record type are refused from any mapping or write instruction. A second set, its name, customer, form, and active flag, is blocked by default and can be lifted one object at a time. Moving a saved document to a different customer is refused outright. Deleting sublist rows needs both that mode and a separate confirmation on the entry. - The version stamp is configuration, not a credential. Verify installation records which NetSuite package version answered, and the app refuses to run a call whose configuration needs more than that. It's a correctness guard, not a security boundary. It can only ever refuse work, and it's read server-side like the rest of the settings.
A call pointed at another RESTlet in the same NetSuite account changes none of this. Salesforce still signs one request to the Continuous endpoint with the stored token pair, and NetSuite forwards it from the inside under the same role. There are no second credentials to store, no second Remote Site entry, no signature computed for someone else's endpoint, and no secret leaves NetSuite. Relaying back to the Continuous endpoint itself is refused, in every form NetSuite accepts an id in, so the forward can't become a second door into an action.
Credential storage
- Secrets live in an org-level Salesforce custom setting, written by the wizard and read server-side by the sync code. After saving, the UI shows only a masked fingerprint, the last four characters.
- Keep Restrict access to custom settings turned on in Setup, under Schema Settings. With it on, only Salesforce admins can read the stored values. Syncs keep working, because the app reads the secrets in its own code.
- Saving with a field left blank keeps its stored value, so rotating credentials only touches the fields you change. See Credentials & authentication.
- Payload and result JSON stored on runs contain business data, never credentials. Signatures are computed per request and never persisted.
Salesforce permissions
Access is split across two permission sets, so day-to-day sync users never need a grant to the configuration surface.
| Permission set | Who | Grants |
|---|---|---|
| Continuous Control | Everyone who triggers syncs or views runs: admins, the integration user, finance and ops | The app and its runtime tabs. The sync-facing Apex entry points: card controllers and the invocable actions. The internal workers run behind them. CRUD on the integration's own runtime objects: sync runs and the POB mirror. The sync status fields across synced objects. READ on the endpoint registry and its NetSuite Endpoints tab, enough to see where a call goes but never to change it |
| Continuous Control Admin | Admins who configure the integration. Assign it in addition to Continuous Control, never alone | CRUD on the configuration objects: field mappings and configurable-call definitions, including the node fields that hold a SOQL filter fragment and a writeback field id. The Calls & Mappings, NetSuite Calls, NetSuite Endpoints, and NetSuite Connection tabs. The Apex entry points behind the mapping editor and connection-setup wizard |
Configuration edits execute in user mode. That's why the object CRUD in the Admin set genuinely gates who can change what a sync writes or which field a node writes back to. A user with only the base set can run and observe syncs, but can't alter what they do.
A sync sends only what its user can read
A sync reads the fields it sends as the person who started it. For a Flow, that's the user whose change started the Flow. The same goes for an added object's records and its row filter.
If that user can't read a mapped field, the sync leaves it out and the run names it in a warning. The rest of the record still syncs. So give sync users read access to every field you map. For orders, that includes the Revenue Cloud fields.
NetSuite role permissions
The access token binds to the shipped Continuous Control Integration role. That role is the outer bound of everything the sync can do.
| Access | On |
|---|---|
| REST Web Services, token login | The role itself |
| Full access | The Continuous custom records, and File Cabinet for the files action |
| Create and edit | The native transactions it lands: sales order, estimate, invoice, credit memo, cash sale, return authorization, customer payment, customer refund |
| Create and edit | The entities it maintains: Customer, Contact, Item |
| View | The reference data it reads: Accounts, Subsidiaries, Currencies, Tax Items, Tax Schedules, Payment Methods |
Prefer this role over Administrator. It carries no vendor, employee, journal entry, or company-setup permission. A connection whose custom mappings write those record types, or the one-time tax setup step, uses an Administrator token instead. Full permission list: Install the NetSuite components.
What data crosses the wire
| Direction | Content |
|---|---|
| Salesforce → NetSuite | The commercial graph: account and contact details, products, contract/order/line commercials, billing structure, invoice/credit-memo/payment/refund documents, optional mapped fields and document files you configured |
| NetSuite → Salesforce | Record ids and counts. POB figures. Subsidiary and currency reference data. The item catalogue, read for product matching in the Connection wizard: internal id, Name/Number, display name, external id, type. Settlement documents, when the pull is enabled. Field metadata for the mapping editor |
Nothing is sent to a third party unless you configure it. The only endpoints involved are your Salesforce org and your NetSuite account, both allow-listed explicitly through the two Remote Site Settings. Any host you deliberately point a call at needs a Remote Site Setting of its own. Salesforce-side deep links to NetSuite are plain URLs with no embedded credentials. NetSuite-side deep links back to Salesforce come from the org base URL carried in each payload.