Code examples
Eight common use cases against the GAB API. Each has a curl call, a TypeScript snippet using @goodsacrossborders/sdk, and a Python equivalent using the stdlib.
1. Fetch a country profile
Get the full customs profile for one destination (allowances, de minimis, VAT, restricted/prohibited).
CURL
curl https://goodsacrossborders.com/api/v1/countries/thailand.json
TYPESCRIPT
import { createClient } from "@goodsacrossborders/sdk";
const gab = createClient();
const thailand = await gab.getCountry("thailand");
console.log(thailand.vatRateStandard, thailand.deMinimisImport);PYTHON
import urllib.request, json
r = urllib.request.urlopen("https://goodsacrossborders.com/api/v1/countries/thailand.json")
country = json.loads(r.read())
print(country["vatRateStandard"], country["deMinimisImport"])2. Look up a single rule (item × country × purpose)
Get a specific rule by composite key, e.g. can I bring a vape to Thailand as a traveller?
CURL
curl https://goodsacrossborders.com/api/v1/rules/vape-e-cigarette_thailand_traveling.json
TYPESCRIPT
const rule = await gab.getRule("vape-e-cigarette", "thailand", "traveling");
console.log(rule.status, rule.statusSummary); // -> "prohibited", "Completely banned..."PYTHON
r = urllib.request.urlopen( "https://goodsacrossborders.com/api/v1/rules/vape-e-cigarette_thailand_traveling.json" ) rule = json.loads(r.read()) print(rule["status"], rule["statusSummary"])
3. Filter rules client-side
Find every restricted rule for a country, or every rule for an item across all countries.
CURL
# fetch all rules + grep curl https://goodsacrossborders.com/api/v1/rules.json | jq '.[] | select(.countrySlug=="japan" and .status=="prohibited")'
TYPESCRIPT
const prohibitedInJapan = await gab.findRules({ countrySlug: "japan" });
const onlyProhibited = prohibitedInJapan.filter((r) => r.status === "prohibited");PYTHON
r = urllib.request.urlopen("https://goodsacrossborders.com/api/v1/rules.json")
rules = json.loads(r.read())
prohibited = [r for r in rules if r["countrySlug"] == "japan" and r["status"] == "prohibited"]4. Sync rule changes nightly
Watch the changelog endpoint and alert when something corrected/removed lands.
CURL
curl https://goodsacrossborders.com/api/v1/changelog.json | jq '.[] | select(.changeType=="corrected" or .changeType=="removed")'
TYPESCRIPT
const log = await gab.listChangelog();
const today = new Date().toISOString().slice(0, 10);
const todays = log.filter((e) => e.date === today);
for (const entry of todays) {
if (entry.changeType === "corrected" || entry.changeType === "removed") {
notifyTeam(entry.summary); // your alert hook
}
}PYTHON
import datetime
r = urllib.request.urlopen("https://goodsacrossborders.com/api/v1/changelog.json")
log = json.loads(r.read())
today = datetime.date.today().isoformat()
for e in log:
if e["date"] == today and e["changeType"] in ("corrected", "removed"):
notify_team(e["summary"])5. Build a duty-rate lookup
Query the bilateral duty matrix to estimate landed cost.
CURL
curl https://goodsacrossborders.com/api/v1/duty-rates.json | jq '.[] | select(.originCountrySlug=="china" and .destinationCountrySlug=="united-states" and .hsChapter=="85")'
TYPESCRIPT
const rates = await gab.listDutyRates();
const match = rates.find(
(r) => r.originCountrySlug === "china"
&& r.destinationCountrySlug === "united-states"
&& r.hsChapter === "85",
);
if (match) console.log(`Duty: ${match.dutyRatePercent}%`);PYTHON
r = urllib.request.urlopen("https://goodsacrossborders.com/api/v1/duty-rates.json")
rates = json.loads(r.read())
match = next((x for x in rates
if x["originCountrySlug"] == "china"
and x["destinationCountrySlug"] == "united-states"
and x["hsChapter"] == "85"), None)
if match: print(f"Duty: {match['dutyRatePercent']}%")6. Power a customs-warning widget at checkout
Given the buyer's country and cart items, surface restricted/prohibited items before payment.
CURL
# pseudocode — combine /items + /rules for each cart line
TYPESCRIPT
async function checkCart(items: string[], destinationSlug: string) {
const flags = [] as Array<{ item: string; status: string; summary: string }>;
for (const itemSlug of items) {
try {
const r = await gab.getRule(itemSlug, destinationSlug, "importing-personal");
if (r.status !== "allowed") {
flags.push({ item: itemSlug, status: r.status, summary: r.statusSummary });
}
} catch { /* no rule indexed — surface as VERIFY */ }
}
return flags;
}PYTHON
def check_cart(items, destination_slug):
flags = []
for slug in items:
try:
r = urllib.request.urlopen(
f"https://goodsacrossborders.com/api/v1/rules/{slug}_{destination_slug}_importing-personal.json"
)
rule = json.loads(r.read())
if rule["status"] != "allowed":
flags.append({"item": slug, "status": rule["status"], "summary": rule["statusSummary"]})
except Exception:
pass
return flags7. List trade lanes with an active FTA
Filter the route-pair feed to lanes where a free-trade agreement is in force.
CURL
curl https://goodsacrossborders.com/api/v1/route-pairs.json | jq '.[] | select(.ftaStatus=="in-force")'
TYPESCRIPT
const lanes = await gab.listRoutePairs();
const active = (lanes as Array<{ ftaStatus?: string; ftaName?: string }>).filter(
(l) => l.ftaStatus === "in-force",
);PYTHON
r = urllib.request.urlopen("https://goodsacrossborders.com/api/v1/route-pairs.json")
lanes = json.loads(r.read())
active = [l for l in lanes if l.get("ftaStatus") == "in-force"]8. Drop into an LLM tool-use schema
Wire the SDK into a function-calling agent so the LLM can return live rules instead of hallucinating.
CURL
# n/a — agent-orchestrator integration
TYPESCRIPT
// Anthropic / OpenAI tool definition
const tools = [{
name: "get_customs_rule",
description: "Live customs rule for an item × country × purpose.",
input_schema: {
type: "object",
properties: {
itemSlug: { type: "string" },
countrySlug: { type: "string" },
purpose: { type: "string", enum: ["traveling", "posting", "importing-personal", "importing-commercial"] },
},
required: ["itemSlug", "countrySlug", "purpose"],
},
}];
// when the model calls get_customs_rule:
async function handleToolCall(args) {
const r = await gab.getRule(args.itemSlug, args.countrySlug, args.purpose);
return { status: r.status, summary: r.statusSummary, sources: r.sourceUrls };
}PYTHON
# Same pattern — wire your function-calling framework's tool handler to:
def handle_tool_call(args):
r = urllib.request.urlopen(
f"https://goodsacrossborders.com/api/v1/rules/{args['itemSlug']}_{args['countrySlug']}_{args['purpose']}.json"
)
rule = json.loads(r.read())
return {"status": rule["status"], "summary": rule["statusSummary"], "sources": rule.get("sourceUrls", [])}See also: /api reference, /developers/openapi spec, /developers/attribution.
We don't have a form backend, so these are pre-filled mailto links. Send a one-line email and we'll add you.