border.bot

border.bot API (v1) reference

Version 1.3.0. Base URL https://api.border.bot. Interactive reference · OpenAPI 3.1 · Markdown · Docs and guides · MCP setup

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://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 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://api.border.bot/mcp (OAuth, no API key). Setup guides: https://border.bot/mcp

Classification

HS/HTS codes.

POST /v1/classify Classify a product

Requires an API key. Operation ID classifyProduct.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
descriptionstringnoWhat the product is: type, material/composition, intended use and user. Required unless productUrl or imageUrl is given.
productUrlstringnoProduct 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.
imageUrlstringnoA 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.
destinationCountrystringyesWhere 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.
originCountrystringnoWhere the product was made (context only). ISO 3166-1 alpha-2, case-insensitive.
modestringnoThe 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).
titlestringnoProduct title (optional extra context).
brandstringnoBrand (optional extra context).
skustringnoYour SKU (stored with the usage record).
pricenumbernoUnit price (optional context).
currencystringnoISO 4217 currency of price.
hsCodeHintstringnoAn 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

curl -X POST 'https://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"}'

POST /v1/classify/batch Classify up to 25 products

Requires an API key. Operation ID classifyBatch.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
itemsClassifyRequest[]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

curl -X POST 'https://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"}]}'

POST /v1/classify/regulator Find an agency product code

Requires an API key. Operation ID classifyRegulator.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
descriptionstringyesWhat the product is, what it is made of, and how it is processed or packed (frozen, smoked, canned…).
destinationCountrystringyesWhere the goods are imported. Its import agency and coding scheme follow from it (for US, FDA’s import product codes).
hsCodestringnoThe 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

curl -X POST 'https://api.border.bot/v1/classify/regulator' \
  -H 'Authorization: Bearer bb_live_...' \
  -H 'Content-Type: application/json' \
  -d '{"description":"<string>","destinationCountry":"<string>"}'

GET /v1/classify/modes Classification modes

Public, no API key needed. Operation ID classifyModes.

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

NameTypeRequiredDescription
destinationstringnoISO-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

curl -X GET 'https://api.border.bot/v1/classify/modes'

GET /v1/classify/blocklist Blocked codes

Requires an API key. Operation ID listBlockedCodes.

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

curl -X GET 'https://api.border.bot/v1/classify/blocklist' \
  -H 'Authorization: Bearer bb_live_...'

POST /v1/classify/blocklist Block a code

Requires an API key. Operation ID addBlockedCode.

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

NameTypeRequiredDescription
codestringyes
destination"*" | stringno
reasonstringno

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

curl -X POST 'https://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"}'

DELETE /v1/classify/blocklist Unblock a code

Requires an API key. Operation ID removeBlockedCode.

Lets classifications suggest the code again. Free. API key scope: settings.

Parameters

NameTypeRequiredDescription
codestringyes
destination"*" | stringno

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

curl -X DELETE 'https://api.border.bot/v1/classify/blocklist' \
  -H 'Authorization: Bearer bb_live_...'

POST /v1/classify/blocklist/import Block many codes

Requires an API key. Operation ID importBlockedCodes.

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

NameTypeRequiredDescription
codesobject[]yes
replacebooleanno

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

curl -X POST 'https://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}'

POST /v1/classify/feedback Say whether a classification was right

Requires an API key. Operation ID sendClassifyFeedback.

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

