Retail ID Labels¶
Metrc's Retail ID program puts a QR code on each retail unit. You download a set of codes for a package, then print them as labels. This page covers doing that through the API.
Metrc never produces a printable PDF on its server. Its own page draws the PDF in your browser. The API gives you the codes as CSV rows, which you can turn into labels with the Label Studio.
| Endpoint | What it does |
|---|---|
GET /v2/packages/product-labels/download/source-packages | Packages you can download labels for |
POST /v2/packages/product-labels/download | Issue labels for packages |
GET /v2/packages/product-labels/print/csv | Read one issued set as CSV rows |
GET /v2/packages/product-labels/print/worker | Read Metrc's instructions for drawing one set as a PDF |
GET /v2/packages/product-labels | Packages that have labels |
GET /v2/packages/product-labels/download-history?packageId= | The sets issued for one package |
POST /v2/packages/product-labels/redownload | Fetch a set issued earlier |
GET /v2/packages/product-labels/download/compliance-templates?packageId= | California's label templates for one package |
Downloading labels is a write: it is a dry run by default, and with submit=true Metrc issues the labels. Metrc offers no way to withdraw them. Metrc's own form warns against labelling bulk material, whose child packages then cannot get labels of their own.
Downloading and printing¶
A download answers with Metrc's response under metrcResponse. Each entry in its result names one issued set. Pass its issuanceId and labelSet to the print endpoint for its format.
import requests
API = "https://api.trackandtrace.tools"
HEADERS = {"Authorization": f"Bearer {ACCESS_TOKEN}"}
PARAMS = {"licenseNumber": "RET00001"}
answer = requests.post(
f"{API}/v2/packages/product-labels/download",
params={**PARAMS, "submit": "true"},
json=[{"packageId": 12345, "labelQuantity": 100, "format": "csv"}],
headers=HEADERS,
).json()
for issued in answer["metrcResponse"]["result"]:
if not issued.get("issuanceId"):
print("Metrc refused this entry:", issued)
continue
rows = requests.get(
f"{API}/v2/packages/product-labels/print/csv",
params={**PARAMS, "issuanceId": issued["issuanceId"], "labelSet": issued.get("labelSet")},
headers=HEADERS,
).json()["csv"]
header, labels = rows[0], rows[1:]
print(header, len(labels), "labels")
A "message": "Success" means Metrc accepted the request. Metrc can still refuse one entry inside it, so check each entry for an issuanceId as above.
For "format": "pdf", read the set from /print/worker instead. Metrc's own page reads an entry whose format is newPdf the same way.
Fetching labels again¶
Each package on GET /v2/packages/product-labels keeps a download history, one row per set. Redownload fetches a set issued earlier, and answers the same way as a download.
history = requests.get(
f"{API}/v2/packages/product-labels/download-history",
params={**PARAMS, "packageId": 12345},
headers=HEADERS,
).json()["data"]
answer = requests.post(
f"{API}/v2/packages/product-labels/redownload",
params={**PARAMS, "submit": "true"},
json={"id": 12345, "format": "csv", "labelSet": history[0]["labelSet"]},
headers=HEADERS,
).json()
Leave out labelSet to send none, as the buttons on Metrc's grid rows do.
Staged labels¶
In California and Michigan, Metrc can issue labels for a tag before any package carries it. Every endpoint above has a staged twin under /v2/packages/staged-product-labels, taking a tagId instead of a packageId: download, redownload, download-history?tagId=, download/source-tags, download/inputs and download/compliance-templates?tagId=. The print endpoints serve both.
California compliance templates¶
California's form offers label templates. Read a package's with GET /v2/packages/product-labels/download/compliance-templates?packageId=12345, then send the chosen template's template as complianceLabelTemplate and its templateId with the download. Both are optional.