# T3 API — LLM / AI Agent Quickstart The T3 API lets you programmatically access Metrc cannabis traceability data available on metrc.com. It is NOT the Metrc 3rd party API and does not use Metrc API keys. Full docs: https://api.trackandtrace.tools/v2/docs ## Discovering endpoints, parameters, and schemas The OpenAPI spec is the source of truth for all endpoints, parameters, request bodies, response schemas, and error formats. Do NOT guess or hardcode these — always fetch the spec first. The full spec is large. Use these query parameter filters to request only what you need. All filters are case-insensitive, combinable, and return a valid, minimal OpenAPI 3.0.2 spec. Multiple values of the same filter and different filter types can be combined in one request (results are merged via union). Filter Purpose Example path Get a specific endpoint's full definition ?path=/v2/packages/active tag Discover all endpoints in a category ?tag=Packages schema Inspect a data model ?schema=MetrcPackage parameter Inspect a reusable query parameter ?parameter=CollectionFilter All filters return transitively-referenced schemas and parameters. GET /v2/spec/openapi.json — Full spec GET /v2/spec/openapi.json?path=/v2/packages/active — Single endpoint GET /v2/spec/openapi.json?tag=Authentication — All auth endpoints GET /v2/spec/openapi.json?tag=Items&schema=Pagination — Combined filters ## Behavioral guidelines - Always authenticate first (see ?tag=Authentication). - Almost every data endpoint requires a licenseNumber query parameter. Fetch available licenses before querying data. - When you receive an error, inspect the response body. The error format is described in the OpenAPI spec. ## Report endpoints and Google Sheets Report endpoints return CSV or JSON data. Use ?tag=Reports to discover them. Each report endpoint has a corresponding data model schema — fetch the report's spec to see the available fieldnames and defaults: GET /v2/spec/openapi.json?path=/v2/packages/active/report The schema's `properties` keys are the valid fieldnames. Nested fields use dot notation (e.g., `item.name`, `item.productCategoryName`). Users will typically want to specify fieldnames to control which columns appear in the output. ### Query parameters for reports licenseNumber — Required. Your Metrc license. secretKey — For URL-based auth (required for IMPORTDATA). contentType=csv — Return CSV instead of JSON. prependCsvMetadata=false — Omit metadata header rows (required for IMPORTDATA). fieldnames=label,item.name — Comma-separated columns derived from schema properties. Nested fields use dot notation. filter=quantity__gte:100 — Filter expressions. sort=label:asc — Sort order. ### Building an IMPORTDATA() URL for Google Sheets IMPORTDATA() URLs must use secret key authentication because there is no way to pass a JWT header. Create a secret key via POST /v2/auth/secretkey, or generate one at /v2/pages/secret-key. URL template: https://api.trackandtrace.tools{REPORT_PATH}?licenseNumber={LICENSE}&secretKey={SECRET_KEY}&contentType=csv&prependCsvMetadata=false&fieldnames={FIELDNAMES} {REPORT_PATH} — The report endpoint path (e.g., /v2/packages/active/report). Discover all report paths with ?tag=Reports. {LICENSE} — The user's Metrc license number (e.g., LIC-00001). {SECRET_KEY} — A UUID secret key created via POST /v2/auth/secretkey. {FIELDNAMES} — Comma-separated list of columns (e.g., label,item.name,quantity). Discover valid fieldnames from the report's schema properties. To use in Google Sheets, wrap the assembled URL in IMPORTDATA(): =IMPORTDATA("https://api.trackandtrace.tools/v2/packages/active/report?licenseNumber=LIC-00001&secretKey=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&contentType=csv&prependCsvMetadata=false&fieldnames=label,locationName,item.name,quantity") ## Writing scripts Use the t3api_utils Python library with uv and PEP 723 inline metadata. t3api_utils docs: https://classvsoftware.github.io/t3api-python-utils/ Example script (run with `uv run script.py`): #!/usr/bin/env python3 # /// script # requires-python = ">=3.8" # dependencies = [ # "t3api_utils", # ] # /// from t3api_utils.api.parallel import load_all_data_sync from t3api_utils.main.utils import ( get_authenticated_client_or_error, interactive_collection_handler, pick_license, ) def main(): api_client = get_authenticated_client_or_error() license = pick_license(api_client=api_client) all_packages = load_all_data_sync( client=api_client, path="/v2/packages/active", license_number=license["licenseNumber"], collectionMask="label,item.name" ) interactive_collection_handler(data=all_packages) if __name__ == "__main__": main() More examples: https://github.com/classvsoftware/t3-api-examples