API overview
The Bigfoot Delivery API lets your system get prices for, order and track same-day deliveries in the Seattle area without going through our website.
You can:
- Get prices. Send pickup, delivery, package and ready time. Get back every service available for that shipment, with its price and delivery deadline.
- Place orders. Choose a service from the quote and order it. Get back a tracking number.
- Track. Look up status and the current price by tracking number.
- Review invoices. List your invoices and see the final price of every order on them.
- Test base URL
https://test-api.bigfootdelivery.app- Production base URL
https://api.bigfootdelivery.app- Authentication
Authorization: Bearer <YOUR_API_KEY>- Format
- JSON over HTTPS (TLS 1.2 or newer)
- Time zone
- Pacific Time. Deadlines and order times come back as ISO 8601 and as a display string.
- Currency
- USD
- Rate limit
- 60 requests per minute, 2,000 per day, per key
- Service area
- King, Pierce and Snohomish counties.
- Version
- v1. Every path starts with
/v1.
Getting started
-
Get your key
We send your API key by a one-time secure link. The link opens once, then the key is gone. Save the key in your password manager or secret store before you close the page.
If the link expired or someone else opened it, tell us. We will issue a new key.
-
Store it on your server
Keep the key in an environment variable or secret store. The examples below read it from
BIGFOOT_API_KEY. -
Get a quote
Send the shipment details to
POST /v1/quoteswithout aservice. You get back every available service, cheapest first. -
Place the order
Send the
quoteIdof the service you chose toPOST /v1/orderswithin 30 minutes. You get back a tracking number. The price matches the quote. -
Track it
Call
GET /v1/orders/{trackingNumber}for status and current price.
Complete example
Names, phone numbers, prices and IDs below are examples. The addresses are public landmarks (Pike Place Market and the Space Needle), so the requests work as written against the test URL.
The examples use a Unix shell (macOS, Linux, or Git Bash or WSL on Windows). Set these first:
export BASE_URL="https://test-api.bigfootdelivery.app" export BIGFOOT_API_KEY="<YOUR_API_KEY>"
1. Quote
curl -X POST "$BASE_URL/v1/quotes" \
-H "Authorization: Bearer $BIGFOOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pickup": {
"company": "Acme Kitchen",
"contact": "Dana Lee",
"phone": "206-555-0100",
"address1": "85 Pike St",
"city": "Seattle",
"state": "WA",
"postalCode": "98101"
},
"delivery": {
"company": "Northwind Offices",
"contact": "Sam Ortiz",
"phone": "206-555-0199",
"address1": "400 Broad St",
"city": "Seattle",
"state": "WA",
"postalCode": "98109"
},
"readyTime": "2026-12-15T09:00:00-08:00",
"package": { "pieces": 1, "weightLb": 10, "lengthIn": 12, "widthIn": 12, "heightIn": 12 },
"reference": "SO-10442"
}'{
"distanceMiles": 1.2,
"readyTimeDisplay": "Tue, Dec 15, 9:00 AM PT",
"options": [
{
"service": "standard",
"serviceName": "Courier Standard",
"description": "Delivered by end of day",
"price": { "base": 30, "options": [], "total": 30, "currency": "USD" },
"deliverBy": "2026-12-15T17:00:00-08:00",
"deliverByDisplay": "Tue, Dec 15, 5:00 PM PT",
"quoteId": "q_k3Vd8Qm2LxR7nPa1sT9wYb",
"expiresAtDisplay": "Tue, Dec 15, 8:40 AM PT"
},
{
"service": "rush",
"serviceName": "Courier Rush",
"description": "Delivered within 2 hours of ready time",
"price": { "base": 40, "options": [], "total": 40, "currency": "USD" },
"deliverBy": "2026-12-15T11:00:00-08:00",
"deliverByDisplay": "Tue, Dec 15, 11:00 AM PT",
"quoteId": "q_Z8mPq4Tn6Wc2Hs9Lk1Ve3R",
"expiresAtDisplay": "Tue, Dec 15, 8:40 AM PT"
},
{
"service": "direct",
"serviceName": "Courier Direct",
"description": "Delivered within 1 hour of ready time",
"price": { "base": 53.5, "options": [], "total": 53.5, "currency": "USD" },
"deliverBy": "2026-12-15T10:00:00-08:00",
"deliverByDisplay": "Tue, Dec 15, 10:00 AM PT",
"quoteId": "q_Hy2Nb7Xr5Fd1Gq8Jm4Ps6T",
"expiresAtDisplay": "Tue, Dec 15, 8:40 AM PT"
}
],
"notAvailable": [
{ "service": "freight", "reason": "Freight is for pallets and shipments over 250 lb or over 60 in on a side" }
]
}2. Place an order for Rush
curl -X POST "$BASE_URL/v1/orders" \
-H "Authorization: Bearer $BIGFOOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "quoteId": "q_Z8mPq4Tn6Wc2Hs9Lk1Ve3R" }'{
"trackingNumber": "123456789",
"status": "submitted",
"service": "rush",
"distanceMiles": 1.2,
"price": { "base": 40, "options": [], "total": 40, "currency": "USD" },
"deliverBy": "2026-12-15T11:00:00-08:00",
"deliverByDisplay": "Tue, Dec 15, 11:00 AM PT"
}3. Check status
curl "$BASE_URL/v1/orders/123456789" \ -H "Authorization: Bearer $BIGFOOT_API_KEY"
Endpoint map
| Method | Path | Use it to | Returns |
|---|---|---|---|
| POST | /v1/quotes | Get prices without placing an order | Every available service, cheapest first, each with a quoteId |
| POST | /v1/orders | Place an order | Tracking number, status, price, delivery deadline |
| GET | /v1/orders/{trackingNumber} | Check one order | Status, current price, times |
| GET | /v1/invoices | List your invoices | Invoice summaries, 25 per page by default |
| GET | /v1/invoices/{invoiceNumber} | See one invoice | Summary plus each order's final price |
POST/v1/quotes
Prices a shipment. No order is placed.
- Without
service: returns every available service inoptions[], cheapest first. Services that aren't available are innotAvailable[]with the reason. - With
service: returns only that service. If it isn't available, you get422 service_not_availableand the message lists the services that are, with prices. - In a quote,
options[]is the list of services to choose from. It is not the extra charges. - Each service in the quote has its own
quoteId. It is valid for 30 minutes (expiresAtDisplay). - If no service is available, you get
422 service_not_availablewith the reasons.
Request body: see request fields. Response: see the complete example.
POST/v1/orders
Places an order. Two ways:
| Send | What happens | Use when |
|---|---|---|
quoteId | Places the order at the quoted price. | Recommended. You got a quote and chose a service. Safe to retry (see Retries). |
service + full shipment | Prices and places the order in one call. The response has the price. | You always use the same service and don't show a price first. |
With a quoteId you can send only the quoteId. You can also change contact names, phones, emails, company names, description, reference and purchaseOrder. Addresses, ready time, package and options must match the quote or be left out. If they differ, you get 400 and need a new quote.
Response: trackingNumber, status, service, distanceMiles, price, deliverBy, deliverByDisplay.
GET/v1/orders/{trackingNumber}
Returns one of your orders. The price is current, so charges added later (for example wait time) show here.
{
"trackingNumber": "123456789",
"status": "in_transit",
"service": "rush",
"distanceMiles": 1.2,
"price": { "base": 40, "options": [], "total": 40, "currency": "USD" },
"deliverBy": "2026-12-15T11:00:00-08:00",
"deliverByDisplay": "Tue, Dec 15, 11:00 AM PT",
"readyTime": "2026-12-15T09:00:00-08:00",
"readyTimeDisplay": "Tue, Dec 15, 9:00 AM PT",
"submittedAt": "2026-12-15T08:12:40-08:00",
"submittedAtDisplay": "Tue, Dec 15, 8:12 AM PT"
}A tracking number that isn't on your account returns 404 order_not_found.
GET/v1/invoices?offset=0&limit=25
Lists your invoices. limit is 1 to 50 (default 25). offset starts at 0. total is the number of invoices.
{
"invoices": [
{
"invoiceNumber": 12345,
"date": "2026-12-31",
"dateDisplay": "Thu, Dec 31, 2026",
"dueDate": "2027-01-30",
"dueDateDisplay": "Sat, Jan 30, 2027",
"isPaid": false,
"totalAmount": 412.5,
"currency": "USD",
"orderCount": 6
}
],
"offset": 0,
"limit": 25,
"total": 1
}GET/v1/invoices/{invoiceNumber}?offset=0&limit=25
One invoice: the summary fields above plus its orders. offset and limit page through the orders.
- Every order on the invoice is listed, including orders placed by phone, email or our website.
placedViaisapifor orders placed through this API,otherfor the rest.quotedTotalanddifferenceFromQuoteare filled in forapiorders only, and arenullotherwise.- Charges added later that have no specific name show as "Additional charge".
{
"invoiceNumber": 12345,
"orders": [
{
"trackingNumber": "123456789",
"service": "rush",
"serviceName": "Courier Rush",
"reference": "SO-10442",
"purchaseOrder": "PO-7781",
"placedVia": "api",
"price": {
"base": 40,
"options": [{ "name": "Additional charge", "amount": 12 }],
"total": 52,
"currency": "USD"
},
"quotedTotal": 40,
"differenceFromQuote": 12
}
],
"ordersOffset": 0,
"ordersLimit": 25
}An unknown invoice number returns 404 invoice_not_found.
Requests and responses
Conventions
- Send
Content-Type: application/jsonon POST requests. Bodies must be under 32 KB. - Field names are camelCase and case-sensitive.
- Unknown fields are rejected with
400 invalid_request. Send only the fields listed here. - Responses may gain new fields over time. Ignore fields you don't use.
- Every response has an
X-Request-Idheader. Log it. We need it to look up a request.
Request fields (quotes and orders)
Quotes and orders use the same body. On orders, everything except quoteId is optional when you send a quoteId.
| Field | Type | Required | Notes |
|---|---|---|---|
service | string | No | standard, rush, direct or freight. Required on orders without a quoteId. |
pickup | object | Yes | Address fields below. |
delivery | object | Yes | Address fields below. |
readyTime | string | Yes | When the package is ready for pickup. Must be in the future. See Times. |
package | object | Yes | Package fields below. |
options | string[] | No | Extra services you request. See Options. Up to 20. |
description | string | No | What's in the package. Up to 500 characters. |
reference | string | No | Your order or job number. Up to 50 characters. Shown on invoices. |
purchaseOrder | string | No | Your PO number. Up to 50 characters. Shown on invoices. |
quoteId | string | Orders only | The quoteId of the service you chose from the quote. |
Address fields (pickup, delivery)
| Field | Type | Required | Notes |
|---|---|---|---|
company | string | No | Up to 100 characters |
contact | string | No | Person the driver asks for. Up to 100 characters. |
phone | string | No | Up to 30 characters |
email | string | No | Valid email or empty |
address1 | string | Yes | Street address. Up to 100 characters. |
address2 | string | No | Suite, floor, unit |
city | string | Yes | Up to 60 characters |
state | string | Yes | 2-letter code, e.g. WA |
postalCode | string | Yes | 98101 or 98101-1234 |
residential | boolean | No | Default false. true adds the residential charge. |
Package fields
| Field | Type | Required | Notes |
|---|---|---|---|
pieces | integer | Yes | 1 to 999 |
weightLb | number | Yes | Total weight of all pieces, in pounds |
lengthIn | number | Yes | Inches, per piece |
widthIn | number | Yes | Inches, per piece |
heightIn | number | Yes | Inches, per piece |
Price object
Every price has the same shape:
{
"base": 40,
"options": [{ "name": "Residential delivery", "amount": 5 }],
"total": 45,
"currency": "USD"
}totalis the amount charged. Use it, not the sum of the parts.options[]lists each extra charge. In a quote, any charge not tied to one option shows as "Other charges". Charges added after the order without a specific name show as "Additional charge".
Times
Delivery deadlines and order times come back twice. In a quote, readyTimeDisplay and expiresAtDisplay are display strings only.
| Field | Example | Use for |
|---|---|---|
deliverBy | 2026-12-15T17:00:00-08:00 | Your system. ISO 8601 with offset. |
deliverByDisplay | Tue, Dec 15, 5:00 PM PT | Showing to people. Pacific Time, 12-hour. |
readyTime is accepted in either format:
- ISO 8601 with offset:
2026-12-15T09:00:00-08:00 - US format, read as Pacific Time:
12/15/2026 9:00 AM
Invoice dates are plain dates (2026-12-31) with a display string (Thu, Dec 31, 2026).
Order status values
| Status | Meaning |
|---|---|
submitted | Received. No driver assigned yet. |
assigned | A driver is assigned |
in_transit | On the way |
in_progress | In progress |
delivered | Delivered |
cancelled | Cancelled |
Treat any value you don't recognize as in_progress. We may add values.
Errors
Every error has an HTTP status and this body. field is included when one field caused the error.
{
"error": {
"code": "ready_time_too_late",
"message": "Standard: ready time is after the 11:00 AM cutoff for this distance. Available services: rush (Courier Rush) $105.00, direct (Courier Direct) $158.50.",
"field": "readyTime"
}
}Branch on code. The message is written for people and may change.
| HTTP | code | Means | What to do |
|---|---|---|---|
| 400 | invalid_request | A field is missing, malformed or unknown, or an order doesn't match its quote | Fix the field named in field. Don't resend unchanged. |
| 401 | unauthorized | Key missing, wrong or revoked | Check the header. Then contact us. |
| 404 | order_not_found | No order with that tracking number on your account | Check the number. |
| 404 | invoice_not_found | No invoice with that number on your account | Check the number. |
| 404 | not_found | Unknown path | Check the URL and /v1 prefix. |
| 405 | method_not_allowed | Wrong HTTP method | Use the method in the endpoint map. |
| 409 | quote_expired | The quote is over 30 minutes old | Get a new quote. The price may have changed. |
| 422 | outside_service_area | An address is outside our area, or the trip is over 44 miles | Call us at 425-888-0100 for a manual quote. |
| 422 | ready_time_too_late | Ready time is past this service's cutoff | Request a quote without service to see which services are still available, or choose a later day. |
| 422 | service_not_available | The service isn't available for this shipment (weight, size or time) | The message lists the available services, with prices. Request a new quote without service. |
| 422 | address_not_found | We couldn't locate an address, or there's no driving route | Check street, city and ZIP. |
| 429 | rate_limited | Over your request limit | Wait and retry with backoff. |
| 500 | internal_error | Something failed on our side | Retry once. If it repeats, send us the X-Request-Id. |
| 502 | upstream_unavailable | Our system is temporarily unavailable | Retry later. On orders, read Retries first. |
Services and options
You don't need to know our services to use the API. Request a quote without service and choose from the services that come back. The quote always has the delivery deadline.
| Service | Max weight | Max size | Timing |
|---|---|---|---|
Standardstandard | 200 lb | 60 in any side | Ready by 12:00 PM (under 30 mi) or 11:00 AM (30–44 mi). Delivered by 5:00 PM. |
Rushrush | 250 lb | 60 in any side | Delivered within 2 hours of ready time (under 5 mi), up to 4.5 hours (35–44 mi) |
Directdirect | 250 lb | 60 in any side | Delivered within 1 hour of ready time (under 5 mi), up to 3.5 hours (35–44 mi) |
Freightfreight | 6,000 lb | 14 × 8 × 7 ft | Ready by 1:00 PM (under 25 mi) or 12:00 PM (25–44 mi). Delivered by 5:00 PM. |
- Distance: driving miles, up to 44 for every service.
- Area: pickup and delivery in King, Pierce or Snohomish county.
- Freight is offered only for shipments over 250 lb or over 60 in on a side. Those shipments get Freight only.
- Weight is total weight. Per-piece weight is total ÷ pieces.
- Dimensional weight = pieces × length × width × height ÷ 139. Prices use the higher of actual and dimensional weight.
Options
Added automatically. Don't send these. Sending one returns 400.
| Charge | Added when |
|---|---|
| Residential pickup / delivery | pickup.residential or delivery.residential is true |
| Weekend | readyTime is on a Saturday or Sunday |
| Holiday | readyTime is on a holiday |
Request these in options[] when you need them:
| Send | Means |
|---|---|
call_before_pickup | Driver calls the pickup contact before arriving |
call_before_delivery | Driver calls the delivery contact before arriving |
Each option appears as its own line in price.options[].
Added by the driver after pickup. As with orders placed on our website, these charges are not in the quote. They show in the order's current price and on the invoice:
- Pieces over 70 lb
- Any side over 48 in
- Stairs or limited access at pickup or delivery
- Pickup or drop-off at an air or marine cargo terminal
Use description to tell us about stairs or a cargo terminal in advance.
Safeguards and limits
| Safeguard | Detail |
|---|---|
| Rate limit | 60 requests per minute and 2,000 per day per key. The daily count resets at midnight UTC (4:00 PM PT, or 5:00 PM PT in summer). Over the limit returns 429. Ask us if you need more. |
| Request size | 32 KB maximum body |
| Strict fields | Unknown fields are rejected. |
| Your data only | A key sees only its own orders and invoices. Anything else returns 404. |
| Quote expiry | A quoteId is valid for 30 minutes |
| Encryption | HTTPS with TLS 1.2 or newer only |
| Outages | If our system is temporarily unavailable you get 502. Requests are not held for later. Retry, or call us at 425-888-0100. |
Charges added after an order
The order price matches the quote. As with orders placed on our website, we may add charges after the order is placed (for example wait time). The current price is always on GET /v1/orders/{trackingNumber}, and the final price is on the invoice.
Retries and duplicate orders
If a request fails or times out, use the table below to decide whether to resend it.
Place orders with a quoteId. If you send the same quoteId again, you get back the order already placed. That makes resending safe.
| Situation | Do this |
|---|---|
Timeout or network error on POST /v1/orders with a quoteId | Resend the same request. If the first one went through, you get that order back. If it didn't, the order is placed now. |
Same, but without a quoteId | Don't retry automatically. Call us at 425-888-0100 to check whether the order went through. |
400: "already being placed" | Another request for this quote is in progress. Wait a few seconds, then resend. |
502 or 400 with "may have been created" | Don't retry. Call us at 425-888-0100. We will confirm the order and give you the tracking number. |
502 on any other request | Retry with backoff: wait 2, 4, then 8 seconds. Stop after 3 tries. |
429 | Wait at least 60 seconds before retrying. |
4xx other than 429 | Don't retry. Fix the request. |
Quotes and GET requests are always safe to retry.
Testing and go-live
-
Build with your test key
Use the test URL and your test key while you build. Quotes create nothing on our side. To see the full flow, you can place a test order. One is plenty. It's marked TEST and we cancel it, so no driver is sent and nothing is billed. If anything looks off, we'll call you.
-
Ask for your production key
When you're ready, email info@bigfootdelivery.com. We send your production key by secure link. Switch your base URL and key together.
Tips for going live
Support
info@bigfootdelivery.com
425-888-0100
425-888-0100
info@bigfootdelivery.com
Include:
- The
X-Request-Idfrom the response - The tracking number or
quoteId, if any - The time of the request (Pacific Time)
- The error
codeandmessage
Never send us your API key. We never ask for it.
Versioning
- This is version 1. Every path starts with
/v1. - We may add fields, status values, options and error codes to v1 without notice. Build to ignore what you don't recognize.
- We won't remove or rename fields in v1. Breaking changes come as a new version, with advance notice by email.
- Service limits, cutoffs and prices can change. The quote always reflects the current rules.
FAQ
Can I change or cancel an order through the API?
No. Call us at 425-888-0100 with the tracking number.
Why does the invoice price differ from the quote?
A charge was added after the order was placed, such as wait time. differenceFromQuote shows the amount.
Do I need a quote before every order?
No. You can place an order with service and the full shipment. A quote first shows you the price, and makes retries safe.
What about deliveries over 44 miles, multiple stops or recurring routes?
Not available through the API. Call us at 425-888-0100.