NameTypeRequiredDescription
usageIdstringno
destinationCountrystringyes
descriptionstringyes
predictedCodestringyes
verdict"right" | "wrong"yes
correctCodestringno
reasonstringno
modestringno
productUrlstring (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

curl -X POST 'https://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"}'

Landed cost

Duties, taxes and fees.

POST /v1/calculate Calculate duties, taxes and landed cost

Requires an API key. Operation ID calculateLandedCost.

Duties, taxes, fees and the landed cost for one HS code / origin / destination (the destinations GET /countries marks landedCost). Costs 1 credit. Unsupported destinations return 422 unsupported_country without charging. API key scope: calculate.

Headers

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
destinationCountrystringyesDestination: one GET /countries marks landedCost. ISO 3166-1 alpha-2, case-insensitive.
currencystringnoISO 4217 currency of value, shippingCost and insuranceCost.
shippingCostnumbernoShipping cost (affects CIF-based duty/VAT bases).
insuranceCostnumbernoInsurance cost.
transportMode"air" | "sea" | "road" | "rail"noTransport mode (fees such as HMF apply to sea freight).
shippingTerms"EXW" | "FCA" | "FAS" | "FOB" | "CFR" | "CIF" | "CPT" | "CIP" | "DAP" | "DPU" | "DDP"noIncoterm 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"noHow the parcel travels: courier (express carriers, default) or postal — affects de minimis and channel-specific regimes.
entryDatestringnoCalculate with the rates in force on this date (YYYY-MM-DD). Default: today.
tradeAgreementstringnoIgnored. Preferential rates are applied automatically from the origin and destination; the agreement used is returned as tradeAgreement.
regionstringnoState, province or territory, where import taxes differ inside the country. Canada needs one (ON, QC, BC…).
purpose"sale" | "gift" | "sample" | "return"noWhy the goods are sent: some thresholds differ for gifts, samples and returns. Default: sale.
businessBuyerbooleannoThe buyer is a business: some taxes are reverse-charged or apply differently.
sellerRegistrationsstring[]noTax 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".
preferencestringnobest (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.
claimsstring[]noExemption, 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.
enforceValidationbooleannoRefuse 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.
hsCodestringyesHS/HTS code (4–10 digits; dots and spaces are ignored).
originCountrystringyesCountry of origin — drives preferential rates and additional duties (e.g. Section 301). ISO 3166-1 alpha-2, case-insensitive.
valuenumberyesTotal customs value of the goods in the shipment (unit price × quantity), in currency, excluding shipping.
quantityintegernoNumber of units.
weightnumbernoShipment weight (needed for weight-based duties). Requires weightUnit.
weightUnit"kg" | "lb"noUnit of weight.
volumeLitersnumbernoVolume of the goods in litres, for duties charged per litre (wine, spirits, fuel).
alcoholPercentnumbernoAlcohol by volume (%), for duties charged per litre of pure alcohol.
componentsobject[]noMetal 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).
metalWeightPercentnumbernoShare of the product’s weight that is metal (0–100), for content-based exemptions.
conditionsstring[]noRate 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.

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

curl -X POST 'https://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}'

POST /v1/calculate/shipment Calculate a whole shipment

Requires an API key. Operation ID calculateShipment.

Duties, taxes, fees and the landed cost of a cart or order to one destination: up to 50 lines, 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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
destinationCountrystringyesDestination: one GET /countries marks landedCost. ISO 3166-1 alpha-2, case-insensitive.
currencystringnoISO 4217 currency of value, shippingCost and insuranceCost.
shippingCostnumbernoShipping cost (affects CIF-based duty/VAT bases).
insuranceCostnumbernoInsurance cost.
transportMode"air" | "sea" | "road" | "rail"noTransport mode (fees such as HMF apply to sea freight).
shippingTerms"EXW" | "FCA" | "FAS" | "FOB" | "CFR" | "CIF" | "CPT" | "CIP" | "DAP" | "DPU" | "DDP"noIncoterm 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"noHow the parcel travels: courier (express carriers, default) or postal — affects de minimis and channel-specific regimes.
entryDatestringnoCalculate with the rates in force on this date (YYYY-MM-DD). Default: today.
tradeAgreementstringnoIgnored. Preferential rates are applied automatically from the origin and destination; the agreement used is returned as tradeAgreement.
regionstringnoState, province or territory, where import taxes differ inside the country. Canada needs one (ON, QC, BC…).
purpose"sale" | "gift" | "sample" | "return"noWhy the goods are sent: some thresholds differ for gifts, samples and returns. Default: sale.
businessBuyerbooleannoThe buyer is a business: some taxes are reverse-charged or apply differently.
sellerRegistrationsstring[]noTax 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".
preferencestringnobest (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.
claimsstring[]noExemption, 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.
enforceValidationbooleannoRefuse 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.
itemsobject[]yesThe shipment’s lines (up to 50), each with its code, origin and line value. 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

curl -X POST 'https://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}]}'

POST /v1/calculate/stacking Duty stacking

Requires an API key. Operation ID dutyStacking.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
itemsobject[]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

curl -X POST 'https://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"}]}'

Products

Product pages and country of origin.

POST /v1/products/extract Read a product page

Requires an API key. Operation ID extractProduct.

Fetch a product page and extract its title, brand, price, materials, images and any stated country of origin. API key scope: origin.

Headers

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
urlstringyesProduct 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

curl -X POST 'https://api.border.bot/v1/products/extract' \
  -H 'Authorization: Bearer bb_live_...' \
  -H 'Content-Type: application/json' \
  -d '{"url":"<string>"}'

Compliance

Restricted and prohibited goods (free).

POST /v1/restrictions Check restricted goods

Requires an API key. Operation ID checkRestrictedGoods.

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

NameTypeRequiredDescription
destinationCountrystringyesShip-to country — its import rules are checked. ISO 3166-1 alpha-2, case-insensitive.
originCountrystringnoShip-from country — its export rules are checked when given. ISO 3166-1 alpha-2, case-insensitive.
itemsRestrictionItem[]yes1–100 items.
referencestringnoYour 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

curl -X POST 'https://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"}]}'

GET /v1/restrictions/checks Restricted-goods checks

Requires an API key. Operation ID listRestrictionChecks.

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

NameTypeRequiredDescription
limitintegerno

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

curl -X GET 'https://api.border.bot/v1/restrictions/checks' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/restrictions/rules Your restricted-goods rules

Requires an API key. Operation ID listRestrictionRules.

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

curl -X GET 'https://api.border.bot/v1/restrictions/rules' \
  -H 'Authorization: Bearer bb_live_...'

POST /v1/restrictions/rules Add a restricted-goods rule

Requires an API key. Operation ID addRestrictionRule.

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

NameTypeRequiredDescription
country"*" | stringno
direction"import" | "export"no
ruleType"prohibition" | "restriction" | "observation"yes
codestringno
keywordsstring[]no
originsstring[]no
titlestringyes
summarystringno

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

curl -X POST 'https://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)"}'

DELETE /v1/restrictions/rules Remove a restricted-goods rule

Requires an API key. Operation ID removeRestrictionRule.

Removes one of your rules by its id. Free. API key scope: settings.

Parameters

NameTypeRequiredDescription
idstring (uuid)yesThe 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

curl -X DELETE 'https://api.border.bot/v1/restrictions/rules' \
  -H 'Authorization: Bearer bb_live_...'

POST /v1/screen Screen a person or company

Requires an API key. Operation ID screenParty.

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

NameTypeRequiredDescription
namestringyesThe person’s or company’s name, as you have it.
companystringnoA company to screen too (a buyer and their employer, say).
countrystringnoThe party’s country (ISO-2): matches with an address, nationality or flag there are flagged countryMatch.
type"individual" | "entity"noOnly parties of this type. Vessels, aircraft and parties of unknown type are always screened.
referencestringnoYour 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

curl -X POST 'https://api.border.bot/v1/screen' \
  -H 'Authorization: Bearer bb_live_...' \
  -H 'Content-Type: application/json' \
  -d '{"name":"<string>"}'

GET /v1/screen/checks Your screening checks

Requires an API key. Operation ID listScreeningChecks.

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

NameTypeRequiredDescription
limitintegerno

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

curl -X GET 'https://api.border.bot/v1/screen/checks' \
  -H 'Authorization: Bearer bb_live_...'

Account

Your workspace, credits and usage.

GET /v1/me Who am I

Requires an API key. Operation ID getWorkspace.

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

curl -X GET 'https://api.border.bot/v1/me' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/credits Credit balance

Requires an API key. Operation ID getCredits.

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

curl -X GET 'https://api.border.bot/v1/credits' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/usage Usage history

Requires an API key. Operation ID listUsage.

Every billable request made by the workspace (dashboard, API and MCP), newest first, with cursor pagination. API key scope: account.

Parameters

NameTypeRequiredDescription
limitintegernoPage size (1–100).
cursorstringnoOpaque cursor from a previous page.
action"classify" | "classify_max" | "classify_regulator" | "calculate" | "calculate_stacking" | "extract_product" | "infer_origin"noOnly 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

curl -X GET 'https://api.border.bot/v1/usage' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/requests Request log

Requires an API key. Operation ID listApiRequests.

Every request your API keys made in the last 30 days, newest first: what it called, how it ended (status and error code), how long it took, and, for requests that change something, the body. Quote a request's requestId (its X-Request-Id) to support. API key scope: account.

Parameters

NameTypeRequiredDescription
limitintegernoPage size (1–100).
cursorstringnoThe next of the previous page.
failed"true" | "false"notrue: only requests that failed (status 400 and up).
requestIdstringnoOne request, by the X-Request-Id its response carried.

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

curl -X GET 'https://api.border.bot/v1/requests' \
  -H 'Authorization: Bearer bb_live_...'

Reference

Public reference data (no key needed).

GET /v1/countries Supported countries

Public, no API key needed. Operation ID listCountries.

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

curl -X GET 'https://api.border.bot/v1/countries'

GET /v1/pricing Pricing

Public, no API key needed. Operation ID getPricing.

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

curl -X GET 'https://api.border.bot/v1/pricing'

Origin

POST /v1/origin Infer country of origin

Requires an API key. Operation ID inferOrigin.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
productUrlstringnoProduct page URL: its structured data and “Made in …” text are read first.
imageUrlstringnoProduct 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.
descriptionstringnoProduct description.
titlestringnoProduct name.
brandstringnoBrand.
skustringnoYour SKU (kept with the result).
gtinstringnoBarcode (GTIN, UPC, EAN). Its GS1 prefix shows where the brand registered: a weak hint, never proof.
materialstringnoMain materials.
categoriesstring[]noCategory path, broadest first.
pricenumbernoSelling price, in currency.
currencystringnoISO 4217 currency of price.
shipFromCountrystringnoCountry the goods ship from (often, not always, where they are made). ISO 3166-1 alpha-2, case-insensitive.
reviewThresholdnumbernoWhen 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

curl -X POST 'https://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"}'

POST /v1/origin/validate Check a declared country of origin

Requires an API key. Operation ID validateOrigin.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
productUrlstringnoProduct page URL: its structured data and “Made in …” text are read first.
imageUrlstringnoProduct 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.
descriptionstringnoProduct description.
titlestringnoProduct name.
brandstringnoBrand.
skustringnoYour SKU (kept with the result).
gtinstringnoBarcode (GTIN, UPC, EAN). Its GS1 prefix shows where the brand registered: a weak hint, never proof.
materialstringnoMain materials.
categoriesstring[]noCategory path, broadest first.
pricenumbernoSelling price, in currency.
currencystringnoISO 4217 currency of price.
shipFromCountrystringnoCountry the goods ship from (often, not always, where they are made). ISO 3166-1 alpha-2, case-insensitive.
reviewThresholdnumbernoWhen 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).
declaredOriginstringyesThe 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

curl -X POST 'https://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."}'

POST /v1/origin/batch Infer or check the origin of up to 50 products

Requires an API key. Operation ID originBatch.

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

NameTypeRequiredDescription
idempotency-keystringnoMake retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace).

