<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryan Bame</title>
    <description>The latest articles on DEV Community by Ryan Bame (@ryan_bame_84).</description>
    <link>https://dev.to/ryan_bame_84</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4063248%2Ff1a308f5-a187-4a5e-bd14-079f7432cad1.png</url>
      <title>DEV Community: Ryan Bame</title>
      <link>https://dev.to/ryan_bame_84</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ryan_bame_84"/>
    <language>en</language>
    <item>
      <title>How to Generate QR Codes in Bulk from a CSV (Static vs. Trackable)</title>
      <dc:creator>Ryan Bame</dc:creator>
      <pubDate>Wed, 14 Oct 2026 21:12:44 +0000</pubDate>
      <link>https://dev.to/ryan_bame_84/how-to-generate-qr-codes-in-bulk-from-a-csv-static-vs-trackable-15lm</link>
      <guid>https://dev.to/ryan_bame_84/how-to-generate-qr-codes-in-bulk-from-a-csv-static-vs-trackable-15lm</guid>
      <description>&lt;h2&gt;
  
  
  How to Generate QR Codes in Bulk from a CSV (Static vs. Trackable)
&lt;/h2&gt;

&lt;p&gt;You have a spreadsheet. Maybe it's 50 product SKUs, 500 rental units, or 5,000 asset tags. Each row needs its own QR code. Generating them one at a time in a web form is a non-starter, so the question becomes: how do you turn a column of URLs into a folder of QR codes without doing it by hand?&lt;/p&gt;

&lt;p&gt;There are two real answers, and which one you pick matters more than the tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: Static codes, generated locally (Python)
&lt;/h2&gt;

&lt;p&gt;If the codes are truly fixed — the URL behind each one will never change and you don't need scan data — you can generate them yourself in a few lines. Here's the whole thing with the &lt;code&gt;qrcode&lt;/code&gt; library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;

&lt;span class="c1"&gt;# input.csv:
#   name,url
#   unit-101,https://example.com/units/101
#   unit-102,https://example.com/units/102
&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it, and &lt;code&gt;out/&lt;/code&gt; fills with one PNG per row. Want SVG for print? Swap in the &lt;code&gt;qrcode.image.svg&lt;/code&gt; factory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;qrcode.image.svg&lt;/span&gt;

&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;image_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SvgImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.svg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is genuinely fine for a lot of jobs. It's free, it runs offline, and the codes work forever. If that's your use case, stop here — you don't need a platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But read the next paragraph before you print 5,000 of them.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with static bulk codes
&lt;/h2&gt;

&lt;p&gt;A static QR code encodes the destination URL &lt;em&gt;directly into the pixels&lt;/em&gt;. That has two consequences that only show up after the codes are in the wild:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You can't change where they point.&lt;/strong&gt; The day a URL changes — a domain migration, a restructured path, a campaign that moved — every printed code pointing at the old URL is dead. On a batch of 5,000, that's 5,000 reprints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You get zero data.&lt;/strong&gt; A static code is a dumb pointer. You will never know how many were scanned, when, where, or on what device. For asset tags that might be acceptable; for anything marketing- or operations-facing, flying blind at scale is expensive.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The batch loop above can't fix either problem, because the limitation is in the format, not the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2: Dynamic codes, generated in bulk from the same CSV
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;dynamic&lt;/em&gt; QR code encodes a short redirect URL instead of the final destination. The pixels point at something like &lt;code&gt;qrch.am/a1b2c3&lt;/code&gt;, which 301s to wherever you want — and you can repoint it later without touching the printed code. Every scan is logged on the way through.&lt;/p&gt;

&lt;p&gt;The bulk workflow is the same shape as the Python script — CSV in, codes out — except the output is a set of trackable, editable codes instead of flat images. Two ways to drive it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upload the CSV in the dashboard.&lt;/strong&gt; Drop your spreadsheet into the &lt;a href="https://qrchameleon.com/products/bulk-qr-code-generator" rel="noopener noreferrer"&gt;bulk QR code generator&lt;/a&gt;, map the URL column, and it mints one dynamic code per row and hands you a ZIP of print-ready PNG/SVG files. This is the fastest path for a one-off batch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Or hit the API for a repeatable pipeline.&lt;/strong&gt; If the batch is part of a system — a nightly job tagging new inventory, a per-tenant onboarding step — generate them programmatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.qrchameleon.com/v1/qr/bulk &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer qrc_your_api_key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "items": [
      { "name": "unit-101", "url": "https://example.com/units/101" },
      { "name": "unit-102", "url": "https://example.com/units/102" }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each returned code is dynamic, so a later &lt;code&gt;PATCH&lt;/code&gt; to its destination updates where the physical code points — no reprint. (Exact request/response schema and rate limits are in the &lt;a href="https://qrchameleon.com/products/qr-code-api" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; — treat the snippet above as the shape, not the spec.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Which should you use?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Static (local script)&lt;/th&gt;
&lt;th&gt;Dynamic (bulk upload / API)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free tier, paid at volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works offline&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (needs the redirect)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Editable after printing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scan analytics&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Per-code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Fixed, fire-and-forget codes&lt;/td&gt;
&lt;td&gt;Anything you'll track or change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rule of thumb: if the batch is &lt;strong&gt;permanent and you don't care about data&lt;/strong&gt;, the 10-line Python script is the right tool and you should use it. If the codes represent anything you might &lt;strong&gt;reprint, repoint, or measure&lt;/strong&gt; — products, properties, campaigns, assets in a system of record — generate them as dynamic codes so a URL change is a one-line edit instead of a reprint run.&lt;/p&gt;

&lt;p&gt;The spreadsheet-to-codes step is easy either way. The decision that actually costs money is static vs. dynamic — make that one on purpose.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Generating a batch right now? The &lt;a href="https://qrchameleon.com/products/bulk-qr-code-generator" rel="noopener noreferrer"&gt;bulk QR code generator&lt;/a&gt; takes a CSV and returns print-ready dynamic codes with scan tracking built in — free to start, no credit card.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>qrcode</category>
      <category>python</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>NetSuite QR Code &amp; Barcode Integration: A SuiteScript Implementation Guide</title>
      <dc:creator>Ryan Bame</dc:creator>
      <pubDate>Wed, 05 Aug 2026 00:47:14 +0000</pubDate>
      <link>https://dev.to/ryan_bame_84/netsuite-qr-code-barcode-integration-a-suitescript-implementation-guide-5090</link>
      <guid>https://dev.to/ryan_bame_84/netsuite-qr-code-barcode-integration-a-suitescript-implementation-guide-5090</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This was originally published on the &lt;a href="https://qrchameleon.com/blog/netsuite-qr-code-barcode-integration/" rel="noopener noreferrer"&gt;QR Chameleon blog&lt;/a&gt;. Reposting here for the SuiteScript crowd.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your NetSuite environment manages 18,000 SKUs across three subsidiaries. The receiving dock scans a printed packing slip every time a pallet arrives, and the operator types the item ID into the Item Fulfillment record by hand. Misreads, transcription errors, and the occasional reversed digit cost real time during cycle counts. Your warehouse team has been asking for native barcode and QR code scanning that hooks into NetSuite item records, and the standard answer has historically been "we'll evaluate NetSuite WMS at next year's renewal."&lt;/p&gt;

&lt;p&gt;There is a faster path. The QR Chameleon REST API plus a few hundred lines of SuiteScript 2.1 closes the loop between NetSuite inventory and a phone-scannable label, with no third-party WMS license and no migration project. I have walked NetSuite admins through this integration in customer environments ranging from single-subsidiary 500-SKU operations up through OneWorld deployments processing thousands of fulfillments per day, and the pattern is consistent enough to write down.&lt;/p&gt;

&lt;p&gt;This guide covers the SuiteScript patterns, governance considerations, webhook architecture, and SuiteCloud Plus tradeoffs that come up when integrating QR codes and barcodes into NetSuite operations. For the product overview and plan requirements behind this integration, see the &lt;a href="https://qrchameleon.com/solutions/netsuite" rel="noopener noreferrer"&gt;NetSuite QR code integration&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why NetSuite Plus QR Code Integration Matters
&lt;/h2&gt;

&lt;p&gt;Native NetSuite handles inventory accounting beautifully and the standard transaction flow (Sales Order → Item Fulfillment → Invoice) is solid. What it does not include out of the box is a printable, scannable identifier per inventory item that survives a real-world warehouse environment and feeds back into the system on every scan.&lt;/p&gt;

&lt;p&gt;Three pressures push mid-market NetSuite customers toward integrated QR codes and barcodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inventory Accuracy at Scale
&lt;/h3&gt;

&lt;p&gt;For a company managing 5,000 to 50,000 SKUs across one or more warehouses, manual cycle counts drift away from physical reality between count cycles. According to &lt;a href="https://www.netsuite.com/portal/resource/articles/inventory-management/inventory-accuracy.shtml" rel="noopener noreferrer"&gt;Oracle NetSuite's own benchmark research&lt;/a&gt;, the average inventory accuracy for organizations without scan-based receiving and picking sits in the 75-85% range. Organizations with scan-based workflows tied directly into the ERP routinely hit 99%+. The gap is not a measurement artifact. It is real shrink, real over-ordering, and real customer back-orders for items the system thinks are in stock.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pick, Pack, and Ship Velocity
&lt;/h3&gt;

&lt;p&gt;A picker carrying a phone with the camera app open can confirm an item, mark a fulfillment line as picked, and move to the next pick in under three seconds per item. The same workflow without scanning takes 20 to 45 seconds per item once you account for finding the printed pick ticket location, reading the SKU, walking back to a terminal, and updating the record. At a 200-line-per-day fulfillment cadence, that is two hours of saved labor per picker per day, every day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audit Trail and Compliance
&lt;/h3&gt;

&lt;p&gt;Industries with regulatory scan-trail requirements (medical devices, food and beverage, controlled goods, government contractors) need a per-scan audit trail tied to the operator, the timestamp, the location, and the inventory transaction. NetSuite Custom Records combined with QR code scan webhooks build that trail without leaving the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Integration Architecture
&lt;/h2&gt;

&lt;p&gt;The integration has four pieces that map cleanly to standard NetSuite primitives.&lt;/p&gt;

&lt;h3&gt;
  
  
  REST API Calls Out (QR Chameleon Generation)
&lt;/h3&gt;

&lt;p&gt;When NetSuite needs to generate a QR code, it calls the &lt;a href="https://qrchameleon.com/blog/qr-code-api-ai-agents/" rel="noopener noreferrer"&gt;QR Chameleon REST API&lt;/a&gt; from a SuiteScript using the &lt;code&gt;N/https&lt;/code&gt; module. The API returns a short link plus an SVG or PNG that NetSuite stores in a custom field, the File Cabinet, or both. Typical use cases include: on creation of a new inventory item, on the transition of an Item Fulfillment record to Picked or Shipped, or on the creation of a Customer Return record.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Event and Scheduled Scripts (Generation Triggers)
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;User Event script&lt;/strong&gt; deployed on the Item record handles single-record generation in real time. As soon as the admin saves a new inventory item, the after-submit event fires, the script calls the QR Chameleon API, and the resulting short link lands in a custom field on the item before the user even sees the saved page. A &lt;strong&gt;Scheduled Script&lt;/strong&gt; handles backfill, for the initial bulk generation when you first roll out the integration across an existing item catalog, or for nightly catch-up on any items that missed the real-time trigger.&lt;/p&gt;

&lt;h3&gt;
  
  
  RESTlets and Workflow Actions (Inbound Webhooks)
&lt;/h3&gt;

&lt;p&gt;When a QR code gets scanned in the field, the QR Chameleon webhook fires an HTTP POST back to a NetSuite &lt;strong&gt;RESTlet&lt;/strong&gt;. The RESTlet authenticates the request via Token-Based Authentication (TBA) or OAuth 2.0, then creates a Custom Record entry capturing the scan: which item, which operator, which timestamp, which location, which Sales Order or Item Fulfillment record (if any).&lt;/p&gt;

&lt;h3&gt;
  
  
  Saved Searches and Workflows (Automation Layer)
&lt;/h3&gt;

&lt;p&gt;Standard NetSuite saved searches identify the work that needs to happen: items missing QR codes, fulfillments awaiting first scan, custom record scan events that warrant follow-up workflow actions. Standard NetSuite Workflows then fire the appropriate next step based on those saved-search results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inventory Item QR Code Generation: SuiteScript 2.1 Code Walkthrough
&lt;/h2&gt;

&lt;p&gt;The single highest-value integration point is generating a QR code automatically when a new inventory item is created or saved. Below is the pattern as a User Event script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */&lt;/span&gt;
&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/record&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;afterSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EDIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sku&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;itemid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Build the destination URL. The QR code resolves to this NetSuite&lt;/span&gt;
        &lt;span class="c1"&gt;// item record (or a customer-facing landing page, depending on use case).&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolveDomain&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;hostType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HostType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPLICATION&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;`/app/common/item/item.nl?id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://qrchameleon.com/api/v1/qr/bulk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer YOUR_API_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;qr_codes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;destination_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sku&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="c1"&gt;// Persist the short link in a custom field on the item record.&lt;/span&gt;
        &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitFields&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INVENTORY_ITEM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;custitem_qr_short_link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;short_url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;afterSubmit&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script deploys as a User Event on the Inventory Item record (and you typically duplicate the deployment for Assembly Item, Kit Item, and Service Item types). The custom field &lt;code&gt;custitem_qr_short_link&lt;/code&gt; stores the short link for downstream use: printing on labels, embedding in customer-facing pages, or surfacing in Saved Searches that need a clickable destination.&lt;/p&gt;

&lt;p&gt;Governance units to budget: one &lt;code&gt;https.post&lt;/code&gt; call uses 10 units, the &lt;code&gt;record.submitFields&lt;/code&gt; uses 10 units, and miscellaneous record context access runs another 10-20 units. A single item save burns roughly 30-40 units against the 1,000-unit User Event budget. The script comfortably handles the standard case without governance pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sales Order and Item Fulfillment: Chain-of-Custody QR Code
&lt;/h2&gt;

&lt;p&gt;For Sales Order and Item Fulfillment records, the QR code pattern shifts from identifying an item type to identifying a specific physical shipment. The QR code printed on the fulfillment packing slip resolves to the fulfillment record itself, which then loads in the operator's phone with the open quantities, the picked quantities, and a button to mark the fulfillment as Shipped.&lt;/p&gt;

&lt;p&gt;The script attaches to the Item Fulfillment record on the Pending Fulfillment to Packed transition. The destination URL points to a customer-facing tracking page that pulls live status from NetSuite via a public Suitelet or REST API endpoint, and the same QR code also resolves to the internal NetSuite record for warehouse staff with appropriate role permissions. Identical QR code, different destinations based on the scanner's authenticated session.&lt;/p&gt;

&lt;p&gt;The chain-of-custody value is in the scan log. Every scan of the fulfillment QR code (at pack, at shipping dock pickup, at carrier handoff, at customer receiving) creates a Custom Record entry in NetSuite tied back to the source Item Fulfillment. Disputes about when a shipment left the dock or when the customer signed for it fall away because the per-scan timestamp and location data are stored in the system of record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhook Subscription: Scan Events Back Into NetSuite
&lt;/h2&gt;

&lt;p&gt;This is the part that closes the loop. Every time someone scans a QR Chameleon link, the platform fires a webhook to a URL you configure. For NetSuite integration, that URL is a RESTlet you deploy in your account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @NApiVersion 2.1
 * @NScriptType Restlet
 */&lt;/span&gt;
&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/record&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validate signature and timestamp first (omitted for brevity)&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scanRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customrecord_qr_scan_event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;isDynamic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_item_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item_id&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_short_url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;short_url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_ip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scanner_ip&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geo_country&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fieldId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custrecord_scan_device&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_agent&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recordId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scanRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;internal_record_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recordId&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then configure the QR Chameleon webhook endpoint URL in the QR Chameleon dashboard to point at this RESTlet's external URL (NetSuite provides one when you deploy a RESTlet with external access enabled). The webhook fires every scan, the RESTlet logs the event to a custom record, and standard NetSuite Saved Searches can now query, alert, and report on real-world scan activity.&lt;/p&gt;

&lt;p&gt;Common Custom Record patterns built on top of scan events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fulfillment confirmation reports (how many scans on each shipment between pack and customer receipt)&lt;/li&gt;
&lt;li&gt;Asset audit reports (when was each tagged asset last scanned, by whom)&lt;/li&gt;
&lt;li&gt;Recall trigger workflows (a scan on a flagged lot fires a Saved Search-based notification to the responsible role)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generate NetSuite-ready QR codes via API.&lt;/strong&gt; The REST API returns SVG or PNG plus the short URL ready to drop into your SuiteScript custom field. &lt;a href="https://qrchameleon.com/pricing" rel="noopener noreferrer"&gt;Get an API token&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saved Search and Workflow Automation Patterns
&lt;/h2&gt;

&lt;p&gt;With the basic generation and scan-logging in place, the automation layer is standard NetSuite work. Three saved-search patterns recur in production deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing QR Codes Search
&lt;/h3&gt;

&lt;p&gt;A saved search on Item with the filter &lt;code&gt;Custom Field — QR Short Link — Is Empty&lt;/code&gt; identifies items missing QR codes. Schedule a Scheduled Script to run hourly that pulls the results of this search and calls the same generation logic from the User Event script. This catches items that were created through CSV import, web services, or any path that bypassed the User Event trigger.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scan Activity Saved Search
&lt;/h3&gt;

&lt;p&gt;A saved search on the custom scan event record, joined back to the related item, sales order, or fulfillment record, surfaces scan activity in real time. This is the foundation for dashboards, KPI widgets on the role center page, and automated alert emails when scan volume drops below expected thresholds (a warehouse went dark, a label batch printed incorrectly, etc.).&lt;/p&gt;

&lt;h3&gt;
  
  
  Unprinted Labels Search
&lt;/h3&gt;

&lt;p&gt;A saved search that filters items where the QR code short link exists but a &lt;code&gt;Last Label Printed&lt;/code&gt; date field is empty or older than a threshold. Schedule a script to email the warehouse manager every morning with the list of items that need labels printed. Pair with a bulk label-export Suitelet or Saved Search results action that calls the QR Chameleon API to fetch print-ready SVGs in a batch.&lt;/p&gt;

&lt;h2&gt;
  
  
  SuiteCloud Plus and High-Volume Considerations
&lt;/h2&gt;

&lt;p&gt;NetSuite's standard SuiteScript governance limits 1,000 units per script execution and constrains concurrent script execution. For mid-market deployments processing hundreds of inventory transactions per hour, the standard governance is enough. For high-volume environments (10,000+ fulfillments per day, or batch-generation campaigns where you need to tag thousands of existing items with QR codes in a single afternoon), the math changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.netsuite.com/portal/products/suitecloud/suiteapp.shtml" rel="noopener noreferrer"&gt;SuiteCloud Plus&lt;/a&gt; is Oracle NetSuite's add-on that raises governance limits and increases concurrent script execution allowances. Practical rule of thumb: if your QR code generation backfill needs to process more than 5,000 items in a single Scheduled Script window, or your real-time User Event scripts are queueing during peak fulfillment hours, the SuiteCloud Plus uplift pays for itself in scan-driven labor savings within a quarter.&lt;/p&gt;

&lt;p&gt;For environments not yet on SuiteCloud Plus, the workaround is batching the work into smaller Scheduled Script windows that run more frequently (every 15 minutes instead of hourly), accepting that backfill of a large existing catalog will take a few days instead of an afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  OneWorld and Subsidiary Considerations
&lt;/h2&gt;

&lt;p&gt;OneWorld deployments add a wrinkle. Inventory items can be shared across subsidiaries, restricted to a single subsidiary, or have subsidiary-specific custom field values. The QR code generation script needs to handle three patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-subsidiary items&lt;/strong&gt; are the simplest case. The QR code destination resolves to the same record regardless of who scans, and the custom field for the short link is set once on the item record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subsidiary-restricted items&lt;/strong&gt; require subsidiary context in the script logic so the right user with the right role sees the right item view when the QR code resolves to the NetSuite record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-subsidiary shared items&lt;/strong&gt; present an architectural choice. Either one shared QR code resolves to a common landing page (and the page itself loads subsidiary-specific content based on the authenticated user), or each subsidiary gets its own QR code per item (more management overhead but cleaner per-subsidiary audit trails). The right answer depends on how the operations team thinks about the inventory: as one global catalog or as parallel subsidiary catalogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 10-Step Implementation Checklist
&lt;/h2&gt;

&lt;p&gt;For NetSuite admins or SuiteCloud developers planning the rollout, the work breaks down predictably.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Provision the QR Chameleon API token&lt;/strong&gt; at the Adapt plan tier or above (the &lt;a href="https://qrchameleon.com/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; covers the full plan matrix).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create the custom fields&lt;/strong&gt;: &lt;code&gt;custitem_qr_short_link&lt;/code&gt; (free-form text) on Inventory Item, Assembly Item, Kit Item, Service Item.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create the Custom Record type&lt;/strong&gt; &lt;code&gt;customrecord_qr_scan_event&lt;/code&gt; with the fields shown in the RESTlet code above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the User Event script&lt;/strong&gt; on each item record type for real-time generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the Scheduled Script&lt;/strong&gt; for catch-up generation on the saved search of items missing QR codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the RESTlet&lt;/strong&gt; for inbound webhook scan events. Configure TBA credentials and capture the external URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure the QR Chameleon webhook&lt;/strong&gt; to fire scan events at the NetSuite RESTlet URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the Item Fulfillment script&lt;/strong&gt; for chain-of-custody QR code generation on the pending-to-packed transition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the saved searches and dashboards&lt;/strong&gt; for missing labels, scan activity, and unprinted labels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Print and apply the first batch of labels.&lt;/strong&gt; Roll out to one warehouse or one item category first. Iterate the destination pages server-side based on operator feedback before expanding.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full bulk-CSV generation pattern, which is what most teams use for the initial backfill, is covered in the &lt;a href="https://qrchameleon.com/blog/qr-code-asset-tracking/" rel="noopener noreferrer"&gt;QR code asset tracking workflow guide&lt;/a&gt;. For physical label substrate and adhesive specifications appropriate for warehouse and manufacturing environments, see the &lt;a href="https://qrchameleon.com/blog/qr-code-asset-tags/" rel="noopener noreferrer"&gt;QR code asset tags guide&lt;/a&gt;. For the broader equipment-tracking patterns that often pair with NetSuite Fixed Asset Management module deployments, the &lt;a href="https://qrchameleon.com/blog/qr-code-equipment-tracking/" rel="noopener noreferrer"&gt;QR code equipment tracking guide&lt;/a&gt; covers the maintenance and calibration angle.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Whether you are integrating QR codes into a single-subsidiary NetSuite deployment or rolling out chain-of-custody scanning across a OneWorld multi-subsidiary operation, &lt;a href="https://qrchameleon.com/signup" rel="noopener noreferrer"&gt;QR Chameleon&lt;/a&gt; bundles the REST API, bulk CSV generation, scan webhook delivery, and SuiteScript-friendly response formats on every plan starting free.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
