# border.bot > border.bot classifies products to HS codes and calculates duties, taxes and landed cost for cross-border parcels, in a web dashboard, over a REST API and through an MCP server for Claude, ChatGPT, Codex, Cursor and other AI clients. --- # HS codes and landed cost for cross-border parcels > Classify products to HS and HTS codes and calculate duties, taxes and landed cost for cross-border parcels in a dashboard, over an API or in Claude via MCP. Source: https://staging.border.bot Last updated: 2026-10-14 Paste a product page or describe the product. border.bot returns the tariff code for the destination country and the duty, import tax and fees due when the parcel arrives. [Create a free account](https://staging-app.border.bot/signup) · [Try the free classifier](https://staging.border.bot/tools/hs-code-classifier) ## How a shipment is handled The example below follows a Heavyweight crew-neck T-shirt made in Vietnam and shipped to Los Angeles, United States. ### Read the product page Paste a product URL or type a description. We read the title, brand, materials and price from the page and look for the country of origin in its product data or text. When the page doesn’t say where the item was made, we estimate it and show the evidence. - Product page: https://shop.example/products/heavyweight-tee - Title: Heavyweight crew-neck T-shirt - Material: 100% cotton jersey knit - Price: $24.00 - Made in: Vietnam, from “Made in Vietnam” on the product page ### Classify it for the destination The product is matched against the destination’s tariff: the 10-digit HTS for the US, 10-digit commodity codes for the UK and Canada, CN and TARIC codes for the EU, and the 6-digit HS code for other countries. Each level of the code comes with its official description and a confidence score. | Level | Code | Description | | --- | --- | --- | | Chapter | 61 | Articles of apparel and clothing accessories, knitted or crocheted | | Heading | 6109 | T-shirts, singlets, tank tops and similar garments, knitted or crocheted | | Subheading | 6109.10 | Of cotton | | Tariff line | 6109.10.00.12 | The 10-digit US statistical line the shipment is declared under | Confidence: High. ### Calculate duty, tax and fees Duty, import tax and customs fees are calculated for that code, origin and destination, one line per charge with the rate used. Added to the goods and shipping, they give the landed cost. | Line | Amount (USD) | Note | | --- | --- | --- | | Goods | 24.00 | From the product page | | Shipping | 6.50 | Your carrier rate | | Duty | 5.40 | For this code and origin | | Fees | 1.10 | Customs processing | | Taxes | 0.00 | No import tax on this item | | Landed cost | 37.00 | What the customer pays in total | _Illustrative figures. Rates change, so run the calculator for a current answer._ ### Charge it at checkout With the landed cost known, you can collect duty and tax at checkout so the customer pays nothing on delivery, and the customs declaration carries the right code and origin. Every result is saved in your account. Status: cleared and delivered to Los Angeles, United States. ## Classification Send a product description, a product page URL or both, with the destination country. You get the tariff code that country’s customs expects, the official description at each level of the code, a confidence score, the reasoning and the closest alternatives. Results with low confidence are flagged for review. For high-value or regulated goods, have a licensed customs broker confirm the code or ask customs for a binding ruling. | Destination | Tariff | Code | | --- | --- | --- | | United States | Harmonized Tariff Schedule (HTS) | 10 digits | | United Kingdom | UK Global Tariff | 10 digits | | European Union | Combined Nomenclature (CN) and TARIC | 8 or 10 digits | | Canada | Customs Tariff | 10 digits | | Other countries | Harmonized System (HS) | 6 digits | [Try the free classifier](https://staging.border.bot/tools/hs-code-classifier) ## Landed cost Give an HS code, or a description to classify first, with the country of origin, the destination, the total goods value and the shipping cost. You get each duty, tax and fee line with the rate used, the de minimis check for the destination and the total in the destination’s currency. Measures that apply only under certain conditions are listed separately and not added to the total. Carrier brokerage and handling fees are not included. Destinations: United States, United Kingdom, Canada, European Union (all 27 member states). Other destinations are checked when you run a calculation, and you’re told if one isn’t covered yet. How a landed cost is built, with hypothetical rates of 10% duty and 20% VAT for a destination that charges duty on goods plus shipping: | Line | Calculation | Amount | | --- | --- | --- | | Goods | Invoice value | 100.00 | | Shipping | Carrier rate | 10.00 | | Customs value | Goods plus shipping | 110.00 | | Duty | 10% of the customs value | 11.00 | | Import VAT | 20% of customs value plus duty | 24.20 | | Landed cost | Goods, shipping, duty and VAT | 145.20 | [Try the free calculator](https://staging.border.bot/tools/landed-cost-calculator) ## REST API Classify and calculate from your own systems: the checkout, the product catalogue, an ERP or shipping software. Requests and responses are JSON over HTTPS. ```bash curl https://api.border.bot/v1/classify \ -H "Authorization: Bearer $BORDERBOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "description": "Heavyweight crew-neck T-shirt, 100% cotton jersey knit", "destinationCountry": "US", "originCountry": "VN" }' ``` Example response (trimmed): ```json { "result": { "hsCode": "6109100012", "hsCodeFormatted": "6109.10.00.12", "nomenclature": "us", "confidence": "high", "needsReview": false, "hierarchy": [ { "level": "chapter", "code": "61", "description": "Articles of apparel … knitted or crocheted" }, { "level": "heading", "code": "6109", "description": "T-shirts, singlets, tank tops …" }, { "level": "subheading", "code": "610910", "description": "Of cotton" } ], "alternatives": [ … ] }, "credits": { "charged": 1, "balance": 99 } } ``` - Authenticate with a workspace API key in the Authorization header. - Errors come back as JSON with a code such as insufficient_credits or rate_limited. - Repeating a request with the same idempotency key returns the first result without charging again. - Calls use the same credits as the dashboard and the MCP server. [Developer quickstart](https://staging.border.bot/developers) · [API reference](https://staging.border.bot/docs/api) ## Use border.bot from Claude, ChatGPT, Codex, Cursor and 30 other MCP clients Add the border.bot MCP server to your AI client and sign in with your border.bot account. The assistant can then classify products and calculate landed cost during a conversation. Each call uses credits from the workspace you pick when you connect. MCP server URL: `https://staging-mcp.border.bot/mcp`. Setup guides: [Claude](https://staging.border.bot/mcp#claude), [ChatGPT](https://staging.border.bot/mcp#chatgpt), [Claude Code](https://staging.border.bot/mcp#claude-code), [Codex](https://staging.border.bot/mcp#codex), [Cursor](https://staging.border.bot/mcp#cursor), [Visual Studio Code](https://staging.border.bot/mcp#vscode), [Gemini CLI](https://staging.border.bot/mcp#gemini-cli), [Gemini](https://staging.border.bot/mcp#gemini), [GitHub Copilot CLI](https://staging.border.bot/mcp#github-copilot-cli), [Perplexity](https://staging.border.bot/mcp#perplexity), [Vibe Work](https://staging.border.bot/mcp#mistral-vibe), [Cline](https://staging.border.bot/mcp#cline). [Setup steps for all 34 clients](https://staging.border.bot/mcp). ## Pricing Credits are prepaid and there is no subscription. A classification uses 1 credit and a landed-cost calculation 1 credit. New accounts get 10 credits free. Credits for a failed call are refunded automatically. ### Credit packs | Pack | Credits | Price | Per credit | Notes | | --- | --- | --- | --- | --- | | Starter | 100 | $19.00 | $0.19 | For trying border.bot on real shipments. | | Growth (most popular) | 500 | $79.00 | $0.16 | For growing stores shipping internationally every day. | | Scale | 2000 | $249.00 | $0.12 | For teams classifying whole catalogues. | | Volume | 10000 | $990.00 | $0.10 | For platforms and high-volume shippers. | ### What each action costs | Action | Cost | What it does | | --- | --- | --- | | Classification (Mini) | 1 credit | The fastest: search by meaning and words, then the reranker. No language model. | | Classification (Pro) | 1 credit | A model rewrites the listing in customs terms, the search stays in the chapters it names, and a model ranks the candidates by the rules of interpretation, with precedent rulings. Brand-only listings are identified on the web. | | Classification (Max) | 3 credits | The highest accuracy: an agent searches the tariff, walks its tree, reads rulings and identifies products on the web. | | Agency product code | 1 credit | Find the product code the destination’s import agency asks for. | | Landed cost calculation | 1 credit | Duties, taxes and fees for one HS code / origin / destination. | | Duty stacking | Free | Which duty lines apply to a code and origin, without a shipment. | | Product URL extraction | Free | Read a product page and extract title, brand, price and materials. | | Country of origin inference | Free | Infer where a product is made from page data and AI. | | Air waybill | 1 credit | One air waybill PDF (master or house), every copy included. | - New accounts get 10 credits free. - The free tools allow 3 free runs per visitor every 30 days, no account needed. Prices as of 2026-10-15. [See live pricing](https://staging.border.bot/pricing). ## Free classifier, calculator and origin finder The free tools work without an account: 3 free runs per visitor every 30 days, shared between the classifier, the calculator and the origin finder. The air waybill generator has its own allowance. - [HS code classifier](https://staging.border.bot/tools/hs-code-classifier) - [Landed cost calculator](https://staging.border.bot/tools/landed-cost-calculator) - [Country of origin finder](https://staging.border.bot/tools/country-of-origin-finder) - [Air waybill generator](https://staging.border.bot/tools/air-waybill-generator) ## Common questions ### What does border.bot do? It finds the HS code for a product and calculates the duty, import tax, fees and total landed cost of shipping it to another country. You can use it in the web dashboard, through the REST API, or from Claude, ChatGPT, Codex, Cursor and other AI clients through our MCP server. ### Which countries and tariff schedules do you cover? Classification returns 10-digit codes for the US (HTS), the UK and Canada, CN and TARIC codes for the EU, and the 6-digit HS code for every other destination. Landed cost calculation covers the US, the UK, Canada, all 27 EU member states and more destinations, checked when you run it. ### How accurate is the classification? Each result shows the official description at every level of the code, a confidence score, the reasoning and the closest alternatives, and low-confidence results are flagged for review. Treat it as a well-documented first answer. For high-value, regulated or disputed goods, have a licensed customs broker confirm it or ask the customs authority for a binding ruling. ### How does pricing work? You buy prepaid credit packs and there is no subscription. Each classification or landed-cost calculation uses credits, the cost of every action is listed on the pricing page, and credits for a failed call are refunded automatically. New accounts start with free credits. ### Can I use border.bot from Claude, ChatGPT, Codex or Cursor? Yes. Add our remote MCP server to your client, sign in with your border.bot account and choose which workspace pays. The assistant can then classify products and calculate landed cost in the conversation, using the same credits as the dashboard. The MCP page has setup steps for each supported client. ### Is the free classifier really free? Yes. The free HS code classifier, landed cost calculator and country of origin finder give each visitor a few runs without an account. Cloudflare Turnstile and a usage limit stop automated abuse. Create an account when you need more. ### What happens to the product data I send? We use it to produce the result and keep it in your workspace history so you can find it again. Payments are handled by Stripe and card details never reach our servers. The security page explains sign-in, API keys, MCP access and data handling in detail. ## Guides - [The EU’s €3 customs duty on parcels under €150](https://staging.border.bot/blog/eu-3-euro-customs-duty): Since 1 July 2026 the EU charges a temporary €3 customs duty on low-value parcels, once per tariff classification. What it covers, who pays and how it adds up. - [US de minimis suspension: what changed for parcels](https://staging.border.bot/blog/us-de-minimis-suspension): US de minimis has been suspended since 29 August 2025. The timeline, the June 2026 CBP rules, how parcels clear now and what ends on 1 July 2027. - [Classify products from Claude and ChatGPT](https://staging.border.bot/blog/classify-products-with-mcp): Connect the border.bot MCP server to Claude, ChatGPT or Cursor, then classify products, check origin and estimate landed cost from a chat. Setup and tips. ## Create an account New accounts get 10 free credits. You get the dashboard, an API key and the MCP server, and you buy more credits when you need them. [Create a free account](https://staging-app.border.bot/signup) --- # Free HS code, landed cost, origin and air waybill tools > Free HS code classifier, landed cost calculator and country of origin finder for cross-border ecommerce. A few free runs per visitor, no account needed. Source: https://staging.border.bot/tools Last updated: 2026-10-13 An HS code classifier, a landed cost calculator, a country of origin finder and an air waybill generator. They run on the same engine as the border.bot dashboard, API and MCP server, and they work without an account. ## HS code classifier Describe a product or paste a product URL and get the HS, HTS, CN/TARIC, UK or Canadian code for its destination, with official descriptions and confidence. [Classify a product](https://staging.border.bot/tools/hs-code-classifier) ## Landed cost calculator Estimate duties, taxes and fees for parcels to the US, UK, Canada, the EU and more, from an HS code or a product description. [Calculate landed cost](https://staging.border.bot/tools/landed-cost-calculator) ## Country of origin finder Paste a product URL or give a title, description or barcode, and get the likely country of manufacture with its probability, alternatives and evidence. [Find the country of origin](https://staging.border.bot/tools/country-of-origin-finder) ## Air waybill generator Fill an IATA air waybill, master or house, with a live preview, the check digit verified and the chargeable weight worked out, and download 3 originals or all 8 copies as a PDF. [Make an air waybill](https://staging.border.bot/tools/air-waybill-generator) ## How free runs work Every visitor gets a small number of free runs, shared between the classifier, the calculator and the origin finder; the air waybill generator has its own allowance. Free runs are checked by Cloudflare Turnstile and counted per visitor, so they stay available for real people. Create an account for free credits and the full dashboard, API and MCP access. ## For AI agents Each tool exposes WebMCP tools to in-browser agents (`classify_product_free`, `calculate_landed_cost_free`, `find_country_of_origin`, `get_free_runs_remaining`, and on the air waybill generator `fill_air_waybill_form`, `create_air_waybill` and `get_free_waybills_remaining`). For automated or high-volume use, call the REST API or connect the MCP server instead. --- # Find the HS code for any product > Find the HS code for any product. Describe it or paste a product URL to get the US HTS, UK, EU CN or Canadian code with official descriptions and confidence. Source: https://staging.border.bot/tools/hs-code-classifier Last updated: 2026-10-14 An HS code is the 6-digit Harmonized System number customs uses to identify a product. Countries add digits of their own: the US declares a 10-digit HTS code, the EU an 8-digit CN or 10-digit TARIC code, and the UK and Canada 10-digit codes. This classifier gives the full code for the destination you choose, with the official description at each level, a confidence score and the closest alternatives. - **Cost:** Free, no account - **Codes:** US HTS, UK, EU CN and TARIC, Canada; 6-digit HS elsewhere - **Input:** A description, a product page URL, or both - **You get:** The code, official descriptions, confidence and alternatives ## Use the tool Describe a product or paste its product page URL and choose where it’s going. You get the code that destination’s customs expects, the official description at every level, a confidence score, the reasoning and the closest alternatives. Open https://staging.border.bot/tools/hs-code-classifier in a browser, describe the product or paste its URL, choose the destination (and origin if known) and submit. In-browser agents can call the WebMCP tool `classify_product_free` on that page. Supported outputs: US HTS (10-digit); Canadian Customs Tariff (10-digit); EU Combined Nomenclature / TARIC; UK Global Tariff (10-digit); Harmonized System (6-digit); National tariff. Every visitor gets a small number of free runs, shared between the classifier, the calculator and the origin finder; the air waybill generator has its own allowance. Free runs are checked by Cloudflare Turnstile and counted per visitor, so they stay available for real people. Create an account for free credits and the full dashboard, API and MCP access. ## Example result Heavyweight crew-neck T-shirt, 100% cotton jersey knit, made in Vietnam, shipped to the United States | | Result | | --- | --- | | Chapter 61 | Articles of apparel and clothing accessories, knitted or crocheted | | Heading 6109 | T-shirts, singlets, tank tops and similar garments, knitted or crocheted | | Subheading 6109.10 | Of cotton | | Tariff line 6109.10.00.12 | The 10-digit US statistical line the shipment is declared under | | Confidence | High | Illustrative: run the classifier for a current answer. ## The code each destination uses | Destination | Tariff schedule | Code length | | --- | --- | --- | | United States | Harmonized Tariff Schedule (HTS) | 10 digits | | United Kingdom | UK Global Tariff | 10 digits | | European Union | Combined Nomenclature (CN) and TARIC | 8 or 10 digits | | Canada | Customs Tariff | 10 digits | | Other countries | Harmonized System (HS) | 6 digits | ## How to find an HS code with border.bot 1. **Describe the product.** Write what the item is, what it’s made of and what it’s for. Or paste the URL of its product page and we’ll read the details from it. 2. **Choose the destination.** Pick the country the parcel is going to. The destination decides the tariff schedule: US HTS, the UK tariff, EU CN/TARIC, the Canadian tariff, or the 6-digit HS for everywhere else. 3. **Add the country of origin.** If you know where the product was made, add it. If you paste a product URL, we look for the origin on the page and show you what we found. 4. **Review the result.** Check the code against its official descriptions, the confidence score and the alternatives. Use “Calculate landed cost” to carry the code straight into the duty and tax calculator. ## What decides the code ### What it’s made of Material often decides the heading or subheading: a cotton T-shirt and a polyester one sit on different lines. For blends, the material that predominates by weight usually counts. ### What it does Function and intended use matter as much as appearance. A bag designed for a laptop and a bag designed for sport can classify differently even if they look alike. ### How it’s made Knitted versus woven apparel are separate chapters (61 and 62). Whether goods are finished, unfinished, assembled or in kit form also changes the answer. ### Who it’s for For clothing and footwear, men’s, women’s, children’s and babies’ goods often have their own lines at the 8- and 10-digit level. ### Sets, parts and accessories Goods put up in sets for retail sale, spare parts and accessories follow their own rules. A set is usually classified by the item that gives it its essential character, and parts often go with the machine they belong to. ### The destination The first six digits are shared worldwide. Digits seven to ten are set by each country, so the same product has a different full code in the US, the UK, the EU and Canada. ## Write a description customs can classify - Name the item plainly: “insulated stainless steel water bottle”, not a brand or a marketing name. - State the material and, for blends, the percentages. - Say what it’s for and who uses it (adult, child, professional). - Mention how it’s made when it matters: knitted or woven, moulded or machined. - For sets and kits, list every item in the set. ## From your own systems and agents - REST API: `POST /v1/classify` (with an API key, charged in credits): [API reference](https://staging.border.bot/docs) - MCP server: the `classify_product` tool at `https://staging-mcp.border.bot/mcp`: [connect an agent](https://staging.border.bot/mcp) - WebMCP on this page: `classify_product_free` (in-browser agents, uses the visitor’s free runs) ## Frequently asked questions ### What is an HS code? An HS code is the number customs uses to identify a product. The Harmonized System, maintained by the World Customs Organization, defines the first six digits; countries add more digits for their own tariffs and statistics. The code determines duty rates, import rules and trade statistics. ### What’s the difference between HS, HTS, CN and TARIC codes? HS is the shared 6-digit international system. The US extends it to the 10-digit Harmonized Tariff Schedule (HTS). The EU extends it to the 8-digit Combined Nomenclature (CN) and the 10-digit TARIC for import measures. The UK and Canada use 10-digit codes of their own. The first six digits match everywhere. ### Why does the code change with the destination? Because each country sets its own digits after the first six. The free classifier returns the code in the destination’s own format: US HTS, UK commodity code, EU CN/TARIC, Canadian classification number, or the 6-digit HS for other countries. ### Can I classify from a product URL? Yes. Paste the product page link and we read the title, description, materials, brand and price from the page, look for the country of origin, and classify from those details. Pages that block automated access may need a written description instead. ### What does the confidence score mean? It reflects how clearly the description points to one code. High confidence means the product fits one line well; medium or low means plausible alternatives exist, so review them or add detail such as material, use or construction. Results that need a human check are flagged. ### Is the result legally binding? No. It is guidance to help you declare goods correctly. The importer of record is responsible for the classification. For certainty on a specific product, ask a licensed customs broker or request a binding ruling from the destination’s customs authority. ### How many free classifications do I get? Each visitor gets a few free runs, shared between the free tools, and the page shows how many you have left. Create an account to keep going with free credits. ## Sources - [World Customs Organization: the Harmonized System](https://www.wcoomd.org/en/topics/nomenclature/overview/what-is-the-harmonized-system.aspx) - [US International Trade Commission: Harmonized Tariff Schedule](https://hts.usitc.gov/) - [UK Trade Tariff](https://www.gov.uk/trade-tariff) - [European Commission: TARIC](https://ec.europa.eu/taxation_customs/dds2/taric/taric_consultation.jsp) - [Canada Border Services Agency: Customs Tariff](https://www.cbsa-asfc.gc.ca/trade-commerce/tariff-tarif/menu-eng.html) --- # Calculate import duty, tax and landed cost > Estimate import duties, taxes, fees and total landed cost for parcels to the US, UK, EU, Canada and more. Enter an HS code or describe the product. Source: https://staging.border.bot/tools/landed-cost-calculator Last updated: 2026-10-14 Landed cost is what a parcel costs once it arrives: the goods, the shipping, and the duty, import tax and customs fees the destination charges. Duty depends on the product’s tariff code and where it was made; import VAT, GST or sales tax and the fees depend on the destination. This calculator gives every line with the rate used, the de minimis check and the total, for the US, UK, Canada, the EU-27 and more. - **Cost:** Free, no account - **Destinations:** The US, UK, Canada, the EU-27 and more - **Input:** HS code or description, origin, destination, value, shipping - **You get:** Duty, tax and fee lines, the de minimis check, landed cost ## Use the tool Enter an HS code, or describe the product and we’ll classify it first. Add the origin, destination, total goods value and shipping. You get every duty, fee and tax line with the rate used, and the total your customer pays to receive the parcel. Open https://staging.border.bot/tools/landed-cost-calculator in a browser, enter an HS code or describe the product, choose origin and destination (the US, UK, Canada, the EU-27 and more), add the total goods value, currency, shipping and quantity, and submit. In-browser agents can call the WebMCP tool `calculate_landed_cost_free` on that page. Every visitor gets a small number of free runs, shared between the classifier, the calculator and the origin finder; the air waybill generator has its own allowance. Free runs are checked by Cloudflare Turnstile and counted per visitor, so they stay available for real people. Create an account for free credits and the full dashboard, API and MCP access. ## Example result Heavyweight crew-neck T-shirt, HTS 6109.10.00.12, made in Vietnam, $24.00 to the United States | | Result | | --- | --- | | Goods | $24.00 | | Shipping | $6.50 | | Duty | $5.40 | | Fees | $1.10 | | Taxes | $0.00 | | Landed cost | $37.00 | Illustrative figures. Rates change, so run the calculator for a current answer. ## What the total includes | Charge | In the total | How it’s worked out | | --- | --- | --- | | Duty | Yes | The rate for the HS code and country of origin, including trade-agreement rates the origin qualifies for | | Import VAT, GST or sales tax | Yes | The destination’s rate on the value it taxes, often goods, shipping and duty together | | Customs fees | Yes | Fees the destination’s customs sets for the entry | | De minimis | Checked | Whether the value is under the destination’s duty or tax threshold | | Conditional measures | Listed, not added | Rates that apply only with a certificate, an end use or a quota | | Carrier brokerage and handling | No | Each carrier sets its own; ask yours | ## How to calculate landed cost with border.bot 1. **Enter the HS code.** Type the product’s HS or HTS code. If you don’t know it, switch to “Describe the product” and we’ll classify it as part of the same run. 2. **Set origin and destination.** Choose where the goods were made and where they’re going. Origin decides preferential and additional duties; the destination decides the tariff, taxes and thresholds. 3. **Add value, shipping and quantity.** Enter the total goods value of the shipment and its currency, the shipping cost, the number of units and, if you have it, the weight. These decide the customs value that duties and taxes are charged on. 4. **Read the breakdown.** Review each duty, fee and tax line with its rate, the de minimis check, any conditional measures, and the total landed cost. ## What changes the total ### The HS code The code sets the base duty rate. A one-line difference in classification can change the duty from zero to double digits, so start from the right code. ### Country of origin Origin is where the goods were made, not where they ship from. It decides whether trade-agreement preferences apply and whether extra duties such as trade remedies are added. ### Customs value Some countries charge duty on the goods value alone; others include shipping and insurance to the border. The calculator applies the right basis for the destination. ### De minimis thresholds Low-value shipments may be exempt from duty, tax or both below a threshold that differs by country and changes over time. The result shows whether one applied. ### Import taxes VAT and GST are usually charged on the customs value plus duty, so duty raises the tax too. Some countries collect tax at checkout for low-value parcels instead of at the border. ### Fees and currency Customs processing fees and exchange rates move the total. Carrier brokerage or handling fees are set by each carrier and are not part of the government charges shown. ## Get a figure you can rely on - Use the code for the destination country, not a generic 6-digit HS code, when you have it. - Use the real transaction value of the goods, in the currency you invoice in. - Include shipping and insurance costs, because several destinations charge duty on them. - Re-check before large shipments: rates, thresholds and trade measures change. ## From your own systems and agents - REST API: `POST /v1/calculate` (with an API key, charged in credits): [API reference](https://staging.border.bot/docs) - MCP server: the `calculate_landed_cost` tool at `https://staging-mcp.border.bot/mcp`: [connect an agent](https://staging.border.bot/mcp) - WebMCP on this page: `calculate_landed_cost_free` (in-browser agents, uses the visitor’s free runs) ## Frequently asked questions ### What is landed cost? Landed cost is the total cost of getting a product to the customer’s door: the goods, shipping and insurance, plus the duties, import taxes and customs fees charged on arrival. Knowing it lets you price correctly and avoid surprise bills on delivery. ### Which destinations does the calculator support? The United States, the United Kingdom, Canada, all 27 EU member states and more. The engine checks each destination live and tells you if one isn’t covered yet; you can always classify the product with the free classifier. ### What is de minimis? A de minimis threshold is the value below which a country waives duty, tax or both on an import. Thresholds differ by country, can apply to duty and tax separately, and change over time. The calculator checks the current rule for the destination. ### Why does the country of origin matter? Duty rates depend on where goods were made. Trade agreements can lower the rate for qualifying goods, while trade remedies and other measures can add duties for specific origins. Shipping from a warehouse in another country does not change the origin. ### Does the result include VAT, GST and sales tax? It includes import taxes charged at the border, such as VAT and GST, with the rate used. US state sales tax is not an import tax and is not included. ### Are carrier fees included? Government fees such as customs processing fees are included where they apply. Brokerage, disbursement or handling fees charged by carriers vary by carrier and contract, so they are not part of the result. ### Is the estimate guaranteed? No. It is an estimate based on the code, origin, values and the rules in force when you run it. Final charges are assessed by customs when the goods are declared, so check the result for high-value shipments. ## Sources - [World Customs Organization: the Harmonized System](https://www.wcoomd.org/en/topics/nomenclature/overview/what-is-the-harmonized-system.aspx) - [US International Trade Commission: Harmonized Tariff Schedule](https://hts.usitc.gov/) - [UK Trade Tariff](https://www.gov.uk/trade-tariff) - [European Commission: TARIC](https://ec.europa.eu/taxation_customs/dds2/taric/taric_consultation.jsp) - [Canada Border Services Agency: Customs Tariff](https://www.cbsa-asfc.gc.ca/trade-commerce/tariff-tarif/menu-eng.html) --- # Find where a product was made > Find where a product was made from its URL, title or barcode. Get the likely country of origin with its probability, alternatives and the evidence behind it. Source: https://staging.border.bot/tools/country-of-origin-finder Last updated: 2026-10-14 A product’s country of origin is where it was made or, when several countries were involved, where it was last substantially transformed. It is not where it ships from or where the brand is based. This finder reads the product page, its “Made in” text and its barcode, and gives the likely country with its probability, the alternatives and the evidence for each. - **Cost:** Free, no account - **Input:** A product URL, title, description or barcode - **You get:** The likely country, its probability, alternatives and evidence - **Review:** Flagged when a person should confirm the origin ## Use the tool Paste a product page URL, or give the title, description or barcode. You get the most likely country of origin with its probability, the other countries it could be, and every piece of evidence behind the answer. Open https://staging.border.bot/tools/country-of-origin-finder in a browser, paste a product page URL or enter a title, description or barcode (GTIN, UPC or EAN), optionally add the brand, materials and ship-from country, and submit. In-browser agents can call the WebMCP tool `find_country_of_origin` on that page. With an account, the REST API (`POST /v1/origin`, `/v1/origin/validate`, `/v1/origin/batch`) and the MCP server do the same. Every visitor gets a small number of free runs, shared between the classifier, the calculator and the origin finder; the air waybill generator has its own allowance. Free runs are checked by Cloudflare Turnstile and counted per visitor, so they stay available for real people. Create an account for free credits and the full dashboard, API and MCP access. ## Example result A merino wool jumper whose product page says “Made in Portugal” | | Result | | --- | --- | | Likely country | Portugal | | Main evidence | “Made in Portugal” in the product description (strong) | | Review | Not needed: the page states the origin | Illustrative: run the finder on a real product page. ## How much each piece of evidence counts | Evidence | Weight | Why | | --- | --- | --- | | Country of origin in the product data | Strong | The shop states it in the data search engines read | | “Made in” text on the page | Strong | A direct statement, quoted so you can check it | | AI estimate from the product, brand and materials | Moderate at most | Used only when the page says nothing, and never high confidence on its own | | Ship-from country | Weak | Goods are often stocked and shipped from another country | | Barcode (GS1) prefix | Weak | It shows where the brand registered, not where the product was made | ## How to find a product’s country of origin with border.bot 1. **Identify the product.** Paste the URL of its product page, or enter the title or a description. A barcode (GTIN, UPC or EAN) works on its own too. 2. **Add what you know.** Brand and materials help narrow the answer. If you know where the goods ship from, add it: it counts as weak evidence, because goods often ship from a different country than the one they were made in. 3. **Run the finder.** We read the product page for structured product data and “Made in” text, check the barcode prefix, and make an AI estimate only when the page doesn’t say. 4. **Check the evidence.** Read the likely country, its probability, the alternatives and what pointed where. When the result is flagged for review, confirm the origin with the supplier or the product label before you declare it. ## What points to a country ### Product page data Many shops publish a country of origin in the page’s structured product data, the same data search engines read. When it’s there, it is usually the strongest evidence. ### “Made in” text Product descriptions, specifications and care details often say “Made in Portugal” or “Imported”. We quote the text we found so you can check it. ### Where it ships from The ship-from country is weak evidence. Goods made in one country are often stocked and shipped from a warehouse in another, and shipping from there doesn’t change their origin. ### Barcode prefix The first digits of a GS1 barcode show which country’s GS1 office issued the brand’s company prefix. That is where the brand registered, not where the product was made, so it counts for little. ### AI estimate When nothing on the page names a country, an AI model estimates one from the product, brand and materials. An estimate alone is never given high confidence. ### What origin means for customs Country of origin is where the goods were made or, if more than one country was involved, where they were last substantially transformed into a new product. It is not where they ship from or where the brand is based. ## Get an answer you can rely on - Use the product page from the brand or manufacturer when you can; resellers often leave the origin out. - Add the barcode if you have it, but don’t treat its prefix as the country of manufacture. - Check the product label or packaging: a “Made in” mark there is better evidence than any estimate. - Ask the supplier for the origin on the commercial invoice or a certificate of origin before large shipments. - Preferential origin under a trade agreement has its own rules and needs supplier proof; this finder estimates where the goods were made. ## From your own systems and agents - REST API: `POST /v1/origin` (with an API key, charged in credits): [API reference](https://staging.border.bot/docs) - MCP server: the `infer_country_of_origin` tool at `https://staging-mcp.border.bot/mcp`: [connect an agent](https://staging.border.bot/mcp) - WebMCP on this page: `find_country_of_origin` (in-browser agents, uses the visitor’s free runs) ## Frequently asked questions ### What is a country of origin? For customs, the country of origin is where goods were wholly obtained or made. When more than one country was involved, it is generally the country where the goods last underwent a substantial transformation, meaning processing that turned them into a new product. Customs uses it to set duty rates, apply trade measures and check marking rules. ### Is the country of origin where the parcel ships from? No. A product made in Vietnam and shipped from a warehouse in Germany still has Vietnam as its country of origin. That’s why the ship-from country only counts as weak evidence here. ### Does the barcode tell me where a product was made? No. A GS1 barcode prefix shows which national GS1 office issued the company’s prefix, which is usually where the brand registered. Products can be made anywhere, so the finder gives the prefix little weight. ### What does the probability mean? It is the finder’s estimate that the top country is right, given the evidence it found. The alternatives show the other countries it could be, each with its own probability. ### Why is my result flagged for review? A result is flagged when its probability is below the review threshold or when strong pieces of evidence point to different countries. The result says why in plain words. Confirm the origin with the supplier or the label before you declare it. ### Is the result legally binding? No. It is an estimate to help you declare goods correctly. The importer is responsible for the declared origin. For certainty, ask the supplier for documentation, consult a licensed customs broker, or request a binding origin ruling from the destination’s customs authority. ### Can I check many products at once? Yes, with an account. The REST API finds origins one product at a time or in batches of up to 50. The API and the MCP server can also check a declared origin against the evidence. ### How many free runs do I get? Each visitor gets a few free runs, shared between the free tools, and the page shows how many you have left. Create an account to keep going with free credits. ## Sources - [US Customs and Border Protection: informed compliance publications on origin and marking](https://www.cbp.gov/trade/rulings/informed-compliance-publications) - [World Customs Organization: rules of origin](https://www.wcoomd.org/en/topics/origin.aspx) --- # Make an air waybill PDF > Make an IATA air waybill PDF for free: master or house AWB, live preview, check digit verified, chargeable weight worked out, 3 originals or all 8 copies. Source: https://staging.border.bot/tools/air-waybill-generator Last updated: 2026-10-13 An air waybill (AWB) is the contract of carriage and the carrier’s receipt for air cargo. IATA Resolution 600a sets its layout and Resolution 600b the conditions printed on the back. This generator fills the standard face from your details, works out the chargeable weight and totals, and gives you a PDF of 3 originals or the full set of 8 copies, each followed by the conditions of contract. - **Cost:** Free, no account - **Layout:** IATA Resolution 600a face, 600b conditions on the reverse - **Waybills:** Master (carrier’s number, check digit verified) or house - **You get:** A vector PDF: 3 originals or all 8 labelled copies ## Use the tool Fill in the waybill and watch the preview: every box updates as you type. Download the PDF when it’s right. It prints on A4 or US Letter. Open https://staging.border.bot/tools/air-waybill-generator in a browser, choose a master or house waybill, fill in the shipper, consignee, issuer, airports (IATA codes), carrier, flights and rating lines, check the live preview and download the PDF (3 originals or the full set of 8, each followed by the IATA conditions of contract). In-browser agents can call the WebMCP tools `fill_air_waybill_form` (free) and `create_air_waybill` (one free waybill) on that page with the whole waybill as JSON. Every visitor gets a small number of free runs, shared between the classifier, the calculator and the origin finder; the air waybill generator has its own allowance. Free runs are checked by Cloudflare Turnstile and counted per visitor, so they stay available for real people. Create an account for free credits and the full dashboard, API and MCP access. ## Example: chargeable weight and charges 4 cartons of cotton T-shirts, 86.4 kg, each 60 × 40 × 45 cm, rate class Q at GBP 3.85 per kg | | Result | | --- | --- | | Volume | 0.432 m³ | | Volume weight | 72 kg | | Chargeable weight | 86.5 kg: the actual weight is higher, rounded up to the next half kilogram | | Weight charge | GBP 333.03 | | Other charges | AWA 25.00, MYC 51.84, SCC 12.96 | | Total prepaid | GBP 422.83 | The tool’s “Fill an example” waybill. ## The copies in a full set | Copy | For | Colour on carrier stock | | --- | --- | --- | | Original 3 | Shipper | Blue | | Copy 8 | Agent | White | | Original 1 | Issuing carrier | Green | | Original 2 | Consignee | Pink | | Copy 4 | Delivery receipt | Yellow | | Copy 5 | Extra copy | White | | Copy 6 | Extra copy | White | | Copy 7 | Extra copy | White | ## How to make an air waybill with border.bot 1. **Choose master or house.** A master waybill uses the carrier’s 3-digit prefix and an 8-digit serial from its allocated stock. A house waybill takes your own number and names the master it travels under. 2. **Enter the parties.** Give the shipper’s and consignee’s names and full addresses, their account numbers with the carrier if they have one, and who issues the waybill. 3. **Add the route and the goods.** Enter airports as IATA codes, the first carrier and the flights, then each rating line: pieces, gross weight, dimensions, rate class and rate. The chargeable weight and totals are worked out for you. 4. **Check the preview.** Every box shows on the live preview as you type, with NVD, NCV and XXX printed where no value or insurance is declared. 5. **Download, print and sign.** Each copy in the PDF is labelled: Original 3 for the shipper, Original 1 for the issuing carrier, Original 2 for the consignee. The shipper signs box 31; the issuing carrier or its agent signs box 32 when it accepts the goods. ## What goes on an air waybill ### The AWB number Three digits for the airline, then an 8-digit serial whose last digit is a check digit: the first seven digits divided by 7, keeping the remainder. A wrong check digit usually means a typing error. ### Chargeable weight Air cargo is charged on the higher of the actual and the volume weight. IATA’s standard is 6000 cm³ per kilogram, so a 60 × 40 × 45 cm carton counts as 18 kg. The result is rounded up to the next half kilogram. ### Rate classes M is the minimum charge, N the normal rate under 45 kg, Q a quantity rate above it, C a specific commodity rate, and R or S a class rate below or above the normal rate. ### Prepaid or collect Weight and valuation charges, and the other charges, are each either prepaid by the shipper (PP) or collected from the consignee (CC). The totals land in the matching column. ### Declared values With no value declared for carriage the box reads NVD and the carrier’s liability limit applies: 26 SDR per kilogram since December 2024. With no customs value it reads NCV, and with no insurance XXX. ### Other charges Each has a two-letter code and A or C for whether it is due to the agent or the carrier: AWC is the waybill fee due to the carrier, MYC a fuel surcharge, SCC a security charge. ## Before you hand it over - Use a number from the carrier’s allocated stock: a valid check digit doesn’t make a number yours. - Many lanes are e-AWB only. If your carrier wants the data electronically, send it through their booking system or your forwarder’s. - Dangerous goods need a separate Shipper’s Declaration. Say so in Handling Information, and add CAO when they may travel on cargo aircraft only. - The shipper answers for the particulars on the face: check names, addresses, pieces and weights against the commercial invoice and packing list. - The printed conditions are IATA’s standard wording; the carrier’s own conditions of carriage and tariffs apply as well. ## From your own systems and agents - REST API: `POST /v1/documents/waybill` (with an API key, charged in credits): [API reference](https://staging.border.bot/docs) - MCP server: the `create_air_waybill` tool at `https://staging-mcp.border.bot/mcp`: [connect an agent](https://staging.border.bot/mcp) - WebMCP on this page: `create_air_waybill` (in-browser agents, uses the visitor’s free runs) ## Frequently asked questions ### What is an air waybill? The document that travels with air cargo. It is the contract of carriage between the shipper and the carrier, the carrier’s receipt for the goods, and the source for customs and the freight bill. It is not a document of title, which is why it is marked “Not negotiable”. ### What is the difference between a master and a house air waybill? A master air waybill (MAWB) is issued by or for the airline and carries its prefix. A forwarder that consolidates several shipments issues each shipper a house air waybill (HAWB) with its own number, and they all travel under one master. ### How is the AWB check digit worked out? Divide the first seven digits of the serial by 7 and take the remainder. For 1234567 the remainder is 5, so the serial is 12345675, and with the prefix 125 the number is 125-1234 5675. ### How many copies does an air waybill have? A standard set has eight, in this order: Original 3 for the shipper, Copy 8 for the agent, Original 1 for the issuing carrier, Original 2 for the consignee, Copy 4 as the delivery receipt, and Copies 5 to 7 as extras. The three originals have the same validity. ### Is a generated air waybill legally valid? It becomes the contract of carriage when the issuing carrier or its authorised agent accepts the goods and signs it. This tool prepares the document: use a number from your carrier’s stock and have the carrier or its agent execute it. ### Do I still need a paper air waybill with e-AWB? Not on lanes where you and the carrier work under an e-AWB agreement: the data is sent electronically. Paper is still used where a carrier or a country requires it, and many shippers print one for their records. ### What do NVD, NCV and XXX mean? NVD means no value declared for carriage, so the carrier’s standard liability limit applies. NCV means no customs value declared. XXX in the insurance box means no insurance was asked for. ### How many free waybills do I get? Each visitor gets a few free waybills, separate from the other free tools, and the page shows how many are left. With an account, waybills cost credits in the dashboard, the API and the MCP server. ## Sources - [IATA Resolution 600b: air waybill conditions of contract](https://www.iata.org/contentassets/783ac75f30d74e32a8eaef26af5696b6/csc-600b-en-28dec2019.pdf) - [ICAO: revised limits of liability under the Montreal Convention (2024)](https://www.icao.int/sites/default/files/secretariat/legal/LEB%20Treaty%20Collection%20Documents/2024_Revised_Limits_of_Liability_Under_the_Montreal_Convention_of_1999_en.pdf) - [Montreal Convention 1999, full text](https://www.iata.org/contentassets/fb1137ff561a4819a2d38f3db7308758/mc99-full-text.pdf) - [IATA: electronic air waybill (e-AWB)](https://www.iata.org/en/programs/cargo/e/eawb/) --- # Pricing > Prepaid credit packs for HS classification and landed cost. Each action has a fixed credit cost, failed calls are refunded, and new accounts get free credits. Source: https://staging.border.bot/pricing Last updated: 2026-10-12 Buy a credit pack, spend it on classifications and calculations, and top up when you need to. Credits are shared by everyone in your workspace and work the same in the dashboard, the API and the MCP server. ## Live pricing ### Credit packs | Pack | Credits | Price | Per credit | Notes | | --- | --- | --- | --- | --- | | Starter | 100 | $19.00 | $0.19 | For trying border.bot on real shipments. | | Growth (most popular) | 500 | $79.00 | $0.16 | For growing stores shipping internationally every day. | | Scale | 2000 | $249.00 | $0.12 | For teams classifying whole catalogues. | | Volume | 10000 | $990.00 | $0.10 | For platforms and high-volume shippers. | ### What each action costs | Action | Cost | What it does | | --- | --- | --- | | Classification (Mini) | 1 credit | The fastest: search by meaning and words, then the reranker. No language model. | | Classification (Pro) | 1 credit | A model rewrites the listing in customs terms, the search stays in the chapters it names, and a model ranks the candidates by the rules of interpretation, with precedent rulings. Brand-only listings are identified on the web. | | Classification (Max) | 3 credits | The highest accuracy: an agent searches the tariff, walks its tree, reads rulings and identifies products on the web. | | Agency product code | 1 credit | Find the product code the destination’s import agency asks for. | | Landed cost calculation | 1 credit | Duties, taxes and fees for one HS code / origin / destination. | | Duty stacking | Free | Which duty lines apply to a code and origin, without a shipment. | | Product URL extraction | Free | Read a product page and extract title, brand, price and materials. | | Country of origin inference | Free | Infer where a product is made from page data and AI. | | Air waybill | 1 credit | One air waybill PDF (master or house), every copy included. | - New accounts get 10 credits free. - The free tools allow 3 free runs per visitor every 30 days, no account needed. Prices as of 2026-10-15. [See live pricing](https://staging.border.bot/pricing). ## Every pack includes - The dashboard, REST API and MCP server - Classification for the US, UK, EU, Canada and 6-digit HS worldwide - Landed cost for the US, UK, Canada, the EU-27 and more - Product URL reading and country-of-origin detection - Team members and API keys at no extra cost - Automatic refunds when a call fails ## Frequently asked questions ### What uses credits? Billable actions such as a classification or a landed-cost calculation. The table on this page lists every action and how many credits it uses; reading a product page and detecting its origin are listed separately. ### Is there a subscription or a minimum? No. You buy prepaid credit packs when you need them. There are no seats, no monthly fees and no minimum commitment. ### What happens if a call fails? Credits are taken in one atomic step just before the call runs. If it fails, they are refunded automatically and the refund shows up in your credit history. ### Do new accounts get free credits? Yes. Every new account starts with free credits, so you can try classification and landed cost in the dashboard, the API and the MCP server before you buy. ### Can my team share credits? Yes. Credits belong to the workspace. Everyone in it, and every API key and MCP connection tied to it, draws from the same balance. ### How do I pay? In the dashboard, with a secure Stripe payment form: card details go straight to Stripe. Credits are added to your workspace as soon as Stripe confirms the payment. [Create a free account](https://staging-app.border.bot/signup) --- # REST API for classification and landed cost > REST API for HS code classification and landed cost. Create an API key, send your first request with curl, and handle credits, errors and idempotent retries. Source: https://staging.border.bot/developers Last updated: 2026-10-09 Call the classification and landed-cost engine behind the border.bot dashboard from your checkout, catalogue or shipping software. It is JSON over HTTPS with Bearer API keys and prepaid credits, and you don’t need an SDK. Base URL: `https://staging-api.border.bot` · [API reference](https://staging.border.bot/docs/api) ## Quickstart ### 1. Create an API key Sign in to the dashboard and create a key for your workspace. It starts with bb_live_ and is shown once, so store it in your secrets manager straight away. ### 2. Classify a product Send a description or a product URL with the destination country. Add the origin if you know it. ```bash curl https://api.border.bot/v1/classify \ -H "Authorization: Bearer $BORDERBOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "description": "Heavyweight crew-neck T-shirt, 100% cotton jersey knit", "destinationCountry": "US", "originCountry": "VN" }' ``` ### 3. Read the result You get the code in the destination’s format, the official description at each level, a confidence score, the reasoning, alternatives, and the credits charged with your new balance. ```json { "result": { "hsCode": "6109100012", "hsCodeFormatted": "6109.10.00.12", "nomenclature": "us", "confidence": "high", "needsReview": false, "hierarchy": [ { "level": "chapter", "code": "61", "description": "Articles of apparel … knitted or crocheted" }, { "level": "heading", "code": "6109", "description": "T-shirts, singlets, tank tops …" }, { "level": "subheading", "code": "610910", "description": "Of cotton" } ], "alternatives": [ … ] }, "credits": { "charged": 1, "balance": 99 } } ``` ### 4. Calculate landed cost Pass the code, origin, destination, total goods value, currency and shipping cost to the landed-cost endpoint to get every duty, tax and fee line and the total. The API reference has the full request and response schemas. ## Concepts ### Authentication Send your key in the Authorization header as Bearer bb_live_…. Keys belong to a workspace and only a hash is stored, so a lost key can’t be shown again. Revoke it and create a new one. ### Credits Each billable call debits the workspace before it runs, in one atomic step, so a balance can never go negative. If the call fails, the credits are refunded automatically. Responses report what was charged and the balance left. ### Safe retries Send an idempotency key with a request and repeat it as often as you need: you get the original result back and are not charged twice. The API reference documents the header. ### Same engine as the dashboard The API, the dashboard, the MCP server and the free tools all run on the same classification and duty engine, with the same prices per action. ## Errors Errors return JSON with a stable machine-readable code and a human-readable message, and the HTTP status that matches the code. | Code | HTTP status | Meaning | | --- | --- | --- | | `invalid_input` | 400 | The request failed validation. The message names the field to fix. | | `unauthorized` | 401 | The API key is missing, malformed or revoked. | | `insufficient_credits` | 402 | The workspace balance is too low for this action. Top up in the dashboard. | | `forbidden` | 403 | The key is valid but not allowed to perform this action (a key without the scope the endpoint needs: details.reason is missing_scope). | | `not_found` | 404 | The resource or path doesn’t exist. | | `conflict` | 409 | A request with the same idempotency key is still running, or the change clashes with existing data. Wait and retry. | | `org_suspended` | 403 | The workspace is suspended. Contact support. | | `payload_too_large` | 413 | The request body is over 10 MB. Link to a photo instead of sending it inline, or split a bulk run. | | `version_retired` | 410 | The API version in the path has passed its sunset date. Move to the version the message names. | | `action_disabled` | 403 | This action is temporarily switched off. Try again later. | | `unsupported_country` | 422 | The destination isn’t covered for this action yet. The message says what is supported. | | `rate_limited` | 429 | Too many requests in a short period. Back off and retry. | | `upstream_error` | 502 | The engine couldn’t complete the request. Credits were refunded; retry. | | `upstream_timeout` | 504 | The engine took too long. Credits were refunded; retry. | | `internal` | 500 | Something went wrong on our side. Credits were refunded. | ## Coverage - US HTS (10-digit) - Canadian Customs Tariff (10-digit) - EU Combined Nomenclature / TARIC - UK Global Tariff (10-digit) - Harmonized System (6-digit) - National tariff Landed cost: United States, United Kingdom, Canada, European Union (all 27 member states). Other destinations are checked when you run a calculation, and you’re told if one isn’t covered yet. ## Prefer an AI assistant? Connect the [MCP server](https://staging.border.bot/mcp) to use the same engine from Claude, ChatGPT, Codex, Cursor or another MCP client. --- # Connect border.bot to your AI tools > Connect border.bot to Claude, ChatGPT, Codex, Cursor, Visual Studio Code, Gemini and other MCP clients. Classify products and calculate landed cost from chat. Source: https://staging.border.bot/mcp Last updated: 2026-10-09 Our remote MCP server lets AI assistants and coding agents classify products and calculate landed cost for you. Add one URL, sign in with your border.bot account, and choose which workspace pays. ## Server URL ```text https://staging-mcp.border.bot/mcp ``` Streamable HTTP transport with OAuth 2.1. Your client finds the sign-in endpoints itself, so there is no API key to paste. ## Set up your client Steps for 34 clients, checked against each vendor’s own documentation on 7 October 2026. Menu names change between versions and plans; if one has moved, look for “connectors”, “integrations” or “MCP” in your client’s settings. - Assistants: [Claude](https://staging.border.bot/mcp#claude), [ChatGPT](https://staging.border.bot/mcp#chatgpt), [Gemini](https://staging.border.bot/mcp#gemini), [Perplexity](https://staging.border.bot/mcp#perplexity), [Vibe Work (formerly Le Chat)](https://staging.border.bot/mcp#mistral-vibe), [Raycast](https://staging.border.bot/mcp#raycast), [LM Studio](https://staging.border.bot/mcp#lm-studio) - Editors and IDEs: [Cursor](https://staging.border.bot/mcp#cursor), [Visual Studio Code](https://staging.border.bot/mcp#vscode), [Devin Desktop (formerly Windsurf)](https://staging.border.bot/mcp#devin-desktop), [Visual Studio](https://staging.border.bot/mcp#visual-studio), [Cline](https://staging.border.bot/mcp#cline), [Zed](https://staging.border.bot/mcp#zed), [Kiro](https://staging.border.bot/mcp#kiro), [Replit](https://staging.border.bot/mcp#replit), [v0](https://staging.border.bot/mcp#v0), [JetBrains Air](https://staging.border.bot/mcp#jetbrains-air), [TraeCode](https://staging.border.bot/mcp#trae) - Command line: [Claude Code](https://staging.border.bot/mcp#claude-code), [Codex](https://staging.border.bot/mcp#codex), [Gemini CLI](https://staging.border.bot/mcp#gemini-cli), [GitHub Copilot CLI](https://staging.border.bot/mcp#github-copilot-cli), [OpenCode](https://staging.border.bot/mcp#opencode), [Warp](https://staging.border.bot/mcp#warp), [Junie CLI](https://staging.border.bot/mcp#junie), [Amp](https://staging.border.bot/mcp#amp), [goose](https://staging.border.bot/mcp#goose), [Qwen Code](https://staging.border.bot/mcp#qwen-code), [Kimi Code CLI](https://staging.border.bot/mcp#kimi-cli) - Automation: [Microsoft Copilot Studio](https://staging.border.bot/mcp#copilot-studio), [n8n](https://staging.border.bot/mcp#n8n), [Zapier](https://staging.border.bot/mcp#zapier), [Make](https://staging.border.bot/mcp#make), [Postman](https://staging.border.bot/mcp#postman) Clients that aren’t listed can connect too, as long as they support remote MCP servers with OAuth. Point yours at the server URL; it finds the authorization server and opens the border.bot sign-in page, where you approve the connection and choose the workspace it may bill. ## Assistants Chat apps where you add border.bot once and then ask for a code or a landed cost in any conversation. ### Claude By Anthropic. Free, Pro, Max, Team and Enterprise (Free is limited to one custom connector). On Team and Enterprise an Owner adds it for the organization. 1. Open Customize › Connectors (claude.ai/customize/connectors), click “+ Add”, then “Add custom connector”. 2. Enter border.bot as the name and `https://staging-mcp.border.bot/mcp` as the remote MCP server URL, then click “Continue”. 3. Review the authentication settings Claude detected and click “Continue”; under Authentication choose “Sign in now” and under OAuth client “Use Claude’s published identity (Recommended)”, then click “Add”. 4. Sign in to border.bot and approve access in the window that opens. 5. In a chat, open “+” › “Connectors” and switch border.bot on. Official setup guide: https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp Notes: One connector covers claude.ai, Claude Desktop, Cowork and the mobile apps. Claude connects from Anthropic’s cloud, so the URL must be publicly reachable. Team/Enterprise: an Owner adds it under Organization settings › Connectors (“Add” › “Custom” › “Web”), then each member clicks “Connect” in Customize › Connectors. ### ChatGPT By OpenAI. ChatGPT on the web. OpenAI’s help center lists full MCP (read and write tools) for Business, Enterprise and Edu (beta) and read/fetch-only custom MCP for Pro in developer mode; workspace admins control who may create plugins with MCP servers. 1. Go to ChatGPT Plugins (chatgpt.com/plugins), select the plus button, then “Add custom MCP server”. 2. Enter border.bot as the name and, under “Connection”, `https://staging-mcp.border.bot/mcp` as the “Server URL”. 3. Choose “OAuth” for authentication, review the risk warning, select “I understand and want to continue”, then “Create as a plugin”. 4. Open the new plugin in your personal plugins, install it with the plus button and sign in to border.bot when asked. 5. In a new chat, type @ and select border.bot. Official setup guide: https://developers.openai.com/api/docs/guides/custom-mcp-server Notes: Not available in the mobile apps. ChatGPT supports Client ID Metadata Documents and Dynamic Client Registration. Write tools ask for confirmation unless marked read-only. Workspaces still on the older flow create it under Settings › Apps › Create with developer mode on. ### Gemini By Google. Personal Google Accounts only (not work or school), 18+ in the US, with Keep Activity on; English only. Added on the web, then usable in the web and mobile apps. 1. On a computer, go to gemini.google.com and click Settings › “Connected Apps” at the bottom. 2. Under “Custom apps”, click “Add a custom app” and enter `https://staging-mcp.border.bot/mcp` as the MCP server URL. 3. Click “Next” and follow the on-screen instructions to sign in to border.bot. 4. In a chat, enter @ and select the app to make sure Gemini uses it. Official setup guide: https://support.google.com/gemini/answer/17209137?hl=en Notes: Gemini registers itself with Dynamic Client Registration, so no client credentials are needed. Write actions always need manual confirmation. ### Perplexity Pro, Max and Enterprise. Enterprise members can add their own only when an admin allows custom connectors. 1. Go to Account settings › Connectors, click “+ Custom connector” in the top-right corner and select “Remote”. 2. Name: border.bot; MCP Server URL: `https://staging-mcp.border.bot/mcp`; Authentication: “OAuth”; Transport: “Streamable HTTP”. 3. Check the acknowledgement box and click “Add”. 4. Click the border.bot connector card to start the sign-in and enable it. Official setup guide: https://www.perplexity.ai/help-center/en/articles/13915507-adding-custom-remote-connectors Notes: Perplexity discovers border.bot’s OAuth endpoints and registers itself dynamically, so no client ID or secret is needed. Enterprise admins can add it for everyone under Enterprise settings › Permissions › Connectors permissions. ### Vibe Work (formerly Le Chat) By Mistral AI. Administrators only: on Free, Pro and Student plans the account owner is the administrator. 1. In Vibe Work (chat.mistral.ai), open the “Connectors” page from the sidebar. 2. Click “+ Add Connector” and switch to the “Custom MCP Connector” tab. 3. Connector name: `borderbot`; Server URL: `https://staging-mcp.border.bot/mcp`; then click “Connect”. 4. Complete the OAuth consent flow when prompted. Official setup guide: https://docs.mistral.ai/vibe/work/connectors/mcp-connectors Notes: Formerly Le Chat. The authentication method (OAuth 2.1 with dynamic client registration) is detected automatically. Under “Connectors” › “My Connectors” › “Functions” you can mark read-only tools “Always allow”. ### Raycast Raycast Pro. 1. Open the “Install MCP Server” command in Raycast. 2. Name: border.bot; Transport: “HTTP”; URL: `https://staging-mcp.border.bot/mcp`; OAuth Type: “Dynamic”. 3. Press “Install MCP Server” (⌘↵), then select “Sign In” to authorize border.bot. 4. In AI Chat or Quick AI, type @ and the server’s name to use it. Official setup guide: https://manual.raycast.com/ai/model-context-protocol Notes: Works on desktop and iOS (HTTP servers only on iOS). The “Logout Server” action in “Manage MCP Servers” clears saved tokens. ### LM Studio By Element Labs. 1. Click “Add to LM Studio”, or open the “Program” tab in the right-hand sidebar, click “Install” › “Edit mcp.json” and add the config snippet. 2. LM Studio opens border.bot’s authorization page in your browser; approve access. 3. border.bot’s tools are then available to your models in chat. Config file mcp.json (Program › Install › Edit mcp.json): ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` One-click install: [Add to LM Studio](lmstudio://add_mcp?name=borderbot&config=eyJ1cmwiOiJodHRwczovL3N0YWdpbmctbWNwLmJvcmRlci5ib3QvbWNwIn0%3D) Official setup guide: https://lmstudio.ai/docs/integrations/mcp-remote Notes: OAuth sign-in for MCP servers needs LM Studio 0.4.10 or later. Install-link format: lmstudio.ai/docs/app/mcp/deeplink. ## Editors and IDEs Code editors and app builders whose agents can call border.bot while they work on your catalogue or checkout code. ### Cursor By Anysphere. 1. Click “Add to Cursor” and confirm when Cursor prompts to install the server, or add the config snippet to `~/.cursor/mcp.json`. 2. Open “Customize” in the sidebar, find `borderbot` and complete the OAuth sign-in it asks for (Cursor CLI: `agent mcp login borderbot`). 3. Ask Agent to use border.bot; Cursor asks for approval before running MCP tools. Config file `~/.cursor/mcp.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` One-click install: [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=borderbot&config=eyJ1cmwiOiJodHRwczovL3N0YWdpbmctbWNwLmJvcmRlci5ib3QvbWNwIn0%3D) Official setup guide: https://cursor.com/docs/mcp Notes: The same `mcp.json` configures the Cursor CLI (`agent`). Install-link format: cursor.com/docs/mcp/install-links. ### Visual Studio Code By Microsoft. Uses GitHub Copilot. Copilot Business and Enterprise members need the “MCP servers in Copilot” policy enabled by their organization. 1. Click “Install in VS Code” and confirm in VS Code, or run “MCP: Add Server” from the Command Palette, choose the HTTP type, enter `https://staging-mcp.border.bot/mcp` and the name `borderbot`, and pick “Copilot Global” to use it in every workspace. 2. Trust the server when prompted; on first connection VS Code opens a browser window to sign in to border.bot. 3. Open the Chat view and ask for border.bot; select “Configure Tools” in the chat input to see its tools. Command: ```bash code --add-mcp '{"name":"borderbot","type":"http","url":"https://staging-mcp.border.bot/mcp"}' ``` Config file `~/.copilot/mcp-config.json`: ```json { "mcpServers": { "borderbot": { "type": "http", "url": "https://staging-mcp.border.bot/mcp", "tools": [ "*" ] } } } ``` One-click install: [Install in VS Code](vscode:mcp/install?%7B%22name%22%3A%22borderbot%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fstaging-mcp.border.bot%2Fmcp%22%7D) Official setup guide: https://code.visualstudio.com/docs/agent-customization/mcp-servers Notes: `~/.copilot/mcp-config.json` is the portable user format VS Code now prefers (shared with GitHub Copilot CLI). The older VS Code format (`.vscode/mcp.json`, or the user-profile file from “MCP: Open User Configuration”) uses a top-level "servers" object: `{"servers": {"borderbot": {"type": "http", "url": "https://staging-mcp.border.bot/mcp"}}}`. For VS Code Insiders use the `vscode-insiders:` scheme. ### Devin Desktop (formerly Windsurf) By Cognition. Enterprise users must turn MCP on in settings. 1. Open the MCP config: in the Cascade panel click “..” (Actions) › “Open MCP config file” (`~/.config/devin/mcp_config.json`), or run `devin mcp add -s user borderbot https://staging-mcp.border.bot/mcp` with Devin CLI. 2. Add border.bot under "mcpServers" using the config snippet and save. 3. Sign in to border.bot when prompted on first use; if the server shows “Needs auth”, click “Authenticate”. Command: ```bash devin mcp add -s user borderbot https://staging-mcp.border.bot/mcp ``` Config file `~/.config/devin/mcp_config.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://docs.devin.ai/desktop/cascade/mcp Notes: Formerly Windsurf (windsurf.com now redirects to Devin Desktop). The file is shared by the legacy Cascade agent, the default Devin Local agent and Devin CLI (Windows: `%APPDATA%\devin\mcp_config.json`). Devin Local asks before each MCP tool call; `devin mcp login borderbot` re-runs the sign-in. ### Visual Studio By Microsoft. Visual Studio 2026, or Visual Studio 2022 17.14 and later, with GitHub Copilot. Organization MCP allow-list policies apply. 1. Click “Install in Visual Studio”, or in the Copilot Chat pane switch to Agent mode, select “Tools”, then the plus (+) button › “Add custom MCP server”, and enter `borderbot` and `https://staging-mcp.border.bot/mcp`. 2. In `.mcp.json`, select “Authentication Required” (or “Manage Authentication”) from the CodeLens above `borderbot` and sign in to border.bot in the browser pop-up. 3. Enable border.bot’s tools in the tool picker and choose “Allow” when Copilot asks to run one. Config file `%USERPROFILE%\.mcp.json`: ```json { "servers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` One-click install: [Install in Visual Studio](https://vs-open.link/mcp-install?%7B%22name%22%3A%22borderbot%22%2C%22url%22%3A%22https%3A%2F%2Fstaging-mcp.border.bot%2Fmcp%22%7D) Official setup guide: https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers Notes: Visual Studio supports any MCP-spec OAuth provider. The install-link format is the one Microsoft’s own “Install” buttons on that page use. A solution-level `.mcp.json` works too. ### Cline 1. In the Cline panel, click the “MCP Servers” icon and open the “Remote Servers” tab. 2. Server Name: `borderbot`; Server URL: `https://staging-mcp.border.bot/mcp`; Transport Type: “Streamable HTTP”; then click “Add Server”. 3. Complete the border.bot authorization in your browser (Cline CLI: run `cline mcp` and choose “Authorize OAuth”). Command: ```bash cline mcp add borderbot https://staging-mcp.border.bot/mcp --transport http --yes ``` Config file `~/.cline/data/settings/cline_mcp_settings.json`: ```json { "mcpServers": { "borderbot": { "type": "streamableHttp", "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://docs.cline.bot/mcp/mcp-overview Notes: The path above is the Cline CLI’s; in the IDE extension use “MCP Servers” › “Configure” › “Configure MCP Servers” to edit the same JSON. Keep "type": "streamableHttp", without it Cline uses legacy SSE. ### Zed By Zed Industries. 1. Open Settings › AI › MCP Servers, click “Add Server” and choose “Add Remote Server”. 2. Enter `borderbot` and `https://staging-mcp.border.bot/mcp` (no Authorization header) and save. 3. Zed prompts you to authenticate with the standard MCP OAuth flow, sign in to border.bot. 4. When the indicator next to `borderbot` is green (“Server is active”), use it from the Agent Panel. Config file `~/.config/zed/settings.json`: ```json { "context_servers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://zed.dev/docs/ai/mcp Notes: Zed also forwards configured MCP servers to external agents over ACP. ### Kiro By Amazon Web Services. 1. Run “Kiro: Open user MCP config (JSON)” from the Command Palette (or select the “Open MCP Config” icon in the Kiro panel). 2. Add border.bot under "mcpServers" using the config snippet and save, servers reconnect automatically. 3. Kiro opens border.bot’s authorization page; sign in and approve. 4. Check the MCP servers tab in the Kiro panel to confirm it is connected. Config file `~/.kiro/settings/mcp.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://kiro.dev/docs/mcp/configuration/ Notes: If MCP is off, enable the MCP support setting (Settings, search “MCP”). Kiro CLI reads the same file. Kiro registers via Dynamic Client Registration and requires the issuer in border.bot’s protected-resource metadata to match the authorization server’s `issuer` exactly. ### Replit 1. Click “Add to Replit”, or go to replit.com/integrations, scroll to “MCP Servers for Replit Agent” and click “+ Add MCP server”. 2. Display name: border.bot; MCP Server URL: `https://staging-mcp.border.bot/mcp`. 3. Click “Test & save” and complete the border.bot OAuth sign-in Replit walks you through. 4. Mention border.bot in an Agent chat to use its tools in any project. One-click install: [Add to Replit](https://replit.com/integrations?mcp=eyJkaXNwbGF5TmFtZSI6ImJvcmRlci5ib3QiLCJiYXNlVXJsIjoiaHR0cHM6Ly9zdGFnaW5nLW1jcC5ib3JkZXIuYm90L21jcCJ9) Official setup guide: https://docs.replit.com/build/connect-via-mcp ### v0 By Vercel. 1. In v0, open the + menu in the prompt form and select “MCPs”. 2. Configure a custom MCP server with `https://staging-mcp.border.bot/mcp` and choose “OAuth” as the authentication. 3. Sign in to border.bot when prompted; v0 then considers its tools in new and existing chats. Official setup guide: https://v0.app/docs/MCP Notes: MCP tools are available to v0 while it generates; the apps v0 builds can’t call them. Tool calls follow your global permission mode (Ask, Auto or Full). ### JetBrains Air By JetBrains. 1. Open Settings › AI › MCP Servers and make sure “Enable MCP support” is on. 2. Click “Add Global MCP Server”, paste the config snippet and save. 3. Click “Connect” next to `borderbot` and approve the connection on border.bot’s authorization page. Config file `.air/mcp.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://www.jetbrains.com/help/air/mcp-servers.html Notes: `.air/mcp.json` is the project-local location (“Add Local MCP Server”); a global server is stored by the app. Air cloud tasks take MCP servers from the repository’s `mcp.json` or a JetBrains Air Teams connector instead. ### TraeCode By ByteDance. 1. Click “Add to TraeCode” and confirm the configuration with “Confirm”, or open Settings (top-right icon) › “MCP” › “Add” › “Add Manually”. 2. If adding manually, paste the config snippet and click “Confirm”. 3. Sign in to border.bot if TraeCode prompts you to. Config file TraeCode mcp.json (Settings › MCP › Add › Add Manually): ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` One-click install: [Add to TraeCode](trae://trae.ai-ide/mcp-import?type=http&name=borderbot&config=eyJ1cmwiOiJodHRwczovL3N0YWdpbmctbWNwLmJvcmRlci5ib3QvbWNwIn0%3D) Official setup guide: https://docs.trae.ai/ide/add-mcp-servers Notes: TraeCode (the TRAE IDE) documents remote HTTP servers with header authentication only; OAuth sign-in isn’t documented, so it may not connect to border.bot’s OAuth-only endpoint. Install-link format: docs.trae.ai/ide/mcp-server-install-links. ## Command line Coding agents that run in a terminal. Most add the server with one command. ### Claude Code By Anthropic. 1. Run `claude mcp add --transport http --scope user borderbot https://staging-mcp.border.bot/mcp`. 2. Start Claude Code, run `/mcp`, select `borderbot` and follow the steps in your browser to log in (or run `claude mcp login borderbot` from your shell). 3. Run `/mcp` again to confirm `borderbot` is connected. Command: ```bash claude mcp add --transport http --scope user borderbot https://staging-mcp.border.bot/mcp ``` Config file `.mcp.json`: ```json { "mcpServers": { "borderbot": { "type": "http", "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://code.claude.com/docs/en/mcp Notes: `--scope user` makes border.bot available in every project; the `.mcp.json` snippet is for sharing it with a team via a repository. Claude Code discovers OAuth and border.bot’s Client ID Metadata Document support automatically and refreshes tokens itself. If you added border.bot as a connector on claude.ai and log in to Claude Code with that account, it already appears in `/mcp`. ### Codex By OpenAI. 1. CLI: run `codex mcp add borderbot --url https://staging-mcp.border.bot/mcp`, then `codex mcp login borderbot` and sign in to border.bot in your browser. 2. IDE extension: open the gear menu › “MCP servers” › “Add server”, enter `borderbot`, choose “Streamable HTTP”, paste `https://staging-mcp.border.bot/mcp`, save and select “Restart extension”, then “Authenticate”. 3. ChatGPT desktop app: “Settings” › “MCP servers” › “Add server” with the same values, save and select “Restart”, then “Authenticate”. 4. Type `/mcp` to see the connected servers. Command: ```bash codex mcp add borderbot --url https://staging-mcp.border.bot/mcp ``` Config file `~/.codex/config.toml`: ```toml [mcp_servers.borderbot] url = "https://staging-mcp.border.bot/mcp" ``` Official setup guide: https://learn.chatgpt.com/docs/extend/mcp Notes: The Codex CLI, IDE extension and ChatGPT desktop app share `~/.codex/config.toml`, so adding border.bot once covers all three. Codex uses a Client ID Metadata Document when the authorization server advertises it and otherwise Dynamic Client Registration, with a loopback callback on 127.0.0.1. ### Gemini CLI By Google. 1. Run `gemini mcp add --transport http --scope user borderbot https://staging-mcp.border.bot/mcp`. 2. Start `gemini` and run `/mcp auth borderbot`; sign in to border.bot in the browser window that opens. 3. Run `/mcp list` to check that `borderbot` is connected. Command: ```bash gemini mcp add --transport http --scope user borderbot https://staging-mcp.border.bot/mcp ``` Config file `~/.gemini/settings.json`: ```json { "mcpServers": { "borderbot": { "httpUrl": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://geminicli.com/docs/tools/mcp-server/ Notes: Use `httpUrl` for Streamable HTTP. `url` means SSE in Gemini CLI. OAuth needs a local browser and a localhost callback, so it doesn’t work in headless or SSH sessions without forwarding. ### GitHub Copilot CLI By GitHub. All Copilot plans. With Copilot from an organization, the Copilot CLI policy must be enabled, and MCP allowlist policies apply. 1. Run `copilot mcp add --transport http borderbot https://staging-mcp.border.bot/mcp`, or in interactive mode enter `/mcp add`, pick “HTTP or SSE”, paste the URL and press Ctrl+S. 2. If `borderbot` shows `needs-auth`, run `/mcp auth borderbot` and sign in to border.bot in your browser. 3. Run `/mcp show borderbot` to see its status and tools. Command: ```bash copilot mcp add --transport http borderbot https://staging-mcp.border.bot/mcp ``` Config file `~/.copilot/mcp-config.json`: ```json { "mcpServers": { "borderbot": { "type": "http", "url": "https://staging-mcp.border.bot/mcp", "tools": [ "*" ] } } } ``` Official setup guide: https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers Notes: Copilot CLI registers itself with Dynamic Client Registration. `~/.copilot/mcp-config.json` is also read by Visual Studio Code. ### OpenCode By Anomaly. 1. Add border.bot under "mcp" in `~/.config/opencode/opencode.json` using the config snippet (or run `opencode mcp add` and choose a remote server). 2. Run `opencode mcp auth borderbot` and authorize in your browser. OpenCode also prompts the first time you use it. 3. Run `opencode mcp list` to check its connection and auth status. Config file `~/.config/opencode/opencode.json`: ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "borderbot": { "type": "remote", "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://opencode.ai/docs/mcp-servers/ Notes: OpenCode uses Dynamic Client Registration automatically; no client ID is needed. ### Warp 1. Open Settings › Agents › MCP servers (or run “Open MCP Servers” from the Command Palette) and click “+ Add”. 2. Paste the config snippet and save. 3. Start `borderbot`; Warp opens a browser to sign in to border.bot the first time. Config file `~/.warp/.mcp.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://docs.warp.dev/agents/capabilities/mcp/ Notes: Servers in `~/.warp/.mcp.json` start automatically and show an authentication modal on first spawn. Credentials stay on the device, so sign in again on a new machine. ### Junie CLI By JetBrains. 1. Add the config snippet to `~/.junie/mcp/mcp.json`, or run `/mcp`, press Ctrl+A to add a server with the MCP Installation Assistant, and choose “User scope” and “Remote”. 2. border.bot shows the “Authorization required” status: select it, choose “Authorize” and log in on the border.bot page that opens. 3. Check that its status changes to “Active”. Config file `~/.junie/mcp/mcp.json`: ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://junie.jetbrains.com/docs/junie-cli-mcp-configuration.html Notes: Junie in JetBrains IDEs reads the same `~/.junie/mcp/mcp.json`, but JetBrains documents OAuth sign-in only for Junie CLI. JetBrains AI Assistant chat can’t sign in to OAuth MCP servers yet. ### Amp 1. Run `amp mcp add borderbot https://staging-mcp.border.bot/mcp` (saved to `amp.mcpServers` in `~/.config/amp/settings.json`). 2. Start the Amp TUI (`amp`); it opens your browser to sign in to border.bot automatically. 3. To use border.bot from every Amp client, including orbs, store it on ampcode.com instead: `amp mcp remote --personal add borderbot https://staging-mcp.border.bot/mcp --auth oauth`, then `amp mcp remote --personal login borderbot`. Command: ```bash amp mcp add borderbot https://staging-mcp.border.bot/mcp ``` Config file `~/.config/amp/settings.json`: ```json { "amp.mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://ampcode.com/docs/customize/mcp Notes: Local sign-in relies on Dynamic Client Registration. Browser OAuth isn’t available inside orbs, so use the remote definition there. ### goose By Agentic AI Foundation. 1. Click “Add to goose”, or run `goose configure` › “Add Extension” › “Remote Extension (Streamable HTTP)” and enter `borderbot` and `https://staging-mcp.border.bot/mcp`. 2. In goose Desktop you can also use the sidebar › “Extensions” › “Add custom extension”. 3. Sign in to border.bot in your browser when goose asks; it registers itself automatically (Client ID Metadata Document or Dynamic Client Registration). Config file `~/.config/goose/config.yaml`: ```yaml extensions: borderbot: name: borderbot type: streamable_http uri: "https://staging-mcp.border.bot/mcp" enabled: true timeout: 300 ``` One-click install: [Add to goose](goose://extension?url=https%3A%2F%2Fstaging-mcp.border.bot%2Fmcp&type=streamable_http&id=borderbot&name=borderbot&description=HS%20codes%2C%20duties%20and%20landed%20cost&timeout=300) Official setup guide: https://goose-docs.ai/docs/getting-started/using-extensions ### Qwen Code By Alibaba Cloud. 1. Run `qwen mcp add --scope user --transport http borderbot https://staging-mcp.border.bot/mcp`. 2. Start `qwen`, enter `/mcp` and authenticate `borderbot`; sign in to border.bot in your browser. 3. Ask the model to use border.bot (restart Qwen Code first if it was already running). Command: ```bash qwen mcp add --scope user --transport http borderbot https://staging-mcp.border.bot/mcp ``` Config file `~/.qwen/settings.json`: ```json { "mcpServers": { "borderbot": { "httpUrl": "https://staging-mcp.border.bot/mcp" } } } ``` Official setup guide: https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/ Notes: OAuth endpoints are discovered and the client registers dynamically. The callback is `http://localhost:7777/oauth/callback`, so sign-in needs a local browser. ### Kimi Code CLI By Moonshot AI. 1. Run `kimi mcp add --transport http --auth oauth borderbot https://staging-mcp.border.bot/mcp`. 2. Run `kimi mcp auth borderbot` and complete the OAuth flow in your browser. 3. Run `kimi mcp test borderbot` (or `/mcp` inside Kimi Code CLI) to check the connection. Command: ```bash kimi mcp add --transport http --auth oauth borderbot https://staging-mcp.border.bot/mcp ``` Official setup guide: https://moonshotai.github.io/kimi-cli/en/customization/mcp.html Notes: Servers are saved to `~/.kimi/mcp.json`; OAuth tokens are kept in `~/.kimi/mcp-oauth/`. ## Automation Agent and workflow builders that call border.bot from a step in a workflow, and an API client for trying its tools by hand. ### Microsoft Copilot Studio By Microsoft. 1. Open your agent’s “Tools” page and select “Add a tool” › “New tool” › “Model Context Protocol”. 2. Server name: border.bot; Server description: what border.bot does (e.g. “Classifies products to HS codes and calculates duties, taxes and landed cost”); Server URL: `https://staging-mcp.border.bot/mcp`. 3. Authentication: “OAuth 2.0”, type “Dynamic discovery”; select “Create”, then “Next”. 4. In “Add tool”, select “Create a new connection”, sign in to border.bot, then “Add to agent”. Official setup guide: https://learn.microsoft.com/en-us/microsoft-copilot-studio/mcp-add-existing-server-to-agent Notes: Copilot Studio supports the Streamable HTTP transport only. The orchestrator uses the server description to decide when to call border.bot. ### n8n 1. Add an “MCP Client Tool” to your AI Agent (or an “MCP Client” node to run one tool as a workflow step). 2. Set “Endpoint” (“MCP Endpoint URL” on the MCP Client node) to `https://staging-mcp.border.bot/mcp` and “Server Transport” to “HTTP Streamable”. 3. Set “Authentication” to “MCP OAuth2”, create a new “MCP OAuth2 API” credential with “Use Dynamic Client Registration” on, and click “Connect my account” to sign in to border.bot. 4. Choose which border.bot tools to expose under “Tools to Include”. Official setup guide: https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolmcp/ Notes: Labels match the current node versions; n8n’s MCP Client Tool page still shows the older “SSE Endpoint” field. ### Zapier MCP Client is in beta. 1. Go to the Apps page, click “+ Add connection”, search for and select “MCP Client”, then click “Add connection”. 2. Server URL: `https://staging-mcp.border.bot/mcp`; Transport: “Streamable HTTP”; OAuth: “Yes”. 3. Click “Yes, Continue to MCP Client”, sign in to border.bot and grant Zapier access. 4. Rename the connection to border.bot, then use its tools in Zaps or Agents. Official setup guide: https://help.zapier.com/hc/en-us/articles/38777069364109-Connect-remote-MCP-servers-to-Zapier-using-MCP-Client Notes: MCP Client supports tool calls only. ### Make MCP Client is in open beta for all users. 1. Add the “MCP Client” module to your scenario and click “Create a connection”. 2. Connection name: border.bot; in “MCP Server” click “+ New MCP Server” and enter `https://staging-mcp.border.bot/mcp` in the “URL” field (leave “API Key / Access token” empty). 3. Click “Save”, then sign in to border.bot and confirm access. Official setup guide: https://apps.make.com/mcp-client Notes: Make’s OAuth redirect URI is `https://www.make.com/oauth/cb/mcp`. ### Postman 1. In a workspace, click + › “MCP” in the left sidebar, choose “HTTP” and enter `https://staging-mcp.border.bot/mcp`. 2. Click “Connect” / “Load Capabilities”; for an OAuth server Postman opens the “OAuth Debugger”, click “Continue” through each phase and sign in when the “Authorization request” step opens your browser. 3. Open the “Tools” tab, pick a tool, fill in its arguments and click “Run”. Official setup guide: https://learning.postman.com/docs/use/send-requests/protocols/mcp-requests/create/ Notes: Useful for testing border.bot’s tools outside an AI client; Postman runs the full MCP OAuth flow (protected-resource metadata, Dynamic Client Registration, PKCE). ## What your assistant can do ### Classify products From a description or a product URL, to the code for any destination, with descriptions, confidence and alternatives. ### Calculate landed cost Duties, taxes and fees for a code, origin and destination, with the total landed cost. ### Read product pages Extract the title, materials, price and country of origin from a product link before classifying. ## Things to ask - “What’s the HTS code for an insulated stainless steel water bottle made in China?” - “Classify this product for import into the UK: https://shop.example/products/linen-shirt” - “Calculate the landed cost of 20 units of 6109.10 from Vietnam to Germany at €12 each, with €40 shipping.” - “Which of these product descriptions need more detail before we can classify them?” ## Billing and security - You sign in on border.bot. The assistant never sees your password. - Each connection is tied to one workspace that you choose when you approve it. - Calls use the same credits and prices as the dashboard and the API, and failed calls are refunded. - Every result is saved to the workspace history, and you can revoke a connection at any time from the dashboard. ## Frequently asked questions ### What is MCP? The Model Context Protocol is an open standard for connecting AI assistants to tools and data. A remote MCP server, like border.bot’s, runs on the web, so you add it with a URL and sign in with OAuth instead of installing anything. ### Do I need an API key for MCP? No. MCP clients sign in with OAuth: you log in to border.bot in your browser and approve the connection. API keys are only for calling the REST API from your own code. ### Which workspace pays for MCP calls? The one you choose when you approve the connection. Each call uses credits from that workspace at the same prices as the dashboard and API, and the results appear in its history. ### How do I disconnect a client? Open the dashboard to see every client connected to your workspace and revoke any of them. Revoking takes effect immediately; the client has to ask you to sign in again. ### Does my AI client’s plan support custom connectors? Support for remote MCP servers depends on the client and sometimes on your plan or edition. Each guide on this page lists the plans its vendor documents. If the option is missing, check the vendor’s setup guide linked from that client’s steps. ### Can I rely on what the assistant tells me? Treat it as an estimate to check. Border Bot is not a customs broker or adviser, and its codes, duties and checks can be wrong or out of date; the assistant can also misreport them. Confirm with the customs authority or a licensed broker before you declare or ship. The terms of service at border.bot/legal/terms apply to MCP use as well. --- # Security and data handling > How border.bot handles sign-in, API keys, MCP authorization, credits, payments and your product data, and how to report a security issue to our team. Source: https://staging.border.bot/security Last updated: 2026-10-12 border.bot runs on Cloudflare Workers, signs people in through WorkOS, takes payments through Stripe and records every credit movement in a ledger. This page explains each part and how to report a security issue. ## Signing in and workspaces - Dashboard sign-in is handled by WorkOS AuthKit. Your session lives in an encrypted, signed cookie. - Work happens inside workspaces (organizations). Each member has a role: admins manage billing, API keys, the team and settings; members classify, calculate and see history. - Admin tooling is protected by Cloudflare Access (Zero Trust) and every request to it is verified. ## Keeping workspaces apart - Each workspace’s data is separated by the database itself. Postgres row-level security only lets a request see and change the rows of the workspace it was authenticated for, even if application code asks for something else. - Each part of border.bot connects with its own database login that can do only what that part needs. The customer dashboard can’t read across workspaces at all, and the credit ledger can only be added to, never edited or deleted. - Automated tests run as those real database logins on every change and try to read and write across workspaces. ## API keys - Keys are created per workspace, start with bb_live_ and are shown once. - We store only a hash of each key, never the key itself, so a leaked database would not reveal usable keys. - Admins can revoke a key at any time; revoked keys stop working immediately. ## AI assistants (MCP) - The MCP server uses OAuth 2.1. You sign in on border.bot; the assistant receives a scoped token, not your password. - When you approve a client you choose which workspace it may bill. - Every connection is listed in the dashboard and can be revoked at any time. ## Credits and payments - Prices are stored on our servers. A client only says which action or credit pack it wants, never how much it costs. - Each billable call debits credits in a single atomic transaction before it runs; a database constraint makes a negative balance impossible, even under heavy concurrency. - If a call fails, its credits are refunded automatically, and every movement is recorded in the credit ledger. - Payments are taken by Stripe’s embedded payment form. Card details go straight to Stripe and never touch our servers, and credits are added only after Stripe’s signed webhook confirms the payment. ## Free tools - The free classifier, calculator and origin finder are protected by Cloudflare Turnstile and rate limits. - Free runs are counted per visitor using keyed hashes of the IP address, its address range and a signed first-party cookie (bb_vid), and aren’t offered from VPN, hosting or Tor networks. We don’t store raw IP addresses for this. ## Your product data - Descriptions, product URLs and values you submit are used to produce your result and are kept in your workspace history so you can find them again. - When you classify from a URL, we fetch that public page to read the product details (see how our page fetcher works at border.bot/bot). - Classification and duty calculation are performed with a specialist trade-data provider that receives the product details needed to produce the result. - Data is stored in PlanetScale Postgres, reached through Cloudflare, and in Cloudflare R2. Our main processors are Cloudflare, PlanetScale, WorkOS, Stripe and our trade-data provider. ## Report a security issue If you think you’ve found a vulnerability, email us with the details and steps to reproduce. Please don’t access other people’s data or degrade the service while testing. We’ll acknowledge your report and keep you updated while we fix it. Email: info@border.bot (subject “Security”). --- # About border.bot > border.bot classifies products and calculates duty, tax and landed cost for merchants who ship parcels abroad, via a dashboard, a REST API and an MCP server. Source: https://staging.border.bot/about Last updated: 2026-10-07 border.bot is a classification and duty-calculation service for merchants who ship parcels abroad. It gives you the HS code and the landed cost of a product, with the reasoning behind each answer, through a web dashboard, a REST API and an MCP server for AI assistants. ## Why it exists Every parcel that crosses a border needs a tariff code, a country of origin and, if you want to avoid surprise charges on delivery, an accurate estimate of the duty and tax. Getting any of them wrong delays parcels, triggers penalties or leaves the customer with a bill they refuse to pay. Most shops either pay a broker for each question or copy codes from a spreadsheet that drifts out of date. border.bot answers those questions directly and shows how it reached each answer. Operations teams use the dashboard, developers call the API from checkout and catalogue systems, and anyone using Claude, ChatGPT, Codex, Cursor or another MCP client can connect the MCP server. ## What you can expect ### Answers you can check Every classification shows the official description at each level of the code, the reasoning, a confidence score and the alternatives that were considered. ### Fixed prices per action You buy credits up front. Each action has a fixed credit cost shown on the pricing page and in the dashboard, and credits for a failed call are refunded automatically. ### The same answer everywhere The dashboard, the API, the MCP server and the free tools use the same engine and the same tariff data. ### Clear limits Results are guidance, not a binding ruling. Low-confidence results are flagged for review, and for high-value or regulated goods we recommend a licensed broker or a binding ruling from customs. Questions? [Contact us](https://staging.border.bot/contact). --- # Contact > Get in touch with border.bot for support, billing questions, partnerships or security reports. Email our team or find answers in the docs and guides. Source: https://staging.border.bot/contact Email is the quickest way to reach us. For product questions, say what you’re shipping, from which country and to where. ## Email us - ### Product support Questions about a classification, a landed-cost result, your account or the dashboard. [info@border.bot](mailto:info@border.bot?subject=Support) - ### Billing Credit packs, invoices, refunds and anything to do with payments. [info@border.bot](mailto:info@border.bot?subject=Billing) - ### Partnerships and volume Platforms, marketplaces, 3PLs and high-volume shippers who want to integrate border.bot. [info@border.bot](mailto:info@border.bot?subject=Partnerships) - ### Security reports Found a vulnerability? Send us the details and how to reproduce it. [info@border.bot](mailto:info@border.bot?subject=Security) ## Documentation and tools - [Free HS code classifier](https://staging.border.bot/tools/hs-code-classifier) - [Free landed cost calculator](https://staging.border.bot/tools/landed-cost-calculator) - [Free country of origin finder](https://staging.border.bot/tools/country-of-origin-finder) - [Developer quickstart](https://staging.border.bot/developers) - [API reference](https://staging.border.bot/docs/api) - [MCP setup for Claude, ChatGPT, Codex, Cursor and other clients](https://staging.border.bot/mcp) - [Security and data handling](https://staging.border.bot/security) --- # border.bot blog > Plain-English guides to HS codes, tariff schedules, landed cost, DDP vs DAP and country of origin for merchants who ship parcels across borders. Source: https://staging.border.bot/blog Last updated: 2026-10-13 Plain-English guides to HS codes, tariff schedules, landed cost, DDP vs DAP and country of origin for merchants who ship parcels across borders. ## [The EU’s €3 customs duty on parcels under €150](https://staging.border.bot/blog/eu-3-euro-customs-duty) Since 1 July 2026 the EU charges a temporary €3 customs duty on low-value parcels, once per tariff classification. What it covers, who pays and how it adds up. Published 2026-10-08 · 2 min read · Markdown: https://staging.border.bot/blog/eu-3-euro-customs-duty.md ## [US de minimis suspension: what changed for parcels](https://staging.border.bot/blog/us-de-minimis-suspension) US de minimis has been suspended since 29 August 2025. The timeline, the June 2026 CBP rules, how parcels clear now and what ends on 1 July 2027. Published 2026-10-08 · 4 min read · Markdown: https://staging.border.bot/blog/us-de-minimis-suspension.md ## [Classify products from Claude and ChatGPT](https://staging.border.bot/blog/classify-products-with-mcp) Connect the border.bot MCP server to Claude, ChatGPT or Cursor, then classify products, check origin and estimate landed cost from a chat. Setup and tips. Published 2026-09-30 · 4 min read · Markdown: https://staging.border.bot/blog/classify-products-with-mcp.md ## [Country of origin: shipped from isn’t made in](https://staging.border.bot/blog/country-of-origin-vs-shipped-from) Why the country a parcel ships from often isn’t its country of origin, how origin is decided, and how it changes duties, marking rules and trade-deal savings. Published 2026-09-16 · 4 min read · Markdown: https://staging.border.bot/blog/country-of-origin-vs-shipped-from.md ## [DDP vs DAP for ecommerce parcels](https://staging.border.bot/blog/ddp-vs-dap-ecommerce) Should you collect duties and taxes at checkout (DDP) or let customers pay on delivery (DAP)? The costs, risks and setup of each, explained for parcel shippers. Published 2026-09-09 · 4 min read · Markdown: https://staging.border.bot/blog/ddp-vs-dap-ecommerce.md ## [Landed cost explained: duties, taxes and fees](https://staging.border.bot/blog/landed-cost-explained) What makes up the landed cost of an international parcel (goods, shipping, duty, import VAT or GST, and fees) and how each part is calculated. Published 2026-09-01 · 5 min read · Markdown: https://staging.border.bot/blog/landed-cost-explained.md ## [HS vs HTS vs CN/TARIC: the digits explained](https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes) Why one product has a 6-digit HS code, a 10-digit US HTS code, an 8-digit EU CN code and a 10-digit TARIC code, and which one goes on which document. Published 2026-08-25 · 4 min read · Markdown: https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes.md ## [What is an HS code, and how do you find yours?](https://staging.border.bot/blog/what-is-an-hs-code) A plain-English guide to HS codes: how the six digits are built, why countries add more, and a step-by-step method for finding the right code for your product. Published 2026-08-18 · 5 min read · Markdown: https://staging.border.bot/blog/what-is-an-hs-code.md RSS: https://staging.border.bot/blog/rss.xml --- # Customs and shipping glossary > Plain definitions of HS, HTS, CN and TARIC codes, de minimis, customs value, duty, import VAT, DDP, DAP, IOSS and landed cost, with links to the full guides. Source: https://staging.border.bot/glossary Last updated: 2026-10-08 Short definitions of the terms that decide what a parcel pays at the border, with links to the full guides. ## Anti-dumping and countervailing duties Extra duties on specific products from specific countries, and sometimes from specific manufacturers, that offset dumping (selling below normal value) or foreign subsidies. They are charged on top of the normal rate, which is why the same HS code can cost more from one origin than from another. Read more: [Country of origin vs shipped from](https://staging.border.bot/blog/country-of-origin-vs-shipped-from). ## Binding ruling A written decision by a customs authority on how a specific product is classified, which that authority then has to apply to it. Examples are CBP rulings in the US (searchable in CROSS), Binding Tariff Information (BTI) in the EU and Advance Tariff Rulings (ATaR) in the UK. Read more: [What is an HS code?](https://staging.border.bot/blog/what-is-an-hs-code). ## CN code (Combined Nomenclature) The EU’s 8-digit product code. The first 6 digits are the HS code and the last 2 are EU subdivisions. The CN sets the EU’s customs duty rates. Read more: [HS vs HTS vs CN/TARIC](https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes). ## Commodity code (UK) The UK’s product code in the UK Trade Tariff: 10 digits for imports and 8 for exports. The first 6 digits are the HS code. Read more: [HS vs HTS vs CN/TARIC](https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes). ## Country of origin Where goods were made, or where they last went through a substantial change, under the importing country’s rules of origin. It decides the duty rate and any extra duties. It is not the country the parcel ships from. Read more: [Country of origin vs shipped from](https://staging.border.bot/blog/country-of-origin-vs-shipped-from). ## Customs value The value duty is calculated on, usually the price paid for the goods (the transaction value). The EU and the UK add transport and insurance to the border (a CIF basis); the US and Canada leave international freight out. Read more: [Landed cost explained](https://staging.border.bot/blog/landed-cost-explained). ## DAP (Delivered at Place) An Incoterms rule: the seller delivers to the named destination, and the buyer pays the import duty and taxes and handles import clearance. For parcels, that usually means the customer pays the carrier on delivery. Read more: [DDP vs DAP for parcels](https://staging.border.bot/blog/ddp-vs-dap-ecommerce). ## DDP (Delivered Duty Paid) An Incoterms rule: the seller handles import clearance and pays the import duty and taxes, so the customer pays nothing on delivery. Ecommerce sellers usually collect the amount at checkout. Read more: [DDP vs DAP for parcels](https://staging.border.bot/blog/ddp-vs-dap-ecommerce), [Free landed cost calculator](https://staging.border.bot/tools/landed-cost-calculator). ## De minimis A value below which a country waives duty, tax or both on an import. Thresholds differ by country and change: the US suspended its $800 duty exemption on 29 August 2025, and since 1 July 2026 the EU charges €3 per tariff classification on parcels worth up to €150. Read more: [US de minimis suspension](https://staging.border.bot/blog/us-de-minimis-suspension), [The EU’s €3 customs duty](https://staging.border.bot/blog/eu-3-euro-customs-duty). ## Duty (customs duty) A tax on imported goods, set by the tariff line for the product’s code and country of origin. It can be a percentage of the customs value (ad valorem), an amount per unit or weight (specific), or both (compound). Read more: [Landed cost explained](https://staging.border.bot/blog/landed-cost-explained), [Free landed cost calculator](https://staging.border.bot/tools/landed-cost-calculator). ## Formal entry (US) The full US customs entry, generally required for shipments worth more than $2,500 and for some goods at any value. It needs a customs bond and is usually filed by a licensed customs broker. Read more: [US de minimis suspension](https://staging.border.bot/blog/us-de-minimis-suspension). ## General Rules of Interpretation (GRI) The six rules, applied in order, that decide which heading and subheading of the Harmonized System a product belongs to. Most products are classified under Rule 1: the wording of the headings and the section and chapter notes. Read more: [What is an HS code?](https://staging.border.bot/blog/what-is-an-hs-code). ## HS code (Harmonized System code) A 6-digit product code from the Harmonized System, maintained by the World Customs Organization and used by most countries as the basis of their tariffs. Countries add digits for their own tariff lines, such as the 10-digit US HTS code. Read more: [What is an HS code?](https://staging.border.bot/blog/what-is-an-hs-code), [Free HS code classifier](https://staging.border.bot/tools/hs-code-classifier). ## HTS code (Harmonized Tariff Schedule of the United States) The US 10-digit product code, published by the US International Trade Commission. The first 6 digits are the HS code, the first 8 set the duty rate, and the last 2 are for statistics. Read more: [HS vs HTS vs CN/TARIC](https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes), [Free HS code classifier](https://staging.border.bot/tools/hs-code-classifier). ## Import VAT and GST Consumption tax charged on imports at the destination’s rate, such as VAT in the EU and the UK or GST in Canada and Australia. It is usually calculated on the customs value plus duty, so duty raises the tax too. Read more: [Landed cost explained](https://staging.border.bot/blog/landed-cost-explained). ## Incoterms Standard trade terms from the International Chamber of Commerce (the current set is Incoterms 2020) that say who pays for and handles transport, insurance and customs. DDP and DAP are the two that matter most for parcels. Read more: [DDP vs DAP for parcels](https://staging.border.bot/blog/ddp-vs-dap-ecommerce). ## Informal entry (US) A simplified US customs entry for most shipments worth $2,500 or less. With de minimis suspended, low-value courier parcels use it, and since 24 July 2026 parcels sent by post use CBP’s postal informal entry process. Read more: [US de minimis suspension](https://staging.border.bot/blog/us-de-minimis-suspension). ## IOSS (Import One-Stop Shop) An EU scheme for collecting VAT at checkout on goods sent to EU consumers in consignments worth up to €150. The registered seller declares and pays the VAT monthly in one EU country, and the parcel clears without VAT being charged again. Read more: [The EU’s €3 customs duty](https://staging.border.bot/blog/eu-3-euro-customs-duty). ## Landed cost The full cost of getting goods to the buyer: the price, shipping and insurance, plus duty, import taxes and fees. It is what the customer pays in total, at checkout or on delivery. Read more: [Landed cost explained](https://staging.border.bot/blog/landed-cost-explained), [Free landed cost calculator](https://staging.border.bot/tools/landed-cost-calculator). ## Merchandise processing fee (MPF) A US CBP fee on imports. Formal entries pay a percentage of the value, with a minimum and a maximum; informal entries pay a smaller flat fee. Read more: [Landed cost explained](https://staging.border.bot/blog/landed-cost-explained). ## Preferential origin Origin that qualifies goods for a lower or zero duty rate under a trade agreement, such as USMCA or the EU–UK Trade and Cooperation Agreement. The goods have to meet that agreement’s rules of origin, and the importer usually needs proof. Read more: [Country of origin vs shipped from](https://staging.border.bot/blog/country-of-origin-vs-shipped-from). ## Section 321 The US de minimis provision (19 U.S.C. 1321), which let shipments worth $800 or less, imported by one person on one day, enter free of duty. It has been suspended for goods from every country since 29 August 2025, and a 2025 law ends it on 1 July 2027. Read more: [US de minimis suspension](https://staging.border.bot/blog/us-de-minimis-suspension). ## TARIC code The EU’s integrated tariff code: 10 digits that add EU measures, such as anti-dumping duties, tariff suspensions and quotas, to the 8-digit CN code. Read more: [HS vs HTS vs CN/TARIC](https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes). --- # HS codes > The Harmonized System (HS2022) has 96 chapters, 1,228 headings and 5,612 six-digit subheadings. Countries build their customs tariffs on these codes and add their own digits after the first six. Source: https://staging.border.bot/hs-codes Last updated: 13 October 2026 [HS codes](https://staging.border.bot/hs-codes) ## Key facts - Edition: HS2022 - Chapters: 96 - Headings: 1,228 - Subheadings: 5,612 ## Chapters Each chapter has a two-digit code. Its headings add two more digits, and their subheadings two more again, for six digits in all. - [01](https://staging.border.bot/hs-codes/01) Live animals (6 headings, 34 subheadings) - [02](https://staging.border.bot/hs-codes/02) Meat and edible meat offal (10 headings, 66 subheadings) - [03](https://staging.border.bot/hs-codes/03) Fish and crustaceans, molluscs and other aquatic invertebrates (9 headings, 225 subheadings) - [04](https://staging.border.bot/hs-codes/04) Dairy produce; birds' eggs; natural honey; edible products of animal origin, not elsewhere specified or included (10 headings, 33 subheadings) - [05](https://staging.border.bot/hs-codes/05) Products of animal origin, not elsewhere specified or included (9 headings, 15 subheadings) - [06](https://staging.border.bot/hs-codes/06) Live trees and other plants; bulbs, roots and the like; cut flowers and ornamental foliage (4 headings, 16 subheadings) - [07](https://staging.border.bot/hs-codes/07) Edible vegetables and certain roots and tubers (14 headings, 73 subheadings) - [08](https://staging.border.bot/hs-codes/08) Edible fruit and nuts; peel of citrus fruit or melons (14 headings, 70 subheadings) - [09](https://staging.border.bot/hs-codes/09) Coffee, tea, maté and spices (10 headings, 39 subheadings) - [10](https://staging.border.bot/hs-codes/10) Cereals (8 headings, 26 subheadings) - [11](https://staging.border.bot/hs-codes/11) Products of the milling industry; malt; starches; inulin; wheat gluten (9 headings, 27 subheadings) - [12](https://staging.border.bot/hs-codes/12) Oil seeds and oleaginous fruits; miscellaneous grains, seeds and fruit; industrial or medicinal plants; straw and fodder (14 headings, 50 subheadings) - [13](https://staging.border.bot/hs-codes/13) Lac; gums, resins and other vegetable saps and extracts (2 headings, 11 subheadings) - [14](https://staging.border.bot/hs-codes/14) Vegetable plaiting materials; vegetable products not elsewhere specified or included (2 headings, 5 subheadings) - [15](https://staging.border.bot/hs-codes/15) Animal, vegetable or microbial fats and oils and their cleavage products; prepared edible fats; animal or vegetable waxes (21 headings, 53 subheadings) - [16](https://staging.border.bot/hs-codes/16) Preparations of meat, of fish, of crustaceans, molluscs or other aquatic invertebrates, or of insects (5 headings, 42 subheadings) - [17](https://staging.border.bot/hs-codes/17) Sugars and sugar confectionery (4 headings, 17 subheadings) - [18](https://staging.border.bot/hs-codes/18) Cocoa and cocoa preparations (6 headings, 11 subheadings) - [19](https://staging.border.bot/hs-codes/19) Preparations of cereals, flour, starch or milk; pastrycooks' products (5 headings, 19 subheadings) - [20](https://staging.border.bot/hs-codes/20) Preparations of vegetables, fruit, nuts or other parts of plants (9 headings, 52 subheadings) - [21](https://staging.border.bot/hs-codes/21) Miscellaneous edible preparations (6 headings, 16 subheadings) - [22](https://staging.border.bot/hs-codes/22) Beverages, spirits and vinegar (9 headings, 24 subheadings) - [23](https://staging.border.bot/hs-codes/23) Residues and waste from the food industries; prepared animal fodder (9 headings, 23 subheadings) - [24](https://staging.border.bot/hs-codes/24) Tobacco and manufactured tobacco substitutes; products, whether or not containing nicotine, intended for inhalation without combustion; other nicotine containing products intended for the intake of nicotine into the human body (4 headings, 16 subheadings) - [25](https://staging.border.bot/hs-codes/25) Salt; sulphur; earths and stone; plastering materials, lime and cement (29 headings, 67 subheadings) - [26](https://staging.border.bot/hs-codes/26) Ores, slag and ash (21 headings, 37 subheadings) - [27](https://staging.border.bot/hs-codes/27) Mineral fuels, mineral oils and products of their distillation; bituminous substances; mineral waxes (16 headings, 43 subheadings) - [28](https://staging.border.bot/hs-codes/28) Inorganic chemicals; organic or inorganic compounds of precious metals, of rare-earth metals, of radioactive elements or of isotopes (50 headings, 180 subheadings) - [29](https://staging.border.bot/hs-codes/29) Organic chemicals (42 headings, 410 subheadings) - [30](https://staging.border.bot/hs-codes/30) Pharmaceutical products (6 headings, 45 subheadings) - [31](https://staging.border.bot/hs-codes/31) Fertilisers (5 headings, 24 subheadings) - [32](https://staging.border.bot/hs-codes/32) Tanning or dyeing extracts; tannins and their derivatives; dyes, pigments and other colouring matter; paints and varnishes; putty and other mastics; inks (15 headings, 45 subheadings) - [33](https://staging.border.bot/hs-codes/33) Essential oils and resinoids; perfumery, cosmetic or toilet preparations (7 headings, 29 subheadings) - [34](https://staging.border.bot/hs-codes/34) Soap, organic surface-active agents, washing preparations, lubricating preparations, artificial waxes, prepared waxes, polishing or scouring preparations, candles and similar articles, modelling pastes, “dental waxes” and dental preparations with a basis of plaster (7 headings, 24 subheadings) - [35](https://staging.border.bot/hs-codes/35) Albuminoidal substances; modified starches; glues; enzymes (7 headings, 15 subheadings) - [36](https://staging.border.bot/hs-codes/36) Explosives; pyrotechnic products; matches; pyrophoric alloys; certain combustible preparations (6 headings, 13 subheadings) - [37](https://staging.border.bot/hs-codes/37) Photographic or cinematographic goods (7 headings, 30 subheadings) - [38](https://staging.border.bot/hs-codes/38) Miscellaneous chemical products (27 headings, 108 subheadings) - [39](https://staging.border.bot/hs-codes/39) Plastics and articles thereof (26 headings, 131 subheadings) - [40](https://staging.border.bot/hs-codes/40) Rubber and articles thereof (17 headings, 80 subheadings) - [41](https://staging.border.bot/hs-codes/41) Raw hides and skins (other than furskins) and leather (11 headings, 37 subheadings) - [42](https://staging.border.bot/hs-codes/42) Articles of leather; saddlery and harness; travel goods, handbags and similar containers; articles of animal gut (other than silk-worm gut) (5 headings, 20 subheadings) - [43](https://staging.border.bot/hs-codes/43) Furskins and artificial fur; manufactures thereof (4 headings, 12 subheadings) - [44](https://staging.border.bot/hs-codes/44) Wood and articles of wood; wood charcoal (21 headings, 128 subheadings) - [45](https://staging.border.bot/hs-codes/45) Cork and articles of cork (4 headings, 7 subheadings) - [46](https://staging.border.bot/hs-codes/46) Manufactures of straw, of esparto or of other plaiting materials; basketware and wickerwork (2 headings, 11 subheadings) - [47](https://staging.border.bot/hs-codes/47) Pulp of wood or of other fibrous cellulosic material; recovered (waste and scrap) paper or paperboard (7 headings, 21 subheadings) - [48](https://staging.border.bot/hs-codes/48) Paper and paperboard; articles of paper pulp, of paper or of paperboard (22 headings, 101 subheadings) - [49](https://staging.border.bot/hs-codes/49) Printed books, newspapers, pictures and other products of the printing industry; manuscripts, typescripts and plans (11 headings, 18 subheadings) - [50](https://staging.border.bot/hs-codes/50) Silk (7 headings, 9 subheadings) - [51](https://staging.border.bot/hs-codes/51) Wool, fine or coarse animal hair; horsehair yarn and woven fabric (13 headings, 38 subheadings) - [52](https://staging.border.bot/hs-codes/52) Cotton (12 headings, 124 subheadings) - [53](https://staging.border.bot/hs-codes/53) Other vegetable textile fibres; paper yarn and woven fabrics of paper yarn (10 headings, 23 subheadings) - [54](https://staging.border.bot/hs-codes/54) Man-made filaments; strip and the like of man-made textile materials (8 headings, 72 subheadings) - [55](https://staging.border.bot/hs-codes/55) Man-made staple fibres (16 headings, 110 subheadings) - [56](https://staging.border.bot/hs-codes/56) Wadding, felt and nonwovens; special yarns; twine, cordage, ropes and cables and articles thereof (9 headings, 30 subheadings) - [57](https://staging.border.bot/hs-codes/57) Carpets and other textile floor coverings (5 headings, 24 subheadings) - [58](https://staging.border.bot/hs-codes/58) Special woven fabrics; tufted textile fabrics; lace; tapestries; trimmings; embroidery (11 headings, 37 subheadings) - [59](https://staging.border.bot/hs-codes/59) Impregnated, coated, covered or laminated textile fabrics; textile articles of a kind suitable for industrial use (11 headings, 24 subheadings) - [60](https://staging.border.bot/hs-codes/60) Knitted or crocheted fabrics (6 headings, 44 subheadings) - [61](https://staging.border.bot/hs-codes/61) Articles of apparel and clothing accessories, knitted or crocheted (17 headings, 106 subheadings) - [62](https://staging.border.bot/hs-codes/62) Articles of apparel and clothing accessories, not knitted or crocheted (17 headings, 104 subheadings) - [63](https://staging.border.bot/hs-codes/63) Other made up textile articles; sets; worn clothing and worn textile articles; rags (10 headings, 52 subheadings) - [64](https://staging.border.bot/hs-codes/64) Footwear, gaiters and the like; parts of such articles (6 headings, 25 subheadings) - [65](https://staging.border.bot/hs-codes/65) Headgear and parts thereof (6 headings, 8 subheadings) - [66](https://staging.border.bot/hs-codes/66) Umbrellas, sun umbrellas, walking-sticks, seat-sticks, whips, riding-crops and parts thereof (3 headings, 6 subheadings) - [67](https://staging.border.bot/hs-codes/67) Prepared feathers and down and articles made of feathers or of down; artificial flowers; articles of human hair (4 headings, 8 subheadings) - [68](https://staging.border.bot/hs-codes/68) Articles of stone, plaster, cement, asbestos, mica or similar materials (15 headings, 50 subheadings) - [69](https://staging.border.bot/hs-codes/69) Ceramic products (13 headings, 30 subheadings) - [70](https://staging.border.bot/hs-codes/70) Glass and glassware (19 headings, 71 subheadings) - [71](https://staging.border.bot/hs-codes/71) Natural or cultured pearls, precious or semi-precious stones, precious metals, metals clad with precious metal, and articles thereof; imitation jewellery; coin (18 headings, 55 subheadings) - [72](https://staging.border.bot/hs-codes/72) Iron and steel (29 headings, 167 subheadings) - [73](https://staging.border.bot/hs-codes/73) Articles of iron or steel (26 headings, 124 subheadings) - [74](https://staging.border.bot/hs-codes/74) Copper and articles thereof (16 headings, 49 subheadings) - [75](https://staging.border.bot/hs-codes/75) Nickel and articles thereof (8 headings, 17 subheadings) - [76](https://staging.border.bot/hs-codes/76) Aluminium and articles thereof (16 headings, 35 subheadings) - [78](https://staging.border.bot/hs-codes/78) Lead and articles thereof (4 headings, 8 subheadings) - [79](https://staging.border.bot/hs-codes/79) Zinc and articles thereof (6 headings, 9 subheadings) - [80](https://staging.border.bot/hs-codes/80) Tin and articles thereof (4 headings, 5 subheadings) - [81](https://staging.border.bot/hs-codes/81) Other base metals; cermets; articles thereof (12 headings, 56 subheadings) - [82](https://staging.border.bot/hs-codes/82) Tools, implements, cutlery, spoons and forks, of base metal; parts thereof of base metal (15 headings, 64 subheadings) - [83](https://staging.border.bot/hs-codes/83) Miscellaneous articles of base metal (11 headings, 36 subheadings) - [84](https://staging.border.bot/hs-codes/84) Nuclear reactors, boilers, machinery and mechanical appliances; parts thereof (86 headings, 538 subheadings) - [85](https://staging.border.bot/hs-codes/85) Electrical machinery and equipment and parts thereof; sound recorders and reproducers, television image and sound recorders and reproducers, and parts and accessories of such articles (48 headings, 296 subheadings) - [86](https://staging.border.bot/hs-codes/86) Railway or tramway locomotives, rolling-stock and parts thereof; railway or tramway track fixtures and fittings and parts thereof; mechanical (including electro-mechanical) traffic signalling equipment of all kinds (9 headings, 23 subheadings) - [87](https://staging.border.bot/hs-codes/87) Vehicles other than railway or tramway rolling-stock, and parts and accessories thereof (16 headings, 98 subheadings) - [88](https://staging.border.bot/hs-codes/88) Aircraft, spacecraft, and parts thereof (6 headings, 26 subheadings) - [89](https://staging.border.bot/hs-codes/89) Ships, boats and floating structures (8 headings, 25 subheadings) - [90](https://staging.border.bot/hs-codes/90) Optical, photographic, cinematographic, measuring, checking, precision, medical or surgical instruments and apparatus; parts and accessories thereof (32 headings, 143 subheadings) - [91](https://staging.border.bot/hs-codes/91) Clocks and watches and parts thereof (14 headings, 48 subheadings) - [92](https://staging.border.bot/hs-codes/92) Musical instruments; parts and accessories of such articles (7 headings, 17 subheadings) - [93](https://staging.border.bot/hs-codes/93) Arms and ammunition; parts and accessories thereof (7 headings, 18 subheadings) - [94](https://staging.border.bot/hs-codes/94) Furniture; bedding, mattresses, mattress supports, cushions and similar stuffed furnishings; luminaires and lighting fittings, not elsewhere specified or included; illuminated signs, illuminated name-plates and the like; prefabricated buildings (6 headings, 54 subheadings) - [95](https://staging.border.bot/hs-codes/95) Toys, games and sports requisites; parts and accessories thereof (6 headings, 39 subheadings) - [96](https://staging.border.bot/hs-codes/96) Miscellaneous manufactured articles (20 headings, 49 subheadings) - [97](https://staging.border.bot/hs-codes/97) Works of art, collectors' pieces and antiques (6 headings, 19 subheadings) ## Frequently asked questions ### How many chapters, headings and subheadings does the Harmonized System have? The Harmonized System (HS2022) has 96 chapters, 1,228 headings and 5,612 six-digit subheadings. ## Sources and updates The Harmonized System legal text comes from border.bot release 1 (edition HS 2022), imported from a file, and has been live since 13 October 2026. This page was last updated on 13 October 2026. Guidance from published tariff data, not a binding ruling. For a decision customs must follow, apply to the destination’s customs authority for a binding tariff ruling. Machine-readable: https://staging.border.bot/hs-codes.json --- # Import rules by country (page 1 of 3) > border.bot lists import rules for 238 countries and territories: VAT and GST rates, de minimis thresholds, currencies, customs unions and… Page 1 of 3. Source: https://staging.border.bot/countries Last updated: 13 October 2026 [Countries](https://staging.border.bot/countries) Page 1 of 3: countries and territories 1 to 100 of 238. Next page: [page 2](https://staging.border.bot/countries?page=2). ## Key facts - Countries and territories: 238 - With live import data: 67 - Customs unions and shared tariffs: 6 ## Countries with live data - [Albania](https://staging.border.bot/countries/albania): taxes - [Argentina](https://staging.border.bot/countries/argentina): taxes - [Armenia](https://staging.border.bot/countries/armenia): taxes - [Australia](https://staging.border.bot/countries/australia): taxes, deminimis - [Austria](https://staging.border.bot/countries/austria): taxes, deminimis; tariff of European Union - [Belgium](https://staging.border.bot/countries/belgium): taxes, deminimis; tariff of European Union - [Brazil](https://staging.border.bot/countries/brazil): taxes - [Bulgaria](https://staging.border.bot/countries/bulgaria): taxes; tariff of European Union - [Canada](https://staging.border.bot/countries/canada): taxes, deminimis - [Chile](https://staging.border.bot/countries/chile): taxes - [China](https://staging.border.bot/countries/china): taxes, deminimis - [Colombia](https://staging.border.bot/countries/colombia): taxes - [Croatia](https://staging.border.bot/countries/croatia): taxes; tariff of European Union - [Cyprus](https://staging.border.bot/countries/cyprus): taxes; tariff of European Union - [Czechia](https://staging.border.bot/countries/czechia): taxes, deminimis; tariff of European Union - [Denmark](https://staging.border.bot/countries/denmark): taxes, deminimis; tariff of European Union - [Estonia](https://staging.border.bot/countries/estonia): taxes, deminimis; tariff of European Union - [European Union](https://staging.border.bot/countries/european-union): taxes, deminimis - [Faroe Islands](https://staging.border.bot/countries/faroe-islands): taxes - [Finland](https://staging.border.bot/countries/finland): taxes, deminimis; tariff of European Union - [France](https://staging.border.bot/countries/france): taxes, deminimis; tariff of European Union - [Germany](https://staging.border.bot/countries/germany): taxes, deminimis; tariff of European Union - [Greece](https://staging.border.bot/countries/greece): taxes, deminimis; tariff of European Union - [Hong Kong](https://staging.border.bot/countries/hong-kong): deminimis - [Hungary](https://staging.border.bot/countries/hungary): taxes, deminimis; tariff of European Union - [Iceland](https://staging.border.bot/countries/iceland): taxes, deminimis - [India](https://staging.border.bot/countries/india): taxes, deminimis - [Indonesia](https://staging.border.bot/countries/indonesia): taxes - [Ireland](https://staging.border.bot/countries/ireland): taxes, deminimis; tariff of European Union - [Israel](https://staging.border.bot/countries/israel): taxes - [Italy](https://staging.border.bot/countries/italy): taxes, deminimis; tariff of European Union - [Japan](https://staging.border.bot/countries/japan): taxes, deminimis - [Latvia](https://staging.border.bot/countries/latvia): taxes, deminimis; tariff of European Union - [Lithuania](https://staging.border.bot/countries/lithuania): taxes, deminimis; tariff of European Union - [Luxembourg](https://staging.border.bot/countries/luxembourg): taxes, deminimis; tariff of European Union - [Malaysia](https://staging.border.bot/countries/malaysia): taxes - [Malta](https://staging.border.bot/countries/malta): taxes; tariff of European Union - [Mexico](https://staging.border.bot/countries/mexico): taxes, deminimis - [Moldova](https://staging.border.bot/countries/moldova): taxes - [Montenegro](https://staging.border.bot/countries/montenegro): taxes - [Morocco](https://staging.border.bot/countries/morocco): taxes - [Netherlands](https://staging.border.bot/countries/netherlands): taxes, deminimis; tariff of European Union - [New Zealand](https://staging.border.bot/countries/new-zealand): taxes - [Norway](https://staging.border.bot/countries/norway): taxes, deminimis - [Peru](https://staging.border.bot/countries/peru): taxes - [Philippines](https://staging.border.bot/countries/philippines): taxes - [Poland](https://staging.border.bot/countries/poland): taxes, deminimis; tariff of European Union - [Portugal](https://staging.border.bot/countries/portugal): taxes, deminimis; tariff of European Union - [Romania](https://staging.border.bot/countries/romania): taxes; tariff of European Union - [Russia](https://staging.border.bot/countries/russia): taxes, deminimis - [Saudi Arabia](https://staging.border.bot/countries/saudi-arabia): taxes, deminimis; tariff of Gulf Cooperation Council - [Serbia](https://staging.border.bot/countries/serbia): taxes - [Singapore](https://staging.border.bot/countries/singapore): taxes, deminimis - [Slovakia](https://staging.border.bot/countries/slovakia): taxes; tariff of European Union - [Slovenia](https://staging.border.bot/countries/slovenia): taxes, deminimis; tariff of European Union - [South Africa](https://staging.border.bot/countries/south-africa): taxes - [South Korea](https://staging.border.bot/countries/south-korea): taxes - [Spain](https://staging.border.bot/countries/spain): taxes, deminimis; tariff of European Union - [Sweden](https://staging.border.bot/countries/sweden): taxes, deminimis; tariff of European Union - [Switzerland](https://staging.border.bot/countries/switzerland): taxes, deminimis - [Taiwan](https://staging.border.bot/countries/taiwan): taxes, deminimis - [Thailand](https://staging.border.bot/countries/thailand): taxes - [Türkiye](https://staging.border.bot/countries/turkiye): taxes - [Ukraine](https://staging.border.bot/countries/ukraine): taxes - [United Arab Emirates](https://staging.border.bot/countries/united-arab-emirates): taxes; tariff of Gulf Cooperation Council - [United Kingdom](https://staging.border.bot/countries/united-kingdom): taxes, deminimis - [Uruguay](https://staging.border.bot/countries/uruguay): taxes ## Customs unions and shared tariffs 6 customs unions and shared tariffs are listed: the European Union (29 members), Gulf Cooperation Council (6 members), Kenya (5 members), South Africa (4 members), Switzerland (1 member) and the United Kingdom (3 members). - [European Union](https://staging.border.bot/countries/european-union): used by Austria, Belgium, Bulgaria, Croatia, Cyprus, Czechia, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Lithuania, Luxembourg, Malta, Monaco, Netherlands, Poland, Portugal, Romania, San Marino, Slovakia, Slovenia, Spain, Sweden - [Gulf Cooperation Council](https://staging.border.bot/countries/gulf-cooperation-council): used by Bahrain, Kuwait, Oman, Qatar, Saudi Arabia, United Arab Emirates - [Kenya](https://staging.border.bot/countries/kenya): used by Burundi, Rwanda, South Sudan, Tanzania, Uganda - [South Africa](https://staging.border.bot/countries/south-africa): used by Botswana, Eswatini, Lesotho, Namibia - [Switzerland](https://staging.border.bot/countries/switzerland): used by Liechtenstein - [United Kingdom](https://staging.border.bot/countries/united-kingdom): used by Guernsey, Isle of Man, Jersey ## Other countries No import data is live for these yet. Their pages list what border.bot holds. [Afghanistan](https://staging.border.bot/countries/afghanistan), [Algeria](https://staging.border.bot/countries/algeria), [American Samoa](https://staging.border.bot/countries/american-samoa), [Andorra](https://staging.border.bot/countries/andorra), [Angola](https://staging.border.bot/countries/angola), [Anguilla](https://staging.border.bot/countries/anguilla), [Antigua and Barbuda](https://staging.border.bot/countries/antigua-and-barbuda), [Aruba](https://staging.border.bot/countries/aruba), [Azerbaijan](https://staging.border.bot/countries/azerbaijan), [Bahamas](https://staging.border.bot/countries/bahamas), [Bahrain](https://staging.border.bot/countries/bahrain), [Bangladesh](https://staging.border.bot/countries/bangladesh), [Barbados](https://staging.border.bot/countries/barbados), [Belarus](https://staging.border.bot/countries/belarus), [Belize](https://staging.border.bot/countries/belize), [Benin](https://staging.border.bot/countries/benin), [Bermuda](https://staging.border.bot/countries/bermuda), [Bhutan](https://staging.border.bot/countries/bhutan), [Bolivia](https://staging.border.bot/countries/bolivia), [Bosnia and Herzegovina](https://staging.border.bot/countries/bosnia-and-herzegovina), [Botswana](https://staging.border.bot/countries/botswana), [British Virgin Islands](https://staging.border.bot/countries/british-virgin-islands), [Brunei](https://staging.border.bot/countries/brunei), [Burkina Faso](https://staging.border.bot/countries/burkina-faso), [Burundi](https://staging.border.bot/countries/burundi), [Cambodia](https://staging.border.bot/countries/cambodia), [Cameroon](https://staging.border.bot/countries/cameroon), [Cape Verde](https://staging.border.bot/countries/cape-verde), [Cayman Islands](https://staging.border.bot/countries/cayman-islands), [Central African Republic](https://staging.border.bot/countries/central-african-republic), [Chad](https://staging.border.bot/countries/chad), [Christmas Island](https://staging.border.bot/countries/christmas-island), [Cocos (Keeling) Islands](https://staging.border.bot/countries/cocos-keeling-islands) Page 1 of 3: countries and territories 1 to 100 of 238. Next page: [page 2](https://staging.border.bot/countries?page=2). Machine-readable: https://staging.border.bot/countries.json --- # border.bot API documentation > Classify products to HS codes and calculate duties, taxes and landed cost for cross-border parcels with the border.bot REST API or MCP server. Source: https://staging.border.bot/docs Last updated: 2026-10-09 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. border.bot classifies products to HS codes and works out the duties, taxes and fees a parcel pays on arrival. The same engine runs the dashboard, the REST API at `https://staging-api.border.bot` and the remote MCP server at `https://staging-mcp.border.bot/mcp`. ## When to use border.bot Use border.bot when software, or an agent working for someone, needs one of these answers for a cross-border shipment: | Job | REST endpoint | MCP | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | --- | | The HS, HTS, CN or UK commodity code for a product, in the destination's format | `POST /v1/classify` (`/classify/batch` for up to 25) | yes | | Landed cost: every duty, tax and fee line and the total for a parcel | `POST /v1/calculate` (`/calculate/shipment` for up to 50 lines) | yes | | How additional duties stack on one line (US Section 232, 301, IEEPA and similar) | `POST /v1/calculate/stacking` | no | | Where a product was made, from a URL, title or barcode | `POST /v1/origin` | yes | | Whether goods are restricted or prohibited in the destination | `POST /v1/restrictions` | yes | | Denied-party screening of a buyer or seller | `POST /v1/screen` | yes | | Thousands of products at once | `POST /v1/bulk/runs` | no | border.bot gives estimates and classifications backed by cited sources. It does not issue binding rulings, file customs declarations or book freight, and it is not a customs broker or adviser: results can be wrong or out of date, so have them checked with the customs authority or a licensed broker before you rely on them, and pass that on to your users. Use of the API and MCP server is covered by the [terms of service](https://staging.border.bot/legal/terms) and the [privacy policy](https://staging.border.bot/legal/privacy). ## Two ways in - **REST API**: JSON over HTTPS with a workspace API key. Best for checkouts, catalogues and back-office jobs. Start with the [quickstart](https://staging.border.bot/docs/quickstart). - **MCP server**: for Claude, ChatGPT, Codex, Cursor and other MCP clients. People sign in with OAuth, so no API key is needed. See [MCP](https://staging.border.bot/docs/mcp). Both use the same prepaid credits. New workspaces get free credits, and three reference endpoints need no key at all (see [authentication](https://staging.border.bot/docs/authentication#endpoints-without-a-key)). ## For agents Every docs page is available as Markdown: add `.md` to its URL or send `Accept: text/markdown`. The index of everything is at [/llms.txt](https://staging.border.bot/llms.txt), and the machine-readable discovery files are listed in [Agent discovery](https://staging.border.bot/docs/agents). --- # Quickstart > Create a border.bot API key, classify a product, then calculate its landed cost, with curl. Source: https://staging.border.bot/docs/quickstart Last updated: 2026-10-09 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. ## 1. Create an API key Sign in to the [dashboard](https://staging-app.border.bot/developers?tab=keys) and open **Developers → API keys**. Create a key for your workspace. It starts with `bb_live_` and is shown once, so put it in your secrets manager straight away. ```bash export BORDERBOT_API_KEY=bb_live_... ``` Check the key works. `GET /v1/me` is free and returns the workspace, the key's scopes and the credit balance: ```bash curl https://staging-api.border.bot/v1/me \ -H "Authorization: Bearer $BORDERBOT_API_KEY" ``` ## 2. Classify a product Send a description or a product URL with the destination country. Add the origin if you know it. ```bash curl -X POST https://staging-api.border.bot/v1/classify \ -H "Authorization: Bearer $BORDERBOT_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"description":"Men'\''s cotton crew-neck t-shirt, knitted","destinationCountry":"US","originCountry":"PT"}' ``` The response has the code in the destination's format, the official description at each level, a confidence score, the reasoning and alternatives. The `X-Credits-Charged` and `X-Credits-Remaining` headers say what the call cost. ## 3. Calculate landed cost Pass the code, the origin and destination, the goods value and the shipping cost: ```bash curl -X POST https://staging-api.border.bot/v1/calculate \ -H "Authorization: Bearer $BORDERBOT_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"hsCode":"6109.10.00.12","originCountry":"PT","destinationCountry":"US","value":120,"currency":"USD","shippingCost":15}' ``` You get every duty, tax and fee line with its legal basis and the total landed cost. The [reference for this endpoint](https://staging.border.bot/docs/api/calculate-landed-cost) lists every field, including shipping terms, preferential rates and seller-collected taxes. ## Next - [Authentication](https://staging.border.bot/docs/authentication): scopes and key handling. - [Credits and retries](https://staging.border.bot/docs/credits): what each call costs and how to retry without paying twice. - [Errors](https://staging.border.bot/docs/errors) and [rate limits](https://staging.border.bot/docs/rate-limits). - [API reference](https://staging.border.bot/docs/api): every endpoint. --- # Authentication > Authenticate border.bot REST calls with a workspace API key and scopes, and MCP clients with OAuth 2.1. Source: https://staging.border.bot/docs/authentication Last updated: 2026-10-10 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. ## API keys REST calls authenticate with a workspace API key in the `Authorization` header: ```http Authorization: Bearer bb_live_... ``` Create and revoke keys in the [dashboard](https://staging-app.border.bot/developers?tab=keys) under **Developers → API keys**. A key is shown once and stored only as a hash, so a lost key can't be recovered: revoke it and create another. A key can also have an expiry date. A missing or invalid key gets `401 unauthorized` with a `WWW-Authenticate: Bearer` header. ## Scopes A key has full access, or only the scopes you pick when you create it. Each endpoint in the [reference](https://staging.border.bot/docs/api) names the scope it needs. A key without that scope gets `403 forbidden` with `details.reason` set to `missing_scope`, and the message says which scope is missing. | Scope | Allows | | --- | --- | | `classify` | Classification: Classify products (single and batch), agency product codes, and feedback on answers. | | `calculate` | Landed cost: Landed cost for a line or a whole shipment, and duty stacking. | | `origin` | Products and origin: Read product pages and work out or check the country of origin. | | `compliance` | Compliance checks: Restricted goods checks and denied-party screening, with the screening history. | | `catalog` | Product catalogue: Read and change the workspace’s catalogue: products, their content and sources, codes per market (review and approval), imports, exports and syncs. Suggesting codes also needs Classification. | | `bulk` | Bulk runs: Start, follow and cancel bulk runs. A run also needs the scope of what it runs: Classification, or Landed cost. | | `documents` | Shipping documents: Generate air waybills (master and house) as PDF. | | `settings` | Workspace rules: Read and change blocked codes and restriction rules. | | `account` | Account: Credit balance, ledger and usage history. | `GET /v1/me` works with any key and reports its `scopes` and `expiresAt`. ## Endpoints without a key These reference endpoints are public and rate limited per IP address: - `GET /v1/countries`: destinations and what each one supports. - `GET /v1/pricing`: what every action costs in credits. - `GET /v1/classify/modes`: the classification modes you can choose. ## MCP clients: OAuth 2.1 The MCP server at `https://staging-mcp.border.bot/mcp` doesn't take API keys. MCP clients sign the user in with OAuth 2.1 (authorization code with PKCE `S256`): - Clients can register themselves with dynamic client registration (`POST https://staging-mcp.border.bot/oauth/register`, RFC 7591) or use a client ID metadata document. - Scopes: `mcp:read` to read, `mcp:write` to run actions that spend credits. - Discovery: [protected resource metadata](https://staging-mcp.border.bot/.well-known/oauth-protected-resource/mcp) (RFC 9728) and [authorization server metadata](https://staging-mcp.border.bot/.well-known/oauth-authorization-server) (RFC 8414). Agents that register themselves should read [auth.md](https://staging.border.bot/auth.md). ## Keeping keys safe - Call the API from your server, never from a browser or a mobile app. - Give each integration its own key with only the scopes it needs, so you can revoke one without breaking the others. - Every call is in the workspace's request log (`GET /v1/requests`, 30 days), with the key that made it. --- # Credits and retries > How border.bot charges prepaid credits per API call, refunds failed calls, and makes retries safe with Idempotency-Key. Source: https://staging.border.bot/docs/credits Last updated: 2026-10-09 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. ## Credits Billable calls spend prepaid credits from the workspace. Each action has a fixed price, set on the server; `GET /v1/pricing` (no key needed) lists them, and so does the [pricing page](https://staging.border.bot/pricing). New workspaces get free credits to start with. The price is taken before the work runs, in one atomic step, so the balance can't go below zero. If the call then fails, the credits are refunded automatically. Every billable response carries: | Header | Meaning | | --------------------- | --------------------------------- | | `X-Credits-Charged` | Credits this call cost. | | `X-Credits-Remaining` | The workspace balance afterwards. | A workspace without enough credits gets `402 insufficient_credits`, with `details.required` and `details.balance`. Top up in the [dashboard](https://staging-app.border.bot). `GET /v1/credits` returns the balance and ledger, and `GET /v1/usage` the usage history. ## Safe retries Send an `Idempotency-Key` header (any unique string, such as a UUID) on billable `POST` requests. Repeating a request with the same key returns the original result and doesn't charge again. While the first request is still running, a repeat gets `409 conflict`; wait and retry. ```bash curl -X POST https://staging-api.border.bot/v1/classify \ -H "Authorization: Bearer $BORDERBOT_API_KEY" \ -H "Idempotency-Key: 4f9c1a52-0b8e-4c5e-9d0a-5d1f2b8a7e31" \ -H "Content-Type: application/json" \ -d '{"description":"Stainless steel water bottle, 750 ml","destinationCountry":"GB"}' ``` Retry on `429`, `502`, `504` and network errors, with the same idempotency key and backoff (honour `Retry-After`). Don't retry other `4xx` errors unchanged: fix the request first. --- # Rate limits > border.bot API rate limits per API key and per IP address, the RateLimit-Policy and Retry-After headers, and how to back off. Source: https://staging.border.bot/docs/rate-limits Last updated: 2026-10-09 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. ## Limits | Who | Limit | | ----------------------------------------------------------------- | ------------------------------------------- | | Calls with an API key | 120 requests per 60 seconds, per key | | Public endpoints (no key) | 120 requests per 60 seconds, per IP address | | OAuth endpoints (`/authorize`, `/oauth/token`, `/oauth/register`) | 30 requests per 60 seconds, per IP address | Batch endpoints count as one request, so use `/classify/batch`, `/origin/batch` or a [bulk run](https://staging.border.bot/docs/api/start-bulk-run) for volume. ## Headers Responses follow the IETF HTTPAPI RateLimit header fields: ```http RateLimit-Policy: "key";q=120;w=60 ``` `q` is the number of requests allowed in a window of `w` seconds. When you go over it, the response is `429 rate_limited` with: ```http RateLimit: "key";r=0;t=60 Retry-After: 60 ``` `r` is what's left (zero) and `t` the seconds until you can send again. Wait at least `Retry-After` seconds before retrying, then send with the same `Idempotency-Key` so a retried billable call is never charged twice. Requests refused for rate limiting are never charged. --- # Errors > border.bot API error format, every error code with its HTTP status, and which errors to retry. Source: https://staging.border.bot/docs/errors Last updated: 2026-10-10 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. Errors return JSON with a stable, machine-readable `code`, a message written for people, and sometimes `details`: ```json { "error": { "code": "insufficient_credits", "message": "This workspace needs 5 credits and has 2.", "details": { "required": 5, "balance": 2 } }, "requestId": "0199c8d2-5b1e-7c3a-9f4e-2d6b8a1c3e5f" } ``` Every response carries an `X-Request-Id`, and error bodies repeat it as `requestId`. It is a UUID (UUIDv7, lowercase); MCP tool results carry the same id in `_meta["border.bot/requestId"]`. Quote it when you contact support, or find the request with `GET /v1/requests?requestId=…` (older requests keep their `req_…` ids, which still match). ## Codes | Code | HTTP | Meaning | | --- | --- | --- | | `invalid_input` | 400 | The request failed validation. The message names the field to fix. | | `unauthorized` | 401 | The API key is missing, malformed or revoked. | | `insufficient_credits` | 402 | The workspace balance is too low for this action. Top up in the dashboard. | | `forbidden` | 403 | The key is valid but not allowed to perform this action (a key without the scope the endpoint needs: details.reason is missing_scope). | | `not_found` | 404 | The resource or path doesn’t exist. | | `conflict` | 409 | A request with the same idempotency key is still running, or the change clashes with existing data. Wait and retry. | | `org_suspended` | 403 | The workspace is suspended. Contact support. | | `payload_too_large` | 413 | The request body is over 10 MB. Link to a photo instead of sending it inline, or split a bulk run. | | `version_retired` | 410 | The API version in the path has passed its sunset date. Move to the version the message names. | | `action_disabled` | 403 | This action is temporarily switched off. Try again later. | | `unsupported_country` | 422 | The destination isn’t covered for this action yet. The message says what is supported. | | `rate_limited` | 429 | Too many requests in a short period. Back off and retry. | | `upstream_error` | 502 | The engine couldn’t complete the request. Credits were refunded; retry. | | `upstream_timeout` | 504 | The engine took too long. Credits were refunded; retry. | | `internal` | 500 | Something went wrong on our side. Credits were refunded. | ## What to retry - `429`, `502` and `504`: retry with backoff and the same `Idempotency-Key`. Credits for a failed call are already refunded. - `409 conflict` on a repeated idempotency key: the first request is still running, so wait and retry. - Everything else: fix the request first. `invalid_input` names the field in its message and lists up to ten problems in `details.issues`. --- # Versioning > How the border.bot API is versioned by path, what counts as a breaking change, and the Deprecation and Sunset headers. Source: https://staging.border.bot/docs/versioning Last updated: 2026-10-09 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. The version is the first part of the path: `https://staging-api.border.bot/v1/classify`. The current version is **v1**. URLs without a version (`/openapi.json`, `/docs`) always serve the current one. ## What can change within a version Only additions: new endpoints, new optional request fields, new response fields and new enum values. Write clients that ignore fields they don't know and handle enum values they haven't seen. Anything that would break a working client ships as a new version. ## Retiring a version When a version is deprecated, its responses carry: | Header | Meaning | | ------------------------------------ | ---------------------------------------------- | | `API-Version` | The version that answered (on every response). | | `Deprecation` | When it was deprecated (RFC 9745). | | `Sunset` | When it stops working (RFC 8594). | | `Link: <…>; rel="successor-version"` | The docs of the version to move to. | After the sunset date, the version answers `410 version_retired`. `GET https://staging-api.border.bot/versions` lists every version with its status, dates and changes. Each version has its own OpenAPI 3.1 document at `https://staging-api.border.bot/v1/openapi.json`. --- # MCP server > Connect Claude, ChatGPT, Codex, Cursor and other MCP clients to the border.bot remote MCP server, with OAuth sign-in. Source: https://staging.border.bot/docs/mcp Last updated: 2026-10-10 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. The border.bot MCP server classifies products, calculates landed cost, infers country of origin and checks restricted goods from inside an MCP client. | | | | --------- | -------------------------------------------------------------------------- | | URL | `https://staging-mcp.border.bot/mcp` | | Transport | Streamable HTTP | | Auth | OAuth 2.1; the client opens a sign-in page, no API key | | Credits | Tools that run the engine spend the workspace's credits, like the REST API | The assistant acts for the person who connected it and bills their workspace. Results are estimates to check with the customs authority or a licensed broker, not customs, tax or legal advice; see the [terms of service](https://staging.border.bot/legal/terms) and [privacy policy](https://staging.border.bot/legal/privacy). ## Connect Add `https://staging-mcp.border.bot/mcp` as a remote (HTTP) MCP server in your client. For example, in Claude Code: ```bash claude mcp add --transport http borderbot https://staging-mcp.border.bot/mcp ``` Or in an `mcp.json` file (Cursor, VS Code and others): ```json { "mcpServers": { "borderbot": { "url": "https://staging-mcp.border.bot/mcp" } } } ``` Step-by-step setup for every client, including Claude, ChatGPT, Codex, Cursor, VS Code and Gemini CLI, is on the [MCP server page](https://staging.border.bot/mcp). The menu at the top of this page also connects Cursor and VS Code in one click. Connected before October 2026 with `https://staging-api.border.bot/mcp`? That address keeps working for existing connections. Use `https://staging-mcp.border.bot/mcp` when you connect a client again. ## Tools Every tool with its input schema is public at [https://staging-mcp.border.bot/mcp/tools.json](https://staging-mcp.border.bot/mcp/tools.json), and the server card at [https://staging.border.bot/.well-known/mcp/server-card.json](https://staging.border.bot/.well-known/mcp/server-card.json). Every tool result carries the id the call was logged under in `_meta["border.bot/requestId"]`, the same UUID as the response's `X-Request-Id`. Quote it when you ask support about a call; it also finds the call in your workspace's request log. --- # Agent discovery > Machine-readable files that let AI agents find and use border.bot - llms.txt, Markdown pages, OpenAPI, MCP server card, AI catalog, agent skills and auth.md. Source: https://staging.border.bot/docs/agents Last updated: 2026-10-10 > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. Everything here is public, needs no key and allows cross-origin requests. ## Read the docs | File | What it is | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | [/llms.txt](https://staging.border.bot/llms.txt) | Index of the site and docs, with when to use border.bot | | [/llms-full.txt](https://staging.border.bot/llms-full.txt) | Every page in one Markdown file | | Any page + `.md` | That page as Markdown, e.g. [/docs/quickstart.md](https://staging.border.bot/docs/quickstart.md). `Accept: text/markdown` works too | | [https://staging-api.border.bot/llms.txt](https://staging-api.border.bot/llms.txt) | Index for the API host | ## Call the API | File | What it is | | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | [OpenAPI 3.1](https://staging-api.border.bot/openapi.json) | The REST API, machine-readable | | [API catalog](https://staging.border.bot/.well-known/api-catalog) | RFC 9727 links to the OpenAPI documents and docs | | [Agent skill](https://staging.border.bot/.well-known/agent-skills/landed-cost/SKILL.md) | How an agent should use border.bot for landed cost ([index](https://staging.border.bot/.well-known/agent-skills/index.json)) | ## Connect over MCP | File | What it is | | ----------------------------------------------------------- | --------------------------------------------------------- | | [MCP server card](https://staging.border.bot/.well-known/mcp/server-card.json) | Server name, version, transport endpoint and capabilities | | [MCP tools](https://staging-mcp.border.bot/mcp/tools.json) | Every tool with its input schema | | [AI catalog](https://staging.border.bot/.well-known/ai-catalog.json) | The MCP server, API and skill as catalog entries | ## Authenticate | File | What it is | | ----------------------------------------------------------------------------------- | ----------------------------- | | [auth.md](https://staging.border.bot/auth.md) | How an agent gets credentials | | [Protected resource metadata](https://staging.border.bot/.well-known/oauth-protected-resource) | RFC 9728, for the MCP server | | [Authorization server metadata](https://staging-mcp.border.bot/.well-known/oauth-authorization-server) | RFC 8414 | ## Behaviour agents can rely on - Errors are JSON with a stable `code` ([errors](https://staging.border.bot/docs/errors)); a missing page returns `404` with a Markdown body when you ask for Markdown. - `RateLimit-Policy` and, on `429`, `RateLimit` and `Retry-After` ([rate limits](https://staging.border.bot/docs/rate-limits)). - `Idempotency-Key` makes retries free ([credits and retries](https://staging.border.bot/docs/credits)). --- # API reference > Every border.bot REST endpoint for HS code classification, landed cost, origin and compliance, with parameters, responses and curl examples. Source: https://staging.border.bot/docs/api > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. Base URL `https://staging-api.border.bot`, version 1.6.0. Machine-readable: [OpenAPI 3.1](https://staging-api.border.bot/v1/openapi.json). Try requests in the [interactive reference](https://staging-api.border.bot/v1/docs/interactive). Classify products to HS/HTS codes and calculate duties, taxes, fees and landed cost for cross-border parcels. **Versions**: This is **v1**, the current version. Within a version, changes are only additive (new endpoints, new optional fields, new enum values). Breaking changes ship as a new version; every version and its dates: https://staging-api.border.bot/versions **Authentication**: send a workspace API key: `Authorization: Bearer bb_live_…`. Create keys in the dashboard. **Credits**: billable requests use prepaid credits (see `GET /v1/pricing`). Prices are set server-side; failed requests are refunded automatically. Every response includes `X-Request-Id` (a UUID; quote it to support) and `API-Version`; billable responses include `X-Credits-Charged` and `X-Credits-Remaining`. **Retries**: send an `Idempotency-Key` header on POST requests; repeating it returns the original result without charging again. **Rate limits**: 120 requests per 60 seconds per API key, and per IP address for public endpoints. Responses carry the IETF `RateLimit-Policy` header (`"key";q=120;w=60` with a key, `"ip";q=120;w=60` without). Over the limit you get 429 `rate_limited` with `RateLimit: "key";r=0;t=60` and `Retry-After` in seconds; wait that long before retrying. **Errors**: `{ "error": { "code", "message", "details"? } }` with a stable `code` (e.g. 402 `insufficient_credits`, 429 `rate_limited`). **MCP**: use border.bot from Claude, ChatGPT, Codex, Cursor, VS Code and other MCP clients at `https://staging-mcp.border.bot/mcp` (OAuth, no API key). Setup guides: https://staging.border.bot/mcp ## Classification HS/HTS codes. - [Classify a product](https://staging.border.bot/docs/api/classify-product): `POST /v1/classify` - [Classify up to 25 products](https://staging.border.bot/docs/api/classify-batch): `POST /v1/classify/batch` - [Find an agency product code](https://staging.border.bot/docs/api/classify-regulator): `POST /v1/classify/regulator` - [Classification modes](https://staging.border.bot/docs/api/classify-modes): `GET /v1/classify/modes` - [Blocked codes](https://staging.border.bot/docs/api/list-blocked-codes): `GET /v1/classify/blocklist` - [Block a code](https://staging.border.bot/docs/api/add-blocked-code): `POST /v1/classify/blocklist` - [Unblock a code](https://staging.border.bot/docs/api/remove-blocked-code): `DELETE /v1/classify/blocklist` - [Block many codes](https://staging.border.bot/docs/api/import-blocked-codes): `POST /v1/classify/blocklist/import` - [Say whether a classification was right](https://staging.border.bot/docs/api/send-classify-feedback): `POST /v1/classify/feedback` ## Landed cost Duties, taxes and fees. - [Calculate duties, taxes and landed cost](https://staging.border.bot/docs/api/calculate-landed-cost): `POST /v1/calculate` - [Calculate a whole shipment](https://staging.border.bot/docs/api/calculate-shipment): `POST /v1/calculate/shipment` - [Duty stacking](https://staging.border.bot/docs/api/duty-stacking): `POST /v1/calculate/stacking` ## Products Product pages and country of origin. - [Read a product page](https://staging.border.bot/docs/api/extract-product): `POST /v1/products/extract` ## Compliance Restricted and prohibited goods (free). - [Check restricted goods](https://staging.border.bot/docs/api/check-restricted-goods): `POST /v1/restrictions` - [Restricted-goods checks](https://staging.border.bot/docs/api/list-restriction-checks): `GET /v1/restrictions/checks` - [Your restricted-goods rules](https://staging.border.bot/docs/api/list-restriction-rules): `GET /v1/restrictions/rules` - [Add a restricted-goods rule](https://staging.border.bot/docs/api/add-restriction-rule): `POST /v1/restrictions/rules` - [Remove a restricted-goods rule](https://staging.border.bot/docs/api/remove-restriction-rule): `DELETE /v1/restrictions/rules` - [Screen a person or company](https://staging.border.bot/docs/api/screen-party): `POST /v1/screen` - [Your screening checks](https://staging.border.bot/docs/api/list-screening-checks): `GET /v1/screen/checks` ## Account Your workspace, credits and usage. - [Who am I](https://staging.border.bot/docs/api/get-workspace): `GET /v1/me` - [Credit balance](https://staging.border.bot/docs/api/get-credits): `GET /v1/credits` - [Usage history](https://staging.border.bot/docs/api/list-usage): `GET /v1/usage` - [Request log](https://staging.border.bot/docs/api/list-api-requests): `GET /v1/requests` ## Reference Public reference data (no key needed). - [Supported countries](https://staging.border.bot/docs/api/list-countries): `GET /v1/countries` - [Pricing](https://staging.border.bot/docs/api/get-pricing): `GET /v1/pricing` ## Origin - [Infer country of origin](https://staging.border.bot/docs/api/infer-origin): `POST /v1/origin` - [Check a declared country of origin](https://staging.border.bot/docs/api/validate-origin): `POST /v1/origin/validate` - [Infer or check the origin of up to 50 products](https://staging.border.bot/docs/api/origin-batch): `POST /v1/origin/batch` ## Shipping documents - [Generate an air waybill PDF](https://staging.border.bot/docs/api/create-air-waybill): `POST /v1/documents/waybill` ## Bulk - [Your bulk runs](https://staging.border.bot/docs/api/list-bulk-runs): `GET /v1/bulk/runs` - [Start a bulk run](https://staging.border.bot/docs/api/start-bulk-run): `POST /v1/bulk/runs` - [Cancel a bulk run](https://staging.border.bot/docs/api/cancel-bulk-run): `DELETE /v1/bulk/runs` - [A bulk run’s progress](https://staging.border.bot/docs/api/bulk-run-status): `GET /v1/bulk/status` - [A bulk run’s results](https://staging.border.bot/docs/api/bulk-results): `GET /v1/bulk/results` ## Catalogue - [List products](https://staging.border.bot/docs/api/list-catalog-products): `GET /v1/catalog/products` - [Create a product](https://staging.border.bot/docs/api/create-catalog-product): `POST /v1/catalog/products` - [Get a product](https://staging.border.bot/docs/api/get-catalog-product): `GET /v1/catalog/products/{id}` - [Update a product](https://staging.border.bot/docs/api/update-catalog-product): `PATCH /v1/catalog/products/{id}` - [Archive a product](https://staging.border.bot/docs/api/archive-catalog-product): `POST /v1/catalog/products/{id}/archive` - [A product’s history](https://staging.border.bot/docs/api/catalog-product-history): `GET /v1/catalog/products/{id}/history` - [A product’s codes](https://staging.border.bot/docs/api/list-catalog-classifications): `GET /v1/catalog/products/{id}/classifications` - [Add a code](https://staging.border.bot/docs/api/create-catalog-classification): `POST /v1/catalog/products/{id}/classifications` - [Suggest codes](https://staging.border.bot/docs/api/suggest-catalog-classifications): `POST /v1/catalog/products/{id}/classifications/suggest` - [Approve a code](https://staging.border.bot/docs/api/approve-catalog-classification): `POST /v1/catalog/products/{id}/classifications/{classificationId}/approve` - [Reject a code](https://staging.border.bot/docs/api/reject-catalog-classification): `POST /v1/catalog/products/{id}/classifications/{classificationId}/reject` - [Classify many products](https://staging.border.bot/docs/api/classify-catalog): `POST /v1/catalog/classify` - [Your imports](https://staging.border.bot/docs/api/list-catalog-imports): `GET /v1/catalog/imports` - [Import a CSV file](https://staging.border.bot/docs/api/import-catalog): `POST /v1/catalog/imports` - [An import](https://staging.border.bot/docs/api/get-catalog-import): `GET /v1/catalog/imports/{id}` - [Export as CSV](https://staging.border.bot/docs/api/export-catalog): `GET /v1/catalog/exports` - [Sync records from a source](https://staging.border.bot/docs/api/sync-catalog): `POST /v1/catalog/sync` - [Approved codes to write back](https://staging.border.bot/docs/api/catalog-sync-codes): `GET /v1/catalog/sync/codes` - [Catalogue vocabularies](https://staging.border.bot/docs/api/list-catalog-terms): `GET /v1/catalog/terms` - [Source kinds](https://staging.border.bot/docs/api/list-catalog-sources): `GET /v1/catalog/sources` - [Default target markets](https://staging.border.bot/docs/api/get-catalog-markets): `GET /v1/catalog/markets` - [Set default target markets](https://staging.border.bot/docs/api/set-catalog-markets): `POST /v1/catalog/markets` --- # Classify a product (POST /v1/classify) > POST /v1/classify: Classify a product. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/classify-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify` Requires an API key (`Authorization: Bearer bb_live_…`). Find the HS/HTS code for a product shipped to `destinationCountry`. Give a description, a product page URL, or both. Costs the mode’s credits (`GET /v1/classify/modes` lists the modes and their prices); a weak answer may escalate to another mode at no extra charge. Failed requests are refunded automatically. API key scope: `classify`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `description` | string | no | What the product is: type, material/composition, intended use and user. Required unless `productUrl` or `imageUrl` is given. | | `productUrl` | string | no | Product page URL. border.bot reads the listing (title, brand, materials, price and any stated country of origin) and classifies from it, with your description when you give one. | | `imageUrl` | string | no | A product photo, classified with vision (in the modes that read photos: see `GET /v1/classify/modes`): a public URL, or the picture itself as a `data:image/jpeg;base64,…` URL (up to 6 MB). When given, the photo is classified instead of the listing URL. | | `destinationCountry` | string | yes | Where the parcel is going: selects the tariff (the national one where border.bot has it, else the 6-digit HS). ISO 3166-1 alpha-2, case-insensitive. | | `originCountry` | string | no | Where the product was made (context only). ISO 3166-1 alpha-2, case-insensitive. | | `mode` | string | no | The classification mode: one of the modes `GET /v1/classify/modes` lists (each with its price and what it reads). Omitted: the default mode. An unknown or unavailable mode is refused (`invalid_input`, with `details.availableModes`). | | `title` | string | no | Product title (optional extra context). | | `brand` | string | no | Brand (optional extra context). | | `sku` | string | no | Your SKU (stored with the usage record). | | `price` | number | no | Unit price (optional context). | | `currency` | string | no | ISO 4217 currency of `price`. | | `hsCodeHint` | string | no | An HS code you believe is close (2–10 digits) — used as a hint, not trusted blindly. | ## Responses - `200`: The classification and the credits charged. (`ClassifyResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"description":"Men'\''s short-sleeve t-shirt, 100% cotton, knitted","destinationCountry":"US","originCountry":"PT"}' ``` --- # Classify up to 25 products (POST /v1/classify/batch) > POST /v1/classify/batch: Classify up to 25 products. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/classify-batch > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify/batch` Requires an API key (`Authorization: Bearer bb_live_…`). Each item is a classify request, run four at a time and charged as one classification by its own mode; one failing (an unclassifiable description, insufficient credits) never stops the others and is refunded. With an `Idempotency-Key`, each item replays on its own. API key scope: `classify`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `items` | ClassifyRequest[] | yes | | ## Responses - `200`: One result per item, in order. (`ClassifyBatchResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify/batch' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"items":[{"description":"Men'\''s short-sleeve t-shirt, 100% cotton, knitted","destinationCountry":"US"},{"description":"Stainless steel water bottle, 750 ml","destinationCountry":"GB"}]}' ``` --- # Find an agency product code (POST /v1/classify/regulator) > POST /v1/classify/regulator: Find an agency product code. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/classify-regulator > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify/regulator` Requires an API key (`Authorization: Bearer bb_live_…`). The product code the destination’s import agency asks for, in that agency’s coding scheme: for the US, FDA’s import product code (e.g. `16AYN07`) for foods, drugs, devices, cosmetics and other goods FDA regulates. The answer names the `agency` and `scheme`, lists the code’s `parts` in order, and says whether the agency’s own check accepted it. Costs 1 credit; goods the agency doesn’t regulate are refused (`details.reason: "not_regulated"`, with `details.agency`) and refunded. API key scope: `classify`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `description` | string | yes | What the product is, what it is made of, and how it is processed or packed (frozen, smoked, canned…). | | `destinationCountry` | string | yes | Where the goods are imported. Its import agency and coding scheme follow from it (for `US`, FDA’s import product codes). | | `hsCode` | string | no | The goods’ tariff code, when known: a hint for the product pick. | ## Responses - `200`: The agency product code and the credits charged. (`RegulatorClassifyResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `422`: No agency product codes for this destination yet (`unsupported_country`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify/regulator' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"description":"","destinationCountry":""}' ``` --- # Classification modes (GET /v1/classify/modes) > GET /v1/classify/modes: Classification modes. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/classify-modes > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/classify/modes` Public: no API key needed. The classification modes you can use (admin configures them: today `mini`, `pro` and `max`), with what each costs and reads, in general or for one destination: whether it reads a product photo, and a photo sent inline, and which mode runs when a request names none. A product page URL works in every mode. No API key needed. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `destination` | string | no | ISO-2 destination: what each mode offers there (photos sent inline need border.bot’s own classifier). | ## Responses - `200`: The modes. (`ClassifyModesResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/classify/modes' ``` --- # Blocked codes (GET /v1/classify/blocklist) > GET /v1/classify/blocklist: Blocked codes. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/list-blocked-codes > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/classify/blocklist` Requires an API key (`Authorization: Bearer bb_live_…`). Codes your classifications never suggest: a blocked line, or every line under a blocked heading, is skipped and the next best answers. Free. API key scope: `settings`. ## Responses - `200`: Your blocked codes. (`BlockedCodesResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/classify/blocklist' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Block a code (POST /v1/classify/blocklist) > POST /v1/classify/blocklist: Block a code. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/add-blocked-code > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify/blocklist` Requires an API key (`Authorization: Bearer bb_live_…`). Never suggest this code (or any line under it) again, for one destination or all. Adding a code that is already blocked updates its reason. Free; up to 5,000 codes. API key scope: `settings`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `code` | string | yes | | | `destination` | "*" \| string | no | | | `reason` | string | no | | ## Responses - `200`: The blocked code. (`BlockedCodeResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify/blocklist' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"code":"6109.10","destination":"US","reason":"Our broker files these under 6109.90"}' ``` --- # Unblock a code (DELETE /v1/classify/blocklist) > DELETE /v1/classify/blocklist: Unblock a code. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/remove-blocked-code > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `DELETE https://staging-api.border.bot/v1/classify/blocklist` Requires an API key (`Authorization: Bearer bb_live_…`). Lets classifications suggest the code again. Free. API key scope: `settings`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `code` | string | yes | | | `destination` | "*" \| string | no | | ## Responses - `200`: Whether a blocked code was removed. (`BlockedCodeRemoveResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X DELETE 'https://staging-api.border.bot/v1/classify/blocklist' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Block many codes (POST /v1/classify/blocklist/import) > POST /v1/classify/blocklist/import: Block many codes. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/import-blocked-codes > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify/blocklist/import` Requires an API key (`Authorization: Bearer bb_live_…`). Block a list of codes at once, or with `replace: true` make the list exactly these. All or nothing: an import that would pass 5,000 codes changes nothing. Free. API key scope: `settings`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `codes` | object[] | yes | | | `replace` | boolean | no | | ## Responses - `200`: What the import added, updated and removed. (`BlockedCodesImportResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify/blocklist/import' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"codes":[{"code":"6109.10","destination":"US","reason":"Our broker files these under 6109.90"},{"code":"9503"}],"replace":false}' ``` --- # Say whether a classification was right (POST /v1/classify/feedback) > POST /v1/classify/feedback: Say whether a classification was right. border.bot API reference (Classification). Source: https://staging.border.bot/docs/api/send-classify-feedback > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/classify/feedback` Requires an API key (`Authorization: Bearer bb_live_…`). Tell border.bot a code was right, or what it should have been. Corrections are reviewed and become test cases the classifier must pass. With the classification’s `usageId`, sending again replaces your earlier verdict until it is reviewed. Free; up to 1,000 a day. API key scope: `classify`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `usageId` | string | no | | | `destinationCountry` | string | yes | | | `description` | string | yes | | | `predictedCode` | string | yes | | | `verdict` | "right" \| "wrong" | yes | | | `correctCode` | string | no | | | `reason` | string | no | | | `mode` | string | no | | | `productUrl` | string (uri) | no | | ## Responses - `200`: The feedback was recorded. (`ClassifyFeedbackResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `classify` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/classify/feedback' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"usageId":"use_01J9ZK8Q7X4N2M","destinationCountry":"US","description":"Yoga mat, 6 mm, TPE","predictedCode":"3926909985","verdict":"wrong","correctCode":"9506910030","reason":"Exercise equipment, not an article of plastics"}' ``` --- # Calculate duties, taxes and landed cost (POST /v1/calculate) > POST /v1/calculate: Calculate duties, taxes and landed cost. border.bot API reference (Landed cost). Source: https://staging.border.bot/docs/api/calculate-landed-cost > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/calculate` Requires an API key (`Authorization: Bearer bb_live_…`). Duties, taxes, fees and the landed cost for one HS code / origin / destination (the destinations `GET /countries` marks `landedCost`), or for a catalogue product by `sku` or `productId` (its approved code for the destination, origin, value, weight and content). Costs 1 credit. Unsupported destinations return 422 `unsupported_country` without charging. API key scope: `calculate`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `destinationCountry` | string | yes | Destination: one `GET /countries` marks `landedCost`. ISO 3166-1 alpha-2, case-insensitive. | | `currency` | string | no | ISO 4217 currency of `value`, `shippingCost` and `insuranceCost`. | | `shippingCost` | number | no | Shipping cost (affects CIF-based duty/VAT bases). | | `insuranceCost` | number | no | Insurance cost. | | `transportMode` | "air" \| "sea" \| "road" \| "rail" | no | Transport mode (fees such as HMF apply to sea freight). | | `shippingTerms` | "EXW" \| "FCA" \| "FAS" \| "FOB" \| "CFR" \| "CIF" \| "CPT" \| "CIP" \| "DAP" \| "DPU" \| "DDP" | no | Incoterm of the price (Incoterms 2020). Under C and D terms (CFR, CIF, CPT, CIP, DAP, DPU, DDP) the price already carries the goods to the destination, so `shippingCost` isn’t added to the customs value again. | | `shipmentChannel` | "courier" \| "postal" \| "freight" | no | How the goods travel and clear: `courier` (an express consignment: DHL, UPS, FedEx…), `postal` (national post) or `freight` (cargo on its own entry). Omitted: from `transportMode` — air is `courier`, sea, road and rail are `freight` (sea cargo is never an express consignment, so `courier` by sea is priced as freight). Affects de minimis and fees (US: the informal-entry MPF, 19 CFR 24.23(b)(2), is charged on freight; express consignments pay the carrier’s per-waybill fee, 24.23(b)(4)). The result’s `shipmentChannel` says which was used. | | `entryDate` | string | no | Calculate with the rates in force on this date (YYYY-MM-DD). Default: today. | | `tradeAgreement` | string | no | Ignored. Preferential rates are applied automatically from the origin and destination; the agreement used is returned as `tradeAgreement`. | | `region` | string | no | State, province or territory, where import taxes differ inside the country. Canada needs one (`ON`, `QC`, `BC`…). | | `purpose` | "sale" \| "gift" \| "sample" \| "return" | no | Why the goods are sent: some thresholds differ for gifts, samples and returns. Default: `sale`. A `gift` is a personal gift, not something bought: a free gift with a purchase is `sale` (or set `giftInConjunctionWithPurchase`). | | `sender` | "person" \| "business" | no | Who sends the goods: a private `person` or a `business`. Gift exemptions are usually for gifts from a person (US: up to $100 per recipient per day, 19 CFR 10.152); a gift from a business qualifies only on the declaration the destination accepts, claimed in `claims` (US: `gift_statement`, the parcel clearly marked as a gift with a statement enclosed, 19 CFR 10.153(c)). Left out, a gift exemption limited to some senders is applied and the result is `estimated`. | | `giftInConjunctionWithPurchase` | boolean | no | The gift is given in conjunction with a purchase (a bonus or free article with an order). It isn’t a gift for customs (US 19 CFR 10.153(a)): gift exemptions don’t apply and the goods are treated as sold. | | `businessBuyer` | boolean | no | The buyer is a business: some taxes are reverse-charged or apply differently. | | `sellerRegistrations` | string[] | no | Tax schemes the seller is registered for (`EU_IOSS`, `GB_VAT`, `AU_GST`, `NZ_GST`, `NO_VOEC`…). Taxes the seller collects at checkout are returned with `collectedBy: "seller"`. | | `preference` | string | no | `best` (default): the lowest preferential rate the origin qualifies for. `none`: the general rate only. Or a programme code (`S` for USMCA into the US). Every option is returned in `options`. | | `claims` | string[] | no | Exemption, relief and quota codes being claimed (US Chapter 99 exclusions such as `9903.88.69`; an end-use authorisation such as TARIC document `N990`; a tariff quota order number such as `050331`). Codes you could claim are returned in `claims.available`. | | `enforceValidation` | boolean | no | Refuse a shipment that matches one of the destination’s `reject` validation rules (400 `invalid_input`, `details.reason: "validation_failed"`, refunded) instead of reporting it in `validation`. | | `declarationType` | "full" \| "simplified" | no | The declaration the goods are entered on, when known: `full` (US formal entry) or `simplified` (US informal entry). Default: what the destination’s value rules require. A full declaration may always be chosen; a simplified one the value rules out is ignored (see `notes`). Fees differ by declaration (US MPF, the cotton assessment). | | `filing` | object | no | How the declaration is filed, when known: `method` `electronic` or `paper`, `preparedBy` `declarant` or `authority` (a customs officer). Default: the destination’s usual filing (electronic, by the declarant). The US informal-entry MPF differs by both. | | `hsCode` | string | no | HS/HTS code (4–10 digits). With `sku` or `productId`, leave it out to use the product’s approved code for the destination. | | `originCountry` | string | no | Country of origin. With `sku` or `productId`, the catalogue’s origin is used when left out. | | `value` | number | no | Total customs value of the line, in `currency`. With `sku` or `productId`: the item’s unit value × `quantity` when left out (it must be in the request’s currency). | | `quantity` | integer | no | Number of units. | | `weight` | number | no | Shipment weight (needed for weight-based duties). Requires `weightUnit`. | | `weightUnit` | "kg" \| "lb" | no | Unit of `weight`. | | `volumeLiters` | number | no | Volume of the goods in litres, for duties charged per litre (wine, spirits, fuel). | | `alcoholPercent` | number | no | Alcohol by volume (%), for duties charged per litre of pure alcohol. | | `components` | object[] | no | Metal content by value (line totals in `currency`), for duties charged on it: US Section 232 steel, aluminum and copper derivatives. Without it, those duties come back as `regulatory` (conditional). | | `metalWeightPercent` | number | no | Share of the product’s weight that is metal (0–100), for content-based exemptions. | | `materials` | object[] | no | What the goods are made of (line totals): harmonised `material` codes (`steel`, `aluminium`, `copper`, `wood`, `component`…; `GET /catalog/terms`) with their weight or share of the weight, value, and where each was produced by stage (`melt_pour`, `smelt`, `cast`, `harvest`, `production`). Measures reserved for declared content apply from them on their own (US Section 232: at least 85% of the aluminium, steel and copper by weight smelted and cast / melted and poured in the United States, Proclamation 11032), and duties charged on content read their value (the non-U.S. content of USMCA goods: the line’s value less the parts produced in the United States). Without them the full rate is charged, never less, and `contentHints` says what would lower it. | | `conditions` | string[] | no | Rate conditions the goods meet, when the destination reserves a rate for them: a harmonised kind (`pharmaceutical`, `end_use`, `certificate`, `company`, `quality`, `route`) or the publisher’s own code (EU TARIC additional code `2500`). Without it the default rate is charged (the unconditional one, or the highest when every rate has a condition); the rates you could claim are returned in `options` with their `condition`. The importer must hold what justifies a claimed condition. | | `declaredPrice` | object | no | The price of the goods per unit, in `currency` (`per`: `100 kg`, `t`, `hl`, `kg`…), for duties set by the price: the EU’s entry prices for fruit and vegetables and minimum import prices (TARIC price conditions). Without it the price is the line’s value over its weight or volume; when that isn’t known either, the highest duty the condition can charge is used and `needs` lists `price`. | | `salePrice` | number | no | The price the importer (or domestic seller) sells the line for, line total in `currency`, for taxes charged on the sale price rather than the customs value (US large cigars, 27 CFR 41.39). Without it the customs value stands in, the result is `estimated` and `needs` lists `sale_price`. | | `entryProvision` | object | no | The special provision the line is entered under, when not its classification alone (US chapter 98): `kind` is `repair_abroad` (9802.00.40/.50), `processing_abroad` (9802.00.60), `assembled_abroad` (9802.00.80), `agreement_provision` (USMCA subchapter XXIII), `returned` (9801.00.10) or `other`, with the provision’s `code`. Duties the provision is outside of are left out (US Section 301, 338, forced-labour, Brazil, Nicaragua and Russia duties, except for 9802 repairs, processing and assembly); repairs and processing pay on `dutiableValue` (the value of the repairs or processing, line total in `currency`), assembly abroad on the value less the U.S. components (`dutiableValue`, or worked out from `materials`). Section 232 stays charged, on the full value under 9802.00.60. | | `sku` | string | no | A SKU in your catalogue: its approved code for the destination, origin, value, weight and content components are used (what the line gives wins). A product without an approved code for the destination is refused without charging (`invalid_input`, `details.reason: "missing_classification"`). | | `productId` | string (uuid) | no | A catalogue product’s id (its first active item), instead of `sku`. | ## Responses - `200`: The landed-cost breakdown and the credits charged. (`CalculateResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `422`: Destination not supported (`unsupported_country`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/calculate' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"hsCode":"6109.10.00.12","originCountry":"CN","destinationCountry":"US","value":120,"currency":"USD","shippingCost":15}' ``` --- # Calculate a whole shipment (POST /v1/calculate/shipment) > POST /v1/calculate/shipment: Calculate a whole shipment. border.bot API reference (Landed cost). Source: https://staging.border.bot/docs/api/calculate-shipment > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/calculate/shipment` Requires an API key (`Authorization: Bearer bb_live_…`). Duties, taxes, fees and the landed cost of a cart or order to one destination: up to 50 lines (by their facts, or catalogue products by `sku`), freight and insurance shared out by value, one de minimis check, and per-entry fees charged once. Costs 1 credit per line. Priced on border.bot’s own data: a destination it doesn’t cover yet returns 422 `unsupported_country` without charging. API key scope: `calculate`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `destinationCountry` | string | yes | Destination: one `GET /countries` marks `landedCost`. ISO 3166-1 alpha-2, case-insensitive. | | `currency` | string | no | ISO 4217 currency of `value`, `shippingCost` and `insuranceCost`. | | `shippingCost` | number | no | Shipping cost (affects CIF-based duty/VAT bases). | | `insuranceCost` | number | no | Insurance cost. | | `transportMode` | "air" \| "sea" \| "road" \| "rail" | no | Transport mode (fees such as HMF apply to sea freight). | | `shippingTerms` | "EXW" \| "FCA" \| "FAS" \| "FOB" \| "CFR" \| "CIF" \| "CPT" \| "CIP" \| "DAP" \| "DPU" \| "DDP" | no | Incoterm of the price (Incoterms 2020). Under C and D terms (CFR, CIF, CPT, CIP, DAP, DPU, DDP) the price already carries the goods to the destination, so `shippingCost` isn’t added to the customs value again. | | `shipmentChannel` | "courier" \| "postal" \| "freight" | no | How the goods travel and clear: `courier` (an express consignment: DHL, UPS, FedEx…), `postal` (national post) or `freight` (cargo on its own entry). Omitted: from `transportMode` — air is `courier`, sea, road and rail are `freight` (sea cargo is never an express consignment, so `courier` by sea is priced as freight). Affects de minimis and fees (US: the informal-entry MPF, 19 CFR 24.23(b)(2), is charged on freight; express consignments pay the carrier’s per-waybill fee, 24.23(b)(4)). The result’s `shipmentChannel` says which was used. | | `entryDate` | string | no | Calculate with the rates in force on this date (YYYY-MM-DD). Default: today. | | `tradeAgreement` | string | no | Ignored. Preferential rates are applied automatically from the origin and destination; the agreement used is returned as `tradeAgreement`. | | `region` | string | no | State, province or territory, where import taxes differ inside the country. Canada needs one (`ON`, `QC`, `BC`…). | | `purpose` | "sale" \| "gift" \| "sample" \| "return" | no | Why the goods are sent: some thresholds differ for gifts, samples and returns. Default: `sale`. A `gift` is a personal gift, not something bought: a free gift with a purchase is `sale` (or set `giftInConjunctionWithPurchase`). | | `sender` | "person" \| "business" | no | Who sends the goods: a private `person` or a `business`. Gift exemptions are usually for gifts from a person (US: up to $100 per recipient per day, 19 CFR 10.152); a gift from a business qualifies only on the declaration the destination accepts, claimed in `claims` (US: `gift_statement`, the parcel clearly marked as a gift with a statement enclosed, 19 CFR 10.153(c)). Left out, a gift exemption limited to some senders is applied and the result is `estimated`. | | `giftInConjunctionWithPurchase` | boolean | no | The gift is given in conjunction with a purchase (a bonus or free article with an order). It isn’t a gift for customs (US 19 CFR 10.153(a)): gift exemptions don’t apply and the goods are treated as sold. | | `businessBuyer` | boolean | no | The buyer is a business: some taxes are reverse-charged or apply differently. | | `sellerRegistrations` | string[] | no | Tax schemes the seller is registered for (`EU_IOSS`, `GB_VAT`, `AU_GST`, `NZ_GST`, `NO_VOEC`…). Taxes the seller collects at checkout are returned with `collectedBy: "seller"`. | | `preference` | string | no | `best` (default): the lowest preferential rate the origin qualifies for. `none`: the general rate only. Or a programme code (`S` for USMCA into the US). Every option is returned in `options`. | | `claims` | string[] | no | Exemption, relief and quota codes being claimed (US Chapter 99 exclusions such as `9903.88.69`; an end-use authorisation such as TARIC document `N990`; a tariff quota order number such as `050331`). Codes you could claim are returned in `claims.available`. | | `enforceValidation` | boolean | no | Refuse a shipment that matches one of the destination’s `reject` validation rules (400 `invalid_input`, `details.reason: "validation_failed"`, refunded) instead of reporting it in `validation`. | | `declarationType` | "full" \| "simplified" | no | The declaration the goods are entered on, when known: `full` (US formal entry) or `simplified` (US informal entry). Default: what the destination’s value rules require. A full declaration may always be chosen; a simplified one the value rules out is ignored (see `notes`). Fees differ by declaration (US MPF, the cotton assessment). | | `filing` | object | no | How the declaration is filed, when known: `method` `electronic` or `paper`, `preparedBy` `declarant` or `authority` (a customs officer). Default: the destination’s usual filing (electronic, by the declarant). The US informal-entry MPF differs by both. | | `items` | object[] | yes | The shipment’s lines (up to 50), each with its code, origin and line value, or a catalogue `sku` (or `productId`) and `quantity`. Freight and insurance are shared out by value. | ## Responses - `200`: The shipment’s landed cost, line by line, and the credits charged. (`CalculateShipmentResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `422`: Destination not covered by border.bot’s own data (`unsupported_country`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/calculate/shipment' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"destinationCountry":"GB","currency":"USD","shippingCost":12,"items":[{"hsCode":"6109.10","originCountry":"CN","value":60,"quantity":3},{"hsCode":"6204.62","originCountry":"BD","value":45}]}' ``` --- # Duty stacking (POST /v1/calculate/stacking) > POST /v1/calculate/stacking: Duty stacking. border.bot API reference (Landed cost). Source: https://staging.border.bot/docs/api/duty-stacking > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/calculate/stacking` Requires an API key (`Authorization: Bearer bb_live_…`). Which duty lines apply to a code from an origin on a date, without a shipment: the base duty, then every additional measure (Section 301, 232, reciprocal…), which exemption codes remove which, the measures that depend on metal content or a claim, and the claim codes you could file. Up to 100 lines; free unless your pricing says otherwise. Answers from border.bot’s own data: a destination it doesn’t cover returns 422 `unsupported_country`. API key scope: `calculate`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `items` | object[] | yes | | ## Responses - `200`: Each line’s stack. (`StackingResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `422`: A destination border.bot’s own data doesn’t cover yet (`unsupported_country`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/calculate/stacking' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"items":[{"hsCode":"8479.89.94","originCountry":"CN","destinationCountry":"US"}]}' ``` --- # Read a product page (POST /v1/products/extract) > POST /v1/products/extract: Read a product page. border.bot API reference (Products). Source: https://staging.border.bot/docs/api/extract-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/products/extract` Requires an API key (`Authorization: Bearer bb_live_…`). Fetch a product page and extract its title, brand, price, materials, images and any stated country of origin. API key scope: `origin`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | yes | Product page URL (http/https). | ## Responses - `200`: The extracted product. (`ExtractProductResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/products/extract' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"url":""}' ``` --- # Check restricted goods (POST /v1/restrictions) > POST /v1/restrictions: Check restricted goods. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/check-restricted-goods > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/restrictions` Requires an API key (`Authorization: Bearer bb_live_…`). Check items against the destination’s import prohibitions and restrictions and, when `originCountry` is given, the origin’s export rules (sanctions, agency requirements such as FDA or APHIS), plus your own rules (`/restrictions/rules`). It uses no credits and is limited to 10 checks per minute per workspace (up to 100 items each). Destinations without coverage return 422 `unsupported_country`. API key scope: `compliance`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `destinationCountry` | string | yes | Ship-to country — its import rules are checked. ISO 3166-1 alpha-2, case-insensitive. | | `originCountry` | string | no | Ship-from country — its export rules are checked when given. ISO 3166-1 alpha-2, case-insensitive. | | `items` | RestrictionItem[] | yes | 1–100 items. | | `reference` | string | no | Your reference (an order or customer id), kept with the check as evidence. | ## Responses - `200`: Matches per item (an empty `restrictions` list means nothing matched). (`RestrictionsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `compliance` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `422`: Restricted-goods checks are not available for this destination (`unsupported_country`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). (`Error`) - `504`: The engine timed out (`upstream_timeout`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/restrictions' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"destinationCountry":"US","originCountry":"CN","items":[{"sku":"LAMP-01","title":"Lithium battery desk lamp","hsCode":"9405.21"}]}' ``` --- # Restricted-goods checks (GET /v1/restrictions/checks) > GET /v1/restrictions/checks: Restricted-goods checks. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/list-restriction-checks > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/restrictions/checks` Requires an API key (`Authorization: Bearer bb_live_…`). Your restricted-goods checks, newest first (up to 200): the evidence of what was checked, for which lane, by which engine, and what matched. Free. API key scope: `compliance`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | | ## Responses - `200`: Your checks. (`RestrictionChecksResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `compliance` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/restrictions/checks' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Your restricted-goods rules (GET /v1/restrictions/rules) > GET /v1/restrictions/rules: Your restricted-goods rules. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/list-restriction-rules > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/restrictions/rules` Requires an API key (`Authorization: Bearer bb_live_…`). Rules your restricted-goods checks apply on top of border.bot’s (a compliance team’s own list). Free. API key scope: `settings`. ## Responses - `200`: Your rules. (`RestrictionRulesResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/restrictions/rules' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Add a restricted-goods rule (POST /v1/restrictions/rules) > POST /v1/restrictions/rules: Add a restricted-goods rule. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/add-restriction-rule > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/restrictions/rules` Requires an API key (`Authorization: Bearer bb_live_…`). A rule matched by HS code (and everything under it), by words in the item, or by origin, for one country or `*`. Free. API key scope: `settings`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `country` | "*" \| string | no | | | `direction` | "import" \| "export" | no | | | `ruleType` | "prohibition" \| "restriction" \| "observation" | yes | | | `code` | string | no | | | `keywords` | string[] | no | | | `origins` | string[] | no | | | `title` | string | yes | | | `summary` | string | no | | ## Responses - `200`: The rule. (`RestrictionRuleResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/restrictions/rules' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"country":"US","ruleType":"prohibition","code":"9304","keywords":["airsoft"],"title":"No airsoft or air guns (company policy)"}' ``` --- # Remove a restricted-goods rule (DELETE /v1/restrictions/rules) > DELETE /v1/restrictions/rules: Remove a restricted-goods rule. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/remove-restriction-rule > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `DELETE https://staging-api.border.bot/v1/restrictions/rules` Requires an API key (`Authorization: Bearer bb_live_…`). Removes one of your rules by its id. Free. API key scope: `settings`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The rule’s id. | ## Responses - `200`: Whether a rule was removed. (`RestrictionRuleRemoveResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X DELETE 'https://staging-api.border.bot/v1/restrictions/rules' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Screen a person or company (POST /v1/screen) > POST /v1/screen: Screen a person or company. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/screen-party > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/screen` Requires an API key (`Authorization: Bearer bb_live_…`). Check a name (and a company) against denied-party lists: the US Consolidated Screening List (the SDN list, the Entity List, the Denied Persons List and the other export-screening lists of Commerce, State and the Treasury). Names and aliases match exactly or fuzzily (from 0.7); each check is kept as your evidence. Free, up to 60 a minute per workspace. A match is a lead to review, not a verdict. API key scope: `compliance`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | The person’s or company’s name, as you have it. | | `company` | string | no | A company to screen too (a buyer and their employer, say). | | `country` | string | no | The party’s country (ISO-2): matches with an address, nationality or flag there are flagged `countryMatch`. | | `type` | "individual" \| "entity" | no | Only parties of this type. Vessels, aircraft and parties of unknown type are always screened. | | `reference` | string | no | Your reference (an order or customer id), kept with the check as evidence. | ## Responses - `200`: The matches, best first, and the lists screened. (`ScreenResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `compliance` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/screen' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"name":""}' ``` --- # Your screening checks (GET /v1/screen/checks) > GET /v1/screen/checks: Your screening checks. border.bot API reference (Compliance). Source: https://staging.border.bot/docs/api/list-screening-checks > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/screen/checks` Requires an API key (`Authorization: Bearer bb_live_…`). Every screening your workspace ran, newest first: the evidence that a name was screened, when, against which lists, and what matched. Free. API key scope: `compliance`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | | ## Responses - `200`: Your checks. (`ScreeningChecksResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `compliance` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/screen/checks' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Who am I (GET /v1/me) > GET /v1/me: Who am I. border.bot API reference (Account). Source: https://staging.border.bot/docs/api/get-workspace > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/me` Requires an API key (`Authorization: Bearer bb_live_…`). The workspace and API key behind this request, with the current credit balance. Any API key may call this. ## Responses - `200`: The calling workspace. (`MeResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/me' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Credit balance (GET /v1/credits) > GET /v1/credits: Credit balance. border.bot API reference (Account). Source: https://staging.border.bot/docs/api/get-credits > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/credits` Requires an API key (`Authorization: Bearer bb_live_…`). Current balance, lifetime totals and the 20 most recent ledger entries (purchases, usage, refunds). API key scope: `account`. ## Responses - `200`: Balance and recent ledger. (`CreditsResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `account` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/credits' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Usage history (GET /v1/usage) > GET /v1/usage: Usage history. border.bot API reference (Account). Source: https://staging.border.bot/docs/api/list-usage > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/usage` Requires an API key (`Authorization: Bearer bb_live_…`). Every billable request made by the workspace (dashboard, API and MCP), newest first, with cursor pagination. API key scope: `account`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Page size (1–100). | | `cursor` | string | no | Opaque cursor from a previous page. | | `action` | "classify" \| "classify_max" \| "classify_regulator" \| "calculate" \| "calculate_stacking" \| "extract_product" \| "infer_origin" \| "air_waybill" | no | Only this action. | ## Responses - `200`: A page of usage events. (`UsageResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `account` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/usage' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Request log (GET /v1/requests) > GET /v1/requests: Request log. border.bot API reference (Account). Source: https://staging.border.bot/docs/api/list-api-requests > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/requests` Requires an API key (`Authorization: Bearer bb_live_…`). Every request made for your workspace (API keys and MCP) within the retention period (400 days by default), newest first: what it called, how it ended (status and error code), how long it took, and, for requests that change something, the body (kept for the first 30 days). Quote a request's `requestId` (its `X-Request-Id`) to support. API key scope: `account`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Page size (1–100). | | `cursor` | string | no | The `next` of the previous page. | | `failed` | "true" \| "false" | no | `true`: only requests that failed (status 400 and up). | | `requestId` | string | no | One request, by the `X-Request-Id` its response carried (a UUID; older requests keep their `req_…` ids, which still match). | ## Responses - `200`: A page of requests. (`ApiRequestsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `account` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/requests' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Supported countries (GET /v1/countries) > GET /v1/countries: Supported countries. border.bot API reference (Reference). Source: https://staging.border.bot/docs/api/list-countries > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/countries` Public: no API key needed. All ISO countries with the nomenclature classification answers in (a 10-digit national tariff where border.bot has one, 6-digit HS elsewhere) and whether landed-cost calculation is supported. No API key needed. ## Responses - `200`: Country coverage. (`CountriesResponse`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/countries' ``` --- # Pricing (GET /v1/pricing) > GET /v1/pricing: Pricing. border.bot API reference (Reference). Source: https://staging.border.bot/docs/api/get-pricing > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/pricing` Public: no API key needed. Credits per action, credit packs and free-tool limits. No API key needed. ## Responses - `200`: Current pricing. (`PricingResponse`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/pricing' ``` --- # Infer country of origin (POST /v1/origin) > POST /v1/origin: Infer country of origin. border.bot API reference (Origin). Source: https://staging.border.bot/docs/api/infer-origin > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/origin` Requires an API key (`Authorization: Bearer bb_live_…`). Where a product is made, as a probability per country with the evidence behind each: the product page’s data, “Made in …” text, a label in the photo, an AI estimate from brand, materials and price, the ship-from country and the barcode’s GS1 prefix. An AI estimate alone is never reported as high confidence. `needsReview` (with `reviewReason`) says when a person should confirm, because origin drives duty rates: below `reviewThreshold` (the request’s, else the workspace’s setting, else the platform default of 0.8), or when strong evidence disagrees. API key scope: `origin`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `productUrl` | string | no | Product page URL: its structured data and “Made in …” text are read first. | | `imageUrl` | string | no | Product photo (JPEG, PNG, WebP or GIF, up to 6 MB), as an http(s) URL or a base64 data URL: a visible “Made in …” label is strong evidence. | | `description` | string | no | Product description. | | `title` | string | no | Product name. | | `brand` | string | no | Brand. | | `sku` | string | no | Your SKU (kept with the result). | | `gtin` | string | no | Barcode (GTIN, UPC, EAN). Its GS1 prefix shows where the brand registered: a weak hint, never proof. | | `material` | string | no | Main materials. | | `categories` | string[] | no | Category path, broadest first. | | `price` | number | no | Selling price, in `currency`. | | `currency` | string | no | ISO 4217 currency of `price`. | | `shipFromCountry` | string | no | Country the goods ship from (often, not always, where they are made). ISO 3166-1 alpha-2, case-insensitive. | | `reviewThreshold` | number | no | When `needsReview` is set (0–1). Inferring: an answer below this probability. Validating: a declaration whose `probabilityOfMisrepresentation` is at or above it. Without it, the workspace’s setting (dashboard → Settings → Origin review) applies, then the platform default (0.8 to infer, 0.3 to validate). | ## Responses - `200`: The most likely origin, its probability, the alternates and the evidence. (`InferOriginResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/origin' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"title":"Organic cotton tee","brand":"Example","productUrl":"https://shop.example.com/products/organic-tee"}' ``` --- # Check a declared country of origin (POST /v1/origin/validate) > POST /v1/origin/validate: Check a declared country of origin. border.bot API reference (Origin). Source: https://staging.border.bot/docs/api/validate-origin > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/origin/validate` Requires an API key (`Authorization: Bearer bb_live_…`). How believable a declared origin is, given everything else known about the product: the share of the evidence pointing elsewhere (`probabilityOfMisrepresentation`), a verdict, the likely origin, and the reasons in words. With no evidence either way the verdict is `unknown`, never a guess. `needsReview` flags it when the misrepresentation probability reaches `reviewThreshold` (the request’s, else the workspace’s setting, else the platform default of 0.3), or when there is no evidence. API key scope: `origin`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `productUrl` | string | no | Product page URL: its structured data and “Made in …” text are read first. | | `imageUrl` | string | no | Product photo (JPEG, PNG, WebP or GIF, up to 6 MB), as an http(s) URL or a base64 data URL: a visible “Made in …” label is strong evidence. | | `description` | string | no | Product description. | | `title` | string | no | Product name. | | `brand` | string | no | Brand. | | `sku` | string | no | Your SKU (kept with the result). | | `gtin` | string | no | Barcode (GTIN, UPC, EAN). Its GS1 prefix shows where the brand registered: a weak hint, never proof. | | `material` | string | no | Main materials. | | `categories` | string[] | no | Category path, broadest first. | | `price` | number | no | Selling price, in `currency`. | | `currency` | string | no | ISO 4217 currency of `price`. | | `shipFromCountry` | string | no | Country the goods ship from (often, not always, where they are made). ISO 3166-1 alpha-2, case-insensitive. | | `reviewThreshold` | number | no | When `needsReview` is set (0–1). Inferring: an answer below this probability. Validating: a declaration whose `probabilityOfMisrepresentation` is at or above it. Without it, the workspace’s setting (dashboard → Settings → Origin review) applies, then the platform default (0.8 to infer, 0.3 to validate). | | `declaredOrigin` | string | yes | The country of origin declared (by a supplier, a listing, a customs entry). ISO 3166-1 alpha-2, case-insensitive. | ## Responses - `200`: The verdict on the declared origin, with reasons. (`ValidateOriginResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/origin/validate' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"declaredOrigin":"US","title":"Wireless earbuds","description":"Bluetooth 5.3. Made in China."}' ``` --- # Infer or check the origin of up to 50 products (POST /v1/origin/batch) > POST /v1/origin/batch: Infer or check the origin of up to 50 products. border.bot API reference (Origin). Source: https://staging.border.bot/docs/api/origin-batch > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/origin/batch` Requires an API key (`Authorization: Bearer bb_live_…`). Each item is inferred, or validated when it has `declaredOrigin`. Items run four at a time, each charged as one origin call; one failing (bad photo, insufficient credits) never stops the others. With an `Idempotency-Key`, each item replays on its own. API key scope: `origin`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `items` | object[] | yes | | | `reviewThreshold` | number | no | The review threshold for every item that doesn’t set its own `reviewThreshold` (see `POST /v1/origin`). | ## Responses - `200`: One result per item, in order. (`OriginBatchResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/origin/batch' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"items":[{"title":"Organic cotton tee","brand":"Example"},{"title":"Wireless earbuds","declaredOrigin":"US","gtin":"6901234567892"}]}' ``` --- # Generate an air waybill PDF (POST /v1/documents/waybill) > POST /v1/documents/waybill: Generate an air waybill PDF. border.bot API reference (Shipping documents). Source: https://staging.border.bot/docs/api/create-air-waybill > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/documents/waybill` Requires an API key (`Authorization: Bearer bb_live_…`). A master or house air waybill on the IATA Resolution 600a face, with the Resolution 600b conditions of contract after each copy (`conditions`), as 3 originals or the full set of 8 (`copies`). Validated before charging: a wrong check digit or non-Latin text answers 400 without a charge. The PDF is an unsigned draft until the issuing carrier or its agent executes it, and acceptance by any airline, agent or authority is not guaranteed: use is subject to the Terms’ Shipping documents section (https://border.bot/legal/terms#shipping-documents). Costs 1 credit. API key scope: `documents`. ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `kind` | "master" \| "house" | no | | | `prefix` | string | no | | | `number` | string | yes | | | `masterNumber` | string | no | | | `shipper` | object | yes | | | `consignee` | object | yes | | | `issuer` | object | yes | | | `agent` | object | no | | | `accountingInformation` | string | no | | | `departure` | string | yes | | | `departureName` | string | no | | | `destination` | string | yes | | | `destinationName` | string | no | | | `routing` | object[] | no | | | `firstCarrierName` | string | no | | | `flights` | string[] | no | | | `referenceNumber` | string | no | | | `optionalShippingInformation` | string | no | | | `currency` | string | yes | | | `weightValuation` | "PP" \| "CC" | no | | | `otherChargesPaid` | "PP" \| "CC" | no | | | `declaredValueCarriage` | number | no | | | `declaredValueCustoms` | number | no | | | `insurance` | number | no | | | `handlingInformation` | string | no | | | `sci` | string | no | | | `weightUnit` | "kg" \| "lb" | no | | | `dimensionUnit` | "cm" \| "in" | no | | | `volumeDivisor` | integer | no | | | `lines` | object[] | yes | | | `otherCharges` | object[] | no | | | `valuationCharge` | number | no | | | `tax` | number | no | | | `shipperSignature` | string | no | | | `executedOn` | string (date) | yes | | | `executedAt` | string | yes | | | `carrierSignature` | string | no | | | `copies` | "originals" \| "full" | no | | | `conditions` | boolean | no | | ## Responses - `200`: The PDF (base64) and the credits charged. (`AirWaybillResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/documents/waybill' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"kind":"master","prefix":"125","number":"12345675","shipper":{"name":"Northwind Apparel Ltd","address":"Unit 4, Bath Road Trading Estate","city":"Hounslow","postcode":"TW4 6HG","country":"GB","phone":"+44 20 7946 0000"},"consignee":{"name":"Harbor Street Retail Inc","address":"1200 Harbor Street, Suite 300","city":"Los Angeles","postcode":"CA 90021","country":"US","phone":"+1 213 555 0100"},"issuer":{"name":"British Airways World Cargo","address":"Heathrow Airport, Hounslow TW6 2JS"},"agent":{"name":"Skyline Forwarding Ltd","city":"London","iataCode":"91-4 7712/0010"},"accountingInformation":"FREIGHT PREPAID","departure":"LHR","departureName":"London Heathrow","destination":"LAX","destinationName":"Los Angeles","routing":[{"to":"LAX","by":"BA"}],"firstCarrierName":"British Airways","flights":["BA0283/14OCT"],"currency":"GBP","weightValuation":"PP","otherChargesPaid":"PP","handlingInformation":"NOTIFY CONSIGNEE ON ARRIVAL. COMMERCIAL INVOICE AND PACKING LIST ATTACHED.","sci":"X","lines":[{"pieces":4,"grossWeight":86.4,"rateClass":"Q","rate":3.85,"description":"Cotton knitted T-shirts and hoodies, 480 units","hsCodes":["610910","611020"],"dimensions":[{"pieces":4,"length":60,"width":40,"height":45}]}],"otherCharges":[{"code":"AW","dueTo":"A","amount":25},{"code":"MY","dueTo":"C","amount":51.84},{"code":"SC","dueTo":"C","amount":12.96}],"shipperSignature":"Skyline Forwarding Ltd","executedOn":"2026-10-13","executedAt":"London","copies":"originals","conditions":true}' ``` --- # Your bulk runs (GET /v1/bulk/runs) > GET /v1/bulk/runs: Your bulk runs. border.bot API reference (Bulk). Source: https://staging.border.bot/docs/api/list-bulk-runs > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/bulk/runs` Requires an API key (`Authorization: Bearer bb_live_…`). Your workspace’s bulk runs, newest first. API key scope: `bulk`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | | ## Responses - `200`: The runs. (`BulkRunsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `bulk` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/bulk/runs' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Start a bulk run (POST /v1/bulk/runs) > POST /v1/bulk/runs: Start a bulk run. border.bot API reference (Bulk). Source: https://staging.border.bot/docs/api/start-bulk-run > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/bulk/runs` Requires an API key (`Authorization: Bearer bb_live_…`). Classify, calculate, find agency product codes or find and check countries of origin for up to 10,000 items in the background. Each item is charged when it runs (as its single request would be) and refunded if it fails; a run stops when your credits run out. Follow it with `GET /bulk/status`, read its answers with `GET /bulk/results`. API key scope: `bulk`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | ## Responses - `200`: The run, queued. (`BulkRunResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `bulk` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/bulk/runs' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"kind":"classify","reference":"catalogue-2026-10","items":[{"description":"Men'\''s cotton t-shirt","destinationCountry":"US"},{"description":"Stainless steel water bottle, 750 ml","destinationCountry":"GB"}]}' ``` --- # Cancel a bulk run (DELETE /v1/bulk/runs) > DELETE /v1/bulk/runs: Cancel a bulk run. border.bot API reference (Bulk). Source: https://staging.border.bot/docs/api/cancel-bulk-run > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `DELETE https://staging-api.border.bot/v1/bulk/runs` Requires an API key (`Authorization: Bearer bb_live_…`). Stops a run after the chunk it is working on. Items already done stay done (and charged). API key scope: `bulk`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | | ## Responses - `200`: The run, cancelled. (`BulkRunResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `bulk` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X DELETE 'https://staging-api.border.bot/v1/bulk/runs' \ -H 'Authorization: Bearer bb_live_...' ``` --- # A bulk run’s progress (GET /v1/bulk/status) > GET /v1/bulk/status: A bulk run’s progress. border.bot API reference (Bulk). Source: https://staging.border.bot/docs/api/bulk-run-status > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/bulk/status` Requires an API key (`Authorization: Bearer bb_live_…`). How far a run has got: items done, succeeded and failed, and the credits charged so far. API key scope: `bulk`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | | ## Responses - `200`: The run. (`BulkRunResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `bulk` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/bulk/status' \ -H 'Authorization: Bearer bb_live_...' ``` --- # A bulk run’s results (GET /v1/bulk/results) > GET /v1/bulk/results: A bulk run’s results. border.bot API reference (Bulk). Source: https://staging.border.bot/docs/api/bulk-results > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/bulk/results` Requires an API key (`Authorization: Bearer bb_live_…`). The answers so far, in item order, up to 1,000 at a time (`next` is the following page’s `offset`). Each is exactly what its single endpoint returns, or the error it failed with. API key scope: `bulk`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | | | `offset` | integer \| null | no | | | `limit` | integer | no | | ## Responses - `200`: A page of results. (`BulkResultsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `bulk` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/bulk/results' \ -H 'Authorization: Bearer bb_live_...' ``` --- # List products (GET /v1/catalog/products) > GET /v1/catalog/products: List products. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/list-catalog-products > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/products` Requires an API key (`Authorization: Bearer bb_live_…`). Your catalogue, newest change first, a page at a time (`cursor`). Filter by words or a SKU prefix (`q`), status, market, products missing an approved code for a market (`missingCodeFor`), products with a code waiting for review (`needsReview`), origin, or source kind. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `q` | string | no | | | `status` | "draft" \| "active" \| "archived" | no | | | `market` | string | no | | | `missingCodeFor` | string | no | | | `needsReview` | boolean \| "0" \| "1" \| "true" \| "false" | no | | | `origin` | string | no | | | `source` | string | no | | | `cursor` | string | no | | | `limit` | integer | no | | ## Responses - `200`: A page of products. (`CatalogProductsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/products' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Create a product (POST /v1/catalog/products) > POST /v1/catalog/products: Create a product. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/create-catalog-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products` Requires an API key (`Authorization: Bearer bb_live_…`). A product with its items (each SKU unique in your catalogue), content components, source and any codes you already hold. Codes are checked against the vocabularies (`GET /catalog/terms`). Free. API key scope: `catalog`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | yes | | | `description` | string \| null | no | | | `brand` | string \| null | no | | | `manufacturerName` | string \| null | no | | | `manufacturerCountry` | string \| null | no | | | `category` | string \| null | no | | | `materialSummary` | string \| null | no | | | `tags` | string[] | no | | | `imageUrls` | string[] | no | | | `productUrl` | string \| null | no | | | `slug` | string \| null | no | | | `originCountry` | string \| null | no | | | `originBasis` | string \| null | no | | | `originEvidence` | object \| null | no | | | `preferentialClaims` | object[] | no | | | `attributes` | object[] | no | | | `markets` | array \| null | no | | | `quantityUnit` | string \| null | no | | | `supplementaryUnits` | object[] | no | | | `extra` | object | no | | | `status` | "draft" \| "active" | no | | | `sku` | string \| null | no | | | `gtin` | string \| null | no | | | `mpn` | string \| null | no | | | `unitValue` | number \| null | no | | | `currency` | string \| null | no | | | `weight` | number \| null | no | | | `weightUnit` | "kg" \| "g" \| "lb" \| "oz" \| null | no | | | `items` | object[] | no | | | `components` | object[] | no | | | `source` | object | no | | | `codes` | object[] | no | | ## Responses - `200`: The product. (`CatalogProductResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `409`: A SKU is already used by another product (`conflict`, `details.reason: "sku_taken"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"title":"Stainless steel water bottle 750 ml","brand":"Acme","materialSummary":"stainless steel body, polypropylene lid","originCountry":"CN","markets":["US","GB","DE"],"sku":"BOTTLE-750","unitValue":20,"currency":"USD","weight":350,"weightUnit":"g","components":[{"material":"steel","weight":300,"weightUnit":"g","value":6,"currency":"USD","origins":[{"kind":"melt_pour","country":"US"}]},{"material":"plastic","weight":50,"weightUnit":"g"}],"source":{"kind":"api","externalIds":{"id":"erp-10023"}}}' ``` --- # Get a product (GET /v1/catalog/products/{id}) > GET /v1/catalog/products/{id}: Get a product. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/get-catalog-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/products/{id}` Requires an API key (`Authorization: Bearer bb_live_…`). A product with its items, content components, sources and current codes per market. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Responses - `200`: The product. (`CatalogProductResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `404`: No such product in your catalogue (`not_found`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/products/{id}' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Update a product (PATCH /v1/catalog/products/{id}) > PATCH /v1/catalog/products/{id}: Update a product. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/update-catalog-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `PATCH https://staging-api.border.bot/v1/catalog/products/{id}` Requires an API key (`Authorization: Bearer bb_live_…`). Changes the fields given, its items (by id or SKU, others added) and its content list. Every change is kept in the product’s history with its actor. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | no | | | `description` | string \| null | no | | | `brand` | string \| null | no | | | `manufacturerName` | string \| null | no | | | `manufacturerCountry` | string \| null | no | | | `category` | string \| null | no | | | `materialSummary` | string \| null | no | | | `tags` | string[] | no | | | `imageUrls` | string[] | no | | | `productUrl` | string \| null | no | | | `slug` | string \| null | no | | | `originCountry` | string \| null | no | | | `originBasis` | string \| null | no | | | `originEvidence` | object \| null | no | | | `preferentialClaims` | object[] | no | | | `attributes` | object[] | no | | | `markets` | array \| null | no | | | `quantityUnit` | string \| null | no | | | `supplementaryUnits` | object[] | no | | | `extra` | object | no | | | `status` | "draft" \| "active" | no | | | `items` | object[] | no | | | `components` | object[] | no | | ## Responses - `200`: The product as it is now. (`CatalogProductResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `404`: No such product in your catalogue (`not_found`). (`Error`) - `409`: A SKU is taken, or the product is archived (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X PATCH 'https://staging-api.border.bot/v1/catalog/products/{id}' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"originCountry":"VN","items":[{"sku":"BOTTLE-750","unitValue":21.5}]}' ``` --- # Archive a product (POST /v1/catalog/products/{id}/archive) > POST /v1/catalog/products/{id}/archive: Archive a product. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/archive-catalog-product > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products/{id}/archive` Requires an API key (`Authorization: Bearer bb_live_…`). Retires a product and its items: out of lists and SKU lookups (its SKUs become free), kept with its sources, content, codes and history. Nothing in the catalogue is ever deleted. Restore it by updating its `status`. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Responses - `200`: The archived product. (`CatalogProductResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products/{id}/archive' \ -H 'Authorization: Bearer bb_live_...' ``` --- # A product’s history (GET /v1/catalog/products/{id}/history) > GET /v1/catalog/products/{id}/history: A product’s history. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/catalog-product-history > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/products/{id}/history` Requires an API key (`Authorization: Bearer bb_live_…`). Every change to the product and its items, sources, content and codes, newest first: who, when, and the values before and after. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Responses - `200`: The changes. (`CatalogHistoryResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/products/{id}/history' \ -H 'Authorization: Bearer bb_live_...' ``` --- # A product’s codes (GET /v1/catalog/products/{id}/classifications) > GET /v1/catalog/products/{id}/classifications: A product’s codes. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/list-catalog-classifications > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/products/{id}/classifications` Requires an API key (`Authorization: Bearer bb_live_…`). Every code the product has had, per market, newest first: suggested, approved, rejected and superseded. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Responses - `200`: The codes. (`CatalogClassificationsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/products/{id}/classifications' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Add a code (POST /v1/catalog/products/{id}/classifications) > POST /v1/catalog/products/{id}/classifications: Add a code. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/create-catalog-classification > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products/{id}/classifications` Requires an API key (`Authorization: Bearer bb_live_…`). A code you hold for a market: a suggestion to review, or approved at once with `approve`. Markets in a customs union share its code (Germany and France the EU’s). Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `market` | string | yes | | | `code` | string | yes | | | `approve` | boolean | no | | | `description` | string \| null | no | | | `note` | string \| null | no | | ## Responses - `200`: The code. (`CatalogClassificationResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products/{id}/classifications' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"market":"US","code":"7323.93.0080","approve":true}' ``` --- # Suggest codes (POST /v1/catalog/products/{id}/classifications/suggest) > POST /v1/catalog/products/{id}/classifications/suggest: Suggest codes. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/suggest-catalog-classifications > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products/{id}/classifications/suggest` Requires an API key (`Authorization: Bearer bb_live_…`). Classifies the product for each market from its title, description, materials, page and photo, and keeps each answer as a suggestion to review (approve it to quote with it). Each market is charged like `POST /classify` and refunded if it fails. API key scope: `classify`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | ## Headers | Name | Type | Required | Description | | --- | --- | --- | --- | | `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `markets` | string[] | yes | | | `mode` | string | no | | ## Responses - `200`: A suggestion (or the error) per market, and the credits charged. (`CatalogSuggestResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`) - `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`) - `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) - `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`) - `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products/{id}/classifications/suggest' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"markets":["US","GB","DE"]}' ``` --- # Approve a code (POST /v1/catalog/products/{id}/classifications/{classificationId}/approve) > POST /v1/catalog/products/{id}/classifications/{classificationId}/approve: Approve a code. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/approve-catalog-classification > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products/{id}/classifications/{classificationId}/approve` Requires an API key (`Authorization: Bearer bb_live_…`). Approves a suggestion: it becomes the code quotes use for its schedule, and the code it replaces is superseded (kept, with the dates it applied). Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | | `classificationId` | string (uuid) | yes | The classification’s id. | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `note` | string \| null | no | | ## Responses - `200`: The approved code. (`CatalogClassificationResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products/{id}/classifications/{classificationId}/approve' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{}' ``` --- # Reject a code (POST /v1/catalog/products/{id}/classifications/{classificationId}/reject) > POST /v1/catalog/products/{id}/classifications/{classificationId}/reject: Reject a code. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/reject-catalog-classification > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/products/{id}/classifications/{classificationId}/reject` Requires an API key (`Authorization: Bearer bb_live_…`). Rejects a suggestion (kept, with your note). Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The product’s id. | | `classificationId` | string (uuid) | yes | The classification’s id. | ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `note` | string \| null | no | | ## Responses - `200`: The rejected code. (`CatalogClassificationResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/products/{id}/classifications/{classificationId}/reject' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{}' ``` --- # Classify many products (POST /v1/catalog/classify) > POST /v1/catalog/classify: Classify many products. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/classify-catalog > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/classify` Requires an API key (`Authorization: Bearer bb_live_…`). A bulk run classifying products (by id or by a filter) for markets, its answers kept as suggestions. Follow it with `GET /bulk/status`; its items are charged like `POST /classify` as they run. API key scope: `classify`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `productIds` | string (uuid)[] | no | | | `filter` | object | no | | | `markets` | string[] | yes | | | `onlyMissing` | boolean | no | | | `mode` | string | no | | ## Responses - `200`: The bulk run. (`BulkRunResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `classify` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Three bulk runs are already going (`rate_limited`). (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/classify' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"filter":{"missingCodeFor":"US"},"markets":["US"]}' ``` --- # Your imports (GET /v1/catalog/imports) > GET /v1/catalog/imports: Your imports. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/list-catalog-imports > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/imports` Requires an API key (`Authorization: Bearer bb_live_…`). Your CSV imports and dry runs, newest first, with their counts and errors. Free. API key scope: `catalog`. ## Responses - `200`: Your imports. (`CatalogImportsResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/imports' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Import a CSV file (POST /v1/catalog/imports) > POST /v1/catalog/imports: Import a CSV file. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/import-catalog > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/imports` Requires an API key (`Authorization: Bearer bb_live_…`). Imports (or, by default, checks: `dryRun`) a CSV file of up to 2,000 rows: columns mapped to fields, each row checked and upserted by its `external_id` or `sku`, errors reported per row. Importing the same file again changes nothing. Free. API key scope: `catalog`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `csv` | string | yes | | | `filename` | string | no | | | `mapping` | object | no | | | `dryRun` | boolean | no | | | `sourceKind` | string | no | | | `connection` | string | no | | | `approveCodes` | boolean | no | | ## Responses - `200`: What the import did (or would do), with the errors per row. (`CatalogImportResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/imports' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"csv":"sku,title,origin_country,unit_value,currency,hs_code_us\nBOTTLE-750,Steel water bottle,CN,20,USD,7323930080","filename":"catalogue.csv","dryRun":true}' ``` --- # An import (GET /v1/catalog/imports/{id}) > GET /v1/catalog/imports/{id}: An import. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/get-catalog-import > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/imports/{id}` Requires an API key (`Authorization: Bearer bb_live_…`). One import’s status, counts and errors per row. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string (uuid) | yes | The import’s id. | ## Responses - `200`: The import. (`CatalogImportRecordResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/imports/{id}' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Export as CSV (GET /v1/catalog/exports) > GET /v1/catalog/exports: Export as CSV. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/export-catalog > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/exports` Requires an API key (`Authorization: Bearer bb_live_…`). Your catalogue (or the products a filter finds, up to 10,000) as CSV: one row per item, every field, and the approved code per market. It imports again as it is. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `q` | string | no | | | `status` | "draft" \| "active" \| "archived" | no | | | `market` | string | no | | | `missingCodeFor` | string | no | | | `needsReview` | boolean \| "0" \| "1" \| "true" \| "false" | no | | | `origin` | string | no | | | `source` | string | no | | ## Responses - `200`: The CSV text. (`CatalogExportResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/exports' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Sync records from a source (POST /v1/catalog/sync) > POST /v1/catalog/sync: Sync records from a source. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/sync-catalog > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/sync` Requires an API key (`Authorization: Bearer bb_live_…`). For connectors: a page of up to 250 records from a store, marketplace, feed or ERP (a source kind from `GET /catalog/sources`), upserted by the source’s own key. Unchanged records only update their sync time. Free. API key scope: `catalog`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `sourceKind` | string | yes | | | `connection` | string | yes | | | `records` | object[] | yes | | ## Responses - `200`: What each record did. (`CatalogSyncResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/sync' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"sourceKind":"woocommerce","connection":"https://shop.example.com","records":[{"externalKey":"1042","externalIds":{"productId":"1040","variationId":"1042"},"groupKey":"1040","product":{"title":"Merino scarf","originCountry":"NZ"},"item":{"sku":"SCARF-GREY","unitValue":49,"currency":"NZD","weight":120,"weightUnit":"g"}}]}' ``` --- # Approved codes to write back (GET /v1/catalog/sync/codes) > GET /v1/catalog/sync/codes: Approved codes to write back. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/catalog-sync-codes > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/sync/codes` Requires an API key (`Authorization: Bearer bb_live_…`). For connectors: the approved codes (and origins) of a connection’s records, approved after `since`, to write back to the source in its own fields. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `sourceKind` | string | yes | | | `connection` | string | yes | | | `since` | string (date-time) | no | Only codes approved after this time. | ## Responses - `200`: One entry per record and approved code. (`CatalogSyncCodesResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/sync/codes' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Catalogue vocabularies (GET /v1/catalog/terms) > GET /v1/catalog/terms: Catalogue vocabularies. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/list-catalog-terms > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/terms` Requires an API key (`Authorization: Bearer bb_live_…`). The harmonised codes catalogue fields take: materials, material origins (by stage), attributes (dangerous goods, restricted), categories, origin bases and quantity units. Free. API key scope: `catalog`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `vocabulary` | "material" \| "material_origin" \| "attribute" \| "category" \| "origin_basis" \| "quantity_unit" | no | | ## Responses - `200`: The codes. (`CatalogTermsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/terms' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Source kinds (GET /v1/catalog/sources) > GET /v1/catalog/sources: Source kinds. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/list-catalog-sources > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/sources` Requires an API key (`Authorization: Bearer bb_live_…`). Where products can come from (the dashboard, files, the API, commerce platforms, marketplaces, feeds), each with the identifiers its records carry. Free. API key scope: `catalog`. ## Responses - `200`: The source kinds. (`CatalogSourceKindsResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/sources' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Default target markets (GET /v1/catalog/markets) > GET /v1/catalog/markets: Default target markets. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/get-catalog-markets > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `GET https://staging-api.border.bot/v1/catalog/markets` Requires an API key (`Authorization: Bearer bb_live_…`). The markets a product without its own ships to (what bulk classification and filters use). Free. API key scope: `catalog`. ## Responses - `200`: The markets. (`CatalogMarketsResponse`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X GET 'https://staging-api.border.bot/v1/catalog/markets' \ -H 'Authorization: Bearer bb_live_...' ``` --- # Set default target markets (POST /v1/catalog/markets) > POST /v1/catalog/markets: Set default target markets. border.bot API reference (Catalogue). Source: https://staging.border.bot/docs/api/set-catalog-markets > Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`. `POST https://staging-api.border.bot/v1/catalog/markets` Requires an API key (`Authorization: Bearer bb_live_…`). Replaces the workspace’s default markets. Free. API key scope: `settings`. ## Request body (JSON) | Name | Type | Required | Description | | --- | --- | --- | --- | | `markets` | string[] | yes | | ## Responses - `200`: The markets. (`CatalogMarketsResponse`) - `400`: Invalid input (`invalid_input`). (`Error`) - `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`) - `403`: The API key doesn’t have the `settings` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`) - `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`) - `500`: Unexpected error (`internal`). (`Error`) ## Example ```bash curl -X POST 'https://staging-api.border.bot/v1/catalog/markets' \ -H 'Authorization: Bearer bb_live_...' \ -H 'Content-Type: application/json' \ -d '{"markets":["US","GB","DE","CA"]}' ``` --- # The EU’s €3 customs duty on parcels under €150 > Since 1 July 2026 the EU charges a temporary €3 customs duty on low-value parcels, once per tariff classification. What it covers, who pays and how it adds up. Source: https://staging.border.bot/blog/eu-3-euro-customs-duty Last updated: 2026-10-08 By border.bot team · Published 2026-10-08 · 2 min read · Tags: de minimis, European Union, duties, VAT Rules as of 8 October 2026. Customs rules change; check the source at the end before you rely on any detail. **Since 1 July 2026, the EU charges a temporary €3 customs duty on parcels worth up to €150 imported from outside the EU.** Before that date, these low-value parcels were exempt from customs duty. ## What the rule covers The duty applies to low-value parcels sent into the EU from outside it, most of them ecommerce orders. The European Commission lists clothing, toys, electronics and other consumer goods worth up to €150 as examples, and describes the duty as temporary. Import VAT is a separate charge. It has applied to ecommerce imports of any value since 1 July 2021, collected either at checkout through the Import One-Stop Shop (IOSS) or when the parcel is imported. ## €3 per tariff classification, not per item The Commission says the duty applies “per item, based on tariff classification and not quantity”. Its examples: - **5 T-shirts:** €3, because all T-shirts fall under the same tariff classification. - **3 T-shirts and a watch:** €6, because T-shirts and watches fall under two different tariff classifications. So an order pays €3 for each distinct tariff classification in it. To know what an order owes, you need the tariff code of every product in it. ## Who pays The seller or the importer declares and pays the duty as part of the customs process. If you ship DDP, it is part of what you collect at checkout. If you ship DAP, your customer pays it on arrival, usually with a carrier handling fee on top. ## A worked example A customer in Germany orders a €40 hoodie and a €12 cap from a store outside the EU. | Line | Amount | | ----------------------------------- | -------------------------------------- | | Goods | €52 | | Customs duty: hoodie classification | €3 | | Customs duty: cap classification | €3 | | Import VAT | Germany’s VAT rate, charged separately | Customs duty for the order is €6. Import VAT is added on top at the destination country’s rate. ## What to do as a seller - **Classify each product** to its EU tariff code. The [free HS code classifier](/tools/hs-code-classifier) returns the EU Combined Nomenclature code for EU destinations. - **Count tariff classifications per order,** not items, when you estimate the duty. - **Show the total at checkout** if you ship DDP. The [landed cost calculator](/tools/landed-cost-calculator) covers EU destinations. ## Source - European Commission, _Ensuring fairness and safety: €3 customs duty for low-value parcels_ (29 June 2026): [commission.europa.eu](https://commission.europa.eu/news-and-media/news/ensuring-fairness-and-safety-eur3-customs-duty-low-value-parcels-2026-06-29_en) --- # US de minimis suspension: what changed for parcels > US de minimis has been suspended since 29 August 2025. The timeline, the June 2026 CBP rules, how parcels clear now and what ends on 1 July 2027. Source: https://staging.border.bot/blog/us-de-minimis-suspension Last updated: 2026-10-08 By border.bot team · Published 2026-10-08 · 4 min read · Tags: de minimis, United States, duties Rules as of 8 October 2026. Customs rules change; check the sources at the end before you rely on any detail. **Since 29 August 2025, a low value no longer exempts goods sold into the US from duty.** The exemption that let a shipment worth $800 or less enter without duty (the de minimis exemption in Section 321 of the Tariff Act) is suspended for goods from every country. CBP made the suspension indefinite in its own regulations in June 2026, and a 2025 law ends the exemption permanently on 1 July 2027. ## Timeline | Date | What happened | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 30 July 2025 | Executive Order 14324 suspends duty-free de minimis treatment for all countries. | | 29 August 2025 | The suspension takes effect. CBP rejects Section 321 manifest filings and Type 86 entries. | | 20 February 2026 | The Supreme Court rules in _Learning Resources, Inc. v. Trump_ that IEEPA does not authorize the President to impose additional tariffs. The ruling does not address de minimis. The same day, Executive Order 14389 ends several IEEPA tariff actions and Executive Order 14388 continues the de minimis suspension. | | 24 June 2026 | A CBP rule suspends de minimis indefinitely for every mode except mail (91 FR 37789). | | 24 July 2026 | A second CBP rule, published with the first, takes effect: de minimis is suspended indefinitely for mail too, and a new postal informal entry process starts (91 FR 37801). | | 8 October 2026 | CBP proposes changes to informal entries of $2,500 or less, including a new electronic entry type for mail and bonds for some entries (91 FR 64532). Comments close on 7 December 2026. | | 1 July 2027 | The One Big Beautiful Bill Act ends the de minimis exemption by law. | ## What is still exempt CBP’s 2026 rules leave two other Section 321 exemptions in place: bona fide gifts, and personal or household articles that travellers bring with them. Neither covers goods sold online. For ecommerce, every parcel now needs a customs entry and payment of the duty owed. ## How a parcel clears now **By courier, express or freight** (every mode except mail), a shipment worth $800 or less needs a formal or informal entry, filed in CBP’s Automated Commercial Environment (ACE) by a party allowed to make entry, with duties, taxes and fees paid. Informal entry covers most shipments worth $2,500 or less. **By post**, since 24 July 2026 shipments worth $2,500 or less use CBP’s new postal informal entry process: - **Who files:** the owner or purchaser of the goods, or a licensed customs broker they designate. The filer needs a CBP import bond. - **What CBP needs:** a spreadsheet giving, for each package, the 10-digit HTS code, country of origin, value, duty rate and duty owed, plus the tracking number and arrival details. - **When:** the spreadsheet and the payment are due by the 7th of the month after the package arrives. - **No collection at the door:** CBP no longer collects duty from the person receiving the parcel. Goods under quotas or antidumping and countervailing duty orders need a formal entry. Goods with partner government agency requirements, duties under HTS chapters 98 or 99, or a free trade agreement claim can use the postal process only during a temporary transition window. After it, they need a formal entry or CBP’s voluntary Entry Type 13 test. ## What a parcel pays now For a commercial shipment, the charges are: 1. **Duty** at the rate for the product’s 10-digit HTS code and its country of origin, plus any additional duties for that product and origin, such as Section 232 or Section 301 duties. 2. **Customs fees**, such as the merchandise processing fee, where they apply to the entry type. 3. **Carrier or broker charges** for clearing the parcel. These vary by carrier and are not set by CBP. The duty depends on where the product was **made**, not where it was shipped from. A product made in China and shipped from a UK warehouse is still a Chinese-origin product for US duty. We explain the difference in [country of origin vs shipped from](/blog/country-of-origin-vs-shipped-from). ## What to do as a seller - **Classify every product to a 10-digit HTS code.** Both entry routes ask for it. The [free HS code classifier](/tools/hs-code-classifier) gives you the code with the official description at each level. - **Record the real country of origin** for each product, from the supplier or the label. - **Decide who pays.** Collect the duty at checkout and ship DDP, or have the customer pay on delivery (DAP) where the carrier offers it. Postal parcels are no longer charged at the door, so settle who files and pays before you ship by mail. The trade-offs are in [DDP vs DAP](/blog/ddp-vs-dap-ecommerce). - **Quote it before you ship.** The [landed cost calculator](/tools/landed-cost-calculator) returns every duty, fee and tax line for an HS code, origin and value. - **Follow the October 2026 proposal.** It would change filing requirements for informal entries and add bond requirements for some of them. ## Sources - CBP, CSMS #66065494, _Suspension of the De Minimis Exemption_ (28 August 2025): [content.govdelivery.com/accounts/USDHSCBP/bulletins/3f01456](https://content.govdelivery.com/accounts/USDHSCBP/bulletins/3f01456) - Federal Register, _Indefinite Suspension of the De Minimis Exemption for Merchandise Arriving Through All Modes Other Than the International Postal Network_, 91 FR 37789 (24 June 2026): [federalregister.gov/d/2026-12670](https://www.federalregister.gov/documents/2026/06/24/2026-12670/indefinite-suspension-of-the-de-minimis-exemption-for-merchandise-arriving-through-all-modes-other) - Federal Register, _Indefinite Suspension of the De Minimis Exemption for Mail Shipments and New Postal Informal Entry Process_, 91 FR 37801 (24 June 2026): [federalregister.gov/d/2026-12669](https://www.federalregister.gov/documents/2026/06/24/2026-12669/indefinite-suspension-of-the-de-minimis-exemption-for-mail-shipments-and-new-postal-informal-entry) - CBP, CSMS #69183472, _Updated Global Guidance for International Mail_ (8 July 2026): [content.govdelivery.com/accounts/USDHSCBP/bulletins/41fa7f0](https://content.govdelivery.com/accounts/USDHSCBP/bulletins/41fa7f0) - Federal Register, _Low-Value Shipments_ (proposed rule), 91 FR 64532 (8 October 2026): [federalregister.gov/d/2026-20650](https://www.federalregister.gov/documents/2026/10/08/2026-20650/low-value-shipments) - CBP, E-Commerce: [cbp.gov/trade/basic-import-export/e-commerce](https://www.cbp.gov/trade/basic-import-export/e-commerce) --- # Classify products from Claude and ChatGPT > Connect the border.bot MCP server to Claude, ChatGPT or Cursor, then classify products, check origin and estimate landed cost from a chat. Setup and tips. Source: https://staging.border.bot/blog/classify-products-with-mcp Last updated: 2026-10-09 By border.bot team · Published 2026-09-30 · 4 min read · Tags: mcp, ai assistants, classification Questions that used to go to a spreadsheet or a broker now often go to an AI assistant first: “What’s the HS code for this?”, “Will my customer pay duty on that?” Assistants understand the question well. On their own, they are not a reliable source of tariff codes: they may recall outdated schedules, mix up countries or invent a plausible-looking number. The **border.bot MCP server** gives the assistant a tool to call for those answers, so the code comes from a classification engine instead of the model’s memory. ## What MCP is The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI assistants to external tools and data. An MCP server describes the tools it offers; the assistant decides when to call them, sends structured inputs and gets structured results back. A **remote** MCP server runs on the web. You add it to your client with a URL and sign in through your browser with OAuth. Nothing is installed locally and no API key goes into a config file. ## What the border.bot server can do Once connected, your assistant can: - **Classify products** from a description or a product URL, for any destination, returning the code in that country’s format with official descriptions, a confidence score and alternatives. - **Read product pages** to pull out the title, materials, price and country of origin before classifying. - **Calculate landed cost** for a code, origin and destination, with each duty, tax and fee and the total. Every call runs on the same engine as the border.bot dashboard and API, uses your workspace’s credits at the same prices, and is saved to your workspace history. ## Setting it up The server URL is `https://mcp.border.bot/mcp`. In short: - **Claude:** Customize › Connectors › “+ Add” › “Add custom connector”, enter the URL, then sign in to border.bot. - **ChatGPT:** on chatgpt.com/plugins, choose the plus button › “Add custom MCP server”, enter the URL with OAuth, then install the plugin and sign in. - **Codex:** run `codex mcp add borderbot --url https://mcp.border.bot/mcp`, then `codex mcp login borderbot`. - **Cursor:** add the URL to `~/.cursor/mcp.json` (or use “Add to Cursor” on the MCP setup page), then complete the sign-in Cursor asks for. When you sign in, you approve the connection and choose **which workspace pays** for the calls. Menu names change between client versions, so check the [MCP setup page](/mcp) for current step-by-step instructions, including Claude Code, Visual Studio Code, Gemini CLI and the other clients we have guides for. ## What to ask Some prompts that work well: > What’s the US HTS code for a men’s 100% cotton crew-neck T-shirt made in Vietnam? Show me the description at each level. > Classify this for import into Germany and tell me where it’s made: https://shop.example/products/merino-beanie > Calculate the landed cost of 50 units at $18 each, HS 4202.92, from China to the UK with $120 shipping. > Here are twelve product descriptions from our catalogue. Classify each one for Canada and list any that come back with low confidence. The last one shows where an assistant shines: it can loop over a list, call the tool for each item and summarise the results, while the codes themselves still come from the tool. ## What happens behind a single question Take the first prompt above. The assistant recognises that it needs a classification, so it calls the border.bot classify tool with structured inputs: the description, the destination (`US`) and the origin (`VN`). border.bot returns a structured result with the 10-digit HTS code, the official description for the chapter, heading, subheading and tariff line, a confidence level, the reasoning and the closest alternatives. Your workspace is charged for one classification. The assistant then writes its answer from that result. Because the code, the descriptions and the confidence come straight from the tool, you can check the assistant’s summary against them, and the same result is waiting in your workspace history if you want to share it with a colleague or re-run it later. ## Tips for reliable answers - **Ask it to use border.bot.** Say “use the border.bot tool” so the assistant doesn’t answer from memory. - **Give it the facts customs needs.** Material, function, construction and who the product is for matter more than the product name. - **Always name the destination.** Codes beyond six digits differ by country. - **Ask for alternatives on low confidence.** If the result is flagged for review, ask the assistant to show the alternatives and what would distinguish them, then add that detail and run it again. - **Keep origin honest.** If the assistant reports an origin detected from a product page, confirm it with your supplier before you rely on it. ## Billing and security - You sign in on border.bot; the assistant receives a scoped OAuth token, never your password. - Each connection is tied to the workspace you chose, and its calls draw on that workspace’s credits. If a call fails, its credits are refunded automatically. - You can see every connected client in the dashboard and revoke any of them at any time. ## Where this fits The MCP server suits ad-hoc questions, research and one-off batches inside the tools your team already uses. For checkout and catalogue automation, use the [REST API](/developers); for reviewing and sharing results, use the dashboard. All three use the same engine and the same credits. To see the results before connecting anything, try the [free HS code classifier](/tools/hs-code-classifier). It runs on the same engine. --- # Country of origin: shipped from isn’t made in > Why the country a parcel ships from often isn’t its country of origin, how origin is decided, and how it changes duties, marking rules and trade-deal savings. Source: https://staging.border.bot/blog/country-of-origin-vs-shipped-from Last updated: 2026-09-16 By border.bot team · Published 2026-09-16 · 4 min read · Tags: country of origin, compliance, duties Your parcels leave a warehouse in the Netherlands. Your products were made in China, Vietnam and Portugal. On the customs declaration, which country is the **country of origin**? Not the Netherlands. Origin is where goods were **made**, not where they were **shipped from**. Mixing the two up is a common mistake in cross-border ecommerce, and it can mean paying the wrong duty or claiming a trade-agreement rate you aren’t entitled to. ## Why the two get mixed up Modern supply chains separate making and shipping. Goods are produced in one country, stored by a 3PL in a second, sold by a brand in a third and shipped to a customer in a fourth. Many shipping tools default the origin field to the warehouse address, and many product feeds don’t carry origin at all. The result: declarations that quietly state the wrong origin. ## What “origin” means to customs There are two different questions customs may ask: ### Non-preferential origin This is the “made in” country used for ordinary duty rates, trade remedies, import restrictions, quotas, marking requirements and statistics. Broadly, goods originate where they were: - **wholly obtained**: grown, mined, or born and raised in one country; or - **last substantially transformed**: where the last processing step that created a new and different article took place. What counts as substantial transformation varies by country and product. Assembling components into a finished product often qualifies; **repacking, relabelling, sorting or simple assembly usually does not**. Storing goods in a warehouse never does. ### Preferential origin This is the origin used to claim a **lower duty rate under a trade agreement**. Each agreement has its own product-specific rules, for example a change of tariff classification, a minimum regional value content or a required manufacturing process. Meeting them usually requires a proof of origin, such as an origin statement on the invoice or a certificate. The key point: shipping goods between two countries that have a trade agreement does **not** by itself make them eligible. The goods must meet the agreement’s origin rules, and you must be able to prove it. ## A few examples - **A phone case moulded in China, stocked in a Dutch warehouse and sold to a UK customer.** Origin: China. Storage and repacking in the Netherlands don’t change it. - **Leather shoes made in Portugal and shipped from a US distribution centre to Canada.** Origin: Portugal, even though the parcel leaves the US. US–Canada trade-agreement preferences don’t apply just because of the shipping route. - **A bicycle assembled in one country from a frame, wheels and components made in several others.** Origin depends on the rules that apply to that product: assembly may or may not be a substantial transformation. This is where rulings and expert advice earn their keep. ## Why origin changes the bill - **Duty rates.** The same product can face a different rate depending on where it was made: lower under a trade agreement, higher where additional duties or trade remedies target that origin. - **Restrictions and sanctions.** Some goods from some origins are restricted, need licences or can’t be imported at all. - **Marking.** Several countries require imported goods to be marked with their country of origin, and false or missing marks can lead to penalties or re-marking at your cost. - **Customer claims.** “Made in” statements on your product pages are consumer-protection claims too; they should match what you declare. ## How to establish origin properly 1. **Ask your supplier.** Get a written statement of where each product is manufactured, and for trade-agreement claims, the supporting origin evidence. 2. **Know the manufacturing steps.** For products assembled from imported components, record where each significant step happens. 3. **Store origin per product, not per warehouse.** Make it a required field in your catalogue and product feeds. 4. **Check the product page.** If you sell other brands, the “Made in” line on the manufacturer’s product page or label is a useful signal, but confirm it with the supplier. 5. **Keep evidence.** Customs can ask for proof long after a shipment clears. ## Common mistakes - Filling the origin field with the **ship-from** country. - Claiming a trade-agreement rate because both countries are **party to the agreement**, without checking the product-specific rule. - Treating **“assembled in”**, **“designed in”** or **“distributed by”** as statements of origin. - Assuming origin never changes. A new supplier, factory or component source can move it. ## How border.bot helps When you classify from a product URL, border.bot looks for the country of origin on the page. It checks structured product data first, then the page text, and falls back to an AI estimate when the page doesn’t say. The result shows **where the origin was found**, with a confidence level. Origin you enter yourself always wins. Try it with the [free HS code classifier](/tools/hs-code-classifier), then carry the code and origin into the [landed cost calculator](/tools/landed-cost-calculator) to see how origin changes the duty. You remain responsible for the origin you declare, so treat a detected origin as a lead to confirm with your supplier, not as proof. --- # DDP vs DAP for ecommerce parcels > Should you collect duties and taxes at checkout (DDP) or let customers pay on delivery (DAP)? The costs, risks and setup of each, explained for parcel shippers. Source: https://staging.border.bot/blog/ddp-vs-dap-ecommerce Last updated: 2026-09-09 By border.bot team · Published 2026-09-09 · 4 min read · Tags: incoterms, landed cost, checkout When you ship a parcel abroad, someone has to pay the import duty and taxes. Under **DDP** you collect them at checkout and pay them at the border. Under **DAP** your customer pays them when the parcel arrives. The choice affects what your customer pays and when, your cash flow, and how many parcels are refused and sent back. ## The terms, briefly DDP and DAP are two of the eleven **Incoterms® rules** published by the International Chamber of Commerce; the current edition is Incoterms 2020. They define who is responsible for what between seller and buyer. - **DAP (Delivered at Place).** The seller delivers the goods to the named place, ready for unloading. The **buyer** handles import clearance and pays import duty and taxes. - **DDP (Delivered Duty Paid).** The seller delivers the goods cleared for import, with duty and taxes paid. The **buyer** pays nothing extra on arrival. You will still hear **DDU** (“delivered duty unpaid”). It was retired from the Incoterms rules in 2010 and replaced in practice by DAP, but many carriers still use the label for parcel services where the recipient pays. For parcels, carriers turn these into products: a “duties paid” or DDP service where they bill you for the duty and tax, and a standard service where they collect from the recipient. ## DAP: the customer pays on delivery **How it works.** You charge for the goods and shipping. The carrier clears the parcel, advances the duty and tax, and collects them from the customer before or at delivery, usually with a handling or disbursement fee on top. **Why merchants choose it** - Nothing to calculate or remit; the carrier deals with customs. - No tax registrations in the destination for you to manage. - Lower checkout price, at least on the surface. **What it costs you** - **Surprise bills.** Customers who didn’t expect to pay on delivery often feel misled, and some refuse the parcel. - **Refusals and returns.** A refused parcel can cost you the outbound shipping, the return shipping and sometimes the goods. - **Support load.** “Why do I have to pay to receive my order?” becomes a common ticket. - **Carrier fees on top.** Handling fees for advancing duty can be a large share of the charge on low-value parcels, and the customer blames you, not the carrier. ## DDP: you collect at checkout **How it works.** You calculate the landed cost at checkout, show it to the customer, and collect it with the order. The carrier clears the parcel and bills you for the duty and tax, or you pay through your own customs arrangements. **Why merchants choose it** - **A single, final price.** The customer pays once and receives the parcel without another bill. - **Fewer refusals.** Nobody refuses a parcel they’ve already fully paid for. - **A domestic-feeling experience** in your key markets. **What it takes** - **Accurate landed cost at checkout.** Undercharge and you pay the difference; overcharge and you lose sales. That means the right HS code, the right country of origin and current rates. See [Landed cost explained](/blog/landed-cost-explained) for the moving parts. - **Tax registration in some markets.** Several destinations collect tax on low-value goods from the seller rather than at the border, which can mean registering there. The EU’s Import One-Stop Shop (IOSS) and the UK’s rules for low-value consignments are well-known examples. Thresholds and rules differ and change, so check each market you sell into. - **A carrier or partner that supports DDP** for the lanes you ship. - **A plan for returns.** Recovering duty and tax on returned goods is possible in some countries and not others, and usually takes paperwork. ## Side by side | | DAP | DDP | | ----------------------- | ------------------------------ | -------------------------------------------- | | Who pays duty and tax | The customer, on delivery | You, collected at checkout | | Price shown at checkout | Goods and shipping only | The full landed cost | | Customer experience | Possible surprise bill and fee | No extra payment on delivery | | Risk of refused parcels | Higher | Lower | | Your admin | Low | Higher: rates, registrations, reconciliation | | Cash flow | No duty or tax to advance | You advance or remit duty and tax | ## Many merchants do both DDP and DAP aren’t an all-or-nothing choice. Common patterns: - **DDP in your top markets, DAP elsewhere.** Put the effort where most of your international revenue is. - **DDP below a value threshold.** Low-value orders, where a delivery charge would feel most unfair, get duties included; high-value orders, where customers expect formalities, ship DAP. - **Let the customer choose.** Offer “duties included” at checkout with DAP as the fallback. ## Making DDP work in practice 1. **Classify every product properly.** Store the 6-digit HS code and the full code for each destination you ship to. 2. **Record the real country of origin** for each product, not the country of the warehouse it ships from. 3. **Calculate landed cost live at checkout** from the code, origin, destination, value and shipping, so thresholds and rates stay current. 4. **Round and display carefully.** Show duties and taxes as a clear line, in the customer’s currency. 5. **Reconcile.** Compare what you collected with what the carrier billed you. Differences usually point to a wrong code or origin. 6. **Re-check after changes.** New tariffs, de minimis changes and new trade measures can make yesterday’s estimate wrong. ## Which to choose DAP is easy to start and expensive in ways that don’t show up on an invoice: refused parcels, support tickets and customers who don’t order again. DDP takes more setup but gives your customers the experience they get from domestic shops. It depends on a correct code and origin for every product and a landed cost calculated at checkout. [border.bot’s API](/developers) returns both, and you can try the numbers on a real product with the [free landed cost calculator](/tools/landed-cost-calculator). --- # Landed cost explained: duties, taxes and fees > What makes up the landed cost of an international parcel (goods, shipping, duty, import VAT or GST, and fees) and how each part is calculated. Source: https://staging.border.bot/blog/landed-cost-explained Last updated: 2026-10-08 By border.bot team · Published 2026-09-01 · 5 min read · Tags: landed cost, duties, taxes Your customer in Toronto sees a $60 jacket at checkout. By the time it reaches their door, shipping, duty, sales tax and fees can add a lot to that price. **Landed cost** is the full amount: everything it takes to get a product from your shelf to your customer’s hands, including the charges collected at the border. It affects two things: whether you make money on international orders, and whether your customer gets a surprise bill on delivery and refuses the parcel. ## What goes into landed cost ### 1. The goods The **transaction value**: what the buyer paid, or will pay, for the goods. It is the starting point for almost every other number, so it should be the real price on the invoice, not a rounded or “gift” value. ### 2. Shipping and insurance What it costs to move the parcel. Shipping matters twice: as a cost in its own right, and because some countries include it in the value that duty is charged on (see _customs value_ below). ### 3. Customs duty The tax on importing goods, set by the destination’s tariff for the product’s code and often its **country of origin**. Duty comes in a few forms: - **Ad valorem**: a percentage of the customs value. This is the most common form. - **Specific**: a fixed amount per unit, kilogram, litre or pair. - **Compound or mixed**: a combination, sometimes with a minimum or maximum. Many products are duty-free under the general rate; others carry substantial duty. Trade agreements can reduce the rate for goods that qualify as originating in a partner country. ### 4. Additional duties On top of the ordinary rate, some goods attract **trade remedy** duties (anti-dumping, countervailing or safeguard duties) or other measures aimed at particular products or origins. They change more often than ordinary tariffs and depend heavily on origin, which is why origin has to be right. Read [Country of origin: shipped from isn’t made in](/blog/country-of-origin-vs-shipped-from) for how origin is decided. ### 5. Import taxes Most countries charge their consumption tax on imports: **VAT** in the EU and the UK, **GST** (and HST) in Canada, Australia and elsewhere. Some goods, such as alcohol, tobacco and certain fuels, also carry **excise** duties. Import VAT and GST are usually charged on the customs value **plus the duty**, so duty raises the tax too. The US has no federal import VAT; US state sales tax is collected domestically and is not a border charge. ### 6. Fees Two very different kinds: - **Government fees**, such as customs processing fees charged on imports in some countries. - **Carrier and broker fees** for clearing the parcel and advancing duty and tax on the customer’s behalf, often called brokerage, disbursement or handling fees. They vary by carrier and contract and can be a large share of the cost on low-value parcels. ### 7. Currency conversion Customs converts your invoice value into its own currency at an official rate, and the customer may pay in yet another currency. Small exchange differences add up on margins. ## Customs value: what duty is charged on Duty is a percentage of the **customs value**, and countries don’t agree on what that includes: - The **EU** and the **UK** generally use a value that includes the cost of transport and insurance up to the border, often described as a CIF basis. - The **United States** and **Canada** generally exclude international freight and insurance, which is closer to an FOB basis. So the same parcel with the same duty rate can pay different duty in different markets simply because the base is different. ## A worked example This hypothetical example uses a 10% duty and a 20% import VAT, with no fees, for a destination that charges duty on a CIF basis: | Line | Calculation | Amount | | --------------- | ----------------------------- | ---------- | | Goods | Invoice value | 100.00 | | Shipping | Carrier rate | 10.00 | | Customs value | Goods + shipping (CIF basis) | 110.00 | | Duty | 10% of 110.00 | 11.00 | | VAT base | Customs value + duty | 121.00 | | Import VAT | 20% of 121.00 | 24.20 | | **Landed cost** | Goods + shipping + duty + VAT | **145.20** | Notice two things: duty was charged on shipping as well as the goods, and VAT was charged on the duty. Ignoring either makes the estimate too low. Real rates, bases and thresholds differ by country and product and change over time, so use a calculator with current rules rather than fixed percentages. ## De minimis: when nothing is charged Many countries waive duty, tax or both on shipments below a **de minimis** value. The thresholds vary widely, can differ for duty and for tax, and change. Two of the largest markets have changed theirs recently: - **United States:** the $800 duty-free de minimis exemption has been suspended for goods from every country since 29 August 2025, and a 2025 law ends it on 1 July 2027. Low-value parcels now need a customs entry and pay the duty owed. See [US de minimis suspension: what changed for parcels](/blog/us-de-minimis-suspension). - **European Union:** import VAT has applied to ecommerce imports of any value since 1 July 2021, often collected at checkout through the Import One-Stop Shop (IOSS). Since 1 July 2026, parcels worth up to €150 also pay a temporary €3 customs duty for each tariff classification they contain. See [The EU's €3 customs duty on parcels under €150](/blog/eu-3-euro-customs-duty). Never hard-code a threshold you read once; check the current rule for each destination. ## Who pays: DDP or DAP Landed cost has to be paid by someone. Under **DDP** (delivered duty paid) you collect it at checkout and pay it at the border, so the customer pays nothing on delivery. Under **DAP** (delivered at place) the customer pays duty, taxes and carrier fees on arrival. We compare the two in [DDP vs DAP for ecommerce parcels](/blog/ddp-vs-dap-ecommerce). ## Putting landed cost to work - **Show it at checkout.** Customers abandon fewer international orders when the total is clear up front. - **Price by market.** If duty and tax are high in a market, decide whether to absorb, pass on or split them. - **Check margins by lane.** The same product can be profitable to one country and loss-making to another. - **Re-run it when things change.** New tariffs, thresholds and exchange rates all move the total. ## Calculate it for your product Our [free landed cost calculator](/tools/landed-cost-calculator) takes an HS code (or a product description), origin, destination, total goods value, shipping and quantity, and returns every duty, fee and tax line with the rate used, the de minimis check, any conditional measures and the total landed cost. It covers the US, UK, Canada, the EU-27 and more. --- # HS vs HTS vs CN/TARIC: the digits explained > Why one product has a 6-digit HS code, a 10-digit US HTS code, an 8-digit EU CN code and a 10-digit TARIC code, and which one goes on which document. Source: https://staging.border.bot/blog/hs-hts-cn-taric-commodity-codes Last updated: 2026-08-25 By border.bot team · Published 2026-08-25 · 4 min read · Tags: hs codes, classification, tariffs Ask three people for the code of the same cotton T-shirt and you may get three different answers: `6109.10`, `6109.10.00.12` and `6109 10 00`. They can all be right. The difference is how many digits each country adds to the shared international code, and which document you are filling in. ## The shared six digits The first six digits come from the **Harmonized System (HS)**, maintained by the World Customs Organization. Chapter (2 digits), heading (4) and subheading (6) mean the same thing in every country that uses the HS. If you only remember one rule, remember this one: **the first six digits of a correct code match everywhere**. After six digits, each country or customs union extends the code for its own duty rates, quotas and statistics. Those extra digits are real subdivisions by gender, value, use, material or a specific trade measure, so you can’t simply add zeros. ## United States: HTS (10 digits) The US uses the **Harmonized Tariff Schedule of the United States (HTSUS)**, published by the US International Trade Commission and applied by US Customs and Border Protection. - Digits 1–6: the HS subheading. - Digits 7–8: the **tariff rate line**, which carries the duty rate. - Digits 9–10: the **statistical suffix**, used for trade statistics. A US code is usually written `6109.10.00.12`. Imports are declared at the full 10 digits. Exports use a separate but closely related 10-digit system, **Schedule B**, maintained by the Census Bureau. The schedule is revised several times a year, so a code that was right last year can need a second look. The official, searchable version is at [hts.usitc.gov](https://hts.usitc.gov/). ## European Union: CN (8 digits) and TARIC (10 digits) The EU has two layers: - The **Combined Nomenclature (CN)** adds two digits to the HS, giving an 8-digit code such as `6109 10 00`. It sets the common customs tariff and is republished every year, applying from 1 January. - **TARIC**, the integrated tariff of the EU, adds two more digits to reach 10. Those digits carry EU measures such as tariff suspensions, quotas, anti-dumping duties and import restrictions. Import declarations into the EU generally use the 10-digit TARIC code, sometimes with additional four-character codes for specific measures. Export declarations use the 8-digit CN code. You can look codes up in the European Commission’s [TARIC database](https://ec.europa.eu/taxation_customs/dds2/taric/taric_consultation.jsp). Import VAT is set by each member state, so the same TARIC code can carry the same duty but different VAT across the EU. ## United Kingdom: commodity codes (10 digits) Since leaving the EU, the UK applies its own tariff, the **UK Global Tariff**. Commodity codes are 10 digits for imports and 8 digits for exports, and they are published in the [UK Trade Tariff](https://www.trade-tariff.service.gov.uk/). Many UK codes still look like their EU equivalents because both grew from the same nomenclature, but the duty rates and measures are the UK’s own. Goods moving into Northern Ireland can follow different arrangements, so check the rules for that route separately. ## Canada: classification numbers (10 digits) Canada’s **Customs Tariff** extends the HS to an 8-digit **tariff item**, which carries the duty rate, plus a 2-digit **statistical suffix**, giving a 10-digit classification number declared to the Canada Border Services Agency. ## Everywhere else Most other countries follow the same pattern: six international digits plus national digits of their own, often reaching eight to ten or more. When no national schedule is available to you, use the 6-digit HS code. It is what most carriers ask for on commercial invoices and postal customs forms. ## Which code goes where | Document or system | Code to use | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | Import declaration in the destination | The destination’s full national code (US HTS, EU TARIC, UK commodity code, Canadian classification number) | | Export declaration | The origin country’s export code (US Schedule B, EU CN, UK 8-digit code) | | Commercial invoice and carrier data | At least the 6-digit HS; many carriers prefer the destination’s full code | | Postal customs forms (CN22/CN23) | The HS code, ideally 6 digits or more | | Your product catalogue | The 6-digit HS for each product, plus the full code for each destination you ship to | ## Why the same product can differ after six digits National subdivisions reflect national policy. The US splits many apparel lines by gender and construction for quota and statistics history; the EU creates TARIC lines to apply measures to specific products and origins; the UK has diverged from the EU since 2021. That is why a product catalogue that stores one “HS code” per product eventually breaks: what you need is the shared six digits plus one full code per destination. ## Keeping codes current The WCO amends the HS itself periodically. The current edition is HS 2022, the next is planned for 2028, and every edition moves, merges and splits subheadings. National schedules change far more often. Build a habit of re-checking codes when a tariff edition changes and whenever duty on a product looks different from what you expected. ## How border.bot handles it When you [classify a product](/tools/hs-code-classifier), choose the destination and border.bot returns the code in that country’s own format: 10-digit US HTS, a UK commodity code, an EU CN or TARIC code, a Canadian classification number, or the 6-digit HS for other destinations. Each result includes the official description at every level, so you can see where the digits came from. New to the topic? Start with [What is an HS code, and how do you find yours?](/blog/what-is-an-hs-code) --- # What is an HS code, and how do you find yours? > A plain-English guide to HS codes: how the six digits are built, why countries add more, and a step-by-step method for finding the right code for your product. Source: https://staging.border.bot/blog/what-is-an-hs-code Last updated: 2026-10-01 By border.bot team · Published 2026-08-18 · 5 min read · Tags: hs codes, classification, basics Every product that crosses a border is declared to customs with a number. That number, the HS code, decides how much duty is charged, whether the goods need a licence or inspection, and which line of the trade statistics they land in. Get it right and your parcel clears quietly. Get it wrong and you risk delays, penalties or a customer who refuses a surprise bill at the door. This guide explains what an HS code is, how its digits are built, and a practical method for finding the right one for your product. ## What an HS code is HS stands for the **Harmonized Commodity Description and Coding System**, usually shortened to the Harmonized System. It is maintained by the [World Customs Organization](https://www.wcoomd.org/en/topics/nomenclature/overview/what-is-the-harmonized-system.aspx) and used by customs authorities in almost every country as the common language for describing goods. The system covers everything that can be traded, from live animals to aircraft, and arranges it from raw materials to finished, manufactured products. Because the first six digits are shared internationally, a code assigned in one country means the same family of goods in another. ## How the digits are built An HS code is a hierarchy. Each pair of digits narrows the description: | Level | Digits | Example | Meaning | | ---------- | ------ | ------- | ------------------------------------------------------------------------ | | Chapter | 2 | 61 | Articles of apparel and clothing accessories, knitted or crocheted | | Heading | 4 | 6109 | T-shirts, singlets, tank tops and similar garments, knitted or crocheted | | Subheading | 6 | 6109.10 | Of cotton | Above the chapters sit 21 **sections**, which group related chapters. Section XI, for example, covers textiles and textile articles. There are 97 chapters, with chapter 77 reserved for future use. Six digits is where the international system stops. Countries then add their own digits for tariff rates and statistics, which is why the same T-shirt has a longer, country-specific code in the United States, the European Union, the United Kingdom and Canada. We explain those national codes in [HS vs HTS vs CN/TARIC: the digits explained](/blog/hs-hts-cn-taric-commodity-codes). ## The rules behind every classification Classification is not a keyword search. It follows the **General Rules for the Interpretation of the Harmonized System** (often called GRIs or GIRs), applied in order: 1. **Headings and notes come first.** Classification is decided by the wording of the headings and the section and chapter notes. Section and chapter titles are for reference only. 2. **Incomplete goods and mixtures.** An unfinished or unassembled article is classified as the finished article if it already has its essential character. Mixtures and combinations of materials are dealt with under the next rule. 3. **When more than one heading fits.** Prefer the most specific description; if that doesn’t settle it, classify by the material or component that gives the goods their essential character; if it is still a tie, take the heading that comes last in numerical order. 4. **Goods that fit nowhere** go under the heading for the goods they are most akin to. 5. **Cases and packing.** Fitted cases, such as a camera case sold with the camera, and normal packing materials usually follow the goods they hold. 6. **Subheadings** are compared with each other using the same rules, only at the same level. In practice, rule 1 decides the large majority of products. The trap is reading only the short heading text: the chapter and section notes often include or exclude goods explicitly, and they are legally binding. ## A step-by-step method for finding your code ### 1. Describe the product precisely Customs classifies what the product _is_, not what it is called. Write down: - what it is, in plain words (“insulated stainless steel drinking bottle”); - what it is made of, with percentages for blends; - what it does and who it is for; - how it is made, when that matters (knitted or woven, moulded or machined); - whether it is a set, a part or an accessory. ### 2. Find the section and chapter Start broad. Is it a textile article, a machine, a plastic article, a toy? Skim the section titles to find the right neighbourhood, then read the **notes** at the start of the section and chapter. They often redirect you: certain textile goods, for instance, are excluded from the apparel chapters. ### 3. Choose the heading Compare the four-digit headings within the chapter. Apply rule 1 strictly: the heading text plus the notes. If two headings seem to fit, work through rule 3. ### 4. Narrow to the subheading Within the heading, choose the six-digit subheading, comparing only subheadings at the same level (rule 6). Material and function are the usual deciders here. ### 5. Extend to the destination’s digits Look up the subheading in the tariff of the country you are shipping to and pick the national line. The destination’s official tariff, such as the [US Harmonized Tariff Schedule](https://hts.usitc.gov/) or the [UK Trade Tariff](https://www.trade-tariff.service.gov.uk/), is the authority for those extra digits. ### 6. Sanity-check against rulings Search published rulings for similar products. The US publishes its customs rulings in [CROSS](https://rulings.cbp.gov/), and the EU publishes binding tariff information decisions. A ruling on a near-identical product is strong evidence; a ruling that disagrees with you is a warning sign. ### 7. Write down your reasoning Record the description you classified, the heading and notes you relied on, and any rulings you checked. If customs ever questions the code, this is your defence, and it makes re-checking easy when the tariff changes. ## Common mistakes - **Classifying by product name.** “Yoga set” or “gift box” says nothing about material or function. - **Reusing your supplier’s code.** The exporter’s code may be for a different country, a different tariff version, or simply wrong. - **Padding a six-digit code with zeros.** National digits are real subdivisions, not filler. - **Ignoring materials.** For textiles, plastics and metals, the material often decides the heading. - **Mixing up parts and accessories.** Parts frequently classify with the machine they belong to, but there are many exceptions in the notes. - **Never revisiting codes.** The HS is amended periodically (the current edition is HS 2022, and the next is scheduled for 2028), and national tariffs change more often. ## When to get a binding ruling If a product is high-value, regulated, or genuinely ambiguous, ask the destination’s customs authority for an advance or binding ruling. It takes time, but it gives you legal certainty for that product. A licensed customs broker can also review your classification. ## How border.bot helps Our [free HS code classifier](/tools/hs-code-classifier) follows the same logic: describe the product or paste its page, choose the destination, and you get the code in that country’s format with the official description at every level, a confidence score, the reasoning and the closest alternatives. Uncertain results are flagged for review, so you know which products to check further. --- # Privacy policy > How Border Bot handles personal data: what we collect and why, our lawful bases, the processors we use, international transfers, retention periods, cookies and your rights under UK and EU GDPR. Source: https://staging.border.bot/legal/privacy What personal data Border Bot collects, why, who processes it for us, how long we keep it and your rights. ## The short version - We collect what we need to run Border Bot: your account details, what you submit for classification and other checks, billing records, and technical data such as IP addresses. - We keep a permanent record of every classification, calculation and check, so that results can be explained to customs later. Full request logs are kept for 400 days. - Product details you submit are sent to AI model providers to produce results. Our hosting and several providers are in the United States. - We use only the cookies the service needs. We don’t use advertising or analytics cookies, and we don’t sell personal data. - You can ask to see, correct, delete or move your data by emailing [info@border.bot](mailto:info@border.bot). ## 1\. Who we are Border Bot (“we”, “us”) runs border.bot, including the website and its free tools, the dashboard, the REST API and the MCP server. We are the controller of the personal data described in this policy, except where we act for a customer, as [explained below](#customer-data). Contact us about anything in this policy at [info@border.bot](mailto:info@border.bot). We have not appointed a data protection officer; the same address reaches the person responsible for data protection. This policy applies under the UK GDPR and the Data Protection Act 2018, and under the EU GDPR where it applies to you. ## 2\. What we collect **Account and workspace data.** Your name, email address and sign-in details (handled by WorkOS, our sign-in provider, which sends the one-time codes we email you), and any profile details you add, such as job title or phone number. For your workspace: its name, website, logo, description, industry and country. When you give us your company’s website during setup, we read it to suggest these details, including contact details the site publishes. **What you submit and the results.** Product descriptions, product page URLs and their content, images and files, HS codes, values, quantities, countries, and for screening the names, companies and countries of the parties you check. We store each request with its result, the data sources it used, and which user, API key or AI assistant made it. We also keep feedback you give on results. **Billing data.** The packages you buy, amounts, invoices and your credit history. Stripe processes card payments; we receive confirmation of payment and limited billing details, never your full card number. **API keys and AI-assistant connections.** Your API keys (stored as hashes), and for each connected assistant its name, the workspace it bills and the permissions you granted. **Request logs.** For every request to our API, including those the website and dashboard make for you: the time, path, status, your IP address, browser or client (user agent), the workspace, user or key, and the full request and response, with passwords, API keys and other secrets removed. **Free tools.** When you use the free tools without an account, we keep keyed hashes (HMAC) of your IP address, of the network range around it and of a random visitor identifier stored in the `bb_vid` cookie; the country and network (ASN) your request came from; and what you entered and the result. We don’t store your raw IP address for this. Cloudflare Turnstile checks that you are a person. **Audit records.** Changes to workspaces, members, keys, billing and settings, with who made them, when, and the IP address they came from. **Crawler and referral statistics.** For visits from search and AI crawlers and AI assistants, we count the page, response status, referring site, crawler name and network (ASN), without your IP address. We collect most of this from you. Some comes from WorkOS (sign-in), Stripe (payment status) and Cloudflare (country and network of a request). You don’t have to give us personal data, but we can’t provide an account without an email address. ## 3\. How we use it and our lawful bases - **To provide the service**: accounts, workspaces, classifications, calculations, checks, history, API keys and AI-assistant connections. Lawful basis: performance of our contract with you. For people who use the service on behalf of a business customer, our legitimate interest in providing the service that customer asked for. - **To bill for credits and keep financial records.** Lawful basis: contract, and the legal obligation to keep tax and accounting records. - **To keep a customs record** of every result and the data it used, so that we and our customers can explain a result to a customs authority later. Lawful basis: our legitimate interest, and our customers’, in being able to show how a result was reached. - **To secure the service and prevent abuse**: request logs, audit records, rate limits, bot checks and free-run limits. Lawful basis: our legitimate interest in keeping the service secure and fair. - **To support you** and send service messages, such as sign-in codes, notice of changes to our terms, and security alerts. Lawful basis: contract and legitimate interest. - **To improve the service**: we review results and feedback to find errors, and may turn a corrected result into a test case for our classifier. Lawful basis: our legitimate interest in accurate results. - **To meet legal obligations** and establish, exercise or defend legal claims. ## 4\. AI processing and automated decisions Classifications, origin findings and some checks are produced with AI models. The product details, page content, images and files you submit, and for screening the names you check, are sent to the AI model providers [listed below](#processors) to produce a result. We send what a task needs, not your account details. The providers process it under their API terms to return a result to us. We don’t make decisions about you that have legal or similarly significant effects based solely on automated processing. The free tools automatically limit or refuse free runs from some networks and after the free-run limit; you can still create an account. ## 5\. Who we share it with We use these service providers (processors) to run Border Bot. They process personal data only for us, under written terms. - **Cloudflare** (US): hosting (Workers), storage (R2 and KV), database connections (Hyperdrive), network security, bot checks (Turnstile), usage statistics (Analytics Engine), AI models (Workers AI), routing of AI requests (AI Gateway), and short-term service logs. We also use Cloudflare Access to protect our own admin tools. - **PlanetScale** (US): our Postgres database, hosted in the eastern United States. - **WorkOS** (US): sign-in, sign-in emails and organisation membership. - **Stripe**: payments and invoices. - **Upstash**: the search index we use to find HS codes. It holds tariff data and receives numeric search vectors derived from product descriptions, not your account details. - **AI model providers**: Google (Vertex AI and Gemini), Anthropic, and other model providers we choose for particular tasks, such as OpenAI, Mistral or Voyage AI. Contact us for the current list. When you ask us to read a product or company web page, our servers fetch it from that website, which sees a request from us but not your details. We may also disclose personal data where the law requires, to protect our rights or others’ safety, to professional advisers, or to a business that takes over the service, in which case this policy will continue to apply to your data. We do not sell personal data or share it for advertising. ## 6\. International transfers Our database and several providers are in the United States, so your personal data is transferred outside the UK and the European Economic Area. Where a transfer needs a safeguard, we rely on the transfer mechanism the provider offers: UK or EU adequacy regulations where they apply (including the UK Extension to the EU-US Data Privacy Framework for certified US companies), the UK International Data Transfer Agreement or Addendum, or the EU Standard Contractual Clauses. Email [info@border.bot](mailto:info@border.bot) for more information or a copy of the relevant safeguard. ## 7\. How long we keep it - **Customs records**: every classification, calculation, restricted-goods check and screening check, with its input, result, data sources and who made it, is kept permanently. Customs authorities can ask what a result was based on years later, and our database is built so these records cannot be deleted in the ordinary course. If the law requires us to erase personal data in them, we do so. - **Audit records** of changes, including the actor and IP address: kept permanently, for the same reason. - **Full request logs**: 400 days, then deleted. Request bodies kept in our quick-view index are cleared after 30 days. After 400 days, the IP address, user agent, query, body and user details are removed from the index, leaving only the time, path and status of each request. We may shorten these periods. - **Short-term service logs** kept by Cloudflare: up to 7 days. - **Account and workspace details**: while your account is open. When you ask us to close your account, we delete or anonymise your profile, except what we must keep under this section. - **Billing records** and credit history: for as long as your workspace exists, and at least as long as tax and accounting law requires. - **AI-assistant connections**: until you disconnect them. Access tokens expire on their own. - **Free-tool records**: free-run counters reset when the free-run period ends. Records of free runs, which hold only hashed identifiers, are kept to detect abuse and have no fixed deletion date yet; we will review this and update this policy. ## 8\. Cookies and similar technologies We use only cookies and browser storage that the service needs or that you choose: - **wos-session** (dashboard): keeps you signed in. Encrypted and HttpOnly. Lasts until you sign out or it expires. - **bb-auth-pending** (dashboard): holds a sign-in in progress for 15 minutes. - **bb\_vid** (free tools): a random, signed identifier that counts your free runs and prevents abuse. HttpOnly, kept for up to one year. - **Cloudflare Turnstile** (free tools): Cloudflare may use cookies or similar signals to tell people from bots. - **sidebar\_state** (cookie, 7 days) and **bb-theme** (browser storage) in the dashboard: remember whether the sidebar is open and your light or dark theme. You can clear them in your browser at any time. We don’t use analytics, advertising or cross-site tracking cookies. ## 9\. Data customers give us about other people When a customer submits personal data about other people, for example a buyer’s or consignee’s name for denied-party screening, we process it for that customer as its processor, under our [terms](https://staging.border.bot/legal/terms). The customer is the controller and is responsible for telling those people. If that applies to you, contact the business that used Border Bot; we will help it respond. ## 10\. Border Bot for Shopify When a merchant installs our Shopify app, Border Bot, Shopify gives us access to that store under the permissions the merchant approves. The app keeps: - The store’s domain, name, country, currency and Shopify plan, and its settings in the app. Each store gets its own border.bot workspace, created when the app is first opened: its products, HS codes and quote history are kept there, separate from every other store, and the app keeps that workspace’s key encrypted. Usage is billed through the store’s Shopify plan. Staff the merchant invites can view the workspace in theborder.bot dashboard. - The store’s products: titles, types, vendors, descriptions, SKUs, prices, weights, images, product page links, HS codes and countries of origin. The app uses them to quote duties and to suggest HS codes, which are written back to Shopify only when the merchant approves them. It also records the email address of the staff member who approved or rejected each suggestion. - For each estimate a buyer sees in checkout or on the cart page: the cart lines (product variant, quantity and price), the destination country and region, the currency and the shipping price. We don’t receive or keep the buyer’s name, email address, street address or payment details. Quotes are cached for a short time by a hash of these details, so a repeat request isn’t charged again. - Counts of quotes and credits used, and billing records for Shopify charges. Product details go to border.bot’s service and our AI providers to classify them, as described above. When a merchant uninstalls the app, the workspace’s keys are revoked at once. Shopify then asks us to erase the store’s data (about 48 hours later): the app deletes everything it holds for that store, and everything that identifies the store is erased from its workspace, including the record of past changes. Only anonymous customs records (HS codes and calculation results, with no store, product names or other details) are kept. Requests from a store’s customers to see or erase their data are answered and recorded. The app holds no personal data about them, so there is nothing to return or delete. ## 11\. Security We protect personal data with encryption in transit, per-workspace isolation enforced by the database, hashed API keys, redacted logs and restricted admin access. Read more on our [security page](https://staging.border.bot/security). No system is perfectly secure; if a breach affects you, we will tell you and the regulator as the law requires. ## 12\. Your rights Under data protection law you have the right to: - get a copy of your personal data; - have inaccurate data corrected; - have your data deleted, where we have no lawful reason to keep it; - restrict our processing, or object to processing based on legitimate interests; - receive data you gave us in a portable format, where processing is based on contract; - withdraw consent at any time, where we rely on it. Email [info@border.bot](mailto:info@border.bot) to use these rights. We may need to confirm your identity. We will reply within one month, which the law allows us to extend in some cases. Some rights are limited for the [customs records](#retention) we must keep, but we will explain any limit that applies. ## 13\. Complaints If you are unhappy with how we handle your personal data, please complain to us first at [info@border.bot](mailto:info@border.bot); we will acknowledge your complaint and tell you the outcome. You can also complain to the UK regulator, the Information Commission (ICO), at [ico.org.uk/make-a-complaint](https://ico.org.uk/make-a-complaint/). If you live in the EU, you can complain to the data protection authority in your country. ## 14\. Children Border Bot is a business service for adults. You must be 18 or over to create an account, and we don’t knowingly collect personal data from children. ## 15\. Changes to this policy We will update this page when our practices change. For significant changes, we will tell account holders in advance by email or in the dashboard. The date at the end of this page shows when it last changed. ## 16\. Contact Questions about privacy: [info@border.bot](mailto:info@border.bot). Last updated 2026-10-15 --- # Terms of service > Terms for using Border Bot: results are estimates to verify with customs or a licensed broker, not customs, tax or legal advice; accounts, API and MCP use, prepaid credits, acceptable use and liability. Source: https://staging.border.bot/legal/terms The terms for using Border Bot: what our results are and aren’t, your responsibilities, credits, acceptable use and our liability. ## The short version - Border Bot is an information tool. We are not a customs broker, customs agent, freight forwarder, or tax or legal adviser, and we do not act for you with any customs authority. - HS codes, duty and tax figures, de minimis thresholds, restricted-goods checks, sanctions and denied-party screening, and origin findings are estimates. They are produced partly by automated and AI systems from public data that changes, and they can be wrong or out of date. - Check every result with the customs authority or a licensed customs broker before you rely on it. You, as importer or exporter, stay legally responsible for what you declare. - We are not liable for duties, taxes, penalties, seizures, delays or other losses that come from relying on a result. Our total liability is capped, but nothing here takes away rights the law does not let us remove, including your statutory rights as a consumer. - Shipping documents such as air waybills are drafts you are responsible for. We don’t issue or carry anything, and we don’t guarantee that an airline, agent or authority will accept them. - Credits are prepaid and are not refunded except where the law requires or these terms say so. Failed calls are refunded automatically. This summary helps you read the terms. The full terms below are what apply. ## 1\. About these terms These terms apply when you use Border Bot at border.bot, including the website and its free tools, the dashboard, the REST API and the MCP server for AI assistants (together, the “service”). Border Bot provides the service. In these terms, “Border Bot”, “we” and “us” mean the provider of the service, and “you” means the person or organisation using it. By creating an account, buying credits or using the service, you agree to these terms. If you use the service for an organisation, you confirm that you can bind it, and “you” includes that organisation. Our [privacy policy](https://staging.border.bot/legal/privacy) explains how we handle personal data. The service is built for businesses. Some terms differ for consumers, meaning individuals using the service wholly or mainly outside their trade, business, craft or profession. Where they differ, we say so. ## 2\. What Border Bot is and is not Border Bot gives you information to help you prepare cross-border shipments: suggested HS and national tariff codes, estimates of duties, taxes and fees (landed cost), de minimis thresholds, checks for restricted and prohibited goods, screening against sanctions and denied-party lists, and findings about a product’s country of origin. Border Bot is not a licensed customs broker, customs agent or representative, freight forwarder, tax adviser or legal adviser. We do not make declarations, act as your direct or indirect customs representative, or deal with any customs or tax authority for you. Nothing in the service is legal, tax or customs advice. Our results are not binding on any authority. Only a customs authority can give a binding ruling on classification, origin or value (for example, a UK Advance Tariff Ruling, an EU Binding Tariff Information decision or a US CBP ruling). Duties and taxes are assessed by customs when goods are declared, and the amount charged can differ from our estimate. ## 3\. Checking results before you rely on them Results are generated partly by automated systems and AI models, working from tariff schedules, rulings, legal notices and lists published by governments and other sources. Those sources change, sometimes without notice, and may be incomplete. AI models can misread a product or a source. A confidence score or a “needs review” flag is our estimate of reliability, not a guarantee. You agree that: - you will check each result with the relevant customs authority or a licensed customs broker before you rely on it to make a declaration, set a price, collect duties or taxes from a buyer, or decide whether goods can be shipped; - you remain responsible for the accuracy of everything you declare to customs, including classification, value and origin, and for meeting duties of care that the law places on you as importer or exporter (for example, the “reasonable care” duty on US importers of record); - a sanctions or denied-party match is a lead to investigate, not a finding, and no match does not mean a person or shipment is cleared. You remain responsible for complying with sanctions and export-control law; - a restricted-goods result does not list every licence, permit, standard or agency rule that may apply to your goods. The results depend on what you give us. Incomplete or inaccurate product details, values or countries will produce unreliable results. ## 4\. Accounts, workspaces and API keys - You must be at least 18 to create an account. Give accurate details and keep them up to date. - Keep your sign-in details and API keys secret. Tell us at [info@border.bot](mailto:info@border.bot) straight away if you think someone has used them without permission. You can revoke keys in the dashboard. - Workspace admins control billing, API keys, members, AI-assistant connections and settings for their workspace. - You are responsible for everything done through your account, your workspace’s API keys and the AI assistants you connect, including the credits they use. ## 5\. Using Border Bot from AI assistants You can connect AI assistants and agents (such as Claude, ChatGPT, Codex or Cursor) to the MCP server. When you approve a connection, you choose the workspace it bills and the permissions it has. The assistant then acts for you: requests it makes count as yours and use your workspace’s credits. The assistant is provided by a third party under its own terms. We do not control how it interprets, summarises or presents our results, and we are not responsible for what it says. If an assistant repeats one of our results, the same limits apply as if you had read it in the dashboard. You can disconnect assistants at any time in the dashboard. ## 6\. Free tools The free classifier, landed-cost calculator, origin finder and air waybill generator on the website are for trying the service. Each visitor gets a small number of free runs, and we may change or withdraw them at any time. Free runs may be limited or unavailable from VPN, hosting and proxy networks, and are never available over Tor. Don’t use automation, scripts, VPNs, proxies, multiple browsers or devices, or any other way to get more free runs or get around the limits or the bot check. For regular or automated use, create an account and use the API. ## 7\. Shipping documents Border Bot can prepare shipping documents, such as air waybills, from details you enter. You agree to this section each time you make one, on the website, in the dashboard, over the API or from an AI assistant. **We prepare documents; we don’t issue or carry anything.** We are not a carrier, an airline, a carrier’s agent, a freight forwarder or a customs broker. We don’t issue, accept, sign, execute, file or transmit any document for you, and we are not a party to any contract of carriage. An air waybill made here is a draft until the issuing carrier or its authorised agent accepts the goods and executes it. The conditions of contract printed on it are IATA’s standard wording, included for convenience; the carrier’s own conditions of carriage and tariffs decide the contract. **Acceptance is never guaranteed.** An airline, handling agent, forwarder, customs or any other authority may refuse, reject, correct or ask you to re-issue a document, may require the same data electronically (for example as an e-AWB) instead of on paper, and may apply its own rules about stock, numbering, format and printing. We don’t promise that any document will be accepted by anyone. **You are responsible for what’s on it.** You must make sure every particular is true, complete and lawful: the parties, addresses, goods description, pieces, weights, dimensions, values, charges, routing and signatures. You must only use an air waybill number the issuing carrier has allocated to you or authorised you to use (a valid check digit does not make a number yours), declare dangerous goods with the separate declaration the regulations require, and comply with the carrier’s conditions, IATA rules, and customs, export-control and sanctions law. Chargeable weights and totals are worked out from what you enter; check them against the carrier’s rates. **Don’t misuse it.** You must not make a document to deceive anyone, to impersonate a carrier or agent, with a number or signature you aren’t entitled to use, or to move goods unlawfully. We may refuse to make documents and close access where we suspect misuse, and we may report it where the law requires. **What we aren’t liable for.** To the extent the law allows, we are not liable for shipments that are refused, rejected, offloaded, held, delayed, returned or seized; for storage, demurrage, rebooking, re-issue, courier or correction costs; for freight differences, duties, taxes, fines or penalties; or for claims by carriers, agents, consignees or authorities, where any of these arise from a document made with Border Bot or from its contents. The limits in [Our liability](#liability) apply, and nothing here affects rights the law does not let us exclude, including your statutory rights as a consumer. **Your responsibility to us.** If you use the service for business, you will cover our reasonable losses and costs arising from a third-party claim caused by a document you made, its contents, or your use of it. ## 8\. Acceptable use You must not: - use the service to break any law, including customs, sanctions and export-control law, or to help anyone evade duties, taxes, restrictions or sanctions; - scrape, crawl or bulk-download the service, or copy its results, tariff data or source data into a database, product or service that competes with Border Bot; - resell, sublicense or rebrand the service or its data wholesale, or give third parties access to your account or API keys, without our written agreement. Showing results to your own customers as part of your business (for example, duties at checkout) is allowed; - get around rate limits, credit charges, free-run limits or security measures, including by creating extra accounts or workspaces; - probe, scan, load-test, overload or disrupt the service, or try to access other customers’ data; - reverse engineer the service, except where the law allows it despite this restriction; - submit malicious code, unlawful content, or personal data the service doesn’t need, including special category data such as health information. We may limit, suspend or block access that breaks these rules or puts the service or other customers at risk. ## 9\. Credits, payment and refunds - Classifications, calculations and other paid actions use prepaid credits. The [pricing page](https://staging.border.bot/pricing) and the API’s pricing endpoint show what each action costs. Some checks are free. - You buy credits in packages through Stripe, our payment provider. Prices are shown in US dollars and exclude taxes unless stated. Credits belong to the workspace that bought them and can’t be transferred or exchanged for cash. - Credits are taken just before an action runs. If it fails, they are returned to your balance automatically and the refund appears in your credit history. A request that repeats an `Idempotency-Key` returns the original result without a second charge. - Credits don’t expire. If we ever introduce expiry, it will apply only to credits bought after we give you notice. - Free credits we give, for example to new workspaces, have no cash value and are not refundable. - Except as set out below or where the law requires, credits are non-refundable, including when a result turns out to be wrong. If a result was clearly wrong because of a fault in the service, tell us and we will look at returning the credits. - If we close your account for reasons other than your breach of these terms, or stop providing the service, we will refund the price of your unused credits. **If you are a consumer** in the UK or the EU, you may cancel a credit purchase within 14 days of buying it by emailing [info@border.bot](mailto:info@border.bot), and we will refund unused credits. If you use credits during those 14 days, you are asking us to start the service straight away, and we will deduct the value of the credits you used. We may change prices and the credits an action uses. A change applies to purchases and actions after it takes effect. We will give at least 30 days’ notice, by email or in the dashboard, before an action uses more credits than before. ## 10\. Your data You keep your rights in the product details, files, URLs and other content you submit (“your data”). You give us permission to use your data to provide, secure, support and improve the service, as described in our privacy policy. We keep records of classifications, calculations and checks, with the data they used, so that results can be explained later. You confirm that you have the right to submit your data and that our use of it as described will not break any law or anyone’s rights. When you ask us to read a web page, you confirm that you may ask us to fetch it. You may use the results for your own business, including sharing them with your customers, brokers and carriers, subject to these terms. ## 11\. Personal data about other people Some features process personal data about people other than you, such as a buyer’s or consignee’s name for denied-party screening. For that data, you are the controller and we process it for you as your processor. You confirm that you have a lawful basis to share it with us and have told those people as the law requires. As your processor, we will: - process it only to provide the service and on your documented instructions, unless the law requires otherwise; - make sure the people who process it are bound by confidentiality; - keep it secure with appropriate technical and organisational measures; - use only the sub-processors named in our privacy policy, under written terms that protect the data, and tell you before we add or replace one so you can object; - help you respond to requests from individuals and meet your security, breach and impact-assessment obligations; - tell you without undue delay if we become aware of a personal data breach affecting it; - delete or return it when our service to you ends, except records that the law, or the customs record-keeping described in our privacy policy, requires us to keep; - give you the information you reasonably need to show compliance with these duties. ## 12\. Data sources and our content The service uses tariff schedules, rulings, legal texts, exchange rates and sanctions and restricted-goods lists published by governments, customs authorities and other third parties. Those sources belong to their publishers and are used under their own terms and licences, some of which require attribution. If you republish source data, you must follow its licence. These terms give you no more rights in third-party data than its licence does. Apart from your data and third-party sources, the service, its software, design, text, compiled data and results belong to us or our licensors. We give you a non-exclusive, non-transferable right to use the service and its results under these terms while your account is open, and to keep using results you obtained afterwards. If you send us feedback, we may use it without any obligation to you. ## 13\. Availability and changes to the service We work to keep the service available and accurate, but we don’t promise it will be uninterrupted or error-free. We may change, add or remove features, data sources, countries and API versions. We will give reasonable notice of changes that significantly reduce what you have paid for, and we announce API version retirements in advance on the API’s versions page. ## 14\. No warranty To the extent the law allows, the service and its results are provided “as is” and “as available”. We make no promise that any result is correct, complete, current or suitable for a particular purpose, or that customs or any other authority will accept it. If you are a consumer, we will provide the service with reasonable care and skill, and this section does not affect your statutory rights. ## 15\. Our liability **What we never exclude.** Nothing in these terms excludes or limits liability for death or personal injury caused by our negligence, for fraud or fraudulent misrepresentation, or any other liability that cannot be excluded or limited by law. If you are a consumer, nothing in these terms affects your statutory rights, including those under the Consumer Rights Act 2015. **If you use the service for business**, to the extent the law allows: - we are not liable for duties, taxes, fees, interest, penalties or fines; for goods that are seized, detained, returned, destroyed or delayed; for refused shipments or lost sales; or for the cost of correcting declarations, where these result from using or relying on a result; - we are not liable for loss of profit, revenue, business, goodwill, opportunity or anticipated savings, for loss or corruption of data, or for any indirect or consequential loss, however it arises; - our total liability to you for all claims arising from or connected with the service or these terms, whether in contract, tort (including negligence) or otherwise, is limited to the greater of US$100 and the amount you paid us in the 12 months before the event that gave rise to the claim. **If you are a consumer**, we are responsible for loss you suffer that is a foreseeable result of our breaking these terms or failing to use reasonable care and skill. We are not responsible for loss that was not foreseeable, or for business losses. Duties and taxes that were legally due on your goods are not a loss we cause, even if our estimate was lower. **Your responsibility.** If you use the service for business, you will cover our reasonable losses and costs arising from a third-party claim caused by your breach of these terms or your unlawful use of the service. ## 16\. Suspension and closing your account You can stop using the service at any time, and ask us to close your account by emailing [info@border.bot](mailto:info@border.bot). We may suspend or close an account or workspace, or revoke API keys and AI-assistant connections, if you seriously or repeatedly break these terms, if you don’t pay, if we must do so by law, or to protect the service or other customers. We will tell you why unless the law or security prevents it, and, where it is reasonable, give you a chance to fix the problem first. We may also close the service, with at least 30 days’ notice to account holders. When an account closes, your right to use the service ends. Sections that by their nature should continue, including those on liability, data sources and the law that applies, stay in force. ## 17\. Changes to these terms We may update these terms, for example when the service or the law changes. We will give account holders at least 30 days’ notice of changes that materially affect them, by email or in the dashboard, unless a change is needed sooner for legal or security reasons. The date at the end of this page shows when they last changed. If you don’t agree to a change, you can stop using the service and, if you are a consumer, ask for a refund of unused credits before the change takes effect. ## 18\. Law and disputes These terms, and any dispute about them or the service, are governed by the law of England and Wales. If you use the service for business, the courts of England and Wales have exclusive jurisdiction. If you are a consumer, you can bring proceedings in the courts of England and Wales or, if you live in Scotland or Northern Ireland, in the courts there. If you live in the EU, you also keep the protection of the mandatory consumer laws of your country and can bring proceedings there. If a court finds part of these terms unenforceable, the rest stays in force. If we don’t enforce a right straight away, we can still enforce it later. You may not transfer these terms without our consent; we may transfer them to a business that takes over the service, and will tell you if we do. Nobody else has rights under these terms. ## 19\. Contact Email [info@border.bot](mailto:info@border.bot) with questions about these terms, or to tell us about a problem. Last updated 2026-10-13