Request body

NameTypeRequiredDescription
itemsobject[]yes
reviewThresholdnumbernoThe 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

curl -X POST 'https://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"}]}'

Bulk

GET /v1/bulk/runs Your bulk runs

Requires an API key. Operation ID listBulkRuns.

Your workspace’s bulk runs, newest first. API key scope: bulk.

Parameters

NameTypeRequiredDescription
limitintegerno

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

curl -X GET 'https://api.border.bot/v1/bulk/runs' \
  -H 'Authorization: Bearer bb_live_...'

POST /v1/bulk/runs Start a bulk run

Requires an API key. Operation ID startBulkRun.

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

NameTypeRequiredDescription

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

curl -X POST 'https://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"}]}'

DELETE /v1/bulk/runs Cancel a bulk run

Requires an API key. Operation ID cancelBulkRun.

Stops a run after the chunk it is working on. Items already done stay done (and charged). API key scope: bulk.

Parameters

NameTypeRequiredDescription
idstringyes

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

curl -X DELETE 'https://api.border.bot/v1/bulk/runs' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/bulk/status A bulk run’s progress

Requires an API key. Operation ID bulkRunStatus.

How far a run has got: items done, succeeded and failed, and the credits charged so far. API key scope: bulk.

Parameters

NameTypeRequiredDescription
idstringyes

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

curl -X GET 'https://api.border.bot/v1/bulk/status' \
  -H 'Authorization: Bearer bb_live_...'

GET /v1/bulk/results A bulk run’s results

Requires an API key. Operation ID bulkResults.

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

NameTypeRequiredDescription
idstringyes
offsetinteger | nullno
limitintegerno

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

curl -X GET 'https://api.border.bot/v1/bulk/results' \
  -H 'Authorization: Bearer bb_live_...'