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
    • NetSuite Customization
    • NetSuite Integration
    • NetSuite Advanced PDF Templates
    • NetSuite Reporting & Analytics Guide
    • Real-World NetSuite Examples
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask A Question
  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • NetSuite Customization
    • NetSuite Integration
    • NetSuite Advanced PDF Templates
    • NetSuite Reporting & Analytics Guide
    • Real-World NetSuite Examples
  • Blog
  • Contact Us
Home/ NetSuite + Slack Integration: The Complete Step-by-Step Guide/Look Up NetSuite Records With a Slack Slash Command

Look Up NetSuite Records With a Slack Slash Command

Part 8 of 13 in the NetSuite + Slack series
Time: 45 minutes  |  Level: Intermediate
You will learn: How to build a /ns command that looks up an order from Slack.
You will need: A sandbox, the signing secret, and a Suitelet you can make available without login.

Imagine a customer service rep is on a call and needs the status of an order. Instead of logging in, searching and clicking through tabs, they type this in Slack:

/ns SO10482

…and a second later, they see the customer, the status, the total and a link to the order. That is a slash command, and it is one of the most loved features of a NetSuite and Slack setup, because it saves small interruptions all day.

How it works

  1. A person types /ns SO10482 in any Slack channel or direct message.
  2. Slack sends the command to a Suitelet URL that you provide.
  3. The Suitelet checks the request is genuinely from Slack, searches NetSuite, and replies with a formatted message.
  4. Only the person who typed the command sees the answer (an “ephemeral” reply), so nothing sensitive is dropped into a public channel.

Part A: Create the command in Slack

  1. Open your app at api.slack.com/apps and choose Slash Commands.
  2. Click Create New Command.
  3. Fill in:
    • Command: /ns
    • Request URL: the external URL of the Suitelet from Part B (you can come back and add it)
    • Short Description: Look up a NetSuite record
    • Usage Hint: SO12345
  4. Save, then Reinstall to Workspace if Slack asks you to (new features often require it).

Make sure the commands scope from Step 1 is in place.

Part B: The Suitelet

Slack’s important rule: it expects an answer within 3 seconds. Keep the lookup light: one search, a few fields, then reply.

/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 *
 * Handles the /ns slash command: looks up a sales order by number.
 */
define(['N/crypto', 'N/encode', 'N/search', 'N/url', 'N/log'],
  (crypto, encode, search, url, log) => {

    // Same signature check as the approvals page.
    const isFromSlack = (request) => {
      const signature = request.headers['X-Slack-Signature'] || request.headers['x-slack-signature'];
      const timestamp = request.headers['X-Slack-Request-Timestamp'] || request.headers['x-slack-request-timestamp'];
      if (!signature || !timestamp) return false;
      if (Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp)) > 300) return false;

      const key = crypto.createSecretKey({ secret: 'custsecret_slack_signing', encoding: encode.Encoding.UTF_8 });
      const hmac = crypto.createHmac({ algorithm: crypto.HashAlg.SHA256, key: key });
      hmac.update({ input: 'v0:' + timestamp + ':' + request.body, inputEncoding: encode.Encoding.UTF_8 });
      return ('v0=' + hmac.digest({ outputEncoding: encode.Encoding.HEX })) === String(signature).toLowerCase();
    };

    const reply = (response, payload) => {
      response.setHeader({ name: 'Content-Type', value: 'application/json' });
      response.write(JSON.stringify(payload));
    };

    const onRequest = (context) => {
      const { request, response } = context;

      try {
        if (request.method !== 'POST' || !isFromSlack(request)) {
          response.write('Unauthorized');
          return;
        }

        // Slack sends slash commands as normal form fields.
        const text = (request.parameters.text || '').trim().toUpperCase();

        if (!text) {
          return reply(response, {
            response_type: 'ephemeral',
            text: 'Try `/ns SO10482` to look up a sales order.'
          });
        }

        // Search for the sales order by its number.
        const results = search.create({
          type: search.Type.SALES_ORDER,
          filters: [
            ['mainline', 'is', 'T'], 'AND',
            ['tranid', 'is', text]
          ],
          columns: ['tranid', 'entity', 'status', 'total', 'shipdate']
        }).run().getRange({ start: 0, end: 1 });

        if (!results.length) {
          return reply(response, {
            response_type: 'ephemeral',
            text: ':mag: I could not find a sales order called *' + text + '*.'
          });
        }

        const r = results[0];
        const domain = url.resolveDomain({ hostType: url.HostType.APPLICATION });
        const link = 'https://' + domain + url.resolveRecord({ recordType: 'salesorder', recordId: r.id });

        return reply(response, {
          response_type: 'ephemeral',
          blocks: [
            { type: 'section', text: { type: 'mrkdwn', text: '*Sales order <' + link + '|' + r.getValue('tranid') + '>*' } },
            {
              type: 'section',
              fields: [
                { type: 'mrkdwn', text: '*Customer*\n' + r.getText('entity') },
                { type: 'mrkdwn', text: '*Status*\n' + r.getText('status') },
                { type: 'mrkdwn', text: '*Total*\n$' + Number(r.getValue('total')).toFixed(2) },
                { type: 'mrkdwn', text: '*Ship date*\n' + (r.getValue('shipdate') || '-') }
              ]
            }
          ]
        });
      } catch (e) {
        log.error('Slash command failed', e.name + ': ' + e.message);
        return reply(response, { response_type: 'ephemeral', text: 'Something went wrong. Please try again in a moment.' });
      }
    };

    return { onRequest };
  });

Deploy the Suitelet

  1. Upload the file and create a script record (Customization > Scripting > Scripts > New).
  2. Create a deployment. Set the status to Released (or Testing while you are developing).
  3. Tick Available Without Login.
  4. Save and copy the External URL.
  5. Paste that URL into the slash command’s Request URL in Slack.

Because this deployment is reachable from the internet, the signature check is essential: it is what keeps out everyone who is not Slack.

Part C: Try it

  1. In Slack, type /ns followed by a real sandbox order number.
  2. You should see a neat card with the order details.
  3. Try a number that does not exist, and an empty /ns, to check the friendly messages.

Important: who is allowed to see what?

The Suitelet runs with the permissions of its owner, so it can see everything that owner can see, even if the Slack user could not see it in NetSuite. That is a real design decision, not a technicality.

Sensible ways to handle it:

  • Keep replies minimal: status, customer name, ship date, link. Leave out margins, costs and personal data.
  • Restrict who can use it. Match the Slack user’s email to a NetSuite employee (as on the approvals page) and only answer for allowed roles or departments.
  • Restrict where it works. Use the channel_id Slack sends to limit the command to specific channels if you wish.
  • Keep replies ephemeral so results are not broadcast to the channel.

Ideas for more commands

Command What it could do
/ns inv INV-2031 Invoice status and amount due
/ns cust Acme Customer contact, balance and credit hold flag
/ns item ABC-100 Quantity available by location
/ns po PO-778 PO status and expected receipt date
/ns help A short list of the commands

A tidy approach is to read the first word after /ns (for example inv, cust, item) and route to a small function for each. Keep each lookup to one search so you stay under Slack’s three-second limit.

What is next

People can now ask NetSuite questions in Slack. Next, let NetSuite talk first every morning with a daily digest.


← Approve Purchase Orders and Other NetSuite Records Right From Slack
Series overview
Send a Daily NetSuite Digest to Slack with a Scheduled Script →
Share
  • Facebook

Sidebar

Ask A Question

Stats

  • Questions 6
  • Answers 6
  • Best Answers 0
  • Users 9
  • 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
  • 22 Points
Begginer
74gold

74gold

  • 0 Questions
  • 20 Points
Begginer
Sophie1022

Sophie1022

  • 0 Questions
  • 20 Points
Begginer

Trending Tags

clientscript netsuite scripting suitescript
  • The SuiteScript 1.0 scripts nobody remembers: Portlets, Mass Updates and Workflow ActionsSeptember 10, 2026
  • You’re on SuiteScript 2.0, not 1.0. Here’s what that actually buys you.September 9, 2026
  • Converting a SuiteScript 1.0 Suitelet to 2.1 (and the ones that were never really forms)September 8, 2026
  • Every NetSuite certification in 2026, and the rules that quietly changedSeptember 7, 2026
  • Converting a SuiteScript 1.0 Scheduled Script to a 2.1 Map/Reduce (and why a straight port is a mistake)September 7, 2026
  • Migrating a SuiteScript 1.0 RESTlet to SS2.1 + OAuth 2.0 before the 2027.1 deadlineAugust 15, 2026
  • How to convert a SuiteScript 1.0 User Event script to SuiteScript 2.1 (with real code)August 14, 2026
  • The complete SuiteScript 1.0 to 2.1 API cheat sheet: nlapiXxx β†’ N/moduleAugust 13, 2026
  • NetSuite Error Messages: Causes and FixesAugust 11, 2026
  • How to audit every SuiteScript 1.0 script in your NetSuite account (step by step)August 11, 2026

Explore

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

Footer

Menu

  • Home
  • About Us
  • Tutorials
    • NetSuite Scripting
    • NetSuite Customization
    • NetSuite Integration
    • NetSuite Advanced PDF Templates
    • NetSuite Reporting & Analytics Guide
    • Real-World NetSuite Examples
  • Blog
  • Contact Us

Quick Links

  • NetSuite Scripting
  • NetSuite Customization
  • NetSuite Advanced PDF Template
  • NetSuite Integration
  • NetSuite Reporting & Analytics

Subscribe for NetSuite Insights....

Β© 2026 The NetSuite Pro. All Rights Reserved