Documentation

The Prestige RFID handbook

Everything you need to understand how credits flow, tags are minted, batches are printed, and scans are aggregated across the platform.

Platform overview

Prestige RFID is a three-tier RBAC platform for issuing and tracking RFID inventory tags with a credit-based distribution model. It has five surfaces:

  • Dashboard — balance, recharge form and audit log
  • Users — manage your downline and reset passwords
  • Products — create catalog entries with auto SKUs
  • Usage log — every generated batch with print-lock status
  • Scanner — bulk UHF stream simulation and aggregation

Role hierarchy

Every account has one role and, except the root Super Admin, exactly one parent.

RoleVisibilityCreditsAccount management
Super AdminGlobalMints creditsManage all accounts, reset any password
ResellerOwn downlineTransfers from own balanceManage accounts they created
UserOwn accountSpends creditsNone (end operator)
Parent-child enforcement
A reseller sees only the accounts they created (parent_id equals their own id). Super Admins see the entire tree.

Credit ledger

Credits are the currency of the platform. 1 credit = 1 RFID sticker. Credits can only flow downward through the hierarchy.

  • Minting: Only Super Admins can create credits from nothing. Recharging any account as a Super Admin does not deduct from their own balance.
  • Transferring: Resellers moving credits to a downline account debit their own balance by the same amount.
  • Auditing: Every recharge writes to the recharge log (who, to whom, how much, when) and is visible on the Dashboard.
  • Deduction: Generating N RFIDs deducts N credits from the operator's balance.
Insufficient credits
A generate request that exceeds the balance is refused with:
"Insufficient Credits. Please contact your reseller to recharge."

Signup bonus — 100 free credits

Every account created with role USER is bootstrapped with 100 credits. Reseller and sub-reseller accounts start at 0, because they redistribute credits from their own balance.

  • 100 credits credited automatically at USER signup
  • Recorded in the credit_recharge_log as a SIGNUP_BONUS row
  • Fully visible in the ledger — no credits appear out of thin air

Products & SKU rules

Products are lightweight catalog entries owned by their creator. Only Product name is mandatory; base price is optional. Product names are unique per operator (case-insensitive) — duplicates raise a clear error on both create and import.

Auto-SKU formula
First 3 uppercase letters of the product name + hyphen + 4-digit sequential counter.
"T-Shirt" → TSH-0001
On collision the counter increments until a unique SKU is found.

Bulk XLS import

Import an entire catalog in one shot from an Excel or CSV file. Only the name column is required; base_price is optional. Auto-SKUs are generated for every row on the server, up to 2,000 rows per import.

  • Download template — pre-formatted headers ready to fill
  • Supports .xlsx, .xls and .csv
  • Preview table before commit — nothing is written until you confirm
  • Duplicate detection: reports rows that clash with your catalog or repeat inside the file
Duplicate report
Rows that fail validation are listed with the exact reason (e.g. "Duplicate — already exists in your catalog") so you can fix and re-import just the affected rows.

RFID generation engine

Tags are 96-bit random hex identifiers, matching the EPC-96 format used by most UHF readers.

  • 24-character uppercase hex per tag, generated via crypto.getRandomValues
  • Per-batch collision check ensures uniqueness inside the batch
  • Full batch payload is stored on the credit_usage_log row
  • Batches can be re-downloaded as print manifests inside the compliance window

Usage log & the 7-day print lock

The Usage Log lists every generated batch with quantity, product, timestamp, status and action. A colored badge shows the compliance state:

🟢 Active (X Days Left)
🔴 Expired
Print lock enforcement
After 7 days from the batch's creation, downloads are permanently disabled. The server drops the RFID payload for expired batches even if the API is called directly — the log row is preserved for accounting.

Labels — Barcode, QR, PDF, HTML & print

Downloading an active batch opens a preview dialog. Choose the symbology and label size once and the platform remembers your selection for next time (stored in localStorage).

  • Symbology toggle — CODE128 barcode or QR Code (remembered per user)
  • Preset sizes: 50×30, 40×25, 30×20, 70×40 mm — or Custom mm (10–200)
  • Print — opens a print-ready sheet auto-triggering the print dialog
  • PDF export — A4 grid with dashed cut lines, real codes rendered per label
  • HTML export — standalone printable file you can share and print anywhere
  • Manifest — plain-text list of every EPC in the batch
Custom label size
Pick Custom size… in the label-size dropdown to enter width × height in millimetres. Custom dimensions apply to the live preview, PDF, HTML, and print output alike.

How-to: generate & scan an RFID

Generate labels
  1. Open ProductsAdd Product (or Import XLS) and give it a unique name.
  2. Confirm you have enough credits on the Dashboard (1 credit = 1 tag).
  3. Click Generate RFID Stickers and enter the target quantity.
  4. Go to Usage LogDownload for Print.
  5. Pick Barcode or QR, choose a preset or Custom size, then export PDF / HTML / Print.
Scan and count
  1. Open Bulk Scanner Station.
  2. Press Start Bulk Scan Session (or the 100-tag simulator).
  3. Watch Total Quantity, Unique Items and Valuation update in real time.
  4. For headless integration, POST EPCs to /api/public/v1/scan/lookup.

Bulk Scanner Station

The Scanner is a workspace that ingests a UHF reader stream and aggregates in real time.

  • Start / Stop live session button — polls the reader every 1.5s
  • Simulate batch button — dumps 100 mock tags into the aggregator
  • Three summary metrics: Total Quantity, Total Valuation, Unique Items
  • Deduplication keyed by EPC — repeat reads of the same tag never inflate totals

Unknown EPCs (tags not registered against a product batch under your account) still count toward Total Quantity but contribute 0 to valuation until they're registered.

Hardware integration — feed a real UHF reader

The Scanner Station is transport-agnostic. Today it polls a simulator; to go live, replace the source of EPCs with whatever your reader emits. Every downstream step (dedupe, lookup, valuation, XLSX / PDF export) stays identical. Pick the pattern that matches where the reader lives.

1 · USB / serial reader on the operator's PC

Handheld or desktop readers (Zebra, Chainway, Impinj Speedway with the desktop SDK, Alien, ThingMagic…) ship a small Windows/Linux service that exposes a local WebSocket or HTTP endpoint. Install the vendor SDK, point it at a port, and connect the browser to it directly.

// inside src/routes/_authenticated/scanner.tsx — replace the setInterval block
const ws = new WebSocket("ws://localhost:8080/tags"); // vendor SDK bridge
ws.onmessage = async (evt) => {
  const { epcs } = JSON.parse(evt.data);           // shape depends on the SDK
  const rows = await lookupRfidsFn({ data: { epcs } });
  ingest(rows);                                     // dedupes + updates metrics
};
wsRef.current = ws;                                 // ws.close() on Stop
Web Serial fallback
For readers that speak ASCII / LLRP over a plain serial port, Chrome / Edge can open the port directly withnavigator.serial.requestPort() — no installer, but the user must click "Connect" once per session.

2 · Networked fixed reader (PoE, ceiling / gate-mounted)

Impinj R700, Zebra FX9600, ThingMagic Izar and similar readers speak LLRP over TCP, or can be configured to push every read as an HTTP webhook / MQTT message. Point them at a public endpoint on this app and fan the reads out to the browser via realtime.

  1. In the reader's admin UI, enable HTTP Push (or Keyword / Tag Report Format → HTTP POST).
  2. Set the destination URL to https://your-app.lovable.app/api/public/reader-webhook.
  3. Set a shared secret header (e.g. X-Reader-Secret) and store the matching value in the backend so the endpoint can reject spoofed traffic.
  4. The endpoint validates the secret, then broadcasts the batch on a realtime channel keyed by your account.
  5. The Scanner page subscribes to that channel while a session is live and calls ingest() for every push.
// browser side — swap the polling for a realtime subscription
const channel = supabase.channel(`reader:${userId}`);
channel
  .on("broadcast", { event: "tags" }, async ({ payload }) => {
    const rows = await lookupRfidsFn({ data: { epcs: payload.epcs } });
    ingest(rows);
  })
  .subscribe();
// on Stop: supabase.removeChannel(channel)
Ask before we build the receiver
The webhook route and realtime broadcast are not scaffolded yet — say the word and we'll add/api/public/reader-webhook, the shared secret, and wire the Scanner page to subscribe.

3 · Android handheld (Chainway C72 / C6, Zebra TC22, Unitech HT380)

The device runs a small companion app (Kotlin / React Native / Flutter) that reads the vendor SDK's callback and POSTs each batch to the same webhook as pattern 2. The Scanner page needs zero changes beyond the realtime subscription.

// Android companion (pseudo-Kotlin) — vendor SDK gives you a callback
uhfReader.setInventoryCallback { tags ->
  Http.post("https://your-app.lovable.app/api/public/reader-webhook") {
    header("X-Reader-Secret", BuildConfig.READER_SECRET)
    json(mapOf("epcs" to tags.map { it.epc }))
  }
}

Recommended reader settings

  • Region: match your country profile (FCC / ETSI / IN)
  • Session: S1 for dense inventory sweeps, S0 for point-and-shoot
  • Q value: 4 for < 100 tags in field, 6-7 for bulk pallet scans
  • Duplicate window: 500ms — the app also dedupes by EPC, so this is belt-and-braces
  • Report format: EPC-96 hex (24 chars) — matches what this platform generates
Testing without hardware
Use the Simulate Batch Stream (100 tags) button on the Scanner page. It mixes real EPCs from your generated batches with random unknowns, so you can validate the full aggregation + export pipeline before any reader is on-site.

Zebra reader configuration — step by step

Zebra ships two families that both plug straight into the patterns above. Handhelds run Android with the Zebra RFID SDK for Android (companion-app pattern 3). Fixed readers run the FX-series firmware with a built-in web console and speak LLRP + HTTP push (pattern 2). Concrete steps for each below.

A · FX9600 / FX7500 fixed reader (LAN / PoE)

  1. Power the reader over PoE and find its IP on your LAN (default hostnameFX9600XXXXXX.local). Browse tohttps://<reader-ip> and sign in with the defaultadmin / change, then rotate the password.
  2. Go to Configure → Region and pick the country profile (FCC for US, ETSI EN 302 208 for EU/UK, IN for India). Wrong region = radio disabled.
  3. Configure → Read Points: enable the antenna ports you have connected, set transmit power (start at 27.0 dBm for portal reads, 30.0 dBm for pallet lanes).
  4. Configure → RF / Singulation Control: Session S1, Tag Population estimated tag count in field, Target A, Inventory State A → B.
  5. Switch operating mode: Communication → Operating Mode → Autonomous (so the reader posts on its own without an LLRP client). Alternative: leave it in IoT Connector mode and use MQTT.
  6. Communication → Data Endpoint: set Protocol = HTTP POST, URL =https://your-app.lovable.app/api/public/reader-webhook, Format = JSON, and add a custom headerX-Reader-Secret: <your-shared-secret>.
  7. Configure → Triggers: Start = Immediate or GPI 1 rising edge (for a foot pedal / light-curtain), Stop = Duration 500 ms or Tag observation. Report = Per tag with fields EPC, Antenna, RSSI, First-seen timestamp.
  8. Hit Save → Commit. The reader now POSTs every read cycle to the app. Open the Scanner page, click Start Bulk Scan Session, and reads appear live.
Zebra 123RFID Desktop
For bench-testing before deployment, install 123RFID Desktop from zebra.com/support. It gives you a live inventory grid and RSSI heatmap using the same reader — useful for tuning power and antenna placement before pointing it at the webhook.

B · RFD40 / RFD90 / MC3390R handheld sled

Handhelds run the Zebra RFID SDK on Android. Sideload the small companion app you (or we) build with the SDK — it opens the reader, listens for inventory callbacks, and POSTs to the same webhook.

  1. Download Zebra RFID SDK for Android from techdocs.zebra.com and addRFIDAPI3Library.aar to the companion app.
  2. Pair the sled with the Android host over Bluetooth (RFD40/90) or USB (MC3390R). Enable the trigger in DataWedge → Profile → RFID Input.
  3. In code, call Readers.attach()connect()Actions.Inventory.perform() and register anEventsNotificationListener.
  4. In the listener callback, batch tags for ~250 ms then POST the EPC list to/api/public/reader-webhook with the shared secret header.
  5. Configure the trigger: Trigger Mode = HOLD, Beeper = on tag, Report EPC only, Session S1, Power 27 dBm.
// Android companion — Kotlin snippet using Zebra RFID SDK 3
reader.Events.addEventsListener(object : RfidEventsListener {
  override fun eventReadNotify(e: RfidReadEvents) {
    val tags = reader.Actions.getReadTags(100) ?: return
    val epcs = tags.map { it.tagID }             // 24-char hex EPCs
    Http.post("https://your-app.lovable.app/api/public/reader-webhook") {
      header("X-Reader-Secret", BuildConfig.READER_SECRET)
      json(mapOf("epcs" to epcs))
    }
  }
  override fun eventStatusNotify(e: RfidStatusEvents) {}
})
reader.Actions.Inventory.perform()

Zebra-specific gotchas

  • FX readers refuse to transmit until region is set — no error, just silence.
  • HTTPS webhooks need a valid cert; FX firmware < 3.x rejects Let's Encrypt chains — Lovable's *.lovable.app cert is fine.
  • Rotate the default admin password before exposing the reader to the network.
  • Firmware upgrades ship as .zpl / .tar — apply via Configure → Firmware, reader reboots ~90s.
  • For dense-reader environments, switch RF Mode to Mode 1002 (dense-reader) to avoid cross-talk.
Reference docs
Full manuals: FX9600 Integrator Guide (MN-002966), RFID3 API Developer Guide and 123RFID Desktop / Mobile User Guide — all ontechdocs.zebra.com.

Public REST API & keys

Every user can mint a bearer API key on the API Keys page and drive the platform from any language or scheduler. Keys are shown once at creation and only the SHA-256 hash is persisted.

  • rfid_ prefixed bearer tokens — create and revoke from the console
  • REST base: /api/public/v1 — no browser session required
  • GET /me · GET/POST /products · POST /products/{id}/rfids
  • GET /usage · GET /usage/{id} — enforces the same 7-day print lock
  • POST /scan/lookup — bulk EPC → product + valuation resolution
Auth header
All requests require Authorization: Bearer rfid_…. See the API reference for full request/response schemas and cURL examples.

Security model

  • Row-Level Security is enabled on every table. Reads are scoped to the owner, their ancestors and Super Admins.
  • The role enum lives in a dedicated table checked via a SECURITY DEFINER function to prevent privilege escalation.
  • All privileged mutations happen server-side inside authenticated server functions; the client never carries a service key.
  • Expired batch payloads are refused server-side, so a leaked download link cannot bypass the print lock.

FAQ

Can a reseller see another reseller's users?
No. Downline visibility is scoped by the parent_id chain and enforced in RLS.
Do credits expire?
No. Credits persist on the account until spent or transferred.
Can I re-download an expired batch after 7 days?
No. The log row is retained for auditing, but the RFID payload is refused server-side.
What if two users generate at the same SKU prefix?
The counter uses the operator's own product count, so SKUs are unique per operator; a global uniqueness check retries on collision.
Can I plug in a real UHF reader?
The Scanner is architected around a tag-lookup API — replace the sampler with your reader's SDK, or POST reads to /api/public/v1/scan/lookup.
Can I import my whole catalog from Excel?
Yes. Products → Import XLS accepts .xlsx / .xls / .csv up to 2,000 rows. Only 'name' is required; duplicate names are flagged per row.
Which barcode format is used?
CODE128 for barcodes, standard QR (error correction M) for QR codes. Your last choice is remembered per browser.
Can I set my own label size?
Yes — pick 'Custom size…' in the label-size dropdown and enter width × height in millimetres (10–200 mm). It applies to preview, PDF, HTML and print.
Do new accounts get any free credits?
Every account created with role USER receives 100 credits automatically. Reseller accounts start at 0 since they redistribute from their own balance.
Ready to try it?
Sign in with your operator credentials and start a batch.