[{"code":"UNAUTHORIZED","common_causes":["Missing Authorization header or secret key","Invalid or malformed JWT token","Secret key not found or deleted"],"description":"The request lacks valid authentication credentials.","http_status_codes":[401],"resolution_steps":["Include a valid JWT token in the Authorization header, or provide a secret key via X-T3-API-Key header or secretKey query parameter","Use POST /v2/auth/credentials to obtain a new JWT","Verify your secret key is still active via GET /v2/auth/secretkey"],"type_url":"https://api.trackandtrace.tools/errors/UNAUTHORIZED"},{"code":"FORBIDDEN","common_causes":["Account has been blocked from API access","Insufficient permissions for the requested resource","License does not have access to this endpoint"],"description":"The server understood the request but refuses to authorize it.","http_status_codes":[403],"resolution_steps":["Check that your account has the necessary permissions","Use the Permissions endpoints to verify available actions","Contact support if you believe access should be granted"],"type_url":"https://api.trackandtrace.tools/errors/FORBIDDEN"},{"code":"NOT_FOUND","common_causes":["Invalid URL path","Resource has been deleted or does not exist","Incorrect license number"],"description":"The requested resource could not be found.","http_status_codes":[404],"resolution_steps":["Verify the endpoint URL is correct","Check that the license number and other identifiers are valid","Refer to the API documentation for available endpoints"],"type_url":"https://api.trackandtrace.tools/errors/NOT_FOUND"},{"code":"PAYMENT_REQUIRED","common_causes":["Attempting to use a premium endpoint without a T3+ subscription","T3+ subscription has expired","API key does not include access to this feature"],"description":"Access to this endpoint requires a T3+ subscription or API key.","http_status_codes":[402],"resolution_steps":["Subscribe to T3+ at https://trackandtrace.tools/plus","Check your subscription status","Contact support for API key access"],"type_url":"https://api.trackandtrace.tools/errors/PAYMENT_REQUIRED"},{"code":"INTERNAL_SERVER_ERROR","common_causes":["Unexpected server-side failure","Temporary infrastructure issue","Bug in the API server"],"description":"An unexpected error occurred on the server.","http_status_codes":[500],"resolution_steps":["Retry the request after a brief delay","If the error persists, contact support with the error details and timestamp"],"type_url":"https://api.trackandtrace.tools/errors/INTERNAL_SERVER_ERROR"},{"code":"INVALID_ENDPOINT_CONFIGURATION","common_causes":["Endpoint does not support the requested data model or action","Server-side configuration error","Attempting an unsupported operation for this resource type"],"description":"The endpoint is misconfigured or does not support the requested operation.","http_status_codes":[500],"resolution_steps":["Verify you are using the correct endpoint for your intended operation","Check the API documentation for supported operations on this endpoint","Contact support if you believe this is a server error"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_ENDPOINT_CONFIGURATION"},{"code":"INVALID_REQUEST_BODY","common_causes":["Missing required fields in the request body","Invalid field values or data types","Malformed JSON"],"description":"The request body failed validation.","http_status_codes":[400],"resolution_steps":["Check the errors array in the response for specific field-level validation failures","Refer to the API documentation for the expected request body schema","Ensure the request body is valid JSON with the correct Content-Type header"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_REQUEST_BODY"},{"code":"INVALID_QUERY_PARAMETER","common_causes":["Missing required query parameter (e.g., licenseNumber)","Invalid value for a query parameter","Query parameter value out of allowed range"],"description":"One or more query parameters are invalid.","http_status_codes":[400],"resolution_steps":["Check the errors array in the response for specific parameter failures","Refer to the API documentation for required and optional query parameters","Verify parameter values are within allowed ranges (e.g., pageSize 1-500)"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_QUERY_PARAMETER"},{"code":"INVALID_CONTENT_TYPE","common_causes":["Unsupported contentType query parameter value","Requesting a format that is not available for this endpoint"],"description":"The requested content type is not supported.","http_status_codes":[400],"resolution_steps":["Use a supported content type (e.g., csv, xlsx, json)","Check the API documentation for available content types on this endpoint"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_CONTENT_TYPE"},{"code":"UNEXPECTED_METRC_STATUS_CODE","common_causes":["The request violated a Metrc business rule, such as a duplicate name or a required field that depends on another field's value","The request referenced an ID that does not exist in Metrc","Metrc is experiencing issues or downtime","Metrc returned an error that T3 does not recognize","Network issue between T3 and Metrc"],"description":"Metrc returned an unexpected HTTP status code. The response status mirrors the one Metrc returned. When Metrc explains the rejection \u2014 for example that an item name is already in use \u2014 its message is included in the detail field.","http_status_codes":[400,500,502],"resolution_steps":["Read the detail field \u2014 when Metrc explains the rejection, its message is quoted there","Retry the request after a brief delay","Check if Metrc is experiencing known outages","If the error persists, contact support with the error details"],"type_url":"https://api.trackandtrace.tools/errors/UNEXPECTED_METRC_STATUS_CODE"},{"code":"OTP_REQUIRED","common_causes":["The Metrc account requires two-factor authentication (Michigan)","OTP was not included in the authentication request"],"description":"A one-time password (OTP) is required to complete authentication.","http_status_codes":[401],"resolution_steps":["Include the otp field in your authentication request","Generate a valid OTP from your authenticator app","If using secret keys, regenerate with the OTP seed included"],"type_url":"https://api.trackandtrace.tools/errors/OTP_REQUIRED"},{"code":"METRC_OTP_FAILURE","common_causes":["OTP has expired (codes are typically valid for 30 seconds)","Incorrect OTP value","OTP seed is out of sync with Metrc"],"description":"The provided one-time password was rejected by Metrc.","http_status_codes":[401],"resolution_steps":["Generate a fresh OTP and retry immediately","Verify your authenticator app's time is synchronized","If using a secret key, regenerate it with the correct OTP seed"],"type_url":"https://api.trackandtrace.tools/errors/METRC_OTP_FAILURE"},{"code":"METRC_LOGIN_FAILURE","common_causes":["Incorrect username or password","Password has been changed in Metrc","Username does not exist on the specified hostname"],"description":"Metrc rejected the login credentials.","http_status_codes":[401],"resolution_steps":["Verify your Metrc credentials by logging in at the Metrc website directly","Check that the hostname matches your Metrc state (e.g., ca.metrc.com)","If your password changed, update your credentials and regenerate any secret keys"],"type_url":"https://api.trackandtrace.tools/errors/METRC_LOGIN_FAILURE"},{"code":"METRC_SESSION_EXPIRED","common_causes":["The Metrc session has been idle for too long","Metrc invalidated the session","Session was logged out from another location"],"description":"The Metrc session has expired and needs to be re-established.","http_status_codes":[401],"resolution_steps":["Obtain a new JWT via POST /v2/auth/credentials","If using a secret key, the session will be re-established automatically on the next request","Retry the failed request"],"type_url":"https://api.trackandtrace.tools/errors/METRC_SESSION_EXPIRED"},{"code":"METRC_RESOURCE_UNAUTHORIZED","common_causes":["The license does not have permission to access this resource type","The Metrc session has expired mid-request","The user's Metrc permissions were changed"],"description":"Metrc denied access to the requested resource. This may indicate the license does not have permission to view this data, or the Metrc session has expired.","http_status_codes":[403],"resolution_steps":["Verify the license has the required permissions in Metrc","Use the Permissions endpoints to check available actions for this license","Try re-authenticating to establish a fresh Metrc session"],"type_url":"https://api.trackandtrace.tools/errors/METRC_RESOURCE_UNAUTHORIZED"},{"code":"METRC_NOT_FOUND_BY_ID","common_causes":["The ID does not exist in Metrc","The resource was deleted or moved","The ID belongs to a different license"],"description":"The specified Metrc resource could not be found by its ID.","http_status_codes":[404],"resolution_steps":["Verify the ID is correct","Check that you are querying the correct license","Search for the resource using alternative identifiers (e.g., label)"],"type_url":"https://api.trackandtrace.tools/errors/METRC_NOT_FOUND_BY_ID"},{"code":"METRC_SESSION_NOT_FOUND","common_causes":["The session has expired or was never created","The encrypted session data was evicted from the cache","Authentication was not completed before making API requests"],"description":"No active Metrc session was found for the provided credentials.","http_status_codes":[401],"resolution_steps":["Obtain a new JWT via POST /v2/auth/credentials","If using a secret key, the session will be re-established automatically","Ensure you are authenticating before making data requests"],"type_url":"https://api.trackandtrace.tools/errors/METRC_SESSION_NOT_FOUND"},{"code":"INVALID_TOKEN","common_causes":["JWT token is corrupted or truncated","Token was not issued by the T3 API","Incorrect token format in the Authorization header"],"description":"The provided authentication token is malformed or invalid.","http_status_codes":[422],"resolution_steps":["Ensure the Authorization header uses the format: Bearer <token>","Obtain a fresh token via POST /v2/auth/credentials","Check that the full token is being sent without truncation"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_TOKEN"},{"code":"TOKEN_EXPIRED","common_causes":["The JWT token's expiration time has passed","Too much time elapsed between obtaining the token and making the request"],"description":"The authentication token has expired.","http_status_codes":[401],"resolution_steps":["Obtain a new JWT via POST /v2/auth/credentials","Consider using secret key authentication for longer-lived access","Implement token refresh logic in your client"],"type_url":"https://api.trackandtrace.tools/errors/TOKEN_EXPIRED"},{"code":"TOKEN_REVOKED","common_causes":["The token was explicitly revoked","The associated session was terminated"],"description":"The authentication token has been revoked.","http_status_codes":[401],"resolution_steps":["Obtain a new JWT via POST /v2/auth/credentials","Check if your account status has changed"],"type_url":"https://api.trackandtrace.tools/errors/TOKEN_REVOKED"},{"code":"FRESH_TOKEN_REQUIRED","common_causes":["The endpoint requires a recently issued token for security","The current token was issued too long ago"],"description":"This operation requires a freshly issued authentication token.","http_status_codes":[401],"resolution_steps":["Obtain a new JWT via POST /v2/auth/credentials immediately before this request","Do not reuse tokens from earlier sessions for sensitive operations"],"type_url":"https://api.trackandtrace.tools/errors/FRESH_TOKEN_REQUIRED"},{"code":"UNEXPECTED_METRC_RESPONSE_STRUCTURE","common_causes":["Metrc changed their response format","Metrc returned an error page instead of data","Network issue caused a partial response"],"description":"Metrc returned a response with an unexpected structure that T3 could not parse.","http_status_codes":[502],"resolution_steps":["Retry the request after a brief delay","If the error persists, contact support \u2014 Metrc may have changed their API"],"type_url":"https://api.trackandtrace.tools/errors/UNEXPECTED_METRC_RESPONSE_STRUCTURE"},{"code":"METRC_ACCOUNT_LOCKED","common_causes":["Multiple failed login attempts with incorrect credentials","Automated systems sending bad credentials repeatedly","Account locked by Metrc administration"],"description":"The Metrc account has been locked due to too many failed login attempts.","http_status_codes":[423],"resolution_steps":["Wait approximately 15 minutes for the lockout to expire","Verify your credentials are correct before retrying","Do not retry with the same incorrect credentials \u2014 this extends the lockout"],"type_url":"https://api.trackandtrace.tools/errors/METRC_ACCOUNT_LOCKED"},{"code":"METRC_BAD_CREDENTIALS_COOLDOWN","common_causes":["A login attempt with incorrect credentials was recently made","T3 is protecting the account from being locked by rate-limiting login attempts"],"description":"A recent failed login attempt has triggered a cooldown period to prevent account lockout.","http_status_codes":[429],"resolution_steps":["Wait for the cooldown period to expire before retrying","Verify your credentials are correct \u2014 use the Metrc website to confirm","If your password recently changed, update your credentials before retrying"],"type_url":"https://api.trackandtrace.tools/errors/METRC_BAD_CREDENTIALS_COOLDOWN"},{"code":"RATE_LIMIT_EXCEEDED","common_causes":["Exceeded the default rate limit of 600 requests/minute","Exceeded an endpoint-specific rate limit","Multiple clients sharing the same credentials"],"description":"Too many requests have been sent in a given time period.","http_status_codes":[429],"resolution_steps":["Reduce request frequency and implement backoff logic","Check the Retry-After header for when to retry","Spread requests across time rather than sending in bursts"],"type_url":"https://api.trackandtrace.tools/errors/RATE_LIMIT_EXCEEDED"},{"code":"GATEWAY_TIMEOUT","common_causes":["Metrc is slow or unresponsive","The request involved a very large dataset","Network connectivity issues between T3 and Metrc"],"description":"The request timed out waiting for a response from Metrc.","http_status_codes":[504],"resolution_steps":["Retry the request after a brief delay","If requesting a large dataset, try paginating with smaller page sizes","Check if Metrc is experiencing known outages"],"type_url":"https://api.trackandtrace.tools/errors/GATEWAY_TIMEOUT"},{"code":"INVALID_REPORT_URL","common_causes":["'reportUrl' was missing, empty, or not a string","The URL exceeded the maximum saved length","The URL carried a parameter the report endpoint rejects, such as an unknown filter field, an unrecognized transform, or an out-of-range rowLimit"],"description":"The supplied report URL could not be saved.","http_status_codes":[400],"resolution_steps":["Request the report URL directly first \u2014 a URL that works as a request is a URL that can be saved","Check the error detail, which names the specific parameter that was rejected","Remove the secretKey parameter; it is stripped on save and never stored"],"type_url":"https://api.trackandtrace.tools/errors/INVALID_REPORT_URL"},{"code":"UNKNOWN_REPORT_PATH","common_causes":["The path was a collection endpoint such as /v2/packages/active rather than its report variant /v2/packages/active/report","The path was misspelled","The report endpoint does not exist for the requested collection"],"description":"The URL path does not name a report endpoint.","http_status_codes":[400],"resolution_steps":["Use a path ending in '/report'","Consult GET /v2/spec/openapi.json for the list of available report paths"],"type_url":"https://api.trackandtrace.tools/errors/UNKNOWN_REPORT_PATH"},{"code":"SAVED_REPORT_NOT_FOUND","common_causes":["The saved report was deleted","The publicId is incorrect","The saved report belongs to a different Metrc account; reports owned by another account are reported as not found rather than as forbidden"],"description":"No saved report with that id belongs to this account.","http_status_codes":[404],"resolution_steps":["List your saved reports with GET /v2/saved-reports","Confirm you are authenticating as the Metrc account that saved the report"],"type_url":"https://api.trackandtrace.tools/errors/SAVED_REPORT_NOT_FOUND"},{"code":"SAVED_REPORT_LIMIT_EXCEEDED","common_causes":["The per-account saved report limit has been reached"],"description":"This account has reached the maximum number of saved reports.","http_status_codes":[409],"resolution_steps":["Delete a saved report you no longer use with DELETE /v2/saved-reports/{publicId}","Contact support if you have a legitimate need for a higher limit"],"type_url":"https://api.trackandtrace.tools/errors/SAVED_REPORT_LIMIT_EXCEEDED"},{"code":"SAVED_REPORT_NAME_CONFLICT","common_causes":["A saved report with the same name already exists for this Metrc account"],"description":"Another saved report on this account already uses that name.","http_status_codes":[409],"resolution_steps":["Choose a different name","List existing names with GET /v2/saved-reports","Update the existing saved report instead with PATCH /v2/saved-reports/{publicId}"],"type_url":"https://api.trackandtrace.tools/errors/SAVED_REPORT_NAME_CONFLICT"},{"code":"SUPPORT_TICKET_NOT_FOUND","common_causes":["The publicId is incorrect","The ticket was filed by a different Metrc account; tickets owned by another account are reported as not found rather than as forbidden","The ticket was deleted"],"description":"No support ticket with that id belongs to this account.","http_status_codes":[404],"resolution_steps":["List your tickets with GET /v2/support/tickets","Confirm you are authenticating as the Metrc account that filed the ticket"],"type_url":"https://api.trackandtrace.tools/errors/SUPPORT_TICKET_NOT_FOUND"},{"code":"SUPPORT_TICKET_LIMIT_EXCEEDED","common_causes":["The per-account open ticket limit has been reached","A client retried a failing submission in a loop"],"description":"This account has too many open support tickets to file another.","http_status_codes":[409],"resolution_steps":["Wait for open tickets to be resolved","Add detail to an existing ticket by email rather than filing a duplicate"],"type_url":"https://api.trackandtrace.tools/errors/SUPPORT_TICKET_LIMIT_EXCEEDED"},{"code":"SUPPORT_TICKET_ATTACHMENT_REJECTED","common_causes":["The file type is not accepted; attachments must be a PNG, JPEG, GIF or WEBP image, a PDF, or plain text, CSV or JSON","A single file exceeds the maximum attachment size","The attachments together exceed the maximum total size","More files were sent than a ticket may carry","The declared file type did not match the file's actual contents, which are sniffed rather than trusted"],"description":"An uploaded attachment was rejected before the ticket was created.","http_status_codes":[400],"resolution_steps":["Check the error detail, which names the offending file","Compress or crop large screenshots before attaching them","Split a report with many attachments across several tickets"],"type_url":"https://api.trackandtrace.tools/errors/SUPPORT_TICKET_ATTACHMENT_REJECTED"},{"code":"LABEL_TEMPLATE_ERROR","common_causes":["A variable name is misspelled or is not present in the label data","An array was indexed but is empty, for example labTests[0] when labTests is []","An attribute was read from a value that is null or is not an object","The template has a Jinja syntax error, such as an unclosed {% if %} or {{ }}","A filter was given the wrong number or type of arguments","renderingOptions.strictTemplates is enabled and an expression resolved to undefined or null, which would otherwise have rendered as blank"],"description":"One or more label layout element templates could not be compiled or rendered against the supplied label data. The response `errors` array identifies each distinct problem by element index, template line and source line.","http_status_codes":[400],"resolution_steps":["Read the errors array: each entry gives elementIndex, line and sourceLine pinpointing the failing expression, plus a resolved field describing the type and size of the value that was actually found","Supply a fallback for values that are legitimately absent, for example {{ package.item.strain | default('N/A') }}","Use {{ value | default('N/A', true) }} to also cover values that are null","Guard optional keys with {% if package.field is defined %} rather than {% if package.field %}","Check an array is populated before indexing it, for example {% if package.labTests %}{{ package.labTests[0].value }}{% endif %}","Call GET /v2/labels/globals to list every built-in t3.* variable, and GET /v2/labels/example for a complete working payload","Set renderingOptions.strictTemplates to true while authoring a layout to surface expressions that would silently render blank"],"type_url":"https://api.trackandtrace.tools/errors/LABEL_TEMPLATE_ERROR"},{"code":"TAG_LIST_UNRESOLVED_ENTRIES","common_causes":["A handle has a typo, or belongs to a different license","The object exists but is in a different state, for example a package that is on hold or inactive rather than active","The handle names an object of a different type than the collection, for example a plant tag resolved against packages","Two objects in the collection share the handle when compared case-insensitively (reason: ambiguous)"],"description":"One or more tag list entries did not resolve to exactly one object in the requested collection. Nothing is returned when any entry fails, so a partial result can never be mistaken for a complete one. The response `errors` array lists every failing entry with its entryId, handle and reason.","http_status_codes":[422],"resolution_steps":["Read the errors array and correct or remove each listed entry with PATCH or DELETE /v2/tag-lists/{tagListId}/entries/{entryId}","Resolve against the collection the objects are actually in, for example endpoint=/v2/packages/onhold"],"type_url":"https://api.trackandtrace.tools/errors/TAG_LIST_UNRESOLVED_ENTRIES"},{"code":"COA_EXTRACTION_REQUIRED","common_causes":["The packages were never scheduled for COA extraction (reason: NOT_SCHEDULED)","Extraction was scheduled and is still running; it takes about a minute per document (reason: IN_PROGRESS)","A package received a new lab result after its tag list was scheduled"],"description":"COA results were requested for packages whose COA documents have not been extracted yet. Nothing was returned.","http_status_codes":[409],"resolution_steps":["Add the packages to a tag list and schedule it with POST /v2/tag-lists/{tagListId}/coa-extraction","Poll GET /v2/tag-lists/{tagListId}/coa-extraction until every package is READY, then retry the request","Read the errors array for each affected package and its document ids"],"type_url":"https://api.trackandtrace.tools/errors/COA_EXTRACTION_REQUIRED"},{"code":"COA_EXTRACTION_UNAVAILABLE","common_causes":["COA extraction has been paused"],"description":"COA extraction is temporarily unavailable. Nothing was scheduled.","http_status_codes":[503],"resolution_steps":["Retry later","Documents already extracted are still served by the coaResults include"],"type_url":"https://api.trackandtrace.tools/errors/COA_EXTRACTION_UNAVAILABLE"}]
