Skip to content

Lab Testing

These endpoints are for testing labs. Only a license whose facility type is a testing laboratory can see the Lab Samples grid or record results, and Metrc offers them in Maine and Missouri. To read results as a grower or processor, use GET /v2/packages/labresults?packageId= instead.

Endpoint What it does
GET /v2/packages/lab-samples One row per recorded test on each sample the lab holds
GET /v2/packages/labresults/record/inputs The test types the lab can record, and what each requires
GET /v2/packages/labresults/record/source-packages Packages Metrc will record results for
POST /v2/packages/labresults/document/file Store a result PDF (Missouri)
POST /v2/packages/labresults/record Record results for sample packages
GET /v2/packages/labresults/document/history?labTestResultId= The documents uploaded for one result

Recording and uploading are dry runs by default. Add submit=true to write to Metrc.

Recording results

Each result names a test type from the inputs endpoint. A test type whose requiresTestResult is true also needs a quantity.

import requests

API = "https://api.trackandtrace.tools"
HEADERS = {"Authorization": f"Bearer {ACCESS_TOKEN}"}
PARAMS = {"licenseNumber": "LAB00001"}

test_types = requests.get(
    f"{API}/v2/packages/labresults/record/inputs", params=PARAMS, headers=HEADERS
).json()["labTestTypes"]
thc = next(t for t in test_types if t["name"].startswith("THC"))

requests.post(
    f"{API}/v2/packages/labresults/record",
    params={**PARAMS, "submit": "true"},
    json=[
        {
            "packageId": 12345,
            "resultDate": "2026-10-23",
            "results": [{"labTestTypeId": thc["id"], "quantity": 21.5, "passed": True}],
        }
    ],
    headers=HEADERS,
)

Record a result for every test in the lab test batches the sample requires. Once recorded, the sample and the package it was cut from both read TestPassed or TestFailed in labTestingStateName. Tests that are informational only, such as Missouri's "R&D/Voluntary Testing" batches, leave both reading NotSubmitted.

Attaching a document (Missouri)

Upload the PDF first, then send the documentFileId it answers with alongside the results.

with open("coa.pdf", "rb") as pdf:
    document_file_id = requests.post(
        f"{API}/v2/packages/labresults/document/file",
        params={**PARAMS, "submit": "true"},
        files={"file": ("coa.pdf", pdf, "application/pdf")},
        headers=HEADERS,
    ).json()["documentFileId"]

Each result in GET /v2/packages/labresults?packageId= carries a labTestResultId. Pass it to the document history endpoint to list every document uploaded for that result, then download one with GET /v2/packages/labresults/document?packageId=&labTestResultDocumentFileId=, using the history row's documentFileId.