API reference 1.0.0-alpha.1
Boxmile Public API
The Boxmile API for your own integrations: rate shipments, track parcels, check addresses and read your balance, with an API key. JSON fields are lowerCamelCase; money is integer US cents in ...Cents fields; timestamps are RFC 3339 UTC. Errors are RFC 9457 problem+json with a stable code. Every answer carries X-Request-Id, and every keyed answer the IETF RateLimit-Policy and RateLimit headers. Within v1, changes are additive only.
The API follows REST. Requests and answers are JSON over HTTPS, and every answer carries an X-Request-Id to quote when you contact us.
https://api.boxmile.comcurl https://api.boxmile.com/v1/services \
-H "Authorization: Bearer $BOXMILE_API_KEY"const response = await fetch('https://api.boxmile.com/v1/services', {
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.get(
"https://api.boxmile.com/v1/services",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json())Authentication
Send your API key as a bearer token: Authorization: Bearer <your API key>. A key belongs to one workspace, and every request acts for that workspace only. To get a key, ask us for API access.
boxmile_sk_live_…Live keys act on real data and money.boxmile_sk_test_…Test keys are read-only.
Keep keys on your server, never in a browser or an app, and read them from the environment as the samples do with BOXMILE_API_KEY.
Scopes
Each endpoint names the scope its key needs. A key with * has every scope.
rates.readThe service catalog and your rate requests.
rates.writeRate a parcel. Nothing is bought.
labels.readTracking.
addresses.readAddress validation.
balance.readYour balance.
A missing, malformed, unknown, revoked or expired key gets 401. A key without the scope, or whose workspace is not active, gets 403. Refused keys count against a limit of 30 a minute for each client address.
curl https://api.boxmile.com/v1/balance \
-H "Authorization: Bearer $BOXMILE_API_KEY"Errors
Errors are RFC 9457 problem details (application/problem+json). Branch on status and the stable code; title is plain text for people and is translated. instance repeats the request ID.
- 400
request.invalid - 401
authentication.required - 403
access.denied - 404
resource.not_found - 429
api.rate_limited - 503
service.unavailable
{
"type": "about:blank",
"title": "Check the request and try again.",
"status": 400,
"code": "request.invalid",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}Rate limits
Each key draws from buckets that refill over time. Every keyed answer carries the IETF RateLimit-Policy header (the bucket, its burst q and the seconds w it takes to refill) and RateLimit (requests r left now and seconds t until it is full).
An empty bucket answers 429 with Retry-After: wait that many seconds, then try again.
HTTP/1.1 200 OK
X-Request-Id: 0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f
RateLimit-Policy: "reads";q=50;w=2
RateLimit: "reads";r=49;t=1Versioning
The version is the first part of every path. Within it, changes are additive only: new endpoints, new optional fields and new values. Ignore fields you do not know, so a new one never breaks your integration. JSON fields are lowerCamelCase, money is integer US cents in fields ending in Cents, and times are RFC 3339 in UTC.
Use it in Postman
The whole API is one Postman collection, kept in step with this reference.
- Download the collection below.
- In Postman, choose Import and drop in the file. It needs no environment file.
- Open the collection’s Variables tab. baseUrl is already set. Paste your API key into apiKey’s Current value only: Postman keeps current values on your machine, so the key is never shared or exported. Never put a key in an initial value, a request or a file.
- Open Catalog › List the carrier services a key can rate and press Send. Then try Rates › Rate a parcel.
- Each request’s documentation gives its scope, parameters, body fields and errors, and its Examples list holds a saved answer for every documented status.
Catalog
This API's own document and the carrier services a key can rate.
GET/v1/openapi
Read this API's OpenAPI document
The reviewed OpenAPI 3.1 document of this API. It needs no key; reads count against a limit per client address.
No key needed
Responses
- 200
The OpenAPI document.
- 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited
curl https://api.boxmile.com/v1/openapiconst response = await fetch('https://api.boxmile.com/v1/openapi');
const data = await response.json();
console.log(response.status, data);import requests
response = requests.get(
"https://api.boxmile.com/v1/openapi",
timeout=30,
)
print(response.status_code, response.json()){
"openapi": "3.1.0",
"info": {
"title": "Boxmile Public API",
"version": "1.0.0"
}
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}GET/v1/services
List the carrier services a key can rate
Every carrier service this deployment offers, in its configured order. Services name the carrier and the carrier's service, never the account or partner that fulfils it. The list has no further page.
Key scope rates.read
Responses
- 200
The services.
- 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited - 503
Rating is not configured on this deployment.
service.unavailable
curl https://api.boxmile.com/v1/services \
-H "Authorization: Bearer $BOXMILE_API_KEY"const response = await fetch('https://api.boxmile.com/v1/services', {
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.get(
"https://api.boxmile.com/v1/services",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json()){
"object": "list",
"items": [
{
"object": "service",
"code": "USPS_GROUND_ADVANTAGE",
"carrier": "usps",
"carrierName": "USPS",
"serviceName": "USPS Ground Advantage"
}
],
"nextCursor": null
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}503service.unavailable
{
"type": "about:blank",
"title": "This feature is not available yet. Try again later.",
"status": 503,
"code": "service.unavailable",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}Rates
Prices for a parcel from the same pipeline as the web app. Nothing is bought.
POST/v1/rates
Rate a parcel
Rates one parcel to one destination, from fromAddress or else your workspace's default origin, for the services named (default: every service in GET /v1/services). Each price comes from the same rating and pricing pipeline as the Boxmile web app, and nothing is bought. The server waits a few seconds: a finished request answers 201, one still rating answers 202 with a Location to poll. A service with no price is listed under unavailable with a reason. Each rate's id is the quote, and its price holds until expiresAt (15 minutes). Test keys can rate.
Key scope rates.write
Request body
toAddressAddressRequiredA postal address. Give postalCode, or city and state. A destination without line1 is rated at a placeholder street, which does not change a price.
Show child attributesHide child attributes
namestringDefaults to Recipient (destination) or Shipping Dept (origin).
up to 200 characters
companystringCompany name.
up to 200 characters
line1stringStreet line 1.
up to 200 characters
line2stringStreet line 2.
up to 200 characters
citystringCity or town.
up to 200 characters
statestringState, province or region code.
up to 200 characters
postalCodestringZIP or postal code.
up to 200 characters
countrystringISO 3166-1 alpha-2 country code.
pattern ^[A-Za-z]{2}$, default US
phonestringPhone number.
up to 200 characters
emailstringEmail address.
up to 200 characters
residentialboolean or nullWhether the address is a residence.
default false
fromAddressAddress or nullLeave out to ship from your workspace's default origin.
Show child attributesHide child attributes
namestringDefaults to Recipient (destination) or Shipping Dept (origin).
up to 200 characters
companystringCompany name.
up to 200 characters
line1stringStreet line 1.
up to 200 characters
line2stringStreet line 2.
up to 200 characters
citystringCity or town.
up to 200 characters
statestringState, province or region code.
up to 200 characters
postalCodestringZIP or postal code.
up to 200 characters
countrystringISO 3166-1 alpha-2 country code.
pattern ^[A-Za-z]{2}$, default US
phonestringPhone number.
up to 200 characters
emailstringEmail address.
up to 200 characters
residentialboolean or nullWhether the address is a residence.
default false
parcelParcelRequiredShow child attributesHide child attributes
weightOznumberRequiredWeight in ounces.
more than 0, at most 2400
lengthInnumberLength in inches.
more than 0, at most 120
widthInnumberWidth in inches.
more than 0, at most 120
heightInnumberHeight in inches.
more than 0, at most 120
servicesarray of string or nullService codes from GET /v1/services. Leave out to rate every service.
1 to 64 items, no repeats
Responses
- 201
Rated. Location is this rate request.
- 202
Still rating after the server's wait (a few seconds). Poll Location; Retry-After is a hint in seconds.
- 400
The body is not valid JSON, has a field this API does not know, misses a required field, has a value out of range, or names a service the catalog does not offer.
request.invalid - 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited - 503
Rating is not configured on this deployment.
service.unavailable
curl https://api.boxmile.com/v1/rates \
-X POST \
-H "Authorization: Bearer $BOXMILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"toAddress": {
"name": "Ada Lovelace",
"line1": "34 Example Road",
"city": "New York",
"state": "NY",
"postalCode": "10001",
"country": "US",
"residential": true
},
"parcel": {
"weightOz": 12,
"lengthIn": 6,
"widthIn": 4,
"heightIn": 2
},
"services": [
"USPS_GROUND_ADVANTAGE",
"UPS_GROUND"
]
}'const response = await fetch('https://api.boxmile.com/v1/rates', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
toAddress: {
name: 'Ada Lovelace',
line1: '34 Example Road',
city: 'New York',
state: 'NY',
postalCode: '10001',
country: 'US',
residential: true,
},
parcel: {
weightOz: 12,
lengthIn: 6,
widthIn: 4,
heightIn: 2,
},
services: [
'USPS_GROUND_ADVANTAGE',
'UPS_GROUND',
],
}),
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.post(
"https://api.boxmile.com/v1/rates",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
json={
"toAddress": {
"name": "Ada Lovelace",
"line1": "34 Example Road",
"city": "New York",
"state": "NY",
"postalCode": "10001",
"country": "US",
"residential": True,
},
"parcel": {
"weightOz": 12,
"lengthIn": 6,
"widthIn": 4,
"heightIn": 2,
},
"services": [
"USPS_GROUND_ADVANTAGE",
"UPS_GROUND",
],
},
timeout=30,
)
print(response.status_code, response.json()){
"object": "rate_request",
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f",
"status": "completed",
"failureReason": null,
"createdAt": "2026-10-20T03:00:00Z",
"rates": [
{
"object": "rate",
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e01",
"service": "USPS_GROUND_ADVANTAGE",
"carrier": "usps",
"carrierName": "USPS",
"serviceName": "USPS Ground Advantage",
"amountCents": 725,
"currency": "usd",
"expiresAt": "2026-10-20T03:15:00Z"
}
],
"unavailable": [
{
"service": "UPS_GROUND",
"reason": "no_rate"
}
]
}202Still rating after the server's wait (a few seconds). Poll Location; Retry-After is a hint in seconds.
{
"object": "rate_request",
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f",
"status": "pending",
"failureReason": null,
"createdAt": "2026-10-20T03:00:00Z",
"rates": [],
"unavailable": []
}400request.invalid
{
"type": "about:blank",
"title": "Check the request and try again.",
"status": 400,
"code": "request.invalid",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}503service.unavailable
{
"type": "about:blank",
"title": "This feature is not available yet. Try again later.",
"status": 503,
"code": "service.unavailable",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}GET/v1/rate-requests/{id}
Read a rate request
A rate request this API key made, as it stands now; another key, even of the same workspace, gets 404. While status is pending, poll again after Retry-After seconds.
Key scope rates.read
Path parameters
idstringRequiredThe rate request's id.
uuid
Responses
- 200
The rate request.
- 400
The id is not a UUID.
request.invalid - 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 404
No rate request with this id was made by your workspace's API keys.
resource.not_found - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited - 503
Rating is not configured on this deployment.
service.unavailable
curl https://api.boxmile.com/v1/rate-requests/0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f \
-H "Authorization: Bearer $BOXMILE_API_KEY"const response = await fetch('https://api.boxmile.com/v1/rate-requests/0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f', {
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.get(
"https://api.boxmile.com/v1/rate-requests/0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json()){
"object": "rate_request",
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f",
"status": "completed",
"failureReason": null,
"createdAt": "2026-10-20T03:00:00Z",
"rates": [
{
"object": "rate",
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e01",
"service": "USPS_GROUND_ADVANTAGE",
"carrier": "usps",
"carrierName": "USPS",
"serviceName": "USPS Ground Advantage",
"amountCents": 725,
"currency": "usd",
"expiresAt": "2026-10-20T03:15:00Z"
}
],
"unavailable": [
{
"service": "UPS_GROUND",
"reason": "no_rate"
}
]
}400request.invalid
{
"type": "about:blank",
"title": "Check the request and try again.",
"status": 400,
"code": "request.invalid",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}404resource.not_found
{
"type": "about:blank",
"title": "The requested resource was not found.",
"status": 404,
"code": "resource.not_found",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}503service.unavailable
{
"type": "about:blank",
"title": "This feature is not available yet. Try again later.",
"status": 503,
"code": "service.unavailable",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}Tracking
Delivery status and carrier scans of your workspace's parcels.
GET/v1/tracking/{trackingNumber}
Track a parcel
The delivery status and carrier scans, newest first, of the parcel with this tracking number that your workspace shipped. A parcel of another workspace, a voided label and an unknown number all answer 404. Test keys can track.
Key scope labels.read
Path parameters
trackingNumberstringRequiredThe carrier tracking number, exactly as on the label (letters and digits).
pattern ^[A-Za-z0-9]{4,64}$
Responses
- 200
The parcel's tracking.
- 400
The tracking number is not 4 to 64 letters and digits.
request.invalid - 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 404
Your workspace has no live parcel with this tracking number.
resource.not_found - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited - 503
Tracking is not configured on this deployment, or its store is busy. Try again later.
service.unavailable
curl https://api.boxmile.com/v1/tracking/1Z999AA10123456784 \
-H "Authorization: Bearer $BOXMILE_API_KEY"const response = await fetch('https://api.boxmile.com/v1/tracking/1Z999AA10123456784', {
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.get(
"https://api.boxmile.com/v1/tracking/1Z999AA10123456784",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json()){
"object": "tracking",
"trackingNumber": "1Z999AA10123456784",
"carrier": "ups",
"carrierName": "UPS",
"status": "in_transit",
"events": [
{
"id": "0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e10",
"occurredAt": "2026-10-20T02:10:00Z",
"status": "In transit",
"description": "Departed facility",
"location": "Louisville, KY"
}
]
}400request.invalid
{
"type": "about:blank",
"title": "Check the request and try again.",
"status": 400,
"code": "request.invalid",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}404resource.not_found
{
"type": "about:blank",
"title": "The requested resource was not found.",
"status": 404,
"code": "resource.not_found",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}503service.unavailable
{
"type": "about:blank",
"title": "This feature is not available yet. Try again later.",
"status": 503,
"code": "service.unavailable",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}Addresses
Address checks. Nothing is stored and no carrier is asked.
POST/v1/addresses/validate
Validate an address
Checks one address's form and answers it standardized. Every address needs line1 and city, and a country Boxmile recognizes and may ship to (sanctioned countries and regions are refused). A US-domestic address (US and the USPS-domestic territories) also needs a USPS state, by code or name, and a 5- or 9-digit ZIP. The state becomes its code, a 9-digit ZIP is written 12345-6789 and runs of spaces become one. No carrier is asked, so carrierVerified is false: a valid address is unverified, or standardized when its form changed. An address that fails a check is a 200 with status invalid and each field's reason. Nothing is stored. Test keys can validate.
Key scope addresses.read
Request body
namestringDefaults to Recipient (destination) or Shipping Dept (origin).
up to 200 characters
companystringCompany name.
up to 200 characters
line1stringStreet line 1.
up to 200 characters
line2stringStreet line 2.
up to 200 characters
citystringCity or town.
up to 200 characters
statestringState, province or region code.
up to 200 characters
postalCodestringZIP or postal code.
up to 200 characters
countrystringISO 3166-1 alpha-2 country code.
pattern ^[A-Za-z]{2}$, default US
phonestringPhone number.
up to 200 characters
emailstringEmail address.
up to 200 characters
residentialboolean or nullWhether the address is a residence.
default false
Responses
- 200
The address's validation.
- 400
The body is not an Address: not JSON, an unknown field, a value that is not text, text over 200 characters, or a country that is not two letters.
request.invalid - 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited
curl https://api.boxmile.com/v1/addresses/validate \
-X POST \
-H "Authorization: Bearer $BOXMILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"line1": "34 Example Road",
"city": "New York",
"state": "new york",
"postalCode": "100011234"
}'const response = await fetch('https://api.boxmile.com/v1/addresses/validate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
line1: '34 Example Road',
city: 'New York',
state: 'new york',
postalCode: '100011234',
}),
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.post(
"https://api.boxmile.com/v1/addresses/validate",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
json={
"line1": "34 Example Road",
"city": "New York",
"state": "new york",
"postalCode": "100011234",
},
timeout=30,
)
print(response.status_code, response.json()){
"object": "address_validation",
"status": "standardized",
"carrierVerified": false,
"address": {
"line1": "34 Example Road",
"line2": null,
"city": "New York",
"state": "NY",
"postalCode": "10001-1234",
"country": "US"
},
"errors": [],
"notices": [
"review_formatting",
"not_verified"
]
}400request.invalid
{
"type": "about:blank",
"title": "Check the request and try again.",
"status": 400,
"code": "request.invalid",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}Balance
Your workspace's wallet totals. Read only.
GET/v1/balance
Read your balance
Your workspace's wallet totals, the same figures the Boxmile web app's billing summary shows. availableCents is what label purchases can spend from: the balance less what is reserved and, while it is on, the carrier-adjustment reserve; it can be negative. reservedCents is the total held for purchases and disputes in flight. No hold by order, payment method or funding reference is shown. Test keys can read the balance.
Key scope balance.read
Responses
- 200
The balance.
- 401
The key is missing, malformed, unknown, revoked or expired.
authentication.required - 403
The key lacks this operation's scope, or its workspace is not active.
access.denied - 429
The bucket is empty. Wait Retry-After seconds.
api.rate_limited - 503
The wallet could not be read in time. Try again later.
service.unavailable
curl https://api.boxmile.com/v1/balance \
-H "Authorization: Bearer $BOXMILE_API_KEY"const response = await fetch('https://api.boxmile.com/v1/balance', {
headers: {
Authorization: `Bearer ${process.env.BOXMILE_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.get(
"https://api.boxmile.com/v1/balance",
headers={"Authorization": f"Bearer {os.environ['BOXMILE_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json()){
"object": "balance",
"availableCents": 12345,
"reservedCents": 300,
"currency": "usd"
}401authentication.required
{
"type": "about:blank",
"title": "Sign in to continue.",
"status": 401,
"code": "authentication.required",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}403access.denied
{
"type": "about:blank",
"title": "You do not have permission to perform this action.",
"status": 403,
"code": "access.denied",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}429api.rate_limited
{
"type": "about:blank",
"title": "Too many requests. Wait the number of seconds in the Retry-After header, then try again.",
"status": 429,
"code": "api.rate_limited",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}503service.unavailable
{
"type": "about:blank",
"title": "This feature is not available yet. Try again later.",
"status": 503,
"code": "service.unavailable",
"params": {},
"locale": "en",
"instance": "urn:boxmile:request:0192f7a0-5c1e-7d3a-9b2e-4f6a8c0d1e2f"
}
