If you are building or buying a cannabis POS, METRC is the compliance layer you cannot avoid in most U.S. markets. We have integrated with METRC in California, Colorado, Nevada, Michigan, Illinois, New York, and a handful of emerging states. The API looks straightforward on paper — REST endpoints, OAuth tokens, JSON payloads — but the real complexity lives in the state-by-state variants, permission models, and operational edge cases that break integrations at 2 a.m. when a manifest fails to close. We wrote this guide because we have lived through those 2 a.m. pages, and we want the next builder to have a map before they start walking.
What METRC actually is (and is not)
METRC is a traceability system operated by Franwell. It tracks cannabis plants and products from seed to sale using unique identifiers: package tags, plant tags, and lab result certificates. Each state contracts with Franwell to run its own METRC instance, which means the API base URL, data fields, and business rules differ by jurisdiction. METRC is not a POS. It is not an inventory management system. It is a compliance reporting pipe, and treating it like anything else is where most integrations fail. The most common mistake we see is vendors trying to use METRC as their primary inventory database. They query METRC for current stock levels, build their POS around those numbers, and then wonder why their counts drift. METRC is eventually consistent by design. It reflects what has been reported, not necessarily what is on the shelf right now. Your POS must own inventory truth locally and push compliance events to METRC asynchronously.
Per-state METRC variants that matter
We have seen teams assume that because they integrated with METRC in California, the Colorado integration will be identical. It is not. Here are the differences that regularly break builds.
California (DCC oversight)
California METRC requires daily sales reporting and manifest completion before a delivery can leave the premises. The DCC expects explicit transfer types — wholesale, retail, or return — and the API enforces recipient license validation on every transfer. If your integration skips recipient validation, the transfer will reject with a generic 400 that takes hours to trace.
Colorado (MED oversight)
Colorado METRC uses a different audit-log format than California. The MED requires timestamped logs for every inventory adjustment, including the reason code. If your POS does not store reason codes locally before pushing to METRC, you will have to reconstruct them during an audit. We learned this the hard way during our first Colorado deployment.
Michigan and Illinois
Both states run METRC but enforce purchase limits tied to the Cannabis Regulation and Taxation Act (CRTA) in Illinois and equivalent rules in Michigan. The API does not enforce these limits — your POS must. That means tracking rolling 30-day grams across all transactions for every patient and recreational customer, then rejecting or flagging over-limit sales before they ever reach METRC.
New York (OCM rules)
New York is the newest METRC state at scale. The OCM has additional fields for social-equity tracking and delivery-route manifests that are not present in the standard METRC spec. If you are building for New York, budget extra time for field mapping.
Common integration pitfalls
Rate limits
METRC API rate limits are not documented consistently per state. In California, we have observed effective limits around 100 requests per minute for sales endpoints. In Colorado, the limit is lower for plant queries. If you are syncing inventory in real time during a busy Saturday, you will hit the wall. We implement token-bucket backoff with jitter and queue non-critical syncs for off-peak windows.
License type permissions
A dispensary license cannot create packages. A cultivator license cannot record retail sales. A microbusiness license has hybrid permissions that vary by state. Your integration must validate the license type before calling an endpoint, or METRC will return a 403 with a message like "License does not have permission to perform this action." We keep a local permission matrix per state to short-circuit invalid requests before they leave our server.
Manifest workflows
A manifest in METRC represents a shipment. It must be created, packages added, and then either submitted or put in a "ready for pickup" state depending on the state. The gotcha: some states require the manifest to be in a specific status before the receiving party can accept it. If your driver leaves before the manifest is accepted on both sides, you have a compliance gap. We built a state machine for manifest status transitions with explicit hooks for driver dispatch so the POS blocks dispatch until the manifest is valid. The second gotcha is package weight tolerances. METRC enforces that a shipped package weight cannot exceed the original package weight by more than a state-defined tolerance — often one gram. If your scale rounds differently than METRC expects, the manifest will reject. We added pre-flight validation that simulates METRCs tolerance check before submission, which catches rounding issues at the POS instead of at the state API.
Native integration versus middleware
Vendors love to say "native METRC integration." In practice, this phrase covers two very different architectures.
Native integration means your POS calls METRC APIs directly from its backend. You own the credentials, the retry logic, the error handling, and the mapping. The advantage is control and latency. The disadvantage is engineering cost — every state change, every API version bump, and every outage is your problem to fix.
Middleware integration means a third-party service — sometimes a dedicated compliance bridge, sometimes a generic iPaaS — sits between your POS and METRC. The middleware handles auth, retries, and state mapping. The advantage is faster time to market. The disadvantage is an additional dependency, latency, and a support ticket dance when something breaks because you do not control the middle layer.
We chose native integration for DubLedger because our operators need sub-second checkout and because we want direct observability into every METRC call. If you are evaluating a POS, ask the vendor which architecture they use and whether they expose METRC call logs to you. If the answer is no, you are flying blind during an audit.
What we would do differently
If we were starting our METRC integration today, we would invest earlier in a unified event log that records every API request and response with correlation IDs. We would also build a simulator environment that mocks each state's METRC instance so we can test manifest workflows without touching production tags. Franwell provides a sandbox, but sandboxes do not always reflect the validation rules of the live environment. A local simulator, paired with real API smoke tests, gives us confidence before every deploy. We would also document our integration decisions more aggressively. Six months after building a workaround for a Colorado edge case, we had to rediscover why the workaround existed. Now we keep an architecture decision record for every METRC quirk, including the state, the API version, the date we observed it, and the ticket where we fixed it. That discipline has saved us dozens of hours on support calls.