Skip to content

Commit 1424809

Browse files
BillLeoutsakosvl346Bill LeoutsakosBill Leoutsakoswaleedlatif1
authored
feat(netsuite): add Oracle NetSuite integration (#6476)
* revise netsuite integration * fix(netsuite): align selector route with snowflake * test(netsuite): remove selector route coverage * test(netsuite): align coverage with snowflake * fix(netsuite): complete integration validation * refactor(netsuite): align integration with codebase patterns * test(netsuite): correct async job citation * fix(netsuite): address final audit findings * fix(netsuite): surface upsert/transform Location, relax task link check Oracle documents the Location response header for create and update, and both tools already require it. Upsert and transform also produce a record but Oracle documents no response headers for either, so they dropped the header entirely and the new record's ID was unreachable. Add a `resource-optional` location mode that captures Location when NetSuite sends it and never fails when it is absent, and wire it to upsert and transform along with their tool and block outputs. Async task discovery rejected the whole response if any task link carried a rel other than `self`, collapsing the picker into a 502. Oracle documents a `self` link per task but never guarantees it is the only one, so skip other relationships and fail only when no self link exists. Also use the shared `truncate` helper in the error sanitizer per the repo convention instead of an inline slice. * fix(netsuite): validate SuiteQL pages against their documented shape The shared collection-page validator required links, items, count, hasMore, offset, and totalResults on every 200, and a missing field turns a successful call into a reported failure. Oracle documents all six for record collections and SuiteAnalytics dataset pages, but its SuiteQL reference lists only links, count, offset, totalResults, and items. A documented SuiteQL response that omits hasMore would therefore have been rejected. Split out a suiteql-page validator that requires the five documented SuiteQL fields and type-checks hasMore only when the account returns it. Record collections and dataset pages keep requiring all six. * chore(netsuite): regenerate tool metadata after rebase on staging The rebase conflicted only in the generated tool-id, tool-metadata, and tool-output artifacts, which NetSuite and the newly landed LogRocket integration both extend. Regenerated from the merged registries: the result is staging's catalog plus the 27 NetSuite tools, with LogRocket's entries intact and no other tool changed. --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> Co-authored-by: Bill Leoutsakos <billleoutsakos@Mac.localdomain> Co-authored-by: Waleed Latif <walif6@gmail.com>
1 parent 046302a commit 1424809

78 files changed

Lines changed: 9596 additions & 36 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/components/icons.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8625,6 +8625,17 @@ export function NewRelicIcon(props: SVGProps<SVGSVGElement>) {
86258625
)
86268626
}
86278627

