SeedLink
CustomersSign inRequest access

Guides/METRC 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
July 26, 2026
Revised
September 20, 2026
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.

Three ways a result reaches a package that already existed, as observed
MechanismWhat it keys onObservedWhere it stops
By itemItemFromFacilityLicenseNumber plus Item.Id, across facilities24 lab-resident samples moved 160 cultivator-side packages (sandbox, July 2026)Packages on a different item are untouched
By lineageThe source lot’s recorded resultsA 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 rightThe package itself59 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.

Lab-state timing at three Rhode Island production cultivator facilities, read-only, 2026-07-24
MeasureFirst cultivatorSecond cultivatorThird cultivatorAll three
Active packages whose LabTestingStateDate is later than their PackagedDate429262196
Child packages built from a parent that had not reached TestPassed138Not reportedNot reportedAt least 138
Of those, children on a different Item.Id than any parent that still received a result59Not reportedNot reportedAt least 59
Packages dispatched on an outgoing transfer before their result landed422127
Destination of those untested transfersA processor or a labA processor or a labA processor or a labNone to a dispensary
Wholesale manifests to a dispensary with results in before dispatchAllAllAllAll

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.

The lab-testing states this page observed, and what each meant for packaging and for a dispensary transfer
`LabTestingState`How a package reached itCutting a child from itTransfer to a dispensary
NotSubmittedThe 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)
SubmittedForTestingPOST /packages/v2/testing with RequiredLabTestBatches moved the source lot here in place (sandbox, 2026-07-26)Not observed separatelyNot observed; the sample left on a Lab Transfer dispatched by hand
TestingInProgressWritten onto the whole lineage when the lab recorded its results after a Lab Transfer (sandbox, 2026-07-26); the sandbox never moved past itNot observedNot observed
TestPassedPushed 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 resultsObserved 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 results

Changing 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.

  1. POST /packages/v2/testing from the untested lot, with RequiredLabTestBatches: ["Raw Plant Material"]. Without that field the call answers HTTP 400 At least one Lab Test Batch is required for Item. With it, the source lot moved from NotSubmitted to SubmittedForTesting in place, with no step in the UI.
  2. A person dispatched a Lab Transfer of the sample to the sandbox lab facility in METRC Connect and received it there.
  3. From the lab license, POST /labtests/v2/record with the batch’s 35 test types, each Passed: true, and OverallPassed: true. The quantities honour each type’s LabTestResultMode: PassWithinMinMax: a flat half-of-maximum value answered 400 on the types that carry a minimum.
  4. 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 TestingInProgress together. The cultivator-side sync read the new state and the potency values on its next pass, without writing anything to METRC.
The calls in the end-to-end run, what each needed, and what METRC answered without it
CallNeededAnswer without it, or from the wrong facility
POST /packages/v2/testingRequiredLabTestBatches: ["Raw Plant Material"]HTTP 400 At least one Lab Test Batch is required for Item
POST /packages/v2 and POST /harvests/v2/packagesA Location; with /locations/v2/active empty, an existing package’s LocationName is acceptedHTTP 400 Location was not specified.
Dispatch of the Lab TransferA person in METRC ConnectPOST /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/recordThe lab license, a package resident at the lab, 35 result rows each Passed: true, OverallPassed: true, and quantities inside each type’s minimum and maximumPackage … 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/finishAn empty package: adjust it to 0 first with reason Consumed during TestingPOST answers 405
PUT /labtests/v2/results/releaseNot needed: the state is set by the record call401
PUT /packages/v2/labtests/requiredOnly before the package has been transferredcannot 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 old

Across 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 ItemFromFacilityLicenseNumber and Item.Id to TestPassed, 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/v2 accepts a not-TestPassed ingredient. 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 a NotSubmitted parent 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 TestPassed with all 280 results recorded on the lot on 2026-04-25. A production batch into a different product category does not inherit: it starts at NotSubmitted with 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/release answers 401, PUT /packages/v2/labtests/required refuses after the transfer, there is no /labtests/v2/stages, and waiting changed nothing. Treat TestingInProgress as the sandbox terminal state and start from a TestPassed lot for anything downstream of a pass.
Can the API send the sample to the lab?
No. Probed on 2026-07-26: POST /transfers/v2/outgoing answers 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 to SubmittedForTesting; 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 on POST /labtests/v2/record regardless 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/results carries 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
SeedLink
GuidesMethodologyContactPrivacyTermsFor Rhode Island buyers
© 2026 SeedLink