GuidesMETRC field guides for Rhode Island
METRC lab results in Rhode Island follow a package that was created before the results came back
On 2026-07-24, across the three Rhode Island production cultivators connected to SeedLink, 196 active packages carried a LabTestingStateDate later than their PackagedDate (42, 92 and 62 per cultivator): each package existed first and the result landed on it afterwards. One of the three had built 138 child packages from a parent that had not reached TestPassed, and 59 of those children carried a different Item.Id than any parent and still received a result. The same behaviour was then reproduced end to end on the Rhode Island sandbox on 2026-07-26: a lab recorded 35 results against a sample, and METRC wrote the same 35 results onto every package in the lineage, including a child cut before any result existed.
- Observed
- Revised
- Environment
- Rhode Island production and sandbox
What this page is
This page records what SeedLink’s integration observed about lab-testing state on the Rhode Island METRC API: three read-only probes across the three production cultivators connected to SeedLink on 2026-07-24, and a series of sandbox writes on 2026-07-25 and 2026-07-26 that reproduced the rule end to end. Every number is dated and sourced in the facts list. It is not METRC documentation and it is not regulatory guidance; it describes how the API behaved for licensed Rhode Island facilities on the dates given.
Counts belong to the three facilities on the day they were read and move with every package created, tested or shipped. The mechanism is what this page is about: which key METRC uses to push a result onto packages that already existed, where that stops, and what the sandbox does and does not reproduce. Other states run their own METRC instances and can differ on every point below.
It does not cover the lab’s COA. The document id lives on the results row that GET /labtests/v2/results returns, and fetching the PDF from it is the subject of the guide on free COAs.
How every number on this site is observed, dated and bounded is on the methodology page, which also lists what SeedLink does not publish.
METRC pushes the result state; nobody receives it
A lab result in METRC is not a document a cultivator collects and attaches to a package. When a lab calls POST /labtests/v2/record against a package flagged IsTestingSample, METRC promotes every sibling package that shares that sample’s ItemFromFacilityLicenseNumber and Item.Id to LabTestingState=TestPassed, and it does so across facilities: the sample sits at the lab, the siblings sit at the cultivator, and the state moves on all of them at once.
The size of that fan-out was visible on the Rhode Island sandbox in July 2026. Results recorded on 24 samples resident at the sandbox lab facility moved all 160 cultivator-side packages sharing their items to TestPassed in one pass. Nothing was written from the cultivator’s credential; the next read of active packages returned the new state.
That is the whole answer to "do I have to fetch the results and apply them": no. An integration that syncs packages from METRC sees the state change on its next read, and an integration that tried to receive results and write them onto packages would be writing a value METRC already owns. Item-level promotion is one of three ways a result reaches a package that already existed, and the other two matter as much.
| Mechanism | What it keys on | Observed | Where it stops |
|---|---|---|---|
| By item | ItemFromFacilityLicenseNumber plus Item.Id, across facilities | 24 lab-resident samples moved 160 cultivator-side packages (sandbox, July 2026) | Packages on a different item are untouched |
| By lineage | The source lot’s recorded results | A child born TestPassed with all 280 of its lot’s results (sandbox, 2026-07-25); 35 results written onto a child cut before any result existed (sandbox, 2026-07-26) | A production batch into a different product category starts at NotSubmitted with 0 results |
| The finished good, tested in its own right | The package itself | 59 children on a different Item.Id than any parent still received a result (production, 2026-07-24) | The package has to exist before the lab can post against it |
Packages are created before results in the normal Rhode Island workflow
One Rhode Island cultivator described the workflow before we measured it: "you can create the package prior to getting the test results, and the test results will follow the new package once they’re entered in." On 2026-07-24 three read-only probes across the three production cultivators connected to SeedLink put numbers on that sentence.
| Measure | First cultivator | Second cultivator | Third cultivator | All three |
|---|---|---|---|---|
Active packages whose LabTestingStateDate is later than their PackagedDate | 42 | 92 | 62 | 196 |
Child packages built from a parent that had not reached TestPassed | 138 | Not reported | Not reported | At least 138 |
Of those, children on a different Item.Id than any parent that still received a result | 59 | Not reported | Not reported | At least 59 |
| Packages dispatched on an outgoing transfer before their result landed | 4 | 22 | 1 | 27 |
| Destination of those untested transfers | A processor or a lab | A processor or a lab | A processor or a lab | None to a dispensary |
| Wholesale manifests to a dispensary with results in before dispatch | All | All | All | All |
The first row is the plain fact: 196 packages existed before their result did. The second row says how they came to exist. POST /packages/v2 accepts an ingredient package that has not passed testing, and one cultivator alone had built 138 children that way, so a refusal to package from an untested parent is a rule an integration adds, not one the state enforces.
The third row rules out the simple story. If a child always rode its parent’s item, the item-level promotion above would explain everything. It does not: 59 of those children carried a different Item.Id than any parent and still received a result. One infused pre-roll item was packaged on 2026-07-16 off a parent that was still NotSubmitted and received its own result on 2026-07-24; pre-roll material at a second cultivator received results 7 days after packaging. A finished good is tested in its own right, which is exactly why the package has to exist before the lab can post against it.
Where an untested package can go, and where METRC stops it
Untested packages do get dispatched on real manifests. By 2026-07-24, 27 packages across the three cultivators (4, 22 and 1) had shipped on outgoing transfers whose results landed afterwards, and every one of them was bound for a processor or a lab. None went to a dispensary, and every wholesale manifest to a dispensary had its results in first.
That pattern is not a habit; METRC enforces it at the destination. On 2026-07-25, on the Rhode Island sandbox, with SeedLink’s own manifest gate forced open by hand, POST /transfers/v2/templates/outgoing for a package in NotSubmitted bound for the sandbox dispensary facility returned HTTP 400 with this message:
Package <label> is marked as NotSubmitted and cannot be transferred to <license> (<facility>). The destination Facility cannot receive Packages with the NotSubmitted Lab Testing State.The rule belongs to the destination facility and it names the state. It was observed against the sandbox dispensary facility; the record treats the sandbox as the same rule engine as production and says that production-grade certainty needs a production observation.
| `LabTestingState` | How a package reached it | Cutting a child from it | Transfer to a dispensary |
|---|---|---|---|
NotSubmitted | The state of a lot before a testing sample is created from it; also the state of a production batch into a different product category (sandbox, 2026-07-25) | Accepted: an infused pre-roll child was packaged on 2026-07-16 off a parent still NotSubmitted (production), and 138 children at one cultivator came from parents that had not passed (2026-07-24) | Refused with HTTP 400 at the template step; the message names the destination facility and the state (sandbox, 2026-07-25) |
SubmittedForTesting | POST /packages/v2/testing with RequiredLabTestBatches moved the source lot here in place (sandbox, 2026-07-26) | Not observed separately | Not observed; the sample left on a Lab Transfer dispatched by hand |
TestingInProgress | Written onto the whole lineage when the lab recorded its results after a Lab Transfer (sandbox, 2026-07-26); the sandbox never moved past it | Not observed | Not observed |
TestPassed | Pushed onto every package sharing the sample’s item at the facility (sandbox, July 2026); inherited by a child cut from a passed lot (sandbox, 2026-07-25) | Accepted; the child is born TestPassed with the lot’s results | Observed on every wholesale manifest to a dispensary at the three production cultivators (2026-07-24) |
SeedLink drew one consequence from the two halves. An awaiting-results hold on a live source package is let through to packaging, since METRC accepts the ingredient and the result follows the child, and only the manifest is gated, since METRC refuses the transfer anyway and the cultivator hears it before the trip rather than as a raw 400. A failed test, a remediation hold and a superseded source block both packaging and the manifest.
Results also run down the lineage, until the product category changes
The sandbox shows inheritance directly. On 2026-07-25 a package was cut off a harvest dated 2026-03-05, and it was born TestPassed carrying all 280 results the lab had recorded on the source lot on 2026-04-25. GET /labtests/v2/results?packageId= on that package, minutes after it was created, returned the full set. The child did not wait for anything: the results were part of what it inherited.
One write breaks that inheritance, and it is the write that produced every genuinely untested sandbox package this page used. POST /packages/v2/ with a new Concentrate item, IsProductionBatch: true and a TestPassed flower package as the ingredient produced a package in LabTestingState=NotSubmitted with 0 lab results. METRC treats a production batch into a different product category as a new product form that needs its own testing.
POST /packages/v2/
{ Item: <new Concentrate item>, IsProductionBatch: true, ProductionBatchNumber: <batch>,
Ingredients: [{ Package: <TestPassed flower package>, ... }] }
-> LabTestingState = NotSubmitted, 0 lab resultsChanging the item afterwards does not undo it. PUT /packages/v2/item back to the Bud/Flower item left the state at NotSubmitted: LabTestingState does not recompute on an item change, in either direction. That yields a flower package, in grams, genuinely awaiting results, which is what the end-to-end run below started from, and it means an item change on a live package leaves whatever lab state the package already had.
The lab records only at its own facility, and the API cannot move the sample
A lab can record results only against packages resident at its own facility. From the sandbox lab license, POST /labtests/v2/record against a package still held by the cultivator answered Package … does not exist in the current Facility. From a cultivator license the same call answered HTTP 401 regardless of body: cultivator licenses on the Rhode Island sandbox lack the Manage Lab Tests permission.
So a sample has to travel, and the API cannot dispatch the transfer that moves it. Probed on the sandbox on 2026-07-26: POST /transfers/v2/outgoing answered 405 (the endpoint exists and is read-only); /transfers/v2/, /external/outgoing and /deliveries answered 404; POST /transfers/v2/external/incoming from the lab answered 401; and a template has no dispatch verb, with /templates/{id}/dispatch, /templates/{id}/transfer and /templates/outgoing/{id}/create all answering 404. The record notes that there is no public API for a facility-to-facility transfer that carries results back to the cultivator side; METRC keeps that in its web UI. Staging a template through the API first leaves only the dispatch to do by hand, and once the lab has recorded its results METRC writes them back across the lineage on its own.
The end-to-end run on the sandbox, 2026-07-26
Everything above was then run as one sequence on the Rhode Island sandbox on 2026-07-26, starting from a lot minted untested by the production-batch write, with a child already cut from it before any result existed, and with a person dispatching the one transfer.
POST /packages/v2/testingfrom the untested lot, withRequiredLabTestBatches: ["Raw Plant Material"]. Without that field the call answers HTTP 400At least one Lab Test Batch is required for Item. With it, the source lot moved fromNotSubmittedtoSubmittedForTestingin place, with no step in the UI.- A person dispatched a Lab Transfer of the sample to the sandbox lab facility in METRC Connect and received it there.
- From the lab license,
POST /labtests/v2/recordwith the batch’s 35 test types, eachPassed: true, andOverallPassed: true. The quantities honour each type’sLabTestResultMode: PassWithinMinMax: a flat half-of-maximum value answered 400 on the types that carry a minimum. - METRC then wrote the same 35 passing results onto every package in the lineage (the source lot, both samples and the child cut before any result existed) and moved all of them to
TestingInProgresstogether. The cultivator-side sync read the new state and the potency values on its next pass, without writing anything to METRC.
| Call | Needed | Answer without it, or from the wrong facility |
|---|---|---|
POST /packages/v2/testing | RequiredLabTestBatches: ["Raw Plant Material"] | HTTP 400 At least one Lab Test Batch is required for Item |
POST /packages/v2 and POST /harvests/v2/packages | A Location; with /locations/v2/active empty, an existing package’s LocationName is accepted | HTTP 400 Location was not specified. |
| Dispatch of the Lab Transfer | A person in METRC Connect | POST /transfers/v2/outgoing 405; /transfers/v2/, /external/outgoing and /deliveries 404; POST /transfers/v2/external/incoming from the lab 401; the template dispatch paths 404 |
POST /labtests/v2/record | The lab license, a package resident at the lab, 35 result rows each Passed: true, OverallPassed: true, and quantities inside each type’s minimum and maximum | Package … does not exist in the current Facility for a package held elsewhere; 401 from a cultivator license; 400 on a flat half-of-maximum quantity for a type with a minimum |
PUT /packages/v2/finish | An empty package: adjust it to 0 first with reason Consumed during Testing | POST answers 405 |
PUT /labtests/v2/results/release | Not needed: the state is set by the record call | 401 |
PUT /packages/v2/labtests/required | Only before the package has been transferred | cannot be changed because it has already been Transferred |
Where the sandbox stops, and how to post results there
The sandbox never advanced that lineage to TestPassed. After the run, METRC’s own UI showed the lot’s only required batch, Raw Plant Material, as Passed with 35 of 35 performed, every result passed and released, the sample adjusted to 0 with reason Consumed during Testing and finished, and the family still read TestingInProgress. Everything that might have moved it was tried: PUT /labtests/v2/results/release answers 401, PUT /packages/v2/labtests/required refuses after the transfer with cannot be changed because it has already been Transferred, there is no /labtests/v2/stages, and waiting changed nothing.
Treat TestingInProgress as the sandbox’s terminal state for a lot that went through a Lab Transfer. To exercise anything downstream of a pass, start from a lot that is already TestPassed: its child is born TestPassed, as the lineage read of 2026-07-25 shows.
A different sandbox path does reach TestPassed, and it is the one that produced the 24-to-160 fan-out in July 2026. The sandbox lab facility can post results for packages already resident there. A working body is [{ Label, ResultDate: YYYY-MM-DD, Results: [about 35 Raw Plant Material types, each { LabTestTypeName, Quantity, Passed: true, Notes: "" }], OverallPassed: true }], sent with the lab’s license number. The package read TestPassed immediately on the 200, with no release call, and every cultivator-side sibling on the same item moved with it. The test types are filtered to Raw Plant Material, excluding the Retest, R&D, Sub-Contract and Final Form variants.
The record does not say why one path ends at TestPassed and the other at TestingInProgress. What it shows is that the two setups differ: the July run posted against samples already resident at the lab, and the 2026-07-26 run declared a required batch on the source lot, moved the sample by Lab Transfer and posted after receipt. Anyone reproducing this on the sandbox picks the path that reaches the state they need. The two verbs that cost a round trip each to learn, PUT /packages/v2/finish on an emptied package and the Location that every package create requires, are in the table above with the answers METRC gave without them.
Check it yourself with two read-only calls
Whether a result followed a package is visible on the package itself and on its results, with no writes.
GET https://api-ri.metrc.com/packages/v2/<label>?licenseNumber=<your license>
Authorization: Basic <base64 of VENDOR_KEY:USER_KEY>
read PackagedDate, LabTestingState, LabTestingStateDate and the package Id
if LabTestingStateDate is later than PackagedDate:
the package existed before its result did
GET https://api-ri.metrc.com/labtests/v2/results?packageId=<Id>&licenseNumber=<your license>
count the rows: on a child cut from a passed lot the count matches the lot’s,
even when the child is minutes oldAcross your active packages, the count of rows whose LabTestingStateDate is later than their PackagedDate is the same measure that gave 196 across three Rhode Island cultivators on 2026-07-24. A package whose results count is 0 while its ingredient was TestPassed is a production batch into a different product category, or something this page has not observed.
Questions
- Do I have to fetch lab results from METRC and write them onto my packages?
- No. When the lab records a result, METRC promotes every package sharing the sample’s
ItemFromFacilityLicenseNumberandItem.IdtoTestPassed, across facilities, and writes the results down the lineage. On the sandbox in July 2026, results on 24 lab-resident samples moved 160 cultivator-side packages in one pass. A sync sees the new state on its next read. - Can I cut a child package from a parent that has not passed testing?
- Yes.
POST /packages/v2accepts a not-TestPassedingredient. One Rhode Island cultivator had 138 children built that way on 2026-07-24, and one infused pre-roll item packaged on 2026-07-16 off aNotSubmittedparent received its own result on 2026-07-24. A block on it is the integration’s rule, not METRC’s. - Can an untested package go on a manifest?
- To a processor or a lab, yes: 27 such packages had shipped across three cultivators by 2026-07-24. To a dispensary, no: on the sandbox on 2026-07-25 the template call answered HTTP 400 with
The destination Facility cannot receive Packages with the NotSubmitted Lab Testing State. - Does a child package inherit its parent’s results?
- Yes, while it stays in the lineage. A package cut on 2026-07-25 off a harvest from 2026-03-05 was born
TestPassedwith all 280 results recorded on the lot on 2026-04-25. A production batch into a different product category does not inherit: it starts atNotSubmittedwith 0 results, and changing the item back does not recompute the state. - Why did the sandbox lot stay at TestingInProgress with every result passed?
- The record does not say.
PUT /labtests/v2/results/releaseanswers 401,PUT /packages/v2/labtests/requiredrefuses after the transfer, there is no/labtests/v2/stages, and waiting changed nothing. TreatTestingInProgressas the sandbox terminal state and start from aTestPassedlot for anything downstream of a pass. - Can the API send the sample to the lab?
- No. Probed on 2026-07-26:
POST /transfers/v2/outgoinganswers 405, the other transfer paths 404 or 401, and a template has no dispatch verb. The API creates the sample and moves the source lot toSubmittedForTesting; a person dispatches the Lab Transfer in METRC Connect. - Which package can the lab record against?
- Only one resident at its own facility. Against a cultivator-held package the lab license gets
Package … does not exist in the current Facility, and a cultivator license gets 401 onPOST /labtests/v2/recordregardless of body, since sandbox cultivator licenses lack the Manage Lab Tests permission. - Where is the COA for a tested package?
- On the results row:
GET /labtests/v2/resultscarries the lab’s document id, and fetching the PDF from it is its own guide, free COAs.
Sources and how to cite this page
- Read-only probes across the three Rhode Island production cultivator facilities connected to SeedLink, 2026-07-24: lab results read by package, propagation identity, and lab state at ship time.
- Rhode Island sandbox, 2026-07-25: a transfer template to the sandbox dispensary facility with the manifest gate forced open, the lineage read on a package minutes old, and the production-batch write.
- Rhode Island sandbox, 2026-07-26: the end-to-end run with a person dispatching the Lab Transfer, and the transfer-verb probe of the same day.
- Rhode Island sandbox, July 2026 (the record gives the month only): lab-side results recorded on 24 resident samples through the sandbox lab pipeline.
- SeedLink METRC field guide (docs/METRC.md), section Lab Testing, read 2026-09-20.
SeedLink, "METRC lab results in Rhode Island follow a package that was created before the results came back", observed 2026-07-26, revised 2026-09-20, https://www.seedlink.net/guides/metrc/lab-results-follow-the-package
Every figure above carries the date it was observed and the environment it was observed in. A count belongs to one facility on one day; the field names, orderings and error messages are the durable part.
Machine-readable copy of this page, with the same facts, dates and sources: /guides/metrc/lab-results-follow-the-package/data.json
Related
- METRC serves the lab COA PDF for free in Rhode Island: one GET returns the raw PDF, and whether a document exists is a per-lab fact
- METRC remediation transfers in Rhode Island: the outgoing delivery’s ShipmentTypeName is the only sign a package is out, and the incoming transfer is the proof it came back
- A METRC transfer template becomes a manifest only when a person dispatches it in METRC Connect: Rhode Island exposes no dispatch endpoint
- Combining two METRC packages of one item in Rhode Island is one POST with two ingredients, and the drained sources stay active until you finish them
- All metrc field guides for rhode island
- Methodology: what SeedLink publishes and what it does not