No commit activity in last 3 years
No release in over 3 years
This library provides an interface to NetSuite via'RESTlets'. This appears to be a quicker and more reliableway of interfacing with NetSuite records than the SOAP API.
 Project Readme

Build Status Coverage Status

NSConnector intro ¶ ↑

This library provides an interface to NetSuite via RESTlets, i.e. SuiteScript . This appears to be a quicker and more reliable way of interfacing with NetSuite records than the SOAP API.

How is this different to the other netsuite connector gems out there?

  • Basically, it uses a javascript RESTlet to communicate as opposed to the SOAP API, so it's completely different and exposes a separate API.

  • It's not built around auto generated WSDL which can make it easier to design a usable API.

  • It can be concurrent, so it at least has the potential to scale. You can only make one request at a time per user using the SOAP API.

  • It's quicker. Not sure why, but the SOAP API is horrendously slow sometimes, RESTlets seem to be quicker, for now.

Documentation¶ ↑

Avaliable at

Features¶ ↑

  • No dependencies

  • Read write for supported types

  • Flexible searching

  • Multithreaded chunked searching for retrieving large datasets

  • Read only sublist support.

  • SubList item creation on creating new records only. (>= v0.0.7)

  • Attaching and detaching records

  • Invoice PDF generation.

  • Record transformations.

Supported NetSuite types¶ ↑

It's pretty trivial to add a new one yourself. These have been tested to work:

  • Contact

  • Customer

  • CustomerPayment

  • Invoice

Installation¶ ↑

Install the RESTlet:

function post(request) {
  func = eval(request.code);
  return func(request);

That's the whole RESTlet. Deploy it to NetSuite, ensuring that the POST function is set to 'post'. Note the 'External URL' when deploying it, that is what you will use in the configuration below.

Configuration¶ ↑

The configuration is stored 'globally' via NSConnector::Config#set_config!

An example config:

  :account_id  => '123',
  :email       => 'email@site',
  :password    => "password",
  :role        => '456',
  :restlet_url => 'https://netsuite/restlet',

Options¶ ↑

:account_id (mandatory)¶ ↑

You can find your Account ID by visiting [Web Service Preferences](

:email (mandatory)¶ ↑

The email address you log into the NetSuite web site with that matches the account_id.

:password (mandatory)¶ ↑

Hopefully a secret.

:role (mandatory)¶ ↑

Can be found in your cookie when logged in, or deep within the jungle of the user interface. TODO: Document the perilous journey through the jungle.

:use_threads (optional)¶ ↑

A bool, set to false to turn off threading when retrieving large result sets. By default we try to split these result sets up into manageable chunks. If you turn this off, they will still be split up, but only one chunk will be retrieved at a time.

:no_threads (optional)¶ ↑

An integer, the number of threads to use. By default, 4.

CRUD usage¶ ↑

Every supported type supports full CRUD via the same standard interface Check the SuiteScript Records Browser [1] for avaliable fields.

Creating¶ ↑

To create a record, simply instantiate a new class of that kind and call .save! on it.

Calling .save! will re-load the saved Record from NetSuite with any other changes that NetSuite's internal logic may have made.


include NSConnector

c = => 'name')
=> <#NSConnector::Contact:nil>

=> [fields...]

c.lastname = 'abc'
=> 'abc'!
=> true

=> 'Abc'

SubLists can be added to a record on creation. Here is how that works:

include NSConnector
c = => 'name')
=> {:addressbook=>

c.addressbook << c.new_addressbook_item({
  :addr1 => 'address line 1',
  :city => 'unicorn valley'
=> true

Reading¶ ↑

You can find by any field or by internalId. Example:

include NSConnector

# Search by any internal field ID, returns an array of Contacts
Contact.search_by('entityId', 42)
=> [<#NSConnector::Contact:12>]

# Fetch one Contact by internalId
=> <#NSConnector::Contact:12>

# Fetch one Customer by entityid
Customer.find_by('entityid', 1234)
=> <#NSConnector::Contact:12>

# Fetch all Contacts, this will take a while. (Request will be broken
# up into smaller ones and spread across multiple threads).
=> [rather large array of NSConnector::Contact]

You can also perform more complex searces. Example:

  ['email', 'contains', '@'],
  ['entityId', 'lessthanorequalto', '1000']
=> [<#NSConnector::Contact:12>, <#NS...]

At any time you can check which fields are avaliable in both the class and instances:


You can also access the raw data store to more easily see what the object contains with:


SubLists¶ ↑

SubLists are exposed differently by the backend API, but that's pretty transparent to us, simply access them as a read only array:

You can see which sublists are avaliable to an object via the sublists accessor:


Updating¶ ↑

Updating records is much like creating new ones. Simply:

  1. Grab the record (see Reading).

c = Contact.find(12)
  1. Update the record to your liking.

c.lastname = 'newname'
  1. Save the record (see Creating)!
=> true

Deleting¶ ↑

Deletion can be done by ID or Record. Example:

  1. By ID

=> true
  1. By Record

c = Contact.find(42)

Record transformations¶ ↑

You can transform records into other records as per the supported transformation types in NetSuite [2]


Invoice.find(2106).transform!(CustomerPayment) do |payment|
  payment.ccnumber = '4222222222222'
=> {"id"=>"2107",
"applied"=>"99.99" ...

Attaching records¶ ↑

You can attach/detach records with #attach! and #detach!, it's pretty simple.

# Attach customer 123 to contacts 1, 2 and 3 with the role of 1
Customer.find(123).attach!(Contact, [1,2,3], :role => 1)

# Or anonymously like:
Customer.attach!(Contact, 123, [1,2,3], :role => 1)

Troubleshooting note:¶ ↑

Should you run into an error something like:

NSConnector::Restlet::RuntimeError: Failed to parse response from Restlet as JSON (): A JSON text must at least contain two octets!

It may just be that your user is being denied access, in which case netsuite seems to believes it is a good idea to simply send a blank response.

Development notes¶ ↑

See HACKING in the repo

License¶ ↑


References¶ ↑


SuiteScript Records Browser


Supported Transformation Types