NetSuite integration mapping
Connection & authentication
- API used: SuiteQL (NetSuite's SQL query language), exposed via a single REST endpoint:
POST https://{account_id}.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql
- Authentication: OAuth 2.0 Machine-to-Machine (M2M), via a JWT assertion signed in ES256 (grant_type=client_credentials). There is no interactive OAuth flow on the user side.
- Token endpoint:
https://{account_id}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token - Request headers:
Authorization: Bearer <token>andPrefer: transient. - On a
401response, the token is automatically regenerated and the request is replayed once; on failure, anInvalidCredentialserror is raised. - Prerequisites on the NetSuite side:
- Enable the REST Web Services and OAuth 2.0 features.
- A role with read rights on
customer,item,transaction,transactionLine,currency,classification, and any custom records, as well as access to REST Web Services / SuiteQL.
Setting up the connection
The connection is machine-to-machine: you register Fincome as a trusted application in your NetSuite account, then you enter three identifiers in Fincome. The signing private key never leaves Fincome — you only import the Fincome public certificate.
- Create the integration record.
Setup ▸ Integration ▸ Manage Integrations ▸ New. Check all the boxes Token-Based Authentication, OAuth 2.0, and Client Credentials (Machine to Machine) Grant, save, then note the Client ID (Consumer Key).
2. Upload the Fincome certificate.
Download the Fincome public certificate: https://fincome-public-assets.s3.eu-west-3.amazonaws.com/netsuite/fincome-netsuite.pem
Then go to Setup ▸ Integration ▸ OAuth 2.0 Client Credentials (M2M) Setup ▸ New: select the integration from step 1, import the certificate and attach it to an entity and a role with REST Web Services / SuiteQL rights (see prerequisites). Note the returned Certificate ID.
3. Fill in Fincome.
In Fincome, open the NetSuite connector and enter your Account ID (Setup ▸ Company ▸ Company Information), your Client ID (step 1), and your Certificate ID (step 2). Optionally, indicate the IDs of your custom revenue recognition fields and your recurring revenue category(ies).
Synchronized objects
The connector processes five flows, in this order:
Flow | NetSuite source | Fincome objects created | Filter condition |
|---|---|---|---|
customer |
| Customer | none (full sync) |
product |
| Product + Price | none |
subscription |
| Subscription |
|
invoice |
| Invoice + InvoiceLineItem |
|
credit_note |
| Invoice + InvoiceLineItem |
|
Field mapping
Customers (customer)
NetSuite field | Fincome field | Note |
|---|---|---|
id | original_id | |
entitytitle | name | |
toplevelparent | root_parent_id | Only set if |
Products & prices (product)
From the item table, the connector creates a Product and a Price:
NetSuite field | Fincome field (Product) |
|---|---|
id | original_id |
itemid | name |
NetSuite field | Fincome field (Price) |
|---|---|
id | original_id |
id | product_id (foreign key to Product) |
itemid | name |
itemrevenuecategory | type → |
Invoices (invoice)
Header (Invoice):
NetSuite field | Fincome field | Note |
|---|---|---|
id | original_id | |
tranId | invoice_number | |
entity | customer_id | foreign key to Customer |
tranDate | date | DD/MM/YYYY format; if absent, the invoice is ignored |
status | status | mapped via the |
Lines (InvoiceLineItem):
NetSuite field | Fincome field | Note |
|---|---|---|
original_id (combined with the invoice id) | ||
— | invoice_id | foreign key to Invoice (line ignored if the invoice is absent) |
itemrevenuecategory + period dates | type |
|
creditforeignamount / debitforeignamount | amount_excluding_tax_after_discount | see § Amounts |
— | tax_amount | always 0 (tax lines excluded) |
quantity | quantity | transformed into |
currency.symbol | currency_code | |
transactionLine.memo | description | |
custcol_iw_rr_start_date | period_start | revenue recognition start date |
custcol_iw_rr_end_date | period_end | +1 day (NetSuite bounds the end inclusively) |
item | price_id | foreign key to Price |
Custom dimensions (custom_axis_field):
NetSuite record | Fincome field |
|---|---|
CUSTOMLIST_IW_CONTRACT_TYPE.name | contract_type |
CUSTOMRECORD_CSEG_IW_CA_COUNTRY.name | country_name |
class |
Subscriptions (subscription)
NetSuite field | Fincome field | Note |
|---|---|---|
id (+ line id) | original_id | combined identifier |
id (transaction) | subscription_set_id | groups the lines of the same |
entity | customer_id | foreign key to Customer |
custcol_iw_rr_start_date | subscription_start_date | |
line amount ÷ number of months of the period | monthly_value | partial months are calculated pro rata |
— | monthly_value_main |
|
Credit notes (credit_note)
Identical structure to invoices, with three differences:
- source =
creditmemotransactions (and notsalesorder); - status mapped via the
creditmemotable (see § Status mapping); original_id= the credit note's own id (it is not a link to an original invoice).
Status mapping
The statuses depend on the source record type.
Sales orders (salesorder) → used for invoices
NetSuite code | NetSuite label | Fincome status |
|---|---|---|
A | Pending Approval | pending |
B | Pending Fulfillment | open |
C | Cancelled | ignored |
D | Partially Fulfilled | open |
E | Pending Billing/Part. Fulf. | open |
F | Pending Billing | open |
G | Billed | open |
H | Closed | ignored |
Y | Undefined | ignored |
Credit notes (creditmemo)
NetSuite code | NetSuite label | Fincome status |
|---|---|---|
A | Open | open |
B | Fully Applied | paid |
C | Undefined | ignored |
D | Voided | ignored |
A record moved to an ignored status (canceled/closed order, voided credit note…) is marked as deleted on the Fincome side during the next sync.
Amounts, quantities, dates & currencies
- Amounts. NetSuite splits each line into two accounting legs. The connector reads the amounts in foreign currency:
creditforeignamount→ positive amount;- otherwise
debitforeignamount→ negative amount (-1 ×). - The
netamountfield is not used. - Quantities. Inverted and rounded up:
-1 × ceil(quantity). - Dates. Expected format DD/MM/YYYY. Period end dates (
period_end) are shifted by +1 day. - Currencies. Amounts are expressed in the transaction's currency (
*foreignamount). They are converted into the company's base currency at the transaction-date rate (*_mainfields). Note: for subscriptions, this date is in the future (tranDate > today), so the conversion uses the exchange rate associated with that future date.
Incremental synchronization & pagination
- Pagination: by
limit(1000) andoffseton SuiteQL. - Cursor:
{ offset, last_modified_date }. Once a flow is exhausted (hasMore = false),offsetresets to 0 andlast_modified_dateadvances to the start date of the last sync. - Last modification field:
- customer →
lastmodifieddate; - subscription / invoice / credit_note →
t.lastmodifieddate. - Deletions. Permanent deletions on the NetSuite side are not propagated: a deleted record simply stops appearing, without being removed from Fincome. However, a record moved to an ignored status (see § Status mapping) is marked as deleted.
Required custom fields & records
These elements must exist in the NetSuite instance for a complete mapping:
Element | Fincome usage |
|---|---|
custcol_iw_rr_start_date | period start (period_start, subscription_start_date) |
custcol_iw_rr_end_date | period end (period_end) |
CUSTOMLIST_IW_CONTRACT_TYPE | contract_type custom dimension |
CUSTOMRECORD_CSEG_IW_CA_COUNTRY | country_name custom dimension |
Updated on: 03/07/2026
Thank you!
