Delivery Examples¶
Recipes for cutting a report down and sending it somewhere: a filtered export, an emailed Excel workbook, a live Google Sheet.
Each uses the same preamble as the first script in Report Examples: a uv script header, imports, and your SECRET_KEY and LICENSE_NUMBER. Scripts authenticate with the X-T3-API-Key header; the plain URLs carry ?secretKey= because they are meant to be pasted somewhere.
Narrowing a report with filters, columns and a row limit¶
Reports return everything by default, which is rarely what you want while you are still building the request. These three parameters work together to cut a report down:
filternarrows which records come back. Repeat it for multiple conditions.columnspicks the columns, in the order you list them.rowLimitcaps how many records are loaded.
Say you want the label and quantity of every active package in the Bulk Storage room holding more than 100 units:
https://api.trackandtrace.tools/v2/packages/active/report?secretKey=YOUR_SECRET_KEY&licenseNumber=EX-00001&filter=locationName__eq:Bulk Storage&filter=quantity__gte:100&filterLogic=and&columns=label,item.name,quantity,unitOfMeasureAbbreviation&sort=quantity:desc&rowLimit=10
# Same preamble as the first example: uv script header,
# imports, SECRET_KEY and LICENSE_NUMBER.
def main():
response = httpx.get(
"https://api.trackandtrace.tools/v2/packages/active/report",
params={
"licenseNumber": LICENSE_NUMBER,
"filter": [
"locationName__eq:Bulk Storage",
"quantity__gte:100",
],
"filterLogic": "and",
"columns": "label,item.name,quantity,unitOfMeasureAbbreviation",
"sort": "quantity:desc",
# Start small while you get the filters right, then remove this.
"rowLimit": 10,
"contentType": "json",
},
headers={"X-T3-API-Key": SECRET_KEY},
# A report waits up to 240 seconds before giving up.
timeout=250.0,
)
response.raise_for_status()
report = response.json()
print(f"{len(report['data'])} packages")
for package in report["data"]:
print(package["label"], package["quantity"])
if __name__ == "__main__":
main()
Build with a small rowLimit, then remove it. See Limiting the Number of Rows.
Note that sort matters once rowLimit is in play: only the first n records are loaded, so sort=quantity:desc&rowLimit=10 gives you the ten largest packages, not ten arbitrary ones.
The column names available for a given report come from its dataModel, which is listed in the metadata preamble and documented under Schemas in the API docs.
Emailing a large report as an Excel workbook¶
The problem: your report is big enough that the request times out. A normal request waits 240 seconds and then returns Report Generation Timeout.
&delivery=email removes the wait: you get a receipt at once, and the report is sent when it is ready. It must still finish building within about five minutes. Pair it with &contentType=xlsx to get an Excel workbook attached to the email:
https://api.trackandtrace.tools/v2/packages/active/report?secretKey=YOUR_SECRET_KEY&licenseNumber=EX-00001&contentType=xlsx&delivery=email&[email protected]
# Same preamble as the first example: uv script header,
# imports, SECRET_KEY and LICENSE_NUMBER.
def main():
response = httpx.get(
"https://api.trackandtrace.tools/v2/packages/active/report",
params={
"licenseNumber": LICENSE_NUMBER,
"contentType": "xlsx",
"delivery": "email",
"email": "[email protected]",
},
headers={"X-T3-API-Key": SECRET_KEY},
# A report waits up to 240 seconds before giving up.
timeout=250.0,
)
response.raise_for_status()
# You get a receipt immediately. The report itself arrives by email.
print(response.json())
if __name__ == "__main__":
main()
The receipt, the errors that arrive by email, and why delivery=email never belongs on a Spreadsheet Sync link are covered in Emailing a Report.
Delivering a report to Google Sheets¶
&contentType=googleSheets builds a Google Sheet. Add &delivery=email and the link is emailed to the account you name instead of returned, which suits a report too large to finish inside a request. (Without delivery=email you get a 302 straight to the sheet; see The googleSheets Format.)
https://api.trackandtrace.tools/v2/packages/active/report?secretKey=YOUR_SECRET_KEY&licenseNumber=EX-00001&contentType=googleSheets&delivery=email&[email protected]
# Same preamble as the first example: uv script header,
# imports, SECRET_KEY and LICENSE_NUMBER.
# Must be a Google account: the sheet is shared with it directly.
GOOGLE_ACCOUNT = "[email protected]"
def main():
response = httpx.get(
"https://api.trackandtrace.tools/v2/packages/active/report",
params={
"licenseNumber": LICENSE_NUMBER,
"contentType": "googleSheets",
"delivery": "email",
"email": GOOGLE_ACCOUNT,
# Without this, anyone with the sheet's link can open and edit it.
"sheetVisibility": "private",
},
headers={"X-T3-API-Key": SECRET_KEY},
# A report waits up to 240 seconds before giving up.
timeout=250.0,
)
response.raise_for_status()
# The sheet link is emailed once the sheet has been created and shared.
print(response.json())
if __name__ == "__main__":
main()
The receipt carries no sheet URL, because the sheet does not exist yet. The recipient must be a Google account, the sheet is public unless you pass sheetVisibility=private, and every request creates a new sheet. See The googleSheets Format.
T3 Reports in the Chrome Extension uses this endpoint, so a sheet it creates behaves the same way.
Next Steps¶
- Read the parameters these use in Shaping a Report and Output Format.
- Set up a permanently live sheet with Spreadsheet Sync.
- If a large report times out, see Limits and Troubleshooting.