API reference
Send an API key as a Bearer token: Authorization: Bearer YOUR_KEY. Make one in the app under Developers. Amounts are in cents unless a call says dollars, and calls under /v1/public need no key. The address is https://app.othermile.com.
Border costs
What goods will cost at the border, by parcel or freight, and how that changed over time.
POST /v1/border/quote- What goods will cost at the border, by parcel or freight (key scope decisions:read). The answer adds mode, incoterm, costs (seller and buyer under the Incoterm) and exporting (export duty, declaration and permits between Canada and the US).
POST /v1/border/history- Border rate history: the same goods priced with the rules that were in force on each date (key scope decisions:read, or a signed in person). The body is a Shipment plus months (1 to 84, default 12); a year back on every plan, three years on Growth, Agency and Business, seven on Scale and Business Plus.
GET /v1/public/border/incoterms- Incoterms 2020: for each term, who pays loading, export clearance, main transport, insurance, unloading, import clearance and duties, and whether it is for sea only
POST /v1/public/border/quote- What goods will cost at the border, with no key needed and a tight rate limit (the free shopper checker)
POST /v1/border/estimate- A border estimate with plain fields and dollars: from, to (CA or US), region, mode (mail or courier), currency, dutyPaid, items [{sku, hs, origin, quantity, price, weightG}]. A key or session with decisions:read.
Orders
Check an order against the store owner's limits, and follow what happened to it.
POST /v1/orders/{id}/parcel-link- The link to this order's parcel page, for the store's emails (one per order)
GET /v1/orders/{id}/customs- Customs data for the parcel: lines (sku, description, hs, hs6, origin, qty, unitValue, value, weightG, cusmaClaim, needs), totals, contents, warnings; and the exporter
GET /v1/orders/{id}/customs.csv- One row per line, for label software or a spreadsheet
GET /v1/orders/{id}/customs/{format}- Customs items for Shippo (shippo.json) or EasyPost (easypost.json); the owner adds their own certification
GET /v1/orders/{id}/invoice.pdf- Commercial invoice (PDF). Not customs advice and not a certification of origin.
GET /v1/orders/{id}/postal.pdf- The details for a postal customs form, CN22 or CN23 (PDF)
POST /v1/orders/upload- Check orders from a spreadsheet: csv (one row per product, rows with the same order number make one order, up to 200 orders), shipFrom, shipBy, currency, mailCost, courierCost. Managers and owners, or a key with decisions:write.
POST /v1/orders/check- Check one order sent as simple fields: id, number, currency, items [{sku, title, quantity, price, hs, origin}] (dollars), shipping, destination {country, region}, shipFrom, shipBy, dutyPaid, channel (zapier, make, api), and mailCost and courierCost for a channel's first order. Empty fields are ignored. Managers and owners, or a key with decisions:write.
GET /v1/orders/find- Orders by the store's order number (with or without #), newest first, up to five. Viewers and up, or a key with decisions:read.
PUT /v1/orders/{id}/shipping-actual- What the label really cost: amount {value, currency}, carrier, service, tracking; null clears it. Reports use it instead of the estimate.
POST /v1/orders- Check an order with the saved owner limits and record it
GET /v1/orders- Recent checked orders
GET /v1/orders/{id}- One checked order
POST /v1/orders/guard- Stateless order check with limits in the request
GET /v1/orders/export- Every order in the last days as a CSV spreadsheet, one row per order with its full cost breakdown
POST /v1/outcomes- Report what actually happened to a parcel
Products
The tariff code, origin and cost of each product, which every check uses.
GET /v1/products/{id}/cusma- The CUSMA readiness checklist for a product: items, status (ready, open, unlikely), summary, warning, savings, rules. A self check, never a certification.
PUT /v1/products/{id}/cusma- Save the owner's answers: made, materials, certificate, records (yes, no, unknown), notes
GET /v1/products- The product list every check uses. view is attention (not confirmed yet), all, confirmed or archived; q searches name and SKU.
POST /v1/products- Add a product by hand, or update it by SKU. A tariff code and origin given here count as confirmed.
PATCH /v1/products/{id}- Change a product. confirm true accepts the code and origin (or the suggestion); changing either clears the confirmation.
DELETE /v1/products/{id}- Archive a product. It comes back if an order carries it again.
POST /v1/products/confirm- Accept the suggestions for the products given (ids) or for every product that has both a code and an origin (all true)
POST /v1/products/upload- A spreadsheet as CSV ({ csv }): sku, title, variant, hs, origin, cusma, cost, currency, price, weight. Good rows are saved; bad rows are listed by line.
GET /v1/products/export- Every product as a CSV spreadsheet
POST /v1/products/import- Bring in or refresh the products of a connected Printify or Printful store ({ connectorId }); runs in the background
Events
Be told when an order is held, approved or blocked, or a border change affects your products.
GET /v1/key- Who an API key belongs to: the business and the key's name and scopes. Keys only (Zapier and Make use it to test a connection).
POST /v1/hooks- Subscribe an address to events (REST hooks for Zapier and Make): url (public https), events (order.released, order.held, order.blocked, order.approved, order.rejected, order.release_failed, order.reroute, approval.settled, decision.made, alert.created), label. Keys only, decisions:read; at most 50 per business.
DELETE /v1/hooks/{id}- Remove a subscription. Only the key that made it can remove it.
GET /v1/hooks/samples- Recent examples of an event, shaped like deliveries ({id, type, createdAt, data}), or a made up one when nothing has happened yet: event. Keys only, decisions:read.
Tariff exposure
For manufacturers and importers: yearly exposure, what ifs, alerts and brokers.
GET /v1/trade/products- Products in the tariff exposure scanner, with the plan limit
POST /v1/trade/products- Add or update one product
POST /v1/trade/import- Upload a CSV of products or recent imports (text/csv)
GET /v1/trade/scan- Yearly tariff exposure, product by product, with CUSMA savings and announced changes
POST /v1/trade/scan- Same, and save it so rule changes are compared with it
POST /v1/trade/whatif- Run a what if without saving it
GET /v1/trade/scenarios- Saved what ifs
POST /v1/trade/scenarios- Save a what if
GET /v1/trade/measures- Measures a what if can change
GET /v1/trade/alerts- Rule change and announced change alerts
GET /v1/trade/brokers- Licensed customs broker partners
AI agents
Any MCP client can connect to https://app.othermile.com/mcp. Without a key it can estimate border costs and read the rules in force; with a key it can also check orders.
Errors and limits
Errors come back as JSON with an error code and a plain English message. Requests are rate limited; a 429 answer means wait a moment and try again.
Every figure is an estimate from official government data, not customs advice.