8628+
export function NetSuiteIcon(props: SVGProps<SVGSVGElement>) {
8629+
return (
8630+
<svg {...props} viewBox='0 0 93.9 59.4' xmlns='http://www.w3.org/2000/svg'>
8631+
<path
8632+
fill='#C74634'
8633+
d='M30.5 59.4H65c16.4-.4 29.3-14.1 28.9-30.4C93.5 13.1 80.7.4 65 0H30.5C14.1-.4.4 12.5 0 28.9s12.5 30 28.9 30.4c.5.1 1 .1 1.6.1m33.7-10.5h-33c-10.6-.3-18.9-9.2-18.6-19.8C13 19 21.1 10.8 31.2 10.5h33c10.6-.3 19.5 8 19.8 18.6s-8 19.5-18.6 19.8z'
8634+
/>
8635+
</svg>
8636+
)
8637+
}
8638+
86288639
export function WizaIcon(props: SVGProps<SVGSVGElement>) {
86298640
return (
86308641
<svg {...props} viewBox='0 0 51 49' fill='none' xmlns='http://www.w3.org/2000/svg'>

apps/docs/components/ui/icon-mapping.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ import {
156156
MongoDBIcon,
157157
MySQLIcon,
158158
Neo4jIcon,
159+
NetSuiteIcon,
159160
NeverBounceIcon,
160161
NewRelicIcon,
161162
NotionIcon,
@@ -440,6 +441,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
440441
mongodb: MongoDBIcon,
441442
mysql: MySQLIcon,
442443
neo4j: Neo4jIcon,
444+
netsuite: NetSuiteIcon,
443445
neverbounce: NeverBounceIcon,
444446
new_relic: NewRelicIcon,
445447
notion: NotionIcon,

apps/docs/content/docs/en/integrations/meta.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@
165165
"mongodb",
166166
"mysql",
167167
"neo4j",
168+
"netsuite",
169+
"netsuite-service-account",
168170
"neverbounce",
169171
"new_relic",
170172
"notion",
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
title: Oracle NetSuite Service Account
3+
description: Configure certificate-based OAuth 2.0 client credentials once and reuse them across NetSuite blocks
4+
---
5+
6+
import { Callout } from 'fumadocs-ui/components/callout'
7+
import { Step, Steps } from 'fumadocs-ui/components/steps'
8+
import { FAQ } from '@/components/ui/faq'
9+
10+
Oracle NetSuite authenticates SuiteTalk machine-to-machine clients with a signed JWT and a certificate mapping. Sim stores the SuiteTalk URL, Client ID, Certificate ID, and private key as one encrypted service-account credential. Every NetSuite block stores only that credential's ID; Sim signs the assertion and injects the short-lived access token on the server.
11+
12+
## Prerequisites
13+
14+
- A dedicated NetSuite integration role with **REST Web Services** and **Log in using OAuth 2.0 Access Tokens**, plus the record and SuiteAnalytics permissions your workflows require.
15+
- An integration record with **Client Credentials (Machine to Machine) Grant** and the **REST Web Services** scope enabled.
16+
- A 3072- or 4096-bit RSA key pair, or a P-256, P-384, or P-521 EC key pair, and a public certificate generated through your organization's certificate process.
17+
- Access to **OAuth 2.0 Client Credentials (M2M) Setup** and **Company URLs** in the target NetSuite environment.
18+
19+
<Callout type="warn">
20+
Create and map credentials separately in production, sandbox, and Release Preview. A sandbox refresh removes its OAuth 2.0 client-credential mappings, and each environment has a different authoritative SuiteTalk URL.
21+
</Callout>
22+
23+
## Configure NetSuite
24+
25+
<Steps>
26+
<Step>
27+
In **Setup → Company → Enable Features**, enable **REST Web Services** and **OAuth 2.0**. Enable **SuiteAnalytics Workbook** if workflows will use datasets.
28+
</Step>
29+
<Step>
30+
Create a dedicated integration role and grant only the record, transaction, subsidiary, and analytics permissions the workflows need. Avoid using Administrator.
31+
</Step>
32+
<Step>
33+
Under **Setup → Integration → Manage Integrations**, create or edit an integration, enable the machine-to-machine client-credentials grant and REST Web Services scope, then save its **Client ID**.
34+
</Step>
35+
<Step>
36+
Upload only the public certificate under **OAuth 2.0 Client Credentials (M2M) Setup**. Map it to the integration, entity, and dedicated role, then save the generated **Certificate ID**. Keep the private key outside NetSuite.
37+
</Step>
38+
<Step>
39+
Under **Setup → Company → Company Information → Company URLs**, copy the complete **SuiteTalk (SOAP and REST Web Services)** URL for this environment.
40+
</Step>
41+
</Steps>
42+
43+
Oracle documents the [role setup](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_157771510070.html), [integration record](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_157771733782.html), [certificate requirements](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/subsect_162755332391.html), and [client-credential mapping](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_162686838198.html).
44+
45+
## Add the Credential to Sim
46+
47+
<Steps>
48+
<Step>
49+
Add an **Oracle NetSuite** block to a workflow and open the **NetSuite Account** dropdown.
50+
</Step>
51+
<Step>
52+
Choose to add a credential, then enter the authoritative SuiteTalk URL, Client ID, Certificate ID, and PEM private key that matches the uploaded certificate.
53+
</Step>
54+
<Step>
55+
Save the credential. Sim validates the URL and key policy, signs a client assertion, and performs a real token exchange before storing the encrypted credential.
56+
</Step>
57+
</Steps>
58+
59+
The private key is encrypted at rest and is never returned through the token endpoint or injected into a workflow tool. At execution time, Sim resolves the selected credential to a short-lived bearer token and the normalized SuiteTalk origin.
60+
61+
## Use Pickers and Manual Values
62+
63+
Selecting the credential enables these account-backed fields:
64+
65+
| Field | Lists | Additional scope |
66+
| --- | --- | --- |
67+
| Record Type | Up to 1,000 record types visible in the metadata catalog | credential |
68+
| Async Task | Up to 100 tasks belonging to a known batch job | job ID |
69+
70+
Picker results reflect the selected role's permissions. Switch any picker to Advanced mode to type an identifier or reference an upstream output. Enter SuiteAnalytics dataset IDs manually after finding them with **List SuiteAnalytics Datasets**. Record IDs, job IDs, transform targets, actions, fields, forms, subresources, and relationship IDs also remain manual because NetSuite does not expose bounded universal listings that would make those choices complete and reliable.
71+
72+
**Create Record** without `replace` returns HTTP 204 with no response body; with `replace`, it returns HTTP 201 and the created record object. Both responses expose NetSuite's validated `location`. The `replace` option applies to create and update, not upsert.
73+
74+
## Rotate or Revoke
75+
76+
To rotate a certificate, create and upload the replacement certificate and create its new NetSuite mapping. Then reconnect the existing Sim credential by re-entering all four required fields: SuiteTalk URL, Client ID, the new Certificate ID, and the replacement private key. Reconnecting changes the encrypted credential fingerprint, so later executions mint against the new material.
77+
78+
After confirming workflows succeed, remove the old certificate mapping in NetSuite so the previous certificate can no longer mint tokens. Deleting a Sim credential removes its workflow bindings but does not revoke the corresponding NetSuite certificate mapping.
79+
80+
<FAQ items={[
81+
{ question: "Why can’t I paste the key into each block?", answer: "The signing key is long-lived account material. Keeping it in one encrypted credential avoids duplicating it in workflow state and lets every block reuse the same verified account connection." },
82+
{ question: "Why is my picker empty?", answer: "The pickers use the selected integration role. Confirm that role can access the metadata catalog or async job, then use Advanced mode when you already know an identifier." },
83+
{ question: "Can one credential access production and sandbox?", answer: "No. Each environment has its own SuiteTalk URL and client-certificate mapping. Create one Sim credential per environment." },
84+
{ question: "Why did the credential stop working after a sandbox refresh?", answer: "NetSuite clears OAuth 2.0 client-credential mappings during a sandbox refresh. Recreate the mapping and reconnect the Sim credential with its new Certificate ID." },
85+
{ question: "Does deleting the credential revoke it in NetSuite?", answer: "No. Remove the certificate mapping in NetSuite as well when decommissioning or responding to a compromise." },
86+
]} />

0 commit comments

Comments
 (0)