Reference
FreightMath API
One calculate call for up to 500 SKU rows. The same formulas as the site. Base URL https://freightmath.io.
Get an API keyAuthentication
Send the key in the Authorization header. The value must start with the seven characters bearer , compared without case, then a token that starts with fm_.
Authorization: Bearer fm_…
A missing key, a revoked key, or any other shape returns 401 Use a bearer API key. A subscription that is not active or trialing, or that has a billing hold, returns 402 This subscription is not active.
Limits
Pro
500
API calls per calendar month. One request is one call, however many rows it contains.
Pro Plus
10,000
API calls per calendar month, plus the branded freight class embed.
- Each JSON body accepts 1 to 500 rows. A CSV with more than 500 data rows is rejected with Send 500 rows or fewer.
- Calculate allows 60 requests per minute for an IP address. Over that, the response is 429 Too many requests.
- The monthly cap returns 429 Monthly API call limit reached, with limit and used.
- Brand updates allow 30 requests an hour. Over that, the response is 429 Too many requests. Try again later.
POST /api/v1/calculate
JSON uses unitSystem. A body whose Content-Type contains text/csv uses the columns sku, unit_system, length, width, height, weight and quantity. unit_system is metric or imperial. An operator key, which is not tied to a subscription, still calculates and returns usage as null. A subscription key counts one call before the rows run.
Request
{
"rows": [
{
"sku": "PAL-1",
"unitSystem": "imperial",
"length": 48,
"width": 40,
"height": 48,
"weight": 500,
"quantity": 1
}
]
}CSV
sku,unit_system,length,width,height,weight,quantity PAL-1,imperial,48,40,48,500,1
Response
{
"apiVersion": "2025-10-16.2",
"results": [
{
"sku": "PAL-1",
"ok": true,
"freightClass": 100,
"densityPcf": 9.375,
"dimKg": {
"iata": 252,
"courier-5000": 303,
"dhl-express": 303,
"fedex": 303,
"ups": 303,
"usps": 252,
"royal-mail": 303,
"dpd": 303,
"dpd-4000": 378
},
"dimLb": {
"iata": 556,
"courier-5000": 664,
"dhl-express": 664,
"fedex": 664,
"ups": 664,
"usps": 556,
"royal-mail": 664,
"dpd": 664,
"dpd-4000": null
}
}
],
"usage": {
"used": 1,
"limit": 500,
"month": "2026-10"
}
}GET /api/pro/account
Returns the plan, calls used in the current UTC month, the period end, and, on Pro Plus, the embed snippet. An operator key returns kind admin, brandedEmbed false, and the message Operator keys are not tied to a plan.
Subscriber response
{
"kind": "subscriber",
"plan": "plus",
"planName": "Pro Plus",
"limit": 10000,
"used": 12,
"month": "2026-10",
"brandedEmbed": true,
"brand": {
"name": "Northline",
"color": "#0e4f5c",
"url": null,
"slug": "examplebrand"
},
"embed": "<script src=\"https://freightmath.io/embed.js\" data-brand=\"examplebrand\" async></script>",
"cancelAtPeriodEnd": false,
"currentPeriodEnd": "2026-11-16T00:00:00.000Z",
"email": "ada@shipper.example"
}POST /api/pro/account
Pro Plus only. name is 1 to 60 characters, color is a hex colour such as #0e4f5c, and url is empty or an https link of at most 200 characters. Pro receives 403 Branded embeds are included with Pro Plus. The public embed script is /embed.js with data-brand set to the subscription slug. It frames /embed/freight-class.
Request
{
"name": "Northline",
"color": "#0e4f5c",
"url": "https://northline.example"
}Response
{
"ok": true,
"brand": {
"ok": true,
"name": "Northline",
"color": "#0e4f5c",
"url": "https://northline.example/"
}
}Errors
- 401Use a bearer API key.
- 402This subscription is not active.
- 403Branded embeds are included with Pro Plus.
- 400Invalid calculation request.
- 400Send 500 rows or fewer.
- 400Empty CSV.
- 400The CSV is empty.
- 400Missing columns:
- 400unit_system must be metric or imperial.
- 400Enter a brand name up to 60 characters.
- 400Use a hex colour such as #0e4f5c.
- 400Brand link must be an https URL.
- 400Brand link is too long.
- 429Too many requests.
- 429Too many requests. Try again later.
- 429Monthly API call limit reached.
- 503FreightMath is temporarily paused.
- 503API keys are not available yet.
OpenAPI for these two routes is at /api/openapi.json.
Examples
curl
curl https://freightmath.io/api/v1/calculate \
-H "Authorization: Bearer fm_your_key" \
-H "Content-Type: application/json" \
-d '{"rows":[{"sku":"PAL-1","unitSystem":"imperial","length":48,"width":40,"height":48,"weight":500,"quantity":1}]}'JavaScript
const response = await fetch("https://freightmath.io/api/v1/calculate", {
method: "POST",
headers: {
Authorization: "Bearer fm_your_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
"rows": [
{
"sku": "PAL-1",
"unitSystem": "imperial",
"length": 48,
"width": 40,
"height": 48,
"weight": 500,
"quantity": 1
}
]
}),
});
const data = await response.json();Python
import json
import urllib.request
body = json.dumps({"rows":[{"sku":"PAL-1","unitSystem":"imperial","length":48,"width":40,"height":48,"weight":500,"quantity":1}]}).encode()
request = urllib.request.Request(
"https://freightmath.io/api/v1/calculate",
data=body,
headers={
"Authorization": "Bearer fm_your_key",
"Content-Type": "application/json",
},
)
print(json.load(urllib.request.urlopen(request)))