Internal · TDR-HPZ

Fast PIM lookups,
one request per column.

An in-memory lookup service for product prices, item names, and SKU / part-number / product-code cross-references — built for Google Sheets batch formulas.

checking status…
Price rows
Name rows
Snapshot age
Open the playground sheet ↗

Start here — no coding needed

Pull product price, name, and codes straight into your sheet by typing one short command. No scripts, no setup.

Install the add-on (one time)

1

Open any Google Sheet

Look at the menu bar across the top.

2

Menu: Extensions → Add-ons → Get add-ons

This opens the Google Workspace Marketplace. If your admin already set it up for everyone, you'll instead see PIM V3 directly under Extensions — then skip to “Use it”.

3

Find “PIM V3” → Install

Approve the permission screen (it only lets the tool fetch product data). Done.

4

Wait a few minutes

Google needs 2–10 minutes to switch the commands on. Try too early and you'll see Unknown function — that's normal. Reload the sheet and wait. Details →

Fastest way to try without installing anything: open the playground sheet — the commands already work there. Use File → Make a copy to play in your own copy.

Use it in 3 steps

1

Put your codes in one column

For example, paste your SKUs down column A, starting at cell A2.

2

Click the empty cell next to the first code

For example, cell B2.

3

Paste one command, press Enter

The whole column fills by itself. Pick what you want below and copy it in.

Copy-paste commands

These assume your codes are in A2:A100. Different spot? Just change that part — see the table below.

💰 Get the price (Rupiah)

=PIM_PRICE(A2:A100,"sku","het","IDR")

🏷️ Get the product name

=PIM_ITEM_NAME(A2:A100,"sku")

🔁 Turn a part number into a SKU

=PIM_FIELD(A2:A100,"partNumber","sku")

✅ Check if a code exists

=PIM_IS_FOUND(A2:A100,"sku")

What it looks like

A — your codesB — you typed =PIM_ITEM_NAME(A2:A4,"sku")
21KY-F11D0Brake Pad | Front
35TL-E5350Oil Filter
4… (fills automatically)

Change it to fit your sheet

A2:A100Where your codes are. Codes in column C, rows 5–200? Write C5:C200.
"sku"What kind of code you pasted: "sku", "partNumber", or "productCode".
"het","IDR"Price kind & currency (price command only). Kind: het / hlp / hot. Currency: IDR, USD, SGD, THB, MYR, VND, BDT…

3 rules to remember

  1. Type the command in the top cell only. Don't drag or copy it down — it fills the column itself.
  2. Keep the cells below empty so the answers have room to appear.
  3. Blank code = blank answer. Code not found = blank.

Why it's fast

The old sheet hit the API once per cell — 100 rows meant hundreds of calls, each running a heavy database view.

Batch

One array formula resolves a whole column in a single HTTP request. 100 rows = 1 call.

In-memory

All product data is loaded into RAM and refreshed every few minutes. Lookups are microseconds; the database is barely touched.

Token-exact

Part numbers are matched by whole token — no missed sets, no substring false-positives.

Authentication

Every data endpoint needs Authorization: Bearer <token> — a static API key or a valid HS256 JWT (same secret as the main API). /healthz and this page are public.

Google Sheets functions

Put one array formula at the top of an output column — it fills the whole column. Identifier = sku, partNumber, or productCode.

Just installed the add-on? Give it a few minutes. Google registers the custom functions per document, and it can take 2–10 minutes (longer for org-wide installs) before PIM_PRICE, PIM_FIELD & co. appear.

If you see Unknown function: 'PIM_FIELD' — it's just the registration lag, not an error in your formula:

  1. Reload the sheet (Cmd/Ctrl+R or reopen the tab).
  2. Type =PIM_ and wait until it shows in autocomplete before using it.
  3. Already shows the error in a cell? Re-enter the formula once functions appear — Sheets caches the error until the cell recalcs.

Try it in the playground sheet ↗

PIM_PRICE(range, id, type, currency)

Unit price. type: het·hlp·hot·marketplace. currency: IDR·USD·SGD·THB·MYR·VND·BDT·EUR·PHP.

=PIM_PRICE(A2:A101,"sku","het","IDR")

PIM_ITEM_NAME(range, id)

Item name incl. variant labels.

=PIM_ITEM_NAME(A2:A101,"sku")

PIM_FIELD(range, from, to)

Cross-reference identifiers.

=PIM_FIELD(A2:A101,"partNumber","sku")

PIM_IS_FOUND(range, id)

TRUE / FALSE existence check.

=PIM_IS_FOUND(A2:A101,"sku")

Migration from the old script

Old (per cell)New (per column)
GET_PRODUCT_PRICE(id,val,type,cur)PIM_PRICE(range,id,type,cur)
GET_ITEM_NAME(id,val)PIM_ITEM_NAME(range,id)
GET_SKU_BY_PARTNUMBER(val)PIM_FIELD(range,"partNumber","sku")
GET_PARTNUMBER_BY_SKU(val)PIM_FIELD(range,"sku","partNumber")
GET_PRODUCT_CODE_BY_SKU(val)PIM_FIELD(range,"sku","productCode")
IS_FOUND(val,type)PIM_IS_FOUND(range,type)

HTTP API

Base URL = this host. Results in a batch response align 1:1 with the input order.

EndpointAuthPurpose
GET/healthzHealth + snapshot stats
POST/v1/lookupbearerBatch lookup (used by Sheets)
GET/v1/pricebearerSingle price (query params)
GET/v1/namebearerSingle item name
GET/v1/fieldbearerSingle cross-reference
POST/admin/refreshrefresh tokenForce a snapshot rebuild

Batch request & response

POST /v1/lookup
{
  "identifier": "sku",        // sku | partNumber | productCode
  "values": ["ABC1", "ABC2"],
  "want": "price",           // price | name | field
  "priceType": "het",
  "currency": "IDR",
  "select": "partNumber"      // when want=field
}
{
  "want": "price",
  "builtAt": "2026-06-27T..Z",
  "results": [
    { "value":"ABC1", "found":true,  "result":125000 },
    { "value":"ABC2", "found":false, "result":null }
  ]
}

Try it

Runs a live POST /v1/lookup against this server. Token stays in your browser.

Matching behavior

Part numbers are slash-joined sets. They're matched by whole token, case-insensitively.

33203-BPV01-SLDRD✅ resolves 33203-BPV01-SLDRD/33203-B7401-SLDRD
62300-BPV77-8AAC1✅ does not match 62300-BPV77-8AAC13

When a token maps to several products, the lowest idProduct wins. sku is a single value (never split).

Admin

Snapshot refreshes automatically every few minutes. Force it after a price update:

curl -X POST "https://<host>/admin/refresh?token=$REFRESH_TOKEN"