Companion RESTlet

Chartstone Toolkit

A drop-in NetSuite RESTlet that closes the gap Chartstone’s /script endpoint can’t reach: file-cabinet ops, roles & permissions, custom records and fields of every type, and generic record CRUD — 29 discoverable functions, all behind a single /restlet call.

Why this exists

Chartstone’s /script endpoint is a fantastic ad-hoc shell — but it runs in NetSuite’s “anonymous” execution context where most NS modules aren’t pre-loaded. That’s fine for SuiteQL-style work, but it can’t do customization-record CRUD: creating a custom field with a TEXT, DATE, CURRENCY type (or any of the other 19 field types), creating a custom record type, assigning role permissions — these all depend on validator and formatter functions that NS lazy-loads from modules /script can’t reach. Same operations from /script either crash with field.validateAndFormatFieldValue is not a function or never get past the create step.

The Toolkit RESTlet runs in a real define([…], cb) context with all the modules pre-declared. Same operations work cleanly. Once installed, an AI agent calls it through Chartstone’s /restlet endpoint and gets a single, discoverable dispatch surface for the whole SuiteScript dev workflow.

What it provides — 29 functions

Discovery (3)

File Cabinet (8)

fileDelete is unique to the Toolkit — Tim Dietrich’s original File Cabinet RESTlet doesn’t expose it.

Roles & Employee (5)

Customizations (8)

Generic record CRUD (5)

Install

1. Download the RESTlet

Grab chartstone-toolkit.restlet.js — single file, ~1,000 lines, no dependencies.

2. Upload to your NetSuite File Cabinet

You can drag-and-drop the file into Documents → Files → SuiteScripts via the NetSuite UI, or — if you’ve already got Tim Dietrich’s File Cabinet RESTlet deployed — upload it programmatically:

curl -sS -X POST "http://127.0.0.1:<port>/restlet" \
  -H "Authorization: Bearer <your-secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "scriptId":     "<your-file-cabinet-restlet-script-id>",
    "deploymentId": "<your-file-cabinet-restlet-deploy-id>",
    "method":       "POST",
    "payload": {
      "function":  "fileCreate",
      "name":      "chartstone-toolkit.restlet.js",
      "fileType":  "JAVASCRIPT",
      "encoding":  "UTF-8",
      "folderID":  -15,
      "isOnline":  false,
      "overwrite": true,
      "contents":  "<file contents>"
    }
  }'

3. Register as a Script + Deployment

NS 2026.1 dropped script-record creation via SuiteScript, so this step is manual (~30 seconds):

  1. Customization → Scripting → Scripts → New
  2. Pick the file you just uploaded.
  3. Create Script Record. NS detects @NScriptType Restlet from the JSDoc.
  4. Set Name: Chartstone Toolkit and ID: _chartstone_toolkit_rl.
  5. Save, then go to the Deployments subtab and Deploy Script.
  6. On the deployment form: Title = Chartstone Toolkit — Deployment 1; ID = _chartstone_toolkit_dep1; Status = Released; Audience = Roles → Administrator only (recommended); Log Level = Debug (move to Error after stable).
  7. Save.
  8. Note the script + deployment internal IDs from the URL: script=NNNN&deploy=N.

4. Tell your AI agent the IDs

Drop the two IDs into your CLAUDE.md (or whatever memory your agent reads). After that, calls go through Chartstone’s /restlet endpoint:

curl -sS -X POST "http://127.0.0.1:<port>/restlet" \
  -H "Authorization: Bearer <your-secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "scriptId":     "<toolkit-script-id>",
    "deploymentId": "<toolkit-deploy-id>",
    "method":       "POST",
    "payload": { "function": "<name>", ...args... }
  }'

Examples

Create a TEXT field on Customer

{
  "function":    "customFieldCreate",
  "fieldFamily": "entity",
  "label":       "Loyalty Tier",
  "scriptid":    "loyalty_tier",
  "fieldtype":   "TEXT",
  "appliesTo":   ["customer"]
}

Create a CURRENCY field on Sales Orders + Invoices

{
  "function":    "customFieldCreate",
  "fieldFamily": "body",
  "label":       "Negotiated Discount",
  "scriptid":    "neg_discount",
  "fieldtype":   "CURRENCY",
  "appliesTo":   ["salesorder", "invoice"]
}

Set a role permission

{
  "function": "rolePermissionSet",
  "roleId":   2088,
  "permkey":  "TRAN_SALESORD",
  "level":    "FULL"
}

Create a custom list with values

{
  "function": "customListCreate",
  "name":     "Priority Levels",
  "scriptid": "priority_levels",
  "values": [
    { "value": "Low" },
    { "value": "Medium" },
    { "value": "High" }
  ]
}

Discovery

The toolkit is self-documenting. Three discovery calls let an agent reflect on what’s available without you naming functions in advance:

# Service info + full function catalog
{ "function": "meta" }

# Per-function documentation
{ "function": "help", "name": "customFieldCreate" }

# All function docs at once
{ "function": "help" }

Response envelope

Success and error responses follow a stable envelope so callers can branch on a single key:

// success
{ "function": "<name>", "version": "0.1.0", ...result fields... }

// error
{
  "function":  "<name>",
  "version":   "0.1.0",
  "error":     "human-readable message",
  "errorCode": "MACHINE_CODE",
  "detail":    { /* optional context */ }
}

ScriptID prefix normalization

NetSuite auto-prefixes script IDs without a separator. The Toolkit normalizes whatever the caller provides so agents don’t have to remember the rules:

You passStored as
customrecord_my_thingcustomrecord_my_thing
_my_thingcustomrecord_my_thing
my_thingcustomrecord_my_thing

Same convention for customlist_*, custentity_*, custbody_*, custcol_*, custitem_*, custevent_*, custrecord_* (Other Fields).

Permissions required

The caller must have, at minimum:

Administrator covers all of them. The recommended deployment audience is Administrator only — this is a power tool.

Limitations

 Download chartstone-toolkit.restlet.js