Free beta: Othermile is free while we test it with our first stores. Paid plans open after the beta. Start free

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.