Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The NetSuite Pro

The NetSuite Pro Logo The NetSuite Pro Logo

The NetSuite Pro Navigation

  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • Advanced PDF Templates in NetSuite
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask A Question
  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • Advanced PDF Templates in NetSuite
  • Blog
  • Contact Us
Home/ NetSuite Scripting/Handling JSON & XML in Scripts (SuiteScript 2.1)

Handling JSON & XML in Scripts (SuiteScript 2.1)

🔹 Why this matters

Most real-world NetSuite automations integrate with other systems. Those systems usually speak JSON (modern REST APIs) or XML (legacy/EDI/fintech). You’ll need to:

  • Parse incoming payloads safely
  • Validate required fields
  • Transform NetSuite records → JSON/XML
  • Call external endpoints (send/receive)
  • Store payloads in File Cabinet for audit/debug

🔹 JSON Essentials (parse, build, validate)

Example 1 — Parse incoming JSON (RESTlet) and validate

/**
 * @NApiVersion 2.1
 * @NScriptType Restlet
 */
define(['N/record'], (record) => {
  // POST /restlet   body = { entityid, email? }
  const post = (body) => {
    try {
      // 1) Body is already an object for RESTlets (SuiteScript parses JSON for you)
      //    Still validate its shape!
      const entityid = (body?.entityid || '').trim();
      const email    = (body?.email || '').trim();

      if (!entityid) {
        return { ok: false, error: 'entityid is required' };
      }

      // 2) Create a Customer using validated fields
      const rec = record.create({ type: record.Type.CUSTOMER, isDynamic: true });
      rec.setValue({ fieldId: 'entityid', value: entityid });
      if (email) rec.setValue({ fieldId: 'email', value: email });

      const id = rec.save();
      return { ok: true, id };
    } catch (e) {
      // Always log internal details; return a safe error to the caller
      log.error('RESTlet JSON parse/validate error', JSON.stringify(e));
      return { ok: false, error: e.message || 'Invalid JSON or business rules failed' };
    }
  };
  return { post };
});

What to notice

  • RESTlets already parse JSON into an object (body), but you must validate fields.
  • Return a consistent envelope: { ok, data?, error? }.

Example 2 — Build JSON from a search (Scheduled Script)

/**
 * @NApiVersion 2.1
 * @NScriptType ScheduledScript
 */
define(['N/search', 'N/file'], (search, file) => {
  const execute = () => {
    try {
      // 1) Collect a small batch of customers
      const results = search.create({
        type: search.Type.CUSTOMER,
        filters: [['isinactive', 'is', 'F']],
        columns: ['internalid', 'entityid', 'email']
      }).run().getRange({ start: 0, end: 10 });

      // 2) Transform rows → array of plain objects
      const payload = results.map(r => ({
        id: r.id,
        entityid: r.getValue('entityid'),
        email: r.getValue('email') || null
      }));

      // 3) Stringify with indentation for readability (audit/debug)
      const json = JSON.stringify({ customers: payload }, null, 2);

      // 4) Save to File Cabinet (optional, great for auditing integrations)
      const f = file.create({
        name: `customers_${Date.now()}.json`,
        fileType: file.Type.JSON,
        contents: json
      });
      // f.folder = <your folder id>
      const fileId = f.save();

      log.debug('JSON built & saved', `File Cabinet ID: ${fileId}`);
    } catch (e) {
      log.error('Build JSON error', e.message);
    }
  };
  return { execute };
});

Pro tip: For large result sets, move to Map/Reduce and stream results into chunks.


Example 3 — Call external JSON API and parse response

/**
 * @NApiVersion 2.1
 * @NScriptType ScheduledScript
 */
define(['N/https', 'N/runtime'], (https, runtime) => {
  const execute = () => {
    try {
      // 1) Read endpoint/key from parameters (never hardcode secrets)
      const script = runtime.getCurrentScript();
      const endpoint = script.getParameter({ name: 'custscript_ext_api_url' });
      const apiKey   = script.getParameter({ name: 'custscript_ext_api_key' });

      // 2) Make request
      const resp = https.get({
        url: endpoint,
        headers: {
          'Accept': 'application/json',
          'Authorization': `Bearer ${apiKey}`
        }
      });

      // 3) Parse safely
      let data;
      try {
        data = JSON.parse(resp.body);
      } catch (e) {
        throw new Error(`Response was not valid JSON (status ${resp.code})`);
      }

      // 4) Validate the shape you expect
      if (!Array.isArray(data?.items)) {
        throw new Error('Invalid payload: "items" array not found');
      }

      log.debug('External items received', data.items.length);
      // ... process items ...
    } catch (e) {
      log.error('External JSON API error', e.message);
    }
  };
  return { execute };
});

Key ideas

  • Never assume response is valid JSON: wrap JSON.parse in try–catch.
  • Validate the expected shape (e.g., must include items array).

🔹 XML Essentials (generate, consume)

Some partners still require XML payloads. You can:

  • Build XML strings (simple cases).
  • Parse basic XML using simple string techniques if the structure is trivial.
  • For complex XML/XPath needs, prefer a robust parser/validator (and confirm the exact N/xml APIs available in your account build).

Tip: Regardless of approach, always escape special characters in data you place inside XML (& < > " ').

Utility — minimal XML escaper

function xmlEscape(s='') {
  return String(s)
    .replace(/&/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"')
    .replace(/'/g, ''');
}

Example 4 — Build a simple XML document to send

/**
 * @NApiVersion 2.1
 * @NScriptType ScheduledScript
 */
define(['N/https', 'N/runtime'], (https, runtime) => {
  const execute = () => {
    try {
      const script = runtime.getCurrentScript();
      const endpoint = script.getParameter({ name: 'custscript_xml_endpoint' });
      const apiKey   = script.getParameter({ name: 'custscript_xml_api_key' });

      // 1) Build an order XML (very simple example)
      const order = {
        id: 'SO1001',
        customer: 'ACME & Co.',
        total: 250.75
      };

      // 2) Escape all dynamic values!
      const xml = [
        '<?xml version="1.0" encoding="UTF-8"?>',
        '<Order>',
        `  <Id>${xmlEscape(order.id)}</Id>`,
        `  <Customer>${xmlEscape(order.customer)}</Customer>`,
        `  <Total>${order.total}</Total>`,
        '</Order>'
      ].join('\n');

      // 3) POST it
      const resp = https.post({
        url: endpoint,
        headers: {
          'Content-Type': 'application/xml',
          'Authorization': `Bearer ${apiKey}`
        },
        body: xml
      });

      if (resp.code < 200 || resp.code >= 300) {
        throw new Error(`XML endpoint returned ${resp.code}: ${resp.body}`);
      }

      log.debug('XML sent successfully', `Status ${resp.code}`);
    } catch (e) {
      log.error('Send XML error', e.message);
    }
  };
  return { execute };
});

What to notice

  • We escaped dynamic values to keep XML well-formed.
  • Some partners require specific namespaces/schemas—follow their spec.

Example 5 — Parse a known simple XML response

If the response format is simple and predictable, you can extract values with lightweight string techniques. (For complex XML, use a full parser and XPath per your account’s available APIs.)

/**
 * @NApiVersion 2.1
 * @NScriptType ScheduledScript
 */
define(['N/https', 'N/runtime'], (https, runtime) => {
  const execute = () => {
    try {
      const script = runtime.getCurrentScript();
      const endpoint = script.getParameter({ name: 'custscript_xml_status_url' });
      const apiKey   = script.getParameter({ name: 'custscript_xml_api_key' });

      // 1) Call partner status endpoint (returns a tiny XML like: <Status><Code>OK</Code><Message>...</Message></Status>)
      const resp = https.get({
        url: endpoint,
        headers: {
          'Accept': 'application/xml',
          'Authorization': `Bearer ${apiKey}`
        }
      });

      const xml = resp.body;

      // 2) Super-light extraction (ONLY if structure is tiny and stable)
      const codeMatch = xml.match(/<Code>([^<]+)<\/Code>/i);
      const msgMatch  = xml.match(/<Message>([^<]+)<\/Message>/i);

      const code = codeMatch ? codeMatch[1] : null;
      const msg  = msgMatch ? msgMatch[1] : null;

      if (!code) throw new Error('Missing <Code> in XML response');

      log.debug('XML status parsed', `Code=${code} | Message=${msg || ''}`);
    } catch (e) {
      log.error('Parse XML error', e.message);
    }
  };
  return { execute };
});

Notes

  • This lightweight parsing works only for tiny, stable payloads.
  • For nested/variable XML, use a proper parser and XPath and validate against the partner’s XSD if provided.

🔹 JSON ⇄ XML transformations

Typical flows:

  • NetSuite → Partner (XML): build XML from NetSuite data; send via HTTPS or SFTP (see your SFTP page).
  • Partner → NetSuite (XML): download XML (SFTP/HTTP), parse, then upsert records.
  • Consider staging files (File Cabinet), and keeping audit copies (saved JSON/XML) for reconciliation.

🔹 Storing payloads for audit

/**
 * Store request/response safely for troubleshooting (avoid secrets).
 */
function savePayload(fileModule, name, mimeType, contents, folderId) {
  try {
    const f = fileModule.create({ name, fileType: mimeType, contents });
    if (folderId) f.folder = folderId;
    return f.save();
  } catch (e) {
    log.error('Save payload error', e.message);
    return null;
  }
}
  • Use file.Type.JSON or file.Type.PLAINTEXT for XML.
  • Do not store secrets; redact tokens before saving.

🔹 Error handling & contracts

  • Always wrap JSON.parse in try–catch.
  • For XML, escape your dynamic values; validate partner responses.
  • Use a consistent envelope in RESTlets: { ok, data?, error? }.
  • Log context (endpoint, IDs, counts) but never log secrets.

🔹 Performance & governance tips

  • Prefer submitFields() over full load + save when updating records after parsing payloads.
  • For large imports/exports, use Map/Reduce and batch by 100–1000 items.
  • For huge XML files, consider SFTP + incremental processing (stream or chunk).

✅ Key Takeaway

  • JSON: use JSON.stringify/parse, validate shapes, keep contracts consistent.
  • XML: escape dynamic values, follow partner schemas, use a proper parser for complex docs.
  • Persist payloads (without secrets) for audit, and scale heavy jobs with Map/Reduce.
Share
  • Facebook

Sidebar

Ask A Question

Stats

  • Questions 6
  • Answers 6
  • Best Answers 0
  • Users 2
  • Popular
  • Answers
  • Rocky

    Issue in running a client script in NetSuite SuiteScript 2.0 ...

    • 1 Answer
  • admin

    How can I send an email with an attachment in ...

    • 1 Answer
  • admin

    How do I avoid SSS_USAGE_LIMIT_EXCEEDED in a Map/Reduce script?

    • 1 Answer
  • admin
    admin added an answer The issue is usually caused by following Wrong script file… September 14, 2025 at 10:33 pm
  • admin
    admin added an answer Steps to send an Invoice PDF by email: define(['N/email', 'N/render',… August 28, 2025 at 3:05 am
  • admin
    admin added an answer This error means your script hit NetSuite’s governance usage limit… August 28, 2025 at 3:02 am

Top Members

Rocky

Rocky

  • 1 Question
  • 21 Points
Begginer
admin

admin

  • 5 Questions
  • 2 Points

Trending Tags

clientscript netsuite scripting suitescript

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

© 2025 The NetSuite Pro. All Rights Reserved