Overview
Spendflo’s comprehensive spend summary and data allows organizations to compare actual expenses incurred against the planned or contracted expenses, providing insight into any deviations that may be present. This information can be used to renegotiate contracts or downgrade existing ones to save costs. To make this process seamless, Spendflo integrates with a number of finance tools.
With this, we help companies uncover Shadow IT by scanning expense data to identify spend on unsanctioned apps before they proliferate. This feature allows businesses to consolidate opportunities where multiple teams are paying for the same app, saving costs and increasing efficiency.
Lastly, Spendflo helps identify paid applications that are under-utilized or no longer in use, allowing companies to stop paying for subscriptions that they don't need. By doing so, they can save costs and optimize their SaaS inventory.
Spendflo integrates with Netsuite and analyzes your organization's SaaS expenses. Spendflo will automatically match transactions to the correct application, summarize expenses and provide insights. This guide follows step by step process on how you can install the integration and gain its maximum benefits.
Prerequisites
This documentation contains the detailed steps to know how to directly integrate with the Netsuite ERP to support vendor management within the Spendflo platform.
Note: To begin the installation, you must be a Netsuite Administrator.Direct Integration with Netsuite ERP
Step 1. Navigate to Integrations → Finance, then click the dropdown to select the finance integration you want to connect.
Step 2. Open the dropdown under Integrations → Finance and select the NetSuite integration. A modal containing the help documentation will appear—click Connect to initiate the integration.
Step 3. Spendflo now uses Truto to connect your Netsuite account securely. Click on “Continue”.
Step 4. Fill in all necessary details such as API tokens and consumer keys. For help generating these credentials, click on “Where can I find this information?” in the modal.
Additionally, to get assisted on where this information can be found, click on the URL “Where can I find this information?” or simply access it from here.
Note: The detailed steps for the same are provided below. Jump to “Setting Up the Integration on Netsuite” for more information.Click on “Connect” to complete the steps.
Netsuite will now be successfully integrated into the Spendflo platform.
In case a second ERP integration needs to be added, click on the dropdown displayed above Add Finance Integration and repeat the steps mentioned above.
NetSuite Post-Integration – Data Import Steps
Step 1: Select Account Types After Successful Integration
Once NetSuite is successfully integrated, a slider panel will appear prompting you to select the Account Types you want imported into Spendflo.
All account codes linked to the selected account types will be imported automatically.
Step 2: Configure Account Types Later
If you closed the slider or skipped the selection:
Go to Integrations → NetSuite → Edit Configuration
Navigate to the Accounts tab
Click on Configure Account Types
Select the required account types
Spendflo will begin importing all related account codes.
Step 3: Allow Time for the Import to Complete
Once account types are selected, Spendflo will take a few minutes to fetch and import all associated account data into the platform.
Step 4: All Other ERP Attributes Are Fully Imported
Apart from accounts, all other ERP attributes available in the user’s NetSuite instance will be imported into Spendflo in full, irrespective of the account type selection.
This includes:
Vendors
Items
Departments
Subsidiaries
Locations
Classes
Everything that exists in NetSuite for these categories will be dumped into the platform.
Step 5: View Imported Data Inside Integration Tabs
After the import completes, users can view all accounts, vendors, departments, subsidiaries, items, and other ERP data inside their respective Integration tabs in Spendflo.
Step 6: Configure the “Show to User” Toggle
Each imported ERP attribute includes a Show to User toggle (enabled by default).
When ON → The attribute appears in the request flow/intake form
When OFF → The attribute is hidden from intake forms but remains in the system
Use this to control what appears to end-users.
Step 7: Allow Daily Sync for New Data
Spendflo performs a daily sync to automatically bring in any new attributes created in NetSuite.
Step 8: Use On-Demand Sync When Needed
A Sync Now button is available within the integration.
Use this anytime to instantly pull newly created or updated ERP data without waiting for the daily sync.
Setting Up the Integration on Netsuite
Step 1. Retrieving Netsuite Account ID
Step 2. Log into your Netsuite portal.
Step 3. Find the URL at the top of your browser.
Step 4. Your Netsuite Account ID is the combination of letters or numbers in your URL before "app.netsuite.com/app/center/card.nl?sc=-29&whence=".
Step 4. Therefore, if the URL on your Netsuite page is https://123432345.app.netsuite.com/app/center/card.nl?sc=-29&whence=.
Step 5. Your Account ID is 123432345. Copy the account ID and keep it; we'll need it in the next steps.
Enable Web Services
If you have not yet enabled REST and SOAP Web Services:
Step 1. In your Netsuite account, go to Setup > Company > Enable Features.
Note: You must be an Administrator of your Netsuite account to see this option.
Step 2. Under SuiteCloud, check the boxes next to SOAP WEB SERVICES and REST WEB SERVICES.
Setup a Role with All Transactions and Setup Permissions
If you do not have a user role already created, then follow the below step -
Note: If you know that you already have a user role with access to all transactions (all setup permissions below must be selected with full access), you can skip these steps. To check, go to Setup, Users/Roles, Manage Roles, and search through your user roles.Step 1. In your Netsuite account, go to Setup, Users/Roles, Manage Roles, and click the New option. You must be an Administrator of your Netsuite account to see this option.

Note: The above step is for a new role creation. You can also ensure to follow the same step by clicking on "Search" to find an existing role within the platform.Step 2. Create a Role by clicking the New Role button.
Step 3. If you have a Multi Subsidiary NetSuite application, ensure the Role has access to all Subsidiaries and has the Allow Cross-Subsidiary Record Viewing box checked.
Step 4. Add each of the below permissions to the Role.
In Transactions, add each of the below permissions:

In Setup, add each of the below permissions:
Setup Custom Segment Permissions
If you want to add custom segments, and have to manage PO, then follow these steps:
Step 1. In NetSuite, go to Setup → User/Roles → Manage Roles page and assign the needed access permissions in the Permission → Setup tab
Add the Custom Segments with Full access.
Add the Custom Record Types with Full access.
Note: Kindly ensure that the level access should be set as Full for both added permissions.Step 2. You can add the records you need on the Role editing page in the Permissions → Custom Record tab. Scroll to the Records column select the necessary Custom Segment option from the drop-down list and set the level access to Full.

Step 3. In Netsuite, go to Customization → Lists, Records, & Fields → Custom Segments and update the Default Record Access Level to Edit permissions for the necessary segments.


In Lists, add each of the below permissions:
In Reports, add each of the below permissions:
Step 5. Click Save.
Assign User to Token-based Authentication Role
Step 1. In setup, go to Users/Roles, and click Manage Users.
Step 2. In Manage Users, either select a user to assign the Role to or create a new user.
Go to Lists > Employees > Employees > New to create a new user. Create the user and grant them NetSuite access by going to the Access tab in the Employee record and select 'Give Access'.
Step 3. In the user's employee record, click Edit and go to the Access tab. In your Access tab, go to Roles and select the Role you just created with all the correct transactions and setup permissions.

Step 4. Click save to apply these changes.
Disclaimer: Cost for new user; you don't need to pay extra for new users as long as you have sufficient licenses available.Follow these steps to check:
Step 1. Navigate to Setup → Company → View Billing Information.
Step 2. Locate the Full Licensed Users section.
Step 3. Compare the following values:
Current Provision Qty: Total number of licenses provisioned.
Current Used Qty: Number of licenses currently in use.
Note:
1. If Current Used Qty equals Current Provision Qty, you cannot create a new employee without acquiring additional licenses.
2. If Current Used Qty is less than Current Provision Qty, you can proceed to create a new employee in the system.
Create an integration to obtain your Consumer Key and Secret
Step 1. Once the user and the role are set up, go to integrations manage integrations in your setup tab and click new.
Step 2. Create the integration. Select the boxes selected below.
Note: Ideally, the CONCURRENCY LIMIT should be set to null. If a value must be specified, the minimum value set should be 3. If neither is an option, the highest possible concurrency limit should be used.
Step 3. Ensure the REST WEB SERVICES box is checked under SCOPE
Step 4. Fill in the TBA AUTHORIZATION FLOW & REDIRECT URI with a value of https://api.truto.one/connect/netsuite/callback
Step 5. Once the integration is saved, you will receive a Consumer Key and Consumer Secret (at the bottom of the confirmation screen). This will only be shown once, so copy them and keep them in a secure place.

Create an Access Token to Obtain your Token ID and Secret
Step 1. In your Setup tab, go to Users/Roles, then Access Tokens and Create a New one.
Step 2. Create a New Access Token with the User Role you either just created or a user role with all permissions above selected.

Steps to add deployment script in the Netsuite account
Step 1. Follow the steps mentioned in this article to add the deployment script Quick guide to adding and deploying a script in Netsuite - Suite Tooth Consulting (paste the deployment script mentioned below in a notepad file and save it with .js extension).
Deployment Script:
/**
* @NApiVersion 2.1
* @NScriptType Suitelet
*/
define(['N/record', 'N/render', 'N/log'], function (record, render) {
function onRequest(context) {
if (context.request.method === 'GET') {
var entity = context.request.parameters.entity
var fieldQuery = context.request.parameters.fields
var fieldsParam = fieldQuery ? fieldQuery.split(',') : []
var defaultValuesQuery = context.request.parameters.defaultValues
var defaultValues = defaultValuesQuery
? JSON.parse(defaultValuesQuery)
: {}
log.debug({
title: 'Before try',
details: 'Entity: ' + entity + 'Entity ID: ' + context.request.parameters.id
});
try {
// Create a dummy Purchase Order record with the specified custom form
if (entity != 'purchase_order_download') {
var poRecord = record.create({
type: record.Type.PURCHASE_ORDER,
isDynamic: true,
defaultValues: defaultValues,
})
var fields = []
}
if (entity == 'purchase_order_expense') {
const fieldIds = poRecord.getSublistFields({
sublistId: 'expense',
})
fieldIds.forEach(function (fieldId) {
if (fieldsParam.length && !fieldsParam.includes(fieldId)) {
return
}
var field = poRecord.getSublistField({
sublistId: 'expense',
fieldId: fieldId,
line: 0,
})
let selectOptions = []
try {
selectOptions = field.getSelectOptions()
} catch (err) {
selectOptions = []
}
if (field && field.isDisplay) {
fields.push({
id: fieldId,
label: field.label,
type: field.type,
isMandatory: field.isMandatory,
isDisplay: field.isDisplay,
options: selectOptions,
})
}
})
} else if (entity == 'purchase_order_item') {
const fieldIds = poRecord.getSublistFields({
sublistId: 'item',
})
fieldIds.forEach(function (fieldId) {
if (fieldsParam.length && !fieldsParam.includes(fieldId)) {
return
}
var field = poRecord.getSublistField({
sublistId: 'item',
fieldId: fieldId,
line: 0,
})
let selectOptions = []
try {
selectOptions = field.getSelectOptions()
} catch (err) {
selectOptions = []
}
if (field && field.isDisplay) {
fields.push({
id: fieldId,
label: field.label,
type: field.type,
isMandatory: field.isMandatory,
isDisplay: field.isDisplay,
options: selectOptions,
})
}
})
} else if (entity == 'purchase_order_download') {
const poId = context.request.parameters.id
log.debug({
title: 'Before: IF entity download',
details: 'PO ID: ' + poId
});
if (!poId) {
context.response.write({
output: 'Missing Purchase Order ID parameter.',
})
return
}
log.debug({
title: 'After: IF entity download',
details: 'PO ID: ' + poId
});
// 2. Generate the PDF file for the Purchase Order using N/render
const pdfFile = render.transaction({
entityId: Number(poId), // internal ID of the Purchase Order
printMode: render.PrintMode.PDF, // ensure the output is PDF (not HTML)
}) // 3. Set response headers for PDF download (Content-Type and optional filename)
log.debug({
title: 'After render',
details: 'PO ID: ' + Number(poId) + 'Mode: ' + render.PrintMode.PDF
});
context.response.setHeader({
name: 'Content-Type',
value: 'application/pdf',
})
context.response.setHeader({
name: 'Content-Disposition',
value: 'attachment; filename="PurchaseOrder_' + poId + '.pdf"',
})
log.debug({
title: 'After set header',
details: 'PO File: ' + pdfFile
});
// 4. Write the PDF file to the response, prompting download
context.response.writeFile({ file: pdfFile, isInline: false })
} else {
// Retrieve all field IDs on the record
var fieldIds = poRecord.getFields()
// Collect field details
fieldIds.forEach(function (fieldId) {
if (fieldsParam.length && !fieldsParam.includes(fieldId)) {
return
}
var field = poRecord.getField({ fieldId: fieldId })
let selectOptions = []
try {
selectOptions = field.getSelectOptions()
} catch (err) {
selectOptions = []
}
if (field && field.isDisplay) {
fields.push({
id: fieldId,
label: field.label,
type: field.type,
isMandatory: field.isMandatory,
isDisplay: field.isDisplay,
options: selectOptions,
})
}
})
}
// Respond with the field details in JSON format
if (entity != 'purchase_order_download') {
context.response.setHeader({
name: 'Content-Type',
value: 'application/json',
})
context.response.write(JSON.stringify(fields))
}
} catch (error) {
// Handle errors (e.g., invalid form ID)
log.debug({
title: 'catch err',
details: error
});
context.response.write('Error: ' + error)
}
}
}
return {
onRequest: onRequest,
}
})Step 2. Once the script is deployed we need to paste the script url in Connect UI screen of Truto while integrating Netsuite in Spendflo:
Go to the customization → scripting → script deployment in Netsuite account.
Click on the view button for the script you deployed.
Copy the URL (this is the script URL that needs to be pasted in Connect UI screen of Truto).
Copy these Access token credentials and store them in a safe place, along with the deployment script and URL. They will only be shown once!
These steps ensure that the Truto integration steps within Spendflo are completed successfully.
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article












