{"openapi":"3.1.0","info":{"title":"Warp Agent API","version":"1.18.1","description":"Programmatic freight quoting, booking, tracking, invoicing, and document retrieval for AI agents and integrations. Supports cargo van, box truck, FTL, LTL, and FTL multi-stop modes.","contact":{"name":"Warp API","url":"https://www.wearewarp.com/freight-api","email":"developers@wearewarp.com"},"license":{"name":"Apache-2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"},"x-logo":{"url":"https://www.wearewarp.com/warp-logo.svg","altText":"Warp"}},"externalDocs":{"description":"Warp Freight API guide: full endpoint reference, code samples, MCP server, CLI, sandbox keys.","url":"https://www.wearewarp.com/freight-api"},"servers":[{"url":"https://www.wearewarp.com/api/v1"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key issued instantly by POST /agents/signup (JSON, no browser, no card). Format: wak_live_* for production, wak_test_* for the sandbox."}},"schemas":{"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","example":"we_…"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"description":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"disabled_at":{"type":"string","format":"date-time","nullable":true},"last_delivered_at":{"type":"string","format":"date-time","nullable":true},"last_error":{"type":"string","nullable":true}}},"QuoteResponse":{"type":"object","properties":{"quote_id":{"type":"string","example":"PRICING_46298af7-e427-4ae7-a6c1-cb2c8bc56805","description":"Your booking token — pass to POST /book to book this quote. This is Warp's canonical quote id: the same id Warp operations can trace, so it is safe to print on tenders, BOLs, and carrier paperwork. (Earlier API versions returned an internal wq_… id here; those ids remain accepted by every endpoint forever.)"},"lane_id":{"type":"string","example":"ln_900_941"},"mode":{"type":"string","enum":["van","box_truck","ftl","ltl"]},"price_usd":{"type":"number","example":1450},"currency":{"type":"string","example":"USD"},"transit_days":{"type":"integer","example":2},"pickup_date":{"type":"string","format":"date"},"delivery_date":{"type":"string","format":"date"},"expires_at":{"type":"string","format":"date-time"},"mode_substituted":{"type":"object","description":"Present ONLY when gw had no LTL service on the lane and substituted a dedicated truck. Additive and optional — absent on every normal LTL quote. service.mode is then 'ftl' and service.vehicle \"53' dry van\" (both existing enum values), and the price is a whole truck, which on a coverage-gap lane can be several times the marketplace LTL rate. Compare with /ltl/market-options before booking.","properties":{"requested":{"type":"string","example":"ltl"},"served":{"type":"string","example":"ftl"},"reason":{"type":"string"},"compare":{"type":"string"}}},"quote_tier":{"type":"string","enum":["firm","indicative"],"description":"firm = all pricing fields present; indicative = an OPTIONAL field (e.g. commodity) is missing. Dims are always required — omitting them returns 400 MISSING_DIMS, not an indicative quote. (LTL only)"},"insurance":{"type":"object","description":"Cargo-insurance quote — present on the quote response ONLY when the request included insuranceInfo and the gateway priced it. Pass insuranceQuoteId to POST /book to bind the policy; total (USD) is funded alongside the freight at booking.","properties":{"insuranceQuoteId":{"type":"string","example":"01J...","description":"Bindable insurance quote id — pass to POST /book as insuranceQuoteId."},"premium":{"type":"number","example":60,"description":"Insurance premium in the quoted currency."},"processingFee":{"type":"number","example":6,"description":"Processing fee in the quoted currency."},"total":{"type":"number","example":66,"description":"premium + processingFee; the amount funded alongside the freight."},"currency_code":{"type":"string","example":"USD"}}},"service":{"type":"object","description":"Service details included with every quote and booking response.","properties":{"mode":{"type":"string","enum":["van","box_truck","ftl","ltl"]},"vehicle":{"type":"string","enum":["Cargo van","26' box truck","53' dry van","LTL (shared)"]},"pickup_date":{"type":"string","format":"date"},"delivery_date":{"type":"string","format":"date"},"transit_days":{"type":"integer"},"pricing":{"type":"string","example":"all_inclusive"},"included_at_no_charge":{"type":"array","items":{"type":"string"}},"dispatch":{"type":"string","example":"+1 213 267 1373"}}},"assumptions":{"type":"object"},"missing_for_ship":{"type":"array","items":{"type":"string"}},"booking_url":{"type":"string"},"book_tool_call":{"type":"object","properties":{"tool":{"type":"string"},"args":{"type":"object","properties":{"quote_id":{"type":"string"}}}}}}},"BookingResponse":{"type":"object","properties":{"booked":{"type":"boolean","example":true},"shipment_id":{"type":"string","description":"The shipment identifier. Pass this as booking_id to GET /api/v1/track. Distinct from order_id on a real booking; identical to order_id in the sandbox mock."},"shipment_number":{"type":"string"},"order_id":{"type":"string","description":"The order this shipment belongs to. Pass this to GET /api/v1/documents. Distinct from shipment_id on a real booking; identical to shipment_id in the sandbox mock."},"order_number":{"type":"string"},"tracking_number":{"type":"string"},"lane_id":{"type":"string"},"tracking_dashboard":{"type":"string","example":"https://customer.wearewarp.com","description":"Customer dashboard URL for live tracking. Always returned on a successful booking — no separate lookup or async buildout needed."},"insuranceStatus":{"type":"string","enum":["booked","failed"],"description":"Cargo-insurance binding outcome (Hai's gateway field, verbatim). Present ONLY when the booking included an insuranceQuoteId. \"booked\" = policy bound; \"failed\" = the freight still booked but insurance did not — the funded premium remains recoverable (see insurance_note)."},"service":{"type":"object","description":"Service details included with every quote and booking response.","properties":{"mode":{"type":"string","enum":["van","box_truck","ftl","ltl"]},"vehicle":{"type":"string","enum":["Cargo van","26' box truck","53' dry van","LTL (shared)"]},"pickup_date":{"type":"string","format":"date"},"delivery_date":{"type":"string","format":"date"},"transit_days":{"type":"integer"},"pricing":{"type":"string","example":"all_inclusive"},"included_at_no_charge":{"type":"array","items":{"type":"string"}},"dispatch":{"type":"string","example":"+1 213 267 1373"}}}}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"details":{}}},"ServiceBlock":{"type":"object","description":"Service details included with every quote and booking response.","properties":{"mode":{"type":"string","enum":["van","box_truck","ftl","ltl"]},"vehicle":{"type":"string","enum":["Cargo van","26' box truck","53' dry van","LTL (shared)"]},"pickup_date":{"type":"string","format":"date"},"delivery_date":{"type":"string","format":"date"},"transit_days":{"type":"integer"},"pricing":{"type":"string","example":"all_inclusive"},"included_at_no_charge":{"type":"array","items":{"type":"string"}},"dispatch":{"type":"string","example":"+1 213 267 1373"}}},"Accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"UpstreamTracking":{"type":"array","nullable":true,"description":"Live carrier tracking from the gateway, passed through unchanged. An ARRAY with one entry per tracking number (we request one, so 0 or 1 elements). Empty = no tracking record yet. null = the upstream call failed; see upstream_tracking_error.","items":{"type":"object","properties":{"trackingNumber":{"type":"string","example":"S4WRFANF79YY"},"statusInfo":{"type":"object","properties":{"status":{"type":"string","example":"inRouteToDropoff","description":"Carrier vocabulary, e.g. needCarrier, dispatched, arrivedAtPickup, pickupSuccessful, inRouteToWareHouse, inRouteToDropoff, complete. Distinct from the top-level `status`, which is only booked/cancelled."},"lastUpdated":{"type":"string","format":"date-time"}}},"location":{"type":"object","description":"Last known position. Absent until the carrier reports one.","properties":{"latitude":{"type":"number","example":37.382544},"longitude":{"type":"number","example":-122.035183},"lastUpdated":{"type":"string","format":"date-time"}}}}}},"ShipmentEvents":{"type":"object","nullable":true,"description":"Event timeline from the gateway, passed through unchanged. null = the upstream call failed; see events_error.","properties":{"data":{"type":"array","items":{"type":"object","properties":{"eventName":{"type":"string","example":"pickupSuccessful","description":"Machine-readable event key. updateAppointmentTimeAtDelivery / updateAppointmentTimeAtPickup carry the new window under details.appointmentInfo — that is the reschedule signal if you would rather react to a change than poll delivery_window."},"message":{"type":"string","example":"Pickup successful"},"when":{"type":"string","format":"date-time","description":"When the event occurred."},"createdWhen":{"type":"string","format":"date-time","description":"When it was recorded."},"details":{"type":"object","description":"Present on some events only. For appointment updates it holds appointmentInfo { from, to }.","additionalProperties":true}}}}}}}},"paths":{"/quote":{"post":{"operationId":"quoteAllModes","summary":"Quote ALL modes in one call (cargo van, box truck, LTL, FTL)","description":"Fans out to the four per-mode quote endpoints server-side and returns one row per mode, cheapest bookable first. Priced rows carry a quote_id that books via POST /book exactly like a single-mode quote; modes that cannot take the load return available:false with that mode's own reason (e.g. LTL requires dimensions). Same auth model as the per-mode endpoints: works keyless for indicative rates, bookable quote ids with an API key. One call counts as four quotes against rate limits. NOT the same as LTL market options: /quote compares MODES (one firm Warp rate each for cargo van, box truck, LTL, FTL - 'which kind of truck?'), while the LTL market-options surface compares CARRIERS within LTL only ('which LTL carrier?'). Typical flow: /quote to pick the mode; if LTL wins and you want carrier choice, use the LTL market options endpoint.","tags":["Quotes"],"security":[{"bearerAuth":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin_zip","destination_zip","pickup_date"],"properties":{"origin_zip":{"type":"string","example":"90210"},"destination_zip":{"type":"string","example":"10001"},"pickup_date":{"type":"string","format":"date","example":"2026-08-01"},"pallets":{"type":"integer","example":2},"weight_lbs_per_pallet":{"type":"number","example":500},"length_in":{"type":"number","description":"Per-pallet length (top-level, like the mode endpoints; needed for a priced LTL row)."},"width_in":{"type":"number"},"height_in":{"type":"number"},"commodity":{"type":"string","description":"Optional; firms up the LTL price."}}}}}},"responses":{"200":{"description":"One row per mode, cheapest available first.","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"mode":{"type":"string","enum":["cargo_van","box_truck","ltl","ftl"]},"available":{"type":"boolean"},"quote_id":{"type":"string","description":"Present when available — your booking token; books via POST /book."},"price_usd":{"type":"number"},"transit_days":{"type":"integer"},"expires_at":{"type":"string","format":"date-time"},"reason":{"type":"string","description":"Present when available=false — why this mode refused."},"details":{"type":"object","description":"The mode's full single-endpoint response, verbatim."}}}},"book":{"type":"object","properties":{"note":{"type":"string"},"url":{"type":"string"}}}}}}}}}}},"/van/quote":{"post":{"summary":"Get a cargo van quote","operationId":"vanQuote","tags":["Quoting"],"description":"All fields required. Max 3 pallets, max 3,500 lbs total. Out-of-range pallets and per-pallet weights are CLAMPED into the supported range and priced as clamped (200 OK), not rejected.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin_zip","destination_zip","pallets","weight_lbs_per_pallet","pickup_date"],"properties":{"origin_zip":{"type":"string","example":"90012","description":"5-digit US ZIP code"},"destination_zip":{"type":"string","example":"94105","description":"5-digit US ZIP code"},"pallets":{"type":"integer","example":2,"description":"1-3 max for cargo van"},"weight_lbs_per_pallet":{"type":"integer","example":800,"description":"Total can't exceed 3,500 lbs"},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"insuranceInfo":{"type":"object","description":"Optional opt-in cargo insurance. When present, the quote response includes an `insurance` block (premium, fees, total, and a bindable insuranceQuoteId); pass that insuranceQuoteId to POST /book to bind coverage with the shipment. Omit for no insurance.","required":["commodity","insuredValue"],"properties":{"commodity":{"type":"string","example":"Electronics","description":"What is being insured (free text)."},"insuredValue":{"type":"number","example":20000,"description":"Declared cargo value to insure, in USD."}}}}}}}},"responses":{"200":{"description":"Firm quote returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Validation error (missing fields, weight exceeded, etc.) — also returned when no rate exists for this lane + vehicle (upstream 'A rate has not yet been determined for this route', relayed with its own 400 status; body code stays UPSTREAM_ERROR)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED — 60/hr per IP keyless, 1,000/hr sandbox key, 10,000/hr live key. Retry-After + X-RateLimit-* headers included.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Upstream error (rating service unreachable or failed; no-rate answers return 400 instead)"}}}},"/box-truck/quote":{"post":{"summary":"Get a 26ft box truck quote","operationId":"boxTruckQuote","tags":["Quoting"],"description":"All fields required. Max 12 pallets, max 10,000 lbs total. Out-of-range pallets and per-pallet weights are CLAMPED into the supported range and priced as clamped (200 OK), not rejected.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin_zip","destination_zip","pallets","weight_lbs_per_pallet","pickup_date"],"properties":{"origin_zip":{"type":"string","example":"90012","description":"5-digit US ZIP code"},"destination_zip":{"type":"string","example":"94105","description":"5-digit US ZIP code"},"pallets":{"type":"integer","example":6,"description":"1-12 max for box truck"},"weight_lbs_per_pallet":{"type":"integer","example":800,"description":"Total can't exceed 10,000 lbs"},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"insuranceInfo":{"type":"object","description":"Optional opt-in cargo insurance. When present, the quote response includes an `insurance` block (premium, fees, total, and a bindable insuranceQuoteId); pass that insuranceQuoteId to POST /book to bind coverage with the shipment. Omit for no insurance.","required":["commodity","insuredValue"],"properties":{"commodity":{"type":"string","example":"Electronics","description":"What is being insured (free text)."},"insuredValue":{"type":"number","example":20000,"description":"Declared cargo value to insure, in USD."}}}}}}}},"responses":{"200":{"description":"Firm quote returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Validation error — also returned when no rate exists for this lane + vehicle (upstream 'A rate has not yet been determined for this route', relayed with its own 400 status; body code stays UPSTREAM_ERROR)"},"429":{"description":"RATE_LIMITED — 60/hr per IP keyless, 1,000/hr sandbox key, 10,000/hr live key. Retry-After + X-RateLimit-* headers included.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Upstream error (rating service unreachable or failed; no-rate answers return 400 instead)"}}}},"/ftl/quote":{"post":{"summary":"Get a 53ft dry van FTL quote","operationId":"ftlQuote","tags":["Quoting"],"description":"Only origin_zip, destination_zip, and pickup_date are required. Pallets and weight are optional (you're buying the whole truck).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin_zip","destination_zip","pickup_date"],"properties":{"origin_zip":{"type":"string","example":"90012","description":"5-digit US ZIP code"},"destination_zip":{"type":"string","example":"94105","description":"5-digit US ZIP code"},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"pallets":{"type":"integer","example":20,"description":"Optional -- doesn't affect FTL price"},"weight_lbs_per_pallet":{"type":"integer","example":1200,"description":"Optional -- doesn't affect FTL price"},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"insuranceInfo":{"type":"object","description":"Optional opt-in cargo insurance. When present, the quote response includes an `insurance` block (premium, fees, total, and a bindable insuranceQuoteId); pass that insuranceQuoteId to POST /book to bind coverage with the shipment. Omit for no insurance.","required":["commodity","insuredValue"],"properties":{"commodity":{"type":"string","example":"Electronics","description":"What is being insured (free text)."},"insuredValue":{"type":"number","example":20000,"description":"Declared cargo value to insure, in USD."}}}}}}}},"responses":{"200":{"description":"Firm quote returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Validation error — also returned when no rate exists for this lane + vehicle (upstream 'A rate has not yet been determined for this route', relayed with its own 400 status; body code stays UPSTREAM_ERROR)"},"429":{"description":"RATE_LIMITED — 60/hr per IP keyless, 1,000/hr sandbox key, 10,000/hr live key. Retry-After + X-RateLimit-* headers included.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Upstream error (rating service unreachable or failed; no-rate answers return 400 instead)"}}}},"/intl/quote":{"post":{"summary":"LIVE international ocean and air rates (China, Vietnam, India, Taiwan, South Korea to any US ZIP) - keyless","operationId":"intlQuote","tags":["Quoting"],"description":"Live international freight rates from real sailing and flight schedules — the ocean and air legs, priced to any US door. mode: 'ocean' (FCL containers via unit='containers' + container_size, or shared space via unit='pallets'/'cartons') or 'air' (pallets or cartons, priced by chargeable weight). LIVE ORIGINS (exact city spellings): China — Shanghai, 'Shenzhen (Yantian)', Guangzhou, Qingdao, Xiamen, Tianjin; Vietnam — 'Ho Chi Minh City'; India — Mumbai, Chennai; Taiwan — Kaohsiung, Taipei; South Korea — Busan, 'Seoul (Incheon)'. Any other origin or city, or a ship_day more than ~7 days out, returns 422 NEEDS_TEAM_QUOTE — a real answer, not a failure: the Warp team prices it within one business day (submit at wearewarp.com/ocean or /air). SLOW: the upstream searches hundreds to thousands of real routes; typically 5-20s, allow up to 110s. Pallets assume 48x40x60 in; cartons require carton_dims. Response tiers are cheapest / fastest / balanced with price_usd (whole-shipment, door delivery per door_service), transit_days, route_number, and valid_until. Locking a tier is not yet an API action — the shipper completes the lock at wearewarp.com/ocean or /air (no charge at lock; a human confirms the booking the same day). Keyless; standard keyless rate budget applies.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode","origin_country","dest_zip","unit","qty","total_weight_lb"],"properties":{"mode":{"type":"string","enum":["ocean","air"]},"origin_country":{"type":"string","enum":["China","Vietnam","India","Taiwan","South Korea"],"description":"Live-priced origins; other countries are team-quoted via the site flows."},"origin_city":{"type":"string","description":"Exact live city spelling (e.g. 'Shenzhen (Yantian)', 'Seoul (Incheon)'). Unlisted cities return NEEDS_TEAM_QUOTE."},"dest_zip":{"type":"string","pattern":"^\\d{5}$","description":"5-digit US destination ZIP."},"unit":{"type":"string","enum":["containers","pallets","cartons"],"description":"'containers' is ocean-only (FCL)."},"qty":{"type":"integer","minimum":1,"description":"Container / pallet / carton count."},"total_weight_lb":{"type":"number","minimum":1,"description":"Total shipment weight, all pieces combined."},"container_size":{"type":"string","enum":["20'DV","40'DV","40'HC"],"description":"FCL only; defaults to 40'DV."},"carton_dims":{"type":"object","properties":{"length_in":{"type":"number"},"width_in":{"type":"number"},"height_in":{"type":"number"}},"description":"Per-carton inches; required when unit='cartons'."},"ship_day":{"type":"string","format":"date","description":"Defaults to two business days out; rates publish ~a week ahead."},"description":{"type":"string","description":"Commodity (defaults to 'General merchandise')."}}}}}},"responses":{"200":{"description":"Live tier envelope: { source: 'live', quote_id, ship_day, raw_route_count, tiers: [{ tier: cheapest|fastest|balanced, price_usd, transit_days, door_service, route_number, valid_until, description }] }"},"400":{"description":"INVALID_JSON, INVALID_ZIP, MISSING_WEIGHT, or MISSING_DIMS (cartons without carton_dims)."},"422":{"description":"NEEDS_TEAM_QUOTE — origin/city/date outside the live rail, or no live routes on the lane. The team prices it within one business day via wearewarp.com/ocean or /air."},"429":{"description":"RATE_LIMITED — standard keyless budget; Retry-After included."},"502":{"description":"UPSTREAM_ERROR — live rating briefly unavailable; the team-quote path still works."},"503":{"description":"INTL_RATES_UNAVAILABLE — live international rating not configured on this deployment."}}}},"/parcel/quote":{"post":{"summary":"LIVE multi-carrier parcel rates (small packages, US domestic) - keyless","operationId":"parcelQuote","tags":["Quoting"],"description":"Live parcel rates across Warp's connected carrier accounts for small packages — the mode below LTL, when the freight is boxes rather than pallets. Send from / to addresses and one or more packages with weight (dimensions strongly recommended: most carriers price on dimensional weight, so omitting them can understate the rate). Returns every carrier service that quoted, cheapest first, with an all-inclusive price_usd — the rate you would pay, resale margin already applied. When Warp's same-day metro network also covers the lane, those options come back separately under same_day (they ship from a Warp pickup location rather than your from-address, which is why they are not ranked against the carrier rows). BOOKING PARCEL IS NOT YET AN API ACTION: these quotes are for pricing and comparison — contact Warp to buy a label. Keyless; standard keyless rate budget applies. Not for palletized freight — use /ltl/quote (or /ltl/market-options for the carrier spread) once the load is on pallets.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","to","packages"],"properties":{"from":{"type":"object","required":["postal_code","country","city","state"],"description":"Origin. City and state are REQUIRED, not just the ZIP — parcel carriers rate on the full address. (Freight quoting is ZIP-only, so this is the first thing a freight integrator gets wrong.) Missing fields return 400 MISSING_ADDRESS naming each one.","properties":{"postal_code":{"type":"string","example":"90001"},"country":{"type":"string","minLength":2,"maxLength":2,"example":"US","description":"2-letter ISO country code."},"city":{"type":"string","example":"Los Angeles"},"state":{"type":"string","example":"CA","description":"2-letter state/province code."},"residential":{"type":"boolean","description":"Residential pickup — some carriers price it differently."}}},"to":{"type":"object","required":["postal_code","country","city","state"],"description":"Destination — city and state required, same as from. Set residential:true for a home delivery: carriers surcharge it, and quoting commercial then shipping residential is the usual reason a bill exceeds its quote.","properties":{"postal_code":{"type":"string","example":"10001"},"country":{"type":"string","minLength":2,"maxLength":2,"example":"US"},"city":{"type":"string","example":"New York"},"state":{"type":"string","example":"NY","description":"2-letter state/province code."},"residential":{"type":"boolean"}}},"packages":{"type":"array","minItems":1,"description":"One entry per physical box. Multiple boxes are rated as one multi-package shipment.","items":{"type":"object","required":["weight_lbs"],"properties":{"weight_lbs":{"type":"number","minimum":0.1,"example":5},"length_in":{"type":"number","example":12,"description":"Strongly recommended — carriers bill dimensional weight."},"width_in":{"type":"number","example":9},"height_in":{"type":"number","example":6},"insured_value_usd":{"type":"number","description":"Declared value for carrier coverage."}}}},"carrier_ids":{"type":"array","items":{"type":"string"},"description":"Restrict to specific connected carrier accounts. Omit to rate every connected carrier."},"service_codes":{"type":"array","items":{"type":"string"},"description":"Restrict to specific services (e.g. ground only)."}}}}}},"responses":{"200":{"description":"Carrier rates, cheapest first","content":{"application/json":{"schema":{"type":"object","properties":{"quote_id":{"type":"string","nullable":true,"description":"Warp's id for this parcel quote."},"rates":{"type":"array","items":{"type":"object","properties":{"rate_id":{"type":"string","nullable":true,"description":"Identifies this specific carrier service + price."},"carrier_code":{"type":"string","nullable":true,"example":"ups"},"service_code":{"type":"string","nullable":true,"example":"ups_ground"},"service_label":{"type":"string","example":"UPS Ground"},"price_usd":{"type":"number","description":"All-inclusive sell price for this service."},"currency":{"type":"string","example":"USD"},"delivery_days":{"type":"integer","nullable":true},"estimated_delivery_date":{"type":"string","nullable":true,"format":"date-time"},"guaranteed":{"type":"boolean","description":"Carrier guarantees the transit commitment."}}}},"same_day":{"type":"object","description":"Present only when Warp's same-day metro network covers the lane. These ship from a Warp pickup location, not your from-address.","properties":{"rates":{"type":"array","items":{"type":"object","properties":{"service_label":{"type":"string"},"price_usd":{"type":"number"},"currency":{"type":"string"},"transit_days":{"type":"integer","nullable":true}}}},"sandbox":{"type":"boolean","description":"Present when the same-day provider is in sandbox — those prices are not live."}}},"invalid_rate_count":{"type":"integer","description":"Carriers that could not rate this package (size/lane limits). Present only when non-zero."},"note":{"type":"string"}}}}}},"400":{"description":"MISSING_ADDRESS / MISSING_PACKAGES / INVALID_JSON"},"422":{"description":"PARCEL_RATE_REJECTED — carriers rejected the request (bad address, oversize package). details carries the carrier's own reason."},"429":{"description":"RATE_LIMITED"},"502":{"description":"PARCEL_UPSTREAM_ERROR"},"503":{"description":"PARCEL_RATES_UNAVAILABLE — live parcel rating is not configured on this deployment."},"504":{"description":"PARCEL_UPSTREAM_TIMEOUT — retryable."}}}},"/ltl/quote":{"post":{"summary":"Get an LTL quote (firm when all fields present, indicative otherwise)","operationId":"ltlQuote","tags":["Quoting"],"description":"Dims (length_in, width_in, height_in) are ALWAYS required — unless you pass a load_template_id or an items[] manifest (one entry per pallet profile, for pallets of varying dimensions). Omitting dims returns 400 MISSING_DIMS; there is no dims-less indicative quote. quote_tier is 'firm' when all fields are present and 'indicative' only when an OPTIONAL field (e.g. commodity, freight_class) is missing. HEIGHT LIMIT: LTL pallets must be 85 in tall or under; over 85 returns 400 EXCEEDS_LTL_LIMITS. Length and width are NOT capped — over 50 in still quotes, at a higher rate. Taller freight still moves: quote /box-truck/quote or /ftl/quote, compare every mode at /quote, or email support@wearewarp.com to arrange it directly.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","anyOf":[{"required":["origin_zip","destination_zip","pallets","weight_lbs_per_pallet","pickup_date","length_in","width_in","height_in"]},{"required":["origin_zip","destination_zip","pickup_date","load_template_id"]},{"required":["origin_zip","destination_zip","pickup_date","items"]}],"properties":{"origin_zip":{"type":"string","example":"90012"},"destination_zip":{"type":"string","example":"94105"},"pallets":{"type":"integer","example":6},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"weight_lbs_per_pallet":{"type":"integer","example":800,"description":"Standard LTL pallets run up to 2,000 lb; heavier is still priced, but compare /box-truck/quote and /ftl/quote."},"freight_class":{"type":"string","example":"85","description":"Optional. Warp uses FAK (Freight All Kinds) rates -- class doesn't affect pricing. Include for BOL documentation if known."},"commodity":{"type":"string","example":"auto parts"},"length_in":{"type":"integer","example":48,"description":"Required when not using a template. Standard LTL pallets run up to 50 in; longer is still priced at a higher rate."},"width_in":{"type":"integer","example":40,"description":"Required when not using a template. Standard LTL pallets run up to 50 in; wider is still priced at a higher rate."},"height_in":{"type":"integer","example":48,"maximum":85,"description":"Required when not using a template. LTL pallets must be 85 in tall or under — over 85 returns 400 EXCEEDS_LTL_LIMITS. Taller freight still moves: use /box-truck/quote or /ftl/quote, or email support@wearewarp.com to arrange it directly."},"items":{"type":"array","description":"Mixed-dimension manifest: one entry per distinct pallet profile. Use this for a shipment whose pallets vary in size/weight. When present it REPLACES the scalar pallets/weight_lbs_per_pallet/length_in/width_in/height_in fields — each entry is priced as its own line item and the exact manifest is replayed at /book. Identical pallets can be grouped with qty.","items":{"type":"object","required":["qty","weight_lbs_per_pallet","length_in","width_in","height_in"],"properties":{"qty":{"type":"integer","example":2,"description":"Number of identical pallets in this line"},"weight_lbs_per_pallet":{"type":"integer","example":150,"description":"Weight per pallet (lbs) for this line."},"length_in":{"type":"integer","example":48},"width_in":{"type":"integer","example":40},"height_in":{"type":"integer","example":48,"maximum":85,"description":"Hard limit 85 in — LTL has no rate above this."}}}},"hazmat":{"type":"boolean","example":false,"description":"Optional. Set true only for DOT-regulated goods (e.g. UN1266 alcohol-based perfume, aerosols, nail polish)."},"load_template_id":{"type":"string","example":"lt_01JRKZ...","description":"Alternative to providing weight/dims/class directly"},"pallet_count":{"type":"integer","example":6},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"insuranceInfo":{"type":"object","description":"Optional opt-in cargo insurance. When present, the quote response includes an `insurance` block (premium, fees, total, and a bindable insuranceQuoteId); pass that insuranceQuoteId to POST /book to bind coverage with the shipment. Omit for no insurance.","required":["commodity","insuredValue"],"properties":{"commodity":{"type":"string","example":"Electronics","description":"What is being insured (free text)."},"insuredValue":{"type":"number","example":20000,"description":"Declared cargo value to insure, in USD."}}}}}}}},"responses":{"200":{"description":"Quote returned (check quote_tier and missing_for_ship) If gw has no LTL service on the lane it substitutes a DEDICATED truck: the response then carries mode_substituted { requested, served, reason, compare } and service.vehicle names the dedicated run instead of 'LTL (shared)'. That price is real and bookable but can be several times the marketplace LTL rate — compare with /ltl/market-options.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Validation error, missing dims, or INVALID_ACCESSORIAL (a slug outside the catalog — the error names the offending slug and lists every valid one; unknown slugs are no longer filtered away silently). Also returned when no rate exists for this lane + vehicle (upstream 'A rate has not yet been determined for this route', relayed with its own 400 status; body code stays UPSTREAM_ERROR)"},"429":{"description":"RATE_LIMITED — 60/hr per IP keyless, 1,000/hr sandbox key, 10,000/hr live key. Retry-After + X-RateLimit-* headers included.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Upstream error (rating service unreachable or failed; no-rate answers return 400 instead)"}}}},"/ltl/market-options":{"post":{"summary":"LTL multi-carrier comparison (~30 carriers) - compares CARRIERS within LTL; use POST /quote to compare MODES","operationId":"ltlMarketOptions","tags":["Quoting"],"description":"Returns the multi-carrier LTL spread (every carrier's rate + transit + a bookable quote_id). Request body: same lane/pallet/dims fields as /ltl/quote, Accessorials use the SAME accessorials { pickup: [], delivery: [] } object as /ltl/quote — pickup_services / delivery_services are accepted aliases for the same thing, and if you send both they are merged, so use whichever your integration already speaks. Carriers re-price for the requested services and any carrier that cannot perform one drops out, so the option count can shrink. An unrecognised slug is rejected with 400 INVALID_ACCESSORIAL rather than ignored. load_template_id, hazmat, freight_class and commodity are not used by this endpoint. SLOW: typically ~20s (allow up to 45s) — it polls every carrier in the marketplace. If the carrier aggregator fails, the response is still 200 with market_options: [] and a note (never a 5xx). Keyless requests return display-only rates; with your live API key, each carrier's quote_id is bookable — POST any one of them to /book to book that specific carrier.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","anyOf":[{"required":["origin_zip","destination_zip","pickup_date","length_in","width_in","height_in"]},{"required":["origin_zip","destination_zip","pickup_date","items"]}],"properties":{"origin_zip":{"type":"string","example":"90012"},"destination_zip":{"type":"string","example":"94105"},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"pallets":{"type":"integer","example":2,"description":"Pallet count (alias: pallet_count). Ignored when items[] is supplied."},"pallet_count":{"type":"integer","description":"Alias for pallets."},"weight_lbs_per_pallet":{"type":"integer","example":500},"length_in":{"type":"integer","example":48,"description":"Required unless items[] is supplied"},"width_in":{"type":"integer","example":40,"description":"Required unless items[] is supplied"},"height_in":{"type":"integer","example":48,"description":"Required unless items[] is supplied"},"items":{"type":"array","description":"Mixed-dimension manifest, same shape as /ltl/quote. When present it REPLACES the scalar pallets/weight/dims fields; every carrier in the spread is priced against the full manifest.","items":{"type":"object","required":["qty","weight_lbs_per_pallet","length_in","width_in","height_in"],"properties":{"qty":{"type":"integer","example":1},"weight_lbs_per_pallet":{"type":"integer","example":500},"length_in":{"type":"integer","example":48},"width_in":{"type":"integer","example":40},"height_in":{"type":"integer","example":48}}}},"pickup_services":{"type":"array","items":{"type":"string"},"example":["liftgate-pickup"],"description":"Accessorials required at the ORIGIN, as hyphenated service slugs. Each carrier re-prices for them, and carriers that cannot perform a requested service drop out of the spread — so the option count can shrink. Common slugs: liftgate-pickup, inside-pickup, residential-pickup, limited-access-pickup, pickup-appointment. Not exhaustive. Use these instead of the `accessorials` object, which this endpoint ignores."},"delivery_services":{"type":"array","items":{"type":"string"},"example":["liftgate-delivery","residential-delivery"],"description":"Accessorials required at the DESTINATION, as hyphenated service slugs. Common slugs: liftgate-delivery, inside-delivery, residential-delivery, limited-access-delivery, delivery-appointment. Not exhaustive."},"accessorials":{"type":"object","description":"Alternative to pickup_services / delivery_services, and the same shape /ltl/quote accepts — use whichever your integration already speaks. Both are honoured and the two are merged, so you can send either. Carriers re-price for the requested services, and any carrier that cannot perform one drops out of the spread.","properties":{"pickup":{"type":"array","items":{"type":"string"},"example":["liftgate-pickup"]},"delivery":{"type":"array","items":{"type":"string"},"example":["liftgate-delivery"]}}},"insuranceInfo":{"type":"object","description":"Optional opt-in cargo insurance. When present, the quote response includes an `insurance` block (premium, fees, total, and a bindable insuranceQuoteId); pass that insuranceQuoteId to POST /book to bind coverage with the shipment. Omit for no insurance.","required":["commodity","insuredValue"],"properties":{"commodity":{"type":"string","example":"Electronics","description":"What is being insured (free text)."},"insuredValue":{"type":"number","example":20000,"description":"Declared cargo value to insure, in USD."}}}}}}}},"responses":{"200":{"description":"Multi-carrier list, sorted by price","content":{"application/json":{"schema":{"type":"object","properties":{"origin_zip":{"type":"string"},"destination_zip":{"type":"string"},"pickup_date":{"type":"string","format":"date"},"market_options":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"carrier_name":{"type":"string"},"service_level":{"type":"string"},"price_usd":{"type":"number"},"transit_days":{"type":"integer","nullable":true},"is_warp":{"type":"boolean"},"bookable":{"type":"boolean","description":"false when the carrier already considers this rate expired (see expires_at) or when the request is keyless/cached. Only a bookable option carries a quote_id."},"expires_at":{"type":"string","format":"date-time","description":"When this specific carrier's rate stops being bookable — the carrier's own deadline, capped at 72h. Rates on one lane routinely differ: a spread can hold options good for 24h alongside others good for 7 days. A value in the PAST means the carrier considers the rate dead; such options are returned for visibility with bookable:false and no quote_id."},"expires_in_seconds":{"type":"integer","description":"expires_at relative to Warp's clock at response time, so you never have to trust that your host clock agrees with ours. Negative means already expired."},"quote_id":{"type":"string","description":"Present when bookable (authed requests only). Same value as option_id — gw's canonical offer id; pass it to POST /book to book this carrier.","example":"01KZRQHPAX33S3ZTKW4G5EJZH9"},"option_id":{"type":"string","description":"Upstream marketplace option id"}}}},"insurance":{"type":"object","description":"Cargo insurance — present ONLY when the request included insuranceInfo and the gateway priced it. SHIPMENT-LEVEL: one policy for the whole spread, so the same insuranceQuoteId binds whichever carrier you book. Pass it to POST /book alongside the carrier's quote_id; total (USD) is funded with the freight.","properties":{"insuranceQuoteId":{"type":"string","example":"01J...","description":"Bindable insurance quote id — pass to POST /book as insuranceQuoteId."},"premium":{"type":"number","example":60,"description":"Insurance premium in the quoted currency."},"processingFee":{"type":"number","example":6,"description":"Processing fee in the quoted currency."},"total":{"type":"number","example":66,"description":"premium + processingFee; the amount funded alongside the freight."},"currency_code":{"type":"string","example":"USD"}}},"retryable":{"type":"boolean","description":"Branch on this instead of parsing the note. true = the carrier sweep timed out / degraded and market_options may be empty or served from cache — safe to retry for a live spread. false = the sweep completed; an empty list here means genuine no-coverage for this lane+config, not worth retrying."},"cached":{"type":"boolean","description":"true when the live sweep timed out and this spread was served from the last-good cached result for the lane. Cached options are DISPLAY-ONLY (bookable:false, no quote_id) because per-carrier option ids expire — re-run for live, bookable quotes."},"as_of":{"type":"string","format":"date-time","description":"Present only when cached:true — when the served spread was captured."},"note":{"type":"string"}}}}}},"400":{"description":"MISSING_DIMS (no dims and no items[] manifest), EXCEEDS_LTL_LIMITS (a pallet over the 85 in height limit — `violations[]` names the offending field and line; quote /box-truck/quote or /ftl/quote instead), EXCEEDS_PALLET_LIMIT (an items[] manifest over 26 lines or 26 total pallets — the error names both limits and nothing is silently trimmed; split the shipment or quote /ftl/quote), or INVALID_ACCESSORIAL (a slug outside the catalog — the error names the offending slug and lists every valid pickup and delivery slug; nothing is silently dropped)."},"429":{"description":"RATE_LIMITED — 60/hr per IP keyless, 1,000/hr sandbox key, 10,000/hr live key. Retry-After + X-RateLimit-* headers included.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/quote/{quote_id}/service-options":{"get":{"summary":"Priced add-on service options for an existing quote","operationId":"quoteServiceOptions","tags":["Quoting"],"description":"PREVIEW — returns per-shipment add-on rates (two-man delivery, inside delivery tiers, liftgate, appointments, ...) for a live quote, where the pricing engine exposes them. Currently responds 409 SERVICE_OPTIONS_UNAVAILABLE for most quotes: per-option rating via the API is not yet enabled platform-side. Until it is, request options via the accessorials field (they attach to the quote and booking) and confirm add-on pricing with your Warp contact.","parameters":[{"name":"quote_id","in":"path","required":true,"schema":{"type":"string"},"description":"quote_id returned by any quote endpoint (legacy wq_… ids are accepted as an alias)."}],"responses":{"200":{"description":"Priced options for pickup and delivery","content":{"application/json":{"schema":{"type":"object","properties":{"quote_id":{"type":"string"},"pickup_options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"two-man-delivery"},"name":{"type":"string","example":"Two Man Delivery"},"rate_usd":{"type":"number","example":250},"description":{"type":"string"}}}},"delivery_options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"rate_usd":{"type":"number"},"description":{"type":"string"}}}},"note":{"type":"string"}}}}}},"400":{"description":"Unknown or expired quote_id"},"409":{"description":"SERVICE_OPTIONS_UNAVAILABLE — per-option rating isn't exposed for this quote's pricing surface"},"502":{"description":"Upstream pricing error"}}}},"/book":{"post":{"summary":"Book a quoted shipment","operationId":"book","tags":["Booking"],"security":[{"bearerAuth":[]}],"description":"patch.delivery is required on every booking and is used exactly as it is sent — addresses are never taken from, or combined with, stored history. It must be complete (zipCode, city, state, street, contactName, phone, email); an incomplete address is rejected with 400 INCOMPLETE_DELIVERY listing the missing fields, and a missing one with 400 DELIVERY_REQUIRED. A field sent as an empty string counts as supplied (company: \"\" means no company name — the BOL name line falls back to contactName from the same request). patch.pickup follows the same rule; omitting it entirely uses your saved default_shipper, whole, when one is complete.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quote_id"],"properties":{"quote_id":{"type":"string","example":"PRICING_46298af7-e427-4ae7-a6c1-cb2c8bc56805","description":"The quote_id from the quote response — Warp's canonical id, the same one on your BOL. Legacy wq_… ids from earlier API versions are accepted forever. Booking with either id is idempotent against the same underlying quote."},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"reference":{"type":"string","description":"Shipment-level reference (PO / external ref). For a reference on a SPECIFIC stop's BOL line, use patch.pickup.refNum / patch.delivery.refNum.","example":"PO-12345"},"promo_code":{"type":"string","description":"Optional promo code, validated at booking. Applies to the FREIGHT price only — insurance is never discounted. Both flat-rate and percentage codes are supported. An unknown, expired or not-yet-active code returns 400 INVALID_PROMO and nothing is charged; if the promo service can't be reached the booking returns 502 PROMO_UNVERIFIED rather than silently charging full price, so retry or re-send the request without the code. On success the response carries promo_applied.","example":"WARP2026"},"standing_order_token":{"type":"string","description":"Internal: set by the weekly automation runner. Authorizes skipping the owner-confirmation hold only while the referenced automation is active and the price is at or under its approved ceiling."},"patch":{"type":"object","properties":{"pickup":{"type":"object","properties":{"zipCode":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"contactName":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"specialInstruction":{"type":"string"},"company":{"type":"string","description":"Facility/company name for this stop - the shipper/consignee name line on the BOL. Defaults to contactName when omitted."},"street2":{"type":"string","description":"Second address line (suite/unit/dock)."},"appointment":{"type":"object","description":"Structured appointment window for this stop, local time (converted using the stop's timezone). Distinct from the appointment accessorial flag.","properties":{"from":{"type":"string","example":"09:00"},"to":{"type":"string","example":"11:00"}}},"refNum":{"type":"string","description":"Reference number (PO / SO / BOL / PRO / etc.) for THIS stop — renders on the stop's \"Reference Number\" line on the BOL. One per stop.","example":"PO-12345"}}},"delivery":{"type":"object","properties":{"zipCode":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"contactName":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"specialInstruction":{"type":"string"},"company":{"type":"string","description":"Facility/company name for this stop - the shipper/consignee name line on the BOL. Defaults to contactName when omitted."},"street2":{"type":"string","description":"Second address line (suite/unit/dock)."},"appointment":{"type":"object","description":"Structured appointment window for this stop, local time (converted using the stop's timezone). Distinct from the appointment accessorial flag.","properties":{"from":{"type":"string","example":"09:00"},"to":{"type":"string","example":"11:00"}}},"refNum":{"type":"string","description":"Reference number (PO / SO / BOL / PRO / etc.) for THIS stop — renders on the stop's \"Reference Number\" line on the BOL. One per stop.","example":"PO-12345"}}},"notes":{"type":"string"}}},"pickup_window":{"type":"object","description":"Optional pickup time window within pickup_date. Times are HH:MM (24h). Collected at booking; omit for a full-day window.","properties":{"from":{"type":"string","example":"08:00"},"to":{"type":"string","example":"17:00"}}},"delivery_window":{"type":"object","description":"Optional delivery time window. Times are HH:MM (24h).","properties":{"from":{"type":"string","example":"08:00"},"to":{"type":"string","example":"17:00"}}},"insuranceQuoteId":{"type":"string","example":"01J...","description":"Optional opt-in cargo insurance. The insuranceQuoteId from this quote's `insurance` block (see the quote response). When present, Warp binds the policy with the shipment and funds the premium alongside the freight; the booking response echoes insuranceStatus. Must match the id issued for this quote_id, else 400 INSURANCE_QUOTE_MISMATCH. Omit for a freight-only booking."}}}}}},"responses":{"200":{"description":"Booking confirmed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponse"}}}},"202":{"description":"CONFIRMATION_REQUIRED — the booking is over the account's confirmation threshold and is held for the account owner's approval. Body carries hold.token, hold.status_url, and hold.expires_at. Nothing is booked or charged; once the owner approves, call /book again with the same quote_id to complete."},"400":{"description":"Invalid input, expired quote, missing delivery address, INVALID_PROMO, or INSURANCE_QUOTE_MISMATCH"},"401":{"description":"Auth failure"},"402":{"description":"Payment needed or spending limit hit: PAYMENT_REQUIRED (no card on file — body carries checkout_url), PAYMENT_ACTION_REQUIRED (card needs authentication), CHARGE_FAILED, WALLET_TOPUP_FAILED, SPEND_CAP_EXCEEDED (rolling-window cap reached — body names the cap and window spend), or BOOKING_MAX_EXCEEDED (over the per-booking limit). Spending limits are set by the account owner in the dashboard; agents cannot change them. Nothing was booked."},"403":{"description":"CONFIRMATION_REJECTED — the account owner rejected this held booking; it cannot proceed with this quote."},"409":{"description":"BOOKING_IN_PROGRESS — the same quote_id is mid-booking in a concurrent request; retry in a few seconds to receive the original confirmation (never a second charge)."},"502":{"description":"Upstream booking error (BOOKING_FAILED / REQUOTE_FAILED). A retried /book with the same quote_id replays the original confirmation if the first attempt actually booked — note the replay body sets idempotent_replay: true, already_charged_cents, and (known caveat) order_id equal to shipment_id."},"503":{"description":"Booking temporarily unavailable (server configuration gap)."}}}},"/rebook":{"post":{"summary":"RETIRED — returns 410. Use POST /book with full addresses.","operationId":"rebook","tags":["Booking"],"security":[{"bearerAuth":[]}],"deprecated":true,"description":"Retired 2026-09-02. Rebook booked entirely from stored records (saved shipper + the last consignee shipped in a zip3 lane bucket), which could ship freight to the wrong consignee for shippers with multiple consignees in one region. Warp no longer stores consignee addresses in lane memory. Every call returns 410 REBOOK_RETIRED; book with POST /book and provide the addresses in full.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lane_id","pickup_date"],"properties":{"lane_id":{"type":"string","example":"ln_900_941"},"pickup_date":{"type":"string","format":"date","example":"2026-04-15"},"pallet_count":{"type":"integer"},"accessorials":{"type":"object","description":"Optional pickup and delivery accessorial services. Slugs match the Warp service-option catalog; unknown slugs are ignored. Requested services are attached to the quote and carried into the booking (services on the booking must match the quote). Several are included at no charge per mode (see included_at_no_charge in the quote response); rates for premium add-ons such as two-man-delivery and the inside-delivery tiers are account-configured — confirm pricing with your Warp contact before relying on price_usd covering them. White-glove-style delivery = two-man-delivery + an inside-delivery tier + delivery-appointment.","properties":{"pickup":{"type":"array","items":{"type":"string","enum":["liftgate-pickup","inside-pickup","residential-pickup","limited-access-pickup","pickup-appointment","driver-assist-pickup","construction-site-pickup","convention-trade-show-pickup","inside-pickup-upstairs-mezzanine-trash-removal","inside-pickup-back-side-of-the-house","inside-pickup-living-space-garage"]}},"delivery":{"type":"array","items":{"type":"string","enum":["liftgate-delivery","inside-delivery","residential-delivery","limited-access-delivery","delivery-appointment","two-man-delivery","driver-assist-delivery","construction-site-delivery","convention-trade-show-delivery","inside-delivery-upstairs-mezzanine-trash-removal","inside-delivery-back-side-of-the-house","inside-delivery-living-space-garage"]}}}},"reference":{"type":"string","description":"PO number or external reference","example":"PO-12345"}}}}}},"responses":{"200":{"description":"Rebook confirmed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponse"}}}},"401":{"description":"Auth failure"},"404":{"description":"Lane not found"},"502":{"description":"Upstream error"}}}},"/load_templates":{"get":{"summary":"List saved load templates","operationId":"listLoadTemplates","tags":["Templates"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Template list","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Auth failure"}}},"post":{"summary":"Create a load template","operationId":"createLoadTemplate","tags":["Templates"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","weight_lbs","length_in","width_in","height_in"],"properties":{"name":{"type":"string","example":"Standard Pallet"},"weight_lbs":{"type":"integer","example":1200},"length_in":{"type":"integer","example":48},"width_in":{"type":"integer","example":40},"height_in":{"type":"integer","example":48},"freight_class":{"type":"string","example":"85"},"commodity":{"type":"string","example":"auto parts"},"hazmat":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Template created"},"400":{"description":"Validation error"},"401":{"description":"Auth failure"}}},"delete":{"summary":"Delete a load template","operationId":"deleteLoadTemplate","tags":["Templates"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"example":"lt_01JRKZ..."}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Auth failure"}}}},"/locations":{"get":{"summary":"List cached locations for the agent","operationId":"listLocations","tags":["Memory"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Location list","content":{"application/json":{"schema":{"type":"object","properties":{"locations":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Auth failure"}}}},"/lanes":{"get":{"summary":"List lane history ordered by ship count","operationId":"listLanes","tags":["Memory"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lane history","content":{"application/json":{"schema":{"type":"object","properties":{"lanes":{"type":"array","items":{"type":"object","properties":{"lane_id":{"type":"string"},"ship_count":{"type":"integer"},"last_shipped_at":{"type":"string","format":"date-time"},"last_pallet_count":{"type":"integer"}}}}}}}}},"401":{"description":"Auth failure"}}}},"/version":{"get":{"summary":"API version and build info","operationId":"version","tags":["Meta"],"responses":{"200":{"description":"Version info","content":{"application/json":{"schema":{"type":"object","properties":{"api":{"type":"string","example":"v1"},"commit":{"type":"string"},"built_at":{"type":"string","format":"date-time"}}}}}}}}},"/openapi.json":{"get":{"summary":"This OpenAPI specification","operationId":"openApiSpec","tags":["Meta"],"responses":{"200":{"description":"OpenAPI 3.1 JSON"}}}},"/developer/webhook":{"get":{"summary":"Read your outbound webhook URL","operationId":"getWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"description":"Returns the destination URL Warp delivers shipment-milestone events to, or null if none is registered. Requires a linked Warp session — sign in once at wearewarp.com/agents/account, otherwise 409 WARP_SESSION_REQUIRED.","responses":{"200":{"description":"Current webhook destination","content":{"application/json":{"schema":{"type":"object","properties":{"webhook_url":{"type":["string","null"],"example":"https://example.com/warp/hooks/8f3k2..."}}}}}},"401":{"description":"Auth failure"},"409":{"description":"WARP_SESSION_REQUIRED — sign in once at wearewarp.com/agents/account, then retry"}}},"post":{"summary":"Register your outbound webhook URL","operationId":"setWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"description":"One URL per account (replaces any existing). Warp then delivers shipment-milestone events (booked, picked up, in transit, delivered, exceptions) to it in real time as JSON POSTs ({ event, timestamp, data }). Deliveries are NOT signed today — include an unguessable secret in the URL (long random path or query token) and reject requests that lack it. Requires a linked Warp session (409 WARP_SESSION_REQUIRED otherwise).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"https-only destination URL","example":"https://example.com/warp/hooks/8f3k2..."}}}}}},"responses":{"200":{"description":"Webhook registered","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"webhook_url":{"type":"string"}}}}}},"400":{"description":"INVALID_URL — missing, relative, or non-https URL"},"401":{"description":"Auth failure"},"409":{"description":"WARP_SESSION_REQUIRED — sign in once at wearewarp.com/agents/account, then retry"}}},"delete":{"summary":"Remove your outbound webhook URL","operationId":"deleteWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Webhook removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"401":{"description":"Auth failure"},"409":{"description":"WARP_SESSION_REQUIRED — sign in once at wearewarp.com/agents/account, then retry"}}}},"/developer/webhook/test":{"post":{"summary":"Fire a test webhook delivery","operationId":"testWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"description":"Sends a test event to your registered webhook URL so you can inspect the exact payload your endpoint receives.","responses":{"200":{"description":"Upstream trigger result ({ success, statusCode, ... })"},"401":{"description":"Auth failure"},"409":{"description":"WARP_SESSION_REQUIRED — sign in once at wearewarp.com/agents/account, then retry"}}}},"/balance":{"get":{"summary":"Read your prepaid wallet balance (your booking runway)","operationId":"balance","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"Returns your account's prepaid wallet balance in USD — the funds available to settle bookings before your saved card is charged. Use it to check runway before booking: if the balance covers the quote, POST /book settles from balance and charges nothing; otherwise /book charges your saved card for the shortfall only. Read-only and scoped to your own account.","responses":{"200":{"description":"Wallet balance","content":{"application/json":{"schema":{"type":"object","properties":{"balance_usd":{"type":"number","example":250},"currency":{"type":"string","example":"USD"},"top_up_url":{"type":"string","description":"Where a human can add funds to this wallet."}}}}}},"401":{"description":"Auth failure"},"409":{"description":"WARP_SESSION_REQUIRED — sign in once at wearewarp.com/agents/account, then retry"}}}},"/track":{"get":{"summary":"Track a booked shipment","operationId":"track","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"Returns the local booking row + live upstream tracking status + event history.","parameters":[{"name":"booking_id","in":"query","required":true,"schema":{"type":"string"},"example":"01JRKZ2M7Q0X8V4B6N3C5D7E9F"}],"responses":{"200":{"description":"Tracking response","content":{"application/json":{"schema":{"type":"object","properties":{"shipment_id":{"type":"string"},"status":{"type":"string","enum":["booked","cancelled"],"description":"Local order state (only booked/cancelled). LIVE movement is under upstream_tracking.statusInfo.status in carrier vocabulary (e.g. inRouteToDropoff, arrivedAtDropoff, complete) — poll that field for transit progress."},"delivery_date":{"type":"string","format":"date","nullable":true,"description":"The delivery date captured AT BOOKING TIME. It never updates. For the current schedule — the value that moves if a date changes — use delivery_window."},"schedule_live":{"type":"boolean","description":"true when pickup_window / delivery_window were fetched live from the shipment record on this request. false = the lookup failed, so a null window means UNKNOWN rather than unscheduled — retry rather than trusting delivery_date."},"pickup_window":{"type":"object","nullable":true,"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["appointment","scheduled"]}},"description":"Live pickup window. kind 'appointment' = a booked appointment; 'scheduled' = the planned window."},"delivery_window":{"type":"object","nullable":true,"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["appointment","scheduled"]}},"description":"Live delivery window, refreshed on every call — the field to drive reminders and ETA displays from. kind 'appointment' = a booked appointment (narrow, committed); 'scheduled' = the planned window (can be a broad same-day span). If the date moves, this moves with it."},"tracking_dashboard":{"type":"string"},"upstream_tracking":{"$ref":"#/components/schemas/UpstreamTracking"},"events":{"$ref":"#/components/schemas/ShipmentEvents"}}}}}},"401":{"description":"Auth failure"},"404":{"description":"Booking not found"}}}},"/bookings":{"get":{"summary":"List recent bookings, newest first","operationId":"listBookings","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"maximum":100}}],"responses":{"200":{"description":"Booking list with optional upstream shipments data","content":{"application/json":{"schema":{"type":"object","properties":{"bookings":{"type":"array","description":"Recent bookings, newest first. Everything a dashboard needs per row.","items":{"type":"object","properties":{"shipment_id":{"type":"string","description":"Internal ULID. Pass this as booking_id to GET /track.","example":"01KTB3PKPGW7DRHM0MP0PCQAXY"},"shipment_number":{"type":"string","example":"S-65359-2623"},"tracking_number":{"type":"string","example":"S-65359-2623"},"lane_id":{"type":"string","example":"ln_900_900"},"mode":{"type":"string","enum":["ltl","ftl","van","box-truck"],"example":"ltl"},"origin_zip":{"type":"string","example":"90007"},"destination_zip":{"type":"string","example":"90038"},"pickup_date":{"type":"string","format":"date","nullable":true,"example":"2026-06-26"},"delivery_date":{"type":"string","format":"date","nullable":true,"example":"2026-06-28"},"pallet_count":{"type":"integer","nullable":true,"example":1},"price_usd":{"type":"number","nullable":true,"description":"All-in booked price. Sum for spend KPIs.","example":96.79},"reference":{"type":"string","nullable":true,"description":"Your PO / order id, if set at booking."},"status":{"type":"string","description":"Local order state: booked or cancelled. Live transit status is on GET /track (upstream_tracking.statusInfo.status).","example":"booked"},"booked_at":{"type":"string","format":"date-time","example":"2026-06-05T05:22:11.104Z"},"cancelled_at":{"type":"string","format":"date-time","nullable":true}}}},"count":{"type":"integer"},"limit":{"type":"integer"},"upstream_shipments":{"type":"object"}}}}}},"401":{"description":"Auth failure"}}}},"/rate-card":{"get":{"summary":"Standard mode rate card + your historical pricing per mode","operationId":"rateCard","tags":["Pricing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Rate card","content":{"application/json":{"schema":{"type":"object","properties":{"pricing":{"type":"string","example":"all_inclusive"},"currency":{"type":"string","example":"USD"},"quote_validity_minutes":{"type":"integer","example":4320},"promo_code":{"type":"object"},"modes":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Auth failure"}}}},"/events":{"get":{"summary":"Get the full tracking event history for a shipment","operationId":"events","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"Proxies upstream /freights/events/{shipmentId}.","parameters":[{"name":"shipment_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event history","content":{"application/json":{"schema":{"type":"object","properties":{"shipment_id":{"type":"string"},"events":{"$ref":"#/components/schemas/ShipmentEvents"}}}}}},"401":{"description":"Auth failure"},"502":{"description":"Upstream error"}}}},"/invoices":{"get":{"summary":"Retrieve invoice for a shipment","operationId":"invoice","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"Proxies upstream /freights/invoices/{orderId}.","parameters":[{"name":"order_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"invoice":{"type":"object"}}}}}},"401":{"description":"Auth failure"},"502":{"description":"Upstream error"}}}},"/documents":{"get":{"summary":"List shipment documents (BOL, POD, customs)","operationId":"documents","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"Proxies upstream /freights/documents/{orderId}.","parameters":[{"name":"order_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by document type (e.g. bol, pod)."},{"name":"podType","in":"query","required":false,"schema":{"type":"string"},"description":"POD sub-type filter, forwarded upstream."}],"responses":{"200":{"description":"Document list","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"documents":{"type":"object"}}}}}},"401":{"description":"Auth failure"},"502":{"description":"Upstream error"}}}},"/automations":{"post":{"summary":"Propose a recurring lane automation (books every week after one owner approval)","operationId":"automationPropose","tags":["Automation"],"security":[{"bearerAuth":[]}],"description":"The agent PROPOSES a standing order: a lane, a weekly pickup day, a selection criteria (lowest_price or fastest_transit), and a per-shipment price ceiling. Nothing activates here — the account owner receives an approval email, and only their approval starts the automation. Once active, Warp re-quotes the lane fresh each week and books the winning option automatically when it is at or under the approved ceiling; over-ceiling weeks book nothing and notify the owner. Every automatic booking is re-verified at commit time against the owner's approval — same lane, price within ceiling, automation still active, quote still live — and anything failing a check falls back to owner confirmation instead of booking; GET /automations/receipts returns that record. A sudden price jump (more than 10% over the last booked price, even under the ceiling) is held for the owner instead of booked. Four consecutive unbooked weeks auto-pause the automation. Proposing an existing lane+weekday again returns 409 with the existing automation instead of creating a duplicate. The owner can pause, resume, cancel, or skip the next pickup at any time from their email link; agents may stop or shrink an automation via POST /automations/manage but can never start, resume, or expand one.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["weekday","ceiling_usd","quote","book"],"properties":{"weekday":{"type":"integer","minimum":0,"maximum":6,"description":"0=Sunday … 6=Saturday. Pickup day each week."},"criteria":{"type":"string","enum":["lowest_price","fastest_transit"],"default":"lowest_price"},"ceiling_usd":{"type":"number","description":"Max auto-booked price per shipment; above this the week books nothing and the owner is emailed."},"label":{"type":"string","description":"Human-readable lane label for the owner's emails."},"quote":{"type":"object","description":"Lane payload for POST /quote (origin_zip, destination_zip, pallets, weight_lbs_per_pallet, dims, commodity). pickup_date is set automatically each run."},"book":{"type":"object","description":"Booking payload for POST /book (addresses, contacts, patch). quote_id and reference are set automatically each run."},"end_date":{"type":"string","description":"Optional YYYY-MM-DD. The automation retires itself (cancelled, owner notified) after the last pickup on or before this date."}}}}}},"responses":{"202":{"description":"Proposed; owner approval email sent. Body carries automation.token for status polling and approval_email_sent."},"400":{"description":"Invalid weekday/criteria/ceiling/end_date or missing payloads"},"401":{"description":"Auth failure"},"409":{"description":"DUPLICATE_AUTOMATION — an automation for this lane+weekday already exists; body carries the existing token and status."}}},"get":{"summary":"Read a proposed/active automation's status","operationId":"automationStatus","tags":["Automation"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"automation.token from the proposal response."}],"responses":{"200":{"description":"Status: pending_approval, active, paused, or cancelled, plus end_date, skip_next_date, and last run info."},"401":{"description":"Auth failure"},"404":{"description":"Not found"}}}},"/automations/receipts":{"get":{"summary":"Authorization record for an automation's bookings","operationId":"automationReceipts","tags":["Automation"],"security":[{"bearerAuth":[]}],"description":"READ-ONLY proof trail. One record per booking that presented this automation's token, capturing the checks it had to pass at commit time — before any payment path — against the owner's approval: the automation was active, the lane matched the owner-approved lane, the final price was within the approved ceiling, and the quote was still live. Bookings that failed any check appear as confirmation_required: they did not book autonomously, they fell back to owner confirmation. This is the artifact that answers 'prove this autonomous booking stayed inside what was authorized' without reconstructing it from logs.","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"automation.token (so_…)."}],"responses":{"200":{"description":"Receipts, newest first: decision, per-check results, price vs ceiling, booked lane vs approved lane, and the resulting shipment id."},"400":{"description":"Missing token"},"401":{"description":"Auth failure"},"404":{"description":"Automation not found for this account"}}}},"/automations/manage":{"post":{"summary":"Stop or shrink an automation (agent-side; safe direction only)","operationId":"automationManage","tags":["Automation"],"security":[{"bearerAuth":[]}],"description":"The agent-side lifecycle for automations it proposed, restricted to the SAFE direction: pause an active automation, cancel any automation permanently, or skip the next pickup (one week, one time). Booking less never needs owner sign-off. There is deliberately no resume, no reactivate, and no ceiling or schedule change here — every spend-increasing transition happens only through the owner's emailed approval link. If the user changes their mind mid-week, cancel or skip takes effect before the next cron run; nothing that has not yet booked will book.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","action"],"properties":{"token":{"type":"string","description":"automation.token from the proposal response."},"action":{"type":"string","enum":["pause","cancel","skip_next"]}}}}}},"responses":{"200":{"description":"New status (and skipped_pickup for skip_next)."},"400":{"description":"Unknown action"},"401":{"description":"Auth failure"},"404":{"description":"Automation not found for this account"},"409":{"description":"TRANSITION_NOT_ALLOWED — e.g. pausing an already-cancelled automation"}}}},"/proof":{"get":{"summary":"Proof of execution — did this shipment actually happen","operationId":"proof","tags":["Lifecycle"],"security":[{"bearerAuth":[]}],"description":"One call that answers whether a booking was physically executed, backed by paperwork: live delivery status, the BOL, the POD, and the customer invoice, combined into an explicit executed verdict. executed is true only when the shipment is delivered AND a POD document is on file — never inferred. Anything not yet on file is named in the missing array rather than omitted, so an agent can tell \"pending paperwork\" from \"never happened\". Sandbox shipment ids are keyless and produce watermarked fictional proof on the sandbox lifecycle clock (BOL ~3 min after booking, POD + executed at ~10 min). Reconciled carrier-cost records are internal-only and deliberately not claimed here.","parameters":[{"name":"booking_id","in":"query","required":true,"schema":{"type":"string"},"description":"Shipment id from /book (S-…) or a sandbox id."}],"responses":{"200":{"description":"Proof bundle","content":{"application/json":{"schema":{"type":"object","properties":{"booking_id":{"type":"string"},"executed":{"type":"boolean","description":"Delivered with a POD on file."},"status":{"type":"string","nullable":true},"delivered_at":{"type":"string","nullable":true},"proof":{"type":"object","properties":{"bol":{"type":"object","properties":{"available":{"type":"boolean"},"url":{"type":"string"}}},"pod":{"type":"object","properties":{"available":{"type":"boolean"},"url":{"type":"string"}}},"invoice":{"type":"object","properties":{"available":{"type":"boolean"}}}}},"missing":{"type":"array","items":{"type":"string"},"description":"Artifacts not yet on file: delivery, bol, pod, invoice."}}}}}},"401":{"description":"Auth failure"},"404":{"description":"Shipment not found"}}}},"/webhooks":{"get":{"summary":"List this account's webhook endpoints","operationId":"listWebhooks","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"description":"Returns every active endpoint registered on the account. Signing secrets are never returned after creation. Also returns the list of event types you can subscribe to.","responses":{"200":{"description":"Endpoints and event types","content":{"application/json":{"schema":{"type":"object","properties":{"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"event_types":{"type":"array","items":{"type":"string"}}}}}}}}},"post":{"summary":"Register a webhook endpoint","operationId":"createWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"description":"Register an https URL to receive signed events. The signing secret is returned exactly once, in this response. Deliveries carry `Warp-Signature: t=<unix seconds>,v1=<hex>` where v1 is HMAC-SHA256 with the secret over the string `${t}.${rawBody}`; reject deliveries whose t is more than 300 seconds from now. Every event is attempted immediately and retried on failure at 1m, 5m, 30m, 2h, 6h and 12h, then marked dead. Event bodies: `{ id, type, created, livemode, data }`. `booking.created` fires for every booking made with this account's key via POST /book; `checkout.completed` fires when a buyer books on a hosted quote page that carries this account's quote and a client_reference_id; `webhook.test` is sent by POST /webhooks/{id}/test. URLs must be public https hosts; localhost, private ranges, IP literals and Warp's own domain are refused. Up to 5 endpoints per account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","example":"https://api.yourplatform.example/warp/webhook"},"events":{"type":"array","items":{"type":"string","enum":["booking.created","checkout.completed","webhook.test"]}},"description":{"type":"string","maxLength":200}}}}}},"responses":{"201":{"description":"Endpoint created. Store the secret now.","content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"$ref":"#/components/schemas/WebhookEndpoint"},"secret":{"type":"string","example":"whsec_…"},"note":{"type":"string"}}}}}},"400":{"description":"INVALID_URL or INVALID_EVENTS"},"409":{"description":"ENDPOINT_LIMIT: the account already has 5 endpoints"}}}},"/webhooks/{id}":{"delete":{"summary":"Delete a webhook endpoint","operationId":"deleteWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted; no further deliveries"},"404":{"description":"NOT_FOUND"}}}},"/webhooks/{id}/test":{"post":{"summary":"Send a signed webhook.test event and wait for the answer","operationId":"testWebhook","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Delivers a `webhook.test` event to this endpoint only and returns what your server answered, so signature verification can be proven end to end without booking anything.","responses":{"200":{"description":"Delivery attempted","content":{"application/json":{"schema":{"type":"object","properties":{"event_id":{"type":"string"},"delivered":{"type":"boolean"},"endpoint_status":{"type":"integer","nullable":true},"error":{"type":"string","nullable":true},"note":{"type":"string"}}}}}},"404":{"description":"NOT_FOUND"}}}},"/agents/signup":{"post":{"summary":"Instant self-serve signup: production and sandbox keys returned inline, no card needed","operationId":"agentSignup","tags":["Account"],"security":[],"description":"Instant self-serve account. Returns production and sandbox keys inline; no card needed to quote (a card is only required at booking time, see POST /agents/card-setup-link). phone is optional: when omitted the account carries Warp's desk line until the owner updates it. gw may require an email one-time code, in which case the first call returns verification_required and the caller re-POSTs the same body plus challenge_id and otp.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["firstName","lastName","email","password"],"properties":{"firstName":{"type":"string","example":"Ada"},"lastName":{"type":"string","example":"Lovelace"},"email":{"type":"string","format":"email","example":"ada@example.com"},"password":{"type":"string","format":"password","description":"Min 8 chars, one uppercase letter, one digit.","example":"Str0ngPass"},"companyName":{"type":"string","example":"Analytical Engines Inc"},"phone":{"type":"string","description":"Optional. When omitted the account carries Warp's desk line until the owner updates it."},"challenge_id":{"type":"string","description":"Present only on the re-POST that answers an email one-time-code challenge."},"otp":{"type":"string","description":"The one-time code from the challenge email. Sent together with challenge_id on the re-POST."}}},"example":{"firstName":"Ada","lastName":"Lovelace","email":"ada@example.com","password":"Str0ngPass1","companyName":"Analytical Engines Inc"}}}},"responses":{"200":{"description":"Account created with keys inline, or an email one-time code is required first.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","description":"Email verification required. Re-POST the same body plus challenge_id and otp.","properties":{"ok":{"type":"boolean","example":true},"verification_required":{"type":"boolean","example":true},"challenge_id":{"type":"string"},"email":{"type":"string"},"next":{"type":"string","description":"Instructions for the re-POST that completes signup."}}},{"type":"object","description":"Account created. Keys are live immediately.","properties":{"ok":{"type":"boolean","example":true},"agentId":{"type":"string"},"email":{"type":"string"},"production_key":{"type":"string","example":"wak_live_...","description":"Bearer token for live bookings."},"booking_key":{"type":"string","description":"Alias of production_key, same value."},"sandbox_key":{"type":"string","example":"wak_test_...","description":"Bearer token for the sandbox; no real charges or shipments."},"session_token":{"type":"string"},"client_secret":{"type":"string","nullable":true},"phone_provided":{"type":"boolean"},"agent_instructions":{"type":"string","description":"A paste block for the agent with the key and the quote, book, track calls."},"next":{"type":"object","properties":{"base_url":{"type":"string"},"auth_header":{"type":"string"},"quote":{"type":"string"},"book":{"type":"string"},"card":{"type":"string"},"track":{"type":"string"},"sandbox":{"type":"string"},"mcp":{"type":"string"},"openapi_url":{"type":"string"},"llms_txt_url":{"type":"string"},"docs_url":{"type":"string"},"account_url":{"type":"string"}}}}}]}}}},"400":{"description":"BAD_REQUEST (invalid input), INVALID_OTP, SIGNUP_REJECTED, or PHONE_REQUIRED"},"409":{"description":"EMAIL_TAKEN"},"429":{"description":"RATE_LIMITED"},"500":{"description":"UPSTREAM_ERROR"}}}},"/agents/card-setup-link":{"post":{"summary":"Get a Stripe-hosted link to put a card on file","operationId":"agentCardSetupLink","tags":["Account"],"security":[{"bearerAuth":[]}],"description":"The agent-shaped door through the card wall. Returns a Stripe-hosted checkout_url the agent hands to its human so the first /book does not end in a 402. After the card is saved the agent re-sends the same /book body; the quote_id stays valid until its expires_at.","responses":{"200":{"description":"Checkout link issued","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"has_card":{"type":"boolean"},"checkout_url":{"type":"string","format":"uri"},"expires_in_hours":{"type":"integer","example":24},"note":{"type":"string"}}}}}},"401":{"description":"Auth failure"},"503":{"description":"Card setup unavailable: Stripe is not configured."}}}},"/agents/me":{"get":{"summary":"Read your account status before your first booking","operationId":"agentMe","tags":["Account"],"security":[{"bearerAuth":[]}],"description":"Read before the first booking to know whether a card is on file.","responses":{"200":{"description":"Account status","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"email":{"type":"string"},"company":{"type":"string","nullable":true},"has_card":{"type":"boolean"},"card_brand":{"type":"string","nullable":true},"card_last4":{"type":"string","nullable":true},"onboard_url":{"type":"string"},"card_setup_link":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Auth failure"}}}},"/agents/spend-policy":{"get":{"summary":"Read the account's spending limits and headroom","operationId":"spendPolicy","tags":["Account"],"security":[{"bearerAuth":[]}],"description":"READ-ONLY. Returns the account's spending limits (rolling-window cap, per-booking maximum, confirmation threshold) and current window usage, so an agent can plan before quoting. There is deliberately no write counterpart anywhere in this API: limits are set only by the account owner in the dashboard. Accounts with no limits return capped:false.","responses":{"200":{"description":"Spending limits and usage","content":{"application/json":{"schema":{"type":"object","properties":{"capped":{"type":"boolean"},"window_days":{"type":"integer"},"cap_usd":{"type":"number","nullable":true},"spent_window_usd":{"type":"number"},"remaining_usd":{"type":"number","nullable":true},"max_per_booking_usd":{"type":"number","nullable":true},"confirm_over_usd":{"type":"number","nullable":true}}}}}},"401":{"description":"Auth failure"}}}},"/agents/profile":{"get":{"summary":"Read the shipper profile — how this account actually ships","operationId":"shipperProfileGet","tags":["Account"],"security":[{"bearerAuth":[]}],"description":"The context an agent should read BEFORE asking questions it should already know the answers to. Two halves: explicit owner-set preferences (default accessorials, preferred mode, standard pallet dims, max transit days) and a derived picture aggregated from this account's own quotes and bookings (top lanes, typical pallet count, usual pickup weekday, recent spend). CONTEXT, NEVER PERMISSION: nothing here gates what an agent may do — spending limits live in /agents/spend-policy. Use it to pre-fill and suggest, not to authorize.","responses":{"200":{"description":"Explicit preferences + derived shipping profile","content":{"application/json":{"schema":{"type":"object","properties":{"preferences":{"type":"object","properties":{"default_accessorials":{"type":"object","properties":{"pickup":{"type":"array","items":{"type":"string"}},"delivery":{"type":"array","items":{"type":"string"}}}},"preferred_mode":{"type":"string","enum":["ltl","ftl","van","box_truck","cheapest"]},"standard_pallet_dims":{"type":"object","properties":{"length":{"type":"integer"},"width":{"type":"integer"},"height":{"type":"integer"}}},"max_transit_days":{"type":"integer"},"notes":{"type":"string"}}},"derived":{"type":"object","description":"Aggregated from this account's own quotes and bookings. Read-only — it updates as the account ships.","properties":{"top_lanes":{"type":"array","items":{"type":"object","properties":{"lane_id":{"type":"string"},"origin_zip":{"type":"string","nullable":true},"destination_zip":{"type":"string","nullable":true},"ship_count":{"type":"integer"},"last_shipped_at":{"type":"string","nullable":true},"last_pallet_count":{"type":"integer","nullable":true}}}},"quotes_90d":{"type":"integer"},"quote_modes_90d":{"type":"object","additionalProperties":{"type":"integer"}},"typical_pallets":{"type":"integer","nullable":true},"bookings_180d":{"type":"integer"},"booked_spend_180d_usd":{"type":"number"},"usual_pickup_weekday":{"type":"string","nullable":true},"first_seen":{"type":"string","nullable":true}}},"purpose":{"type":"string","enum":["context_not_permission"]},"note":{"type":"string"}}}}}},"401":{"description":"Auth failure"}}},"put":{"summary":"Set explicit shipper preferences","operationId":"shipperProfilePut","tags":["Account"],"security":[{"bearerAuth":[]}],"description":"Merge-updates the explicit preferences half of the profile (partial PUT — omitted keys keep their value, null clears a key). Allowed keys only: default_accessorials, preferred_mode, standard_pallet_dims, max_transit_days, notes. Unknown keys are rejected by name. The derived half cannot be written — it comes from what the account actually ships.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"default_accessorials":{"type":"object","properties":{"pickup":{"type":"array","items":{"type":"string"}},"delivery":{"type":"array","items":{"type":"string"}}}},"preferred_mode":{"type":"string","enum":["ltl","ftl","van","box_truck","cheapest"]},"standard_pallet_dims":{"type":"object","properties":{"length":{"type":"integer","minimum":12,"maximum":96},"width":{"type":"integer","minimum":12,"maximum":96},"height":{"type":"integer","minimum":12,"maximum":96}}},"max_transit_days":{"type":"integer","minimum":1,"maximum":14},"notes":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Merged preferences as now stored"},"400":{"description":"Validation failure — unknown key or bad value, named in error"},"401":{"description":"Auth failure"}}}},"/consolidate":{"post":{"summary":"Find consolidation savings across 2-12 upcoming loads","operationId":"consolidate","tags":["Quoting"],"description":"The money-finder. Give it the loads you plan to ship (2-12); it clusters loads sharing an exact origin+destination zip whose pickup dates fall inside window_days and that together fit one 53' dry van (26 pallet positions / 44,000 lbs, non-stackable positions — stated fit model), then prices every cluster BOTH ways through the real quote machinery: one combined FTL vs the sum of individual LTLs. Both sides come back as bookable quote ids, so acting on a proposal is a normal /book call on the truck's quote_id. Loads that can't consolidate are returned under unconsolidated WITH the reason (no lane partner / outside window / exceeds trailer / cluster full) — never silently dropped. A cluster whose truck prices above its LTLs is still returned with recommended:false: the math is shown, not curated. Auth optional — keyless requests price via the house quote account exactly like the quote endpoints. Same lane + different delivery doors is /multistop/quote's job.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["loads"],"properties":{"loads":{"type":"array","minItems":2,"maxItems":12,"items":{"type":"object","required":["origin_zip","destination_zip","pickup_date","pallets","weight_lbs_per_pallet"],"properties":{"origin_zip":{"type":"string","pattern":"^\\d{5}$"},"destination_zip":{"type":"string","pattern":"^\\d{5}$"},"pickup_date":{"type":"string","format":"date"},"pallets":{"type":"integer","minimum":1,"maximum":26},"weight_lbs_per_pallet":{"type":"integer","minimum":50,"maximum":5000},"ref":{"type":"string","maxLength":64,"description":"Caller reference (PO number, order id) echoed back verbatim."},"length":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"}}}},"window_days":{"type":"integer","minimum":1,"maximum":7,"default":3,"description":"Loads picking up within this many days of each other may ride together."}}}}}},"responses":{"200":{"description":"Consolidation proposals + the loads that couldn't, with reasons","content":{"application/json":{"schema":{"type":"object","properties":{"window_days":{"type":"integer"},"proposals":{"type":"array","items":{"type":"object","properties":{"lane":{"type":"object","properties":{"origin_zip":{"type":"string"},"destination_zip":{"type":"string"}}},"pickup_date":{"type":"string"},"pickup_window":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}}},"loads":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"ref":{"type":"string","nullable":true},"pallets":{"type":"integer"},"weight_lbs":{"type":"integer"},"pickup_date":{"type":"string"},"ltl_quote":{"type":"object","properties":{"quote_id":{"type":"string"},"price_usd":{"type":"number"},"transit_days":{"type":"integer"}}}}}},"consolidated_truck":{"type":"object","properties":{"mode":{"type":"string"},"vehicle":{"type":"string"},"quote_id":{"type":"string"},"price_usd":{"type":"number"},"transit_days":{"type":"integer"},"pickup_date":{"type":"string"},"delivery_date":{"type":"string"}}},"separate_ltl_total_usd":{"type":"number","nullable":true},"savings_usd":{"type":"number","nullable":true},"savings_pct":{"type":"number","nullable":true},"recommended":{"type":"boolean"},"trailer_fill":{"type":"object","properties":{"pallet_positions":{"type":"integer"},"of_positions":{"type":"integer"},"weight_lbs":{"type":"integer"},"of_weight_lbs":{"type":"integer"},"position_fill_pct":{"type":"integer"}}},"quote_tier":{"type":"string","enum":["firm","indicative"]}}}},"unconsolidated":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"ref":{"type":"string","nullable":true},"reason":{"type":"string","enum":["no_lane_partner","outside_window","exceeds_trailer","cluster_full"]},"explanation":{"type":"string"}}}},"total_savings_usd":{"type":"number"},"summary":{"type":"string"}}}}}},"400":{"description":"Validation failure — the offending load index is named"}}}},"/book/hold":{"get":{"summary":"Poll a held booking awaiting owner approval","operationId":"bookHold","tags":["Booking"],"security":[{"bearerAuth":[]}],"description":"Check the state of a booking held by the confirmation threshold (see /book's 202). status is pending, approved, rejected, or expired, with a next_step sentence. After approval, call /book again with the same quote_id to complete — approval alone never books.","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"hold.token from /book's 202 response."}],"responses":{"200":{"description":"Hold state","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"quote_id":{"type":"string"},"price_usd":{"type":"number"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"expires_at":{"type":"string"},"next_step":{"type":"string"}}}}}},"401":{"description":"Auth failure"},"404":{"description":"Hold not found (or belongs to another account)"}}}},"/quote-history":{"get":{"summary":"List your past quote requests","operationId":"quoteHistory","tags":["Memory"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Quote history","content":{"application/json":{"schema":{"type":"object","properties":{"quote_history":{"type":"array","description":"Past quote requests, newest first.","items":{"type":"object","properties":{"quote_id":{"type":"string","example":"wq_01M1CAP123BE9TEXNK9NY5BK7S"},"mode":{"type":"string","enum":["ltl","ftl","van","box-truck"],"example":"ltl"},"origin_zip":{"type":"string","example":"93725"},"destination_zip":{"type":"string","example":"80216"},"pallets":{"type":"integer","example":18},"price_usd":{"type":"number","nullable":true,"example":5148.14},"created_at":{"type":"string","format":"date-time","example":"2026-08-31T16:33:17.894Z"}}}}}}}}},"401":{"description":"Auth failure"}}}},"/multistop/quote":{"post":{"summary":"Quote an FTL multi-stop shipment","operationId":"multistopQuote","tags":["Multi-stop"],"security":[{"bearerAuth":[]}],"description":"One truck, one route, multiple stops. The route model is first pickup (pickup_info) → intermediate stops (transits, in order) → final delivery (delivery_info). snake_case keys shown here are translated to the gateway's camelCase (/freights/quote/multi-stops); camelCase equivalents are also accepted. Set vehicle_type to get a priced quote — without it the gateway answers \"A rate has not yet been determined for this route\".","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pickup_date","pickup_info","transits","delivery_info","list_items"],"properties":{"pickup_date":{"type":"string","format":"date","example":"2026-06-22"},"pickup_info":{"type":"object","required":["zipcode"],"description":"First pickup stop.","properties":{"zipcode":{"type":"string","example":"90001"}}},"transits":{"type":"array","minItems":1,"description":"Intermediate stops between first pickup and final delivery, in route order.","items":{"type":"object","required":["zipcode"],"properties":{"zipcode":{"type":"string","example":"92101"}}}},"delivery_info":{"type":"object","required":["zipcode"],"description":"Final delivery stop.","properties":{"zipcode":{"type":"string","example":"85001"}}},"list_items":{"type":"array","items":{"type":"object","description":"Freight item. Same field set the single-stop gateway quote uses; send dims in inches (size_unit IN) and weight in lbs.","properties":{"name":{"type":"string","example":"1"},"length":{"type":"number","example":48},"width":{"type":"number","example":40},"height":{"type":"number","example":48},"size_unit":{"type":"string","example":"IN"},"total_weight":{"type":"number","example":5000,"description":"Total weight across the quantity, not per piece"},"weight_unit":{"type":"string","example":"lbs"},"quantity":{"type":"integer","example":10},"packaging":{"type":"string","example":"pallet"}}}},"vehicle_type":{"type":"string","example":"DRY_VAN_53","description":"Vehicle code. Optional to the validator but required in practice to resolve a rate."},"shipment_type":{"type":"string","example":"FTL"}}}}}},"responses":{"200":{"description":"Multi-stop quote returned","content":{"application/json":{"schema":{"type":"object","properties":{"quote_id":{"type":"string","example":"PRICING_MULTI_df23163d-2ad1-40c2-94a0-24bf2919a13c"},"total_charge":{"type":"number","example":2281.81},"transit_time":{"type":"integer","example":39600,"description":"Seconds"},"rate_detail":{"type":"object"}}}}}},"400":{"description":"Validation failure (gateway message passed through as { error, code: UPSTREAM_ERROR, upstream_status, upstream_response })"},"401":{"description":"Auth failure"},"502":{"description":"Upstream error"}}}},"/multistop/book":{"post":{"summary":"Book a quoted multi-stop FTL shipment","operationId":"multistopBook","tags":["Multi-stop"],"security":[{"bearerAuth":[]}],"description":"Books the route quoted by /multistop/quote as per-leg shipments: one entry per pickup→delivery pair, each referencing the quoted stop sequence by stop_index. snake_case keys are translated to the gateway's camelCase (/freights/booking/multi-stops); camelCase equivalents are also accepted. No Stripe charge fires here — multi-stop pricing settles via your Warp account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quote_id","shipments"],"properties":{"quote_id":{"type":"string","example":"PRICING_MULTI_df23163d-2ad1-40c2-94a0-24bf2919a13c","description":"From /multistop/quote"},"shipments":{"type":"array","minItems":2,"description":"One leg per pickup→delivery pair riding the quoted route.","items":{"type":"object","required":["pickup_info","delivery_info","list_items"],"properties":{"pickup_info":{"type":"object","required":["stop_index","address","window_time"],"properties":{"stop_index":{"type":"integer","description":"Index into the quoted stop sequence: 0 = the quote's pickup_info stop, then transits in order, last = the quote's delivery_info stop."},"address":{"type":"object","required":["zipcode"],"properties":{"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zipcode":{"type":"string","description":"Exact field name the gateway validates; zip/zip_code/zipCode are normalized to it"}}},"window_time":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time","example":"2026-06-22T08:00:00.000Z"},"to":{"type":"string","format":"date-time","example":"2026-06-22T23:59:59.000Z"}}},"contact_name":{"type":"string"},"contact_phone":{"type":"string"},"contact_email":{"type":"string"}}},"delivery_info":{"type":"object","required":["stop_index","address","window_time"],"properties":{"stop_index":{"type":"integer","description":"Index into the quoted stop sequence: 0 = the quote's pickup_info stop, then transits in order, last = the quote's delivery_info stop."},"address":{"type":"object","required":["zipcode"],"properties":{"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zipcode":{"type":"string","description":"Exact field name the gateway validates; zip/zip_code/zipCode are normalized to it"}}},"window_time":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time","example":"2026-06-22T08:00:00.000Z"},"to":{"type":"string","format":"date-time","example":"2026-06-22T23:59:59.000Z"}}},"contact_name":{"type":"string"},"contact_phone":{"type":"string"},"contact_email":{"type":"string"}}},"list_items":{"type":"array","items":{"type":"object","description":"Freight item. Same field set the single-stop gateway quote uses; send dims in inches (size_unit IN) and weight in lbs.","properties":{"name":{"type":"string","example":"1"},"length":{"type":"number","example":48},"width":{"type":"number","example":40},"height":{"type":"number","example":48},"size_unit":{"type":"string","example":"IN"},"total_weight":{"type":"number","example":5000,"description":"Total weight across the quantity, not per piece"},"weight_unit":{"type":"string","example":"lbs"},"quantity":{"type":"integer","example":10},"packaging":{"type":"string","example":"pallet"}}},"description":"Items riding this leg"}}}}}}}}},"responses":{"200":{"description":"Multi-stop booking confirmed (gateway response returned verbatim)"},"400":{"description":"Validation failure (gateway message passed through as { error, code: UPSTREAM_ERROR, upstream_status, upstream_response })"},"401":{"description":"Auth failure"},"502":{"description":"Upstream error"}}}},"/tools/freight-class":{"post":{"summary":"Calculate NMFTA density-based LTL freight class","operationId":"freightClassCalc","tags":["Tools"],"description":"Public free utility. No auth required for first 60 req/hr per IP. wak_test_* keys get 1,000/hr; wak_live_* keys get 10,000/hr. CORS open. Returns data + meta envelope with rate-limit, docs, upgrade URL, and attribution.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["length","width","height","weight"],"properties":{"length":{"type":"number","example":48,"description":"Length (default inches; use units=cm for centimeters)"},"width":{"type":"number","example":40,"description":"Width (default inches)"},"height":{"type":"number","example":48,"description":"Height (default inches)"},"weight":{"type":"number","example":500,"description":"Total weight (default pounds; use weight_unit=kg for kilograms)"},"units":{"type":"string","enum":["in","cm"],"description":"Defaults to in"},"weight_unit":{"type":"string","enum":["lb","kg"],"description":"Defaults to lb"}}}}}},"responses":{"200":{"description":"Computed freight class with rate-limit meta","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"freight_class":{"type":"string","example":"100"},"density_pcf":{"type":"number","example":9.42},"cubic_feet":{"type":"number","example":53.33},"class_band":{"type":"string","example":"Standard"},"note":{"type":"string"}}},"meta":{"type":"object","properties":{"request_id":{"type":"string"},"tier":{"type":"string","enum":["anon","sandbox","live"]},"rate_limit":{"type":"object","properties":{"limit":{"type":"integer"},"remaining":{"type":"integer"},"reset_at":{"type":"string","format":"date-time"}}},"docs":{"type":"string"},"upgrade":{"type":"string"},"attribution":{"type":"string"}}}}}}}},"400":{"description":"BAD_INPUT — missing/invalid dimensions or weight","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED — tier limit reached; meta.upgrade points to the next tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Calculate NMFTA freight class via query params","operationId":"freightClassCalcGet","tags":["Tools"],"description":"Convenience GET. Same response shape as POST.","parameters":[{"name":"length","in":"query","required":true,"schema":{"type":"number"},"example":48},{"name":"width","in":"query","required":true,"schema":{"type":"number"},"example":40},{"name":"height","in":"query","required":true,"schema":{"type":"number"},"example":48},{"name":"weight","in":"query","required":true,"schema":{"type":"number"},"example":500},{"name":"units","in":"query","required":false,"schema":{"type":"string","enum":["in","cm"]}},{"name":"weight_unit","in":"query","required":false,"schema":{"type":"string","enum":["lb","kg"]}}],"responses":{"200":{"description":"Computed freight class"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/density":{"post":{"summary":"Calculate freight density (PCF) + freight class","operationId":"densityCalc","tags":["Tools"],"description":"Public free utility. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open. Returns data + meta envelope.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["length","width","height","weight"],"properties":{"length":{"type":"number","example":48},"width":{"type":"number","example":40},"height":{"type":"number","example":48},"weight":{"type":"number","example":500},"pieces":{"type":"number","example":1,"description":"Optional, defaults to 1"},"units":{"type":"string","enum":["in","cm"]},"weight_unit":{"type":"string","enum":["lb","kg"]}}}}}},"responses":{"200":{"description":"Density (PCF) + cubic feet + freight class with rate-limit meta"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Calculate freight density via query params","operationId":"densityCalcGet","tags":["Tools"],"parameters":[{"name":"length","in":"query","required":true,"schema":{"type":"number"}},{"name":"width","in":"query","required":true,"schema":{"type":"number"}},{"name":"height","in":"query","required":true,"schema":{"type":"number"}},{"name":"weight","in":"query","required":true,"schema":{"type":"number"}},{"name":"pieces","in":"query","required":false,"schema":{"type":"number"}},{"name":"units","in":"query","required":false,"schema":{"type":"string","enum":["in","cm"]}},{"name":"weight_unit","in":"query","required":false,"schema":{"type":"string","enum":["lb","kg"]}}],"responses":{"200":{"description":"Density + cubic feet + freight class"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/dim-weight":{"post":{"summary":"Calculate dimensional weight + billable weight","operationId":"dimWeightCalc","tags":["Tools"],"description":"Public free utility. Returns dim weight, actual weight, and billable max(dim, actual). Default dim factor 139 (US ground). 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["length","width","height","weight"],"properties":{"length":{"type":"number","example":24},"width":{"type":"number","example":18},"height":{"type":"number","example":12},"weight":{"type":"number","example":8},"dim_factor":{"type":"number","example":139,"description":"139 ground · 166 air · 250 metric"},"units":{"type":"string","enum":["in","cm"]},"weight_unit":{"type":"string","enum":["lb","kg"]}}}}}},"responses":{"200":{"description":"Dim weight + actual + billable with rate-limit meta"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Calculate dim weight via query params","operationId":"dimWeightCalcGet","tags":["Tools"],"parameters":[{"name":"length","in":"query","required":true,"schema":{"type":"number"}},{"name":"width","in":"query","required":true,"schema":{"type":"number"}},{"name":"height","in":"query","required":true,"schema":{"type":"number"}},{"name":"weight","in":"query","required":true,"schema":{"type":"number"}},{"name":"dim_factor","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"Dim weight + billable"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/cbm":{"post":{"summary":"Calculate cubic meters (CBM) + volumetric weight for ocean / air","operationId":"cbmCalc","tags":["Tools"],"description":"Public free utility. Returns CBM, total CBM, and volumetric weight for both air (×167) and ocean (×1000) billing. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["length","width","height"],"properties":{"length":{"type":"number","example":120},"width":{"type":"number","example":100},"height":{"type":"number","example":150},"qty":{"type":"number","example":4,"description":"Defaults to 1"},"units":{"type":"string","enum":["cm","in"],"description":"Defaults to cm"}}}}}},"responses":{"200":{"description":"CBM + total CBM + air/ocean volumetric weight with rate-limit meta"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Calculate CBM via query params","operationId":"cbmCalcGet","tags":["Tools"],"parameters":[{"name":"length","in":"query","required":true,"schema":{"type":"number"}},{"name":"width","in":"query","required":true,"schema":{"type":"number"}},{"name":"height","in":"query","required":true,"schema":{"type":"number"}},{"name":"qty","in":"query","required":false,"schema":{"type":"number"}},{"name":"units","in":"query","required":false,"schema":{"type":"string","enum":["cm","in"]}}],"responses":{"200":{"description":"CBM + total + volumetric weights"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/rate-per-mile":{"post":{"summary":"Compute $/mile + vs-benchmark comparison","operationId":"ratePerMileCalc","tags":["Tools"],"description":"Public free utility. Returns rate per mile plus a comparison against published 2026 averages (LTL $2.80/mi, TL $3.20/mi). 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["total_cost","miles"],"properties":{"total_cost":{"type":"number","example":1450,"description":"Total invoice in USD"},"miles":{"type":"number","example":480,"description":"Lane distance in miles"},"mode":{"type":"string","enum":["ltl","tl"],"description":"Defaults to tl"}}}}}},"responses":{"200":{"description":"Rate + benchmark + vs_benchmark_pct"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Compute rate per mile via query params","operationId":"ratePerMileCalcGet","tags":["Tools"],"parameters":[{"name":"total_cost","in":"query","required":true,"schema":{"type":"number"}},{"name":"miles","in":"query","required":true,"schema":{"type":"number"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["ltl","tl"]}}],"responses":{"200":{"description":"Rate + benchmark"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/pallet-weight":{"post":{"summary":"Total pallet weight from cases + tare","operationId":"palletWeightCalc","tags":["Tools"],"description":"Public free utility. Adds case weight × case count + pallet tare × pallet count. Returns total and per-pallet weight. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cases","weight_per_case"],"properties":{"cases":{"type":"number","example":40},"weight_per_case":{"type":"number","example":25,"description":"Pounds per case"},"pallet_tare_lb":{"type":"number","example":45,"description":"Empty pallet weight; defaults to 45 for 48x40 hardwood"},"pallets":{"type":"number","example":2,"description":"Defaults to 1"}}}}}},"responses":{"200":{"description":"Total + per-pallet weight"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Calculate pallet weight via query params","operationId":"palletWeightCalcGet","tags":["Tools"],"parameters":[{"name":"cases","in":"query","required":true,"schema":{"type":"number"}},{"name":"weight_per_case","in":"query","required":true,"schema":{"type":"number"}},{"name":"pallet_tare_lb","in":"query","required":false,"schema":{"type":"number"}},{"name":"pallets","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"Total + per-pallet weight"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/truck-payload":{"post":{"summary":"Truck / van payload analysis with utilization %","operationId":"truckPayloadCalc","tags":["Tools"],"description":"Public free utility. Given cargo weight (and optional volume + pallet count) and a vehicle type, returns remaining capacity and utilization percentages. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cargo_weight"],"properties":{"cargo_weight":{"type":"number","example":4500,"description":"Cargo weight in pounds"},"vehicle":{"type":"string","enum":["cargo_van","sprinter_van","box_truck_16","box_truck_26","dry_van_53"],"description":"Defaults to dry_van_53"},"cargo_volume":{"type":"number","example":1100,"description":"Optional cubic feet"},"cargo_pallets":{"type":"number","example":8,"description":"Optional pallet count"}}}}}},"responses":{"200":{"description":"Vehicle specs + remaining capacity + utilization"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Truck payload via query params","operationId":"truckPayloadCalcGet","tags":["Tools"],"parameters":[{"name":"cargo_weight","in":"query","required":true,"schema":{"type":"number"}},{"name":"vehicle","in":"query","required":false,"schema":{"type":"string","enum":["cargo_van","sprinter_van","box_truck_16","box_truck_26","dry_van_53"]}},{"name":"cargo_volume","in":"query","required":false,"schema":{"type":"number"}},{"name":"cargo_pallets","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"Vehicle + remaining capacity"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/freight-insurance":{"post":{"summary":"Estimate cargo insurance premium by commodity","operationId":"freightInsuranceCalc","tags":["Tools"],"description":"Public free utility. Premium = max($25, cargo_value × rate%); cost-per-$100 and 2% deductible. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cargo_value"],"properties":{"cargo_value":{"type":"number","example":50000,"description":"Insured cargo value in USD"},"commodity":{"type":"string","enum":["general","electronics","fragile","perishable"],"description":"Defaults to general"}}}}}},"responses":{"200":{"description":"Premium + cost-per-$100 + estimated deductible"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Cargo insurance premium via query params","operationId":"freightInsuranceCalcGet","tags":["Tools"],"parameters":[{"name":"cargo_value","in":"query","required":true,"schema":{"type":"number"}},{"name":"commodity","in":"query","required":false,"schema":{"type":"string","enum":["general","electronics","fragile","perishable"]}}],"responses":{"200":{"description":"Premium"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/fuel-surcharge":{"post":{"summary":"LTL fuel surcharge for the 6 largest US carriers","operationId":"fuelSurchargeCalc","tags":["Tools"],"description":"Public free utility. Uses each carrier's published FSC at the current DOE on-highway diesel baseline, scales linearly with the supplied diesel_price. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["base_rate","carrier"],"properties":{"base_rate":{"type":"number","example":1000,"description":"Base linehaul rate (USD)"},"carrier":{"type":"string","enum":["fedex_freight","old_dominion","xpo","estes","saia","abf"]},"diesel_price":{"type":"number","example":5.5,"description":"Optional $/gal. Defaults to cached DOE baseline."}}}}}},"responses":{"200":{"description":"Effective surcharge % + dollar impact + DOE baseline"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Fuel surcharge via query params","operationId":"fuelSurchargeCalcGet","tags":["Tools"],"parameters":[{"name":"base_rate","in":"query","required":true,"schema":{"type":"number"}},{"name":"carrier","in":"query","required":true,"schema":{"type":"string","enum":["fedex_freight","old_dominion","xpo","estes","saia","abf"]}},{"name":"diesel_price","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"Surcharge + total"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/accessorial":{"post":{"summary":"LTL accessorial fee ranges + invoice impact","operationId":"accessorialCalc","tags":["Tools"],"description":"Public free utility. Pass an array of accessorial slugs (and optional base_rate). Returns industry-standard fee ranges, totals, and percent impact. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["selected"],"properties":{"selected":{"type":"array","items":{"type":"string","enum":["liftgate_pickup","liftgate_delivery","residential_delivery","inside_delivery","appointment","reweigh","reclassification","limited_access"]},"example":["liftgate_pickup","residential_delivery","appointment"]},"base_rate":{"type":"number","example":850,"description":"Optional base rate; enables invoice + percent fields in response"}}}}}},"responses":{"200":{"description":"Selected accessorials + totals"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Accessorial fees via query params (comma-separated)","operationId":"accessorialCalcGet","tags":["Tools"],"parameters":[{"name":"selected","in":"query","required":true,"schema":{"type":"string"},"example":"liftgate_pickup,residential_delivery,appointment","description":"Comma-separated slugs"},{"name":"base_rate","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"Accessorial totals"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}},"/tools/container-load":{"post":{"summary":"Container / trailer pallet-fit analysis","operationId":"containerLoadCalc","tags":["Tools"],"description":"Public free utility. Geometric pallet-fit for shipping containers and trailers. Returns two real loading patterns. pallets_floor_straight is uniform orientation, the standard dry van pattern: 26 for a 48x40 pallet in a 53 ft trailer. pallets_floor is the best achievable with orientations mixed and pin-wheeled: 30 in that trailer, 10 in a 20 ft container, 20 in a 40 ft. Plus double-stack height check, floor + volume utilization, and weight-limited flag. 60 req/hr anon · 1,000/hr sandbox · 10,000/hr live. CORS open.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pallet_length","pallet_width","pallet_height","pallet_weight"],"properties":{"pallet_length":{"type":"number","example":48,"description":"Inches"},"pallet_width":{"type":"number","example":40,"description":"Inches"},"pallet_height":{"type":"number","example":56,"description":"Loaded pallet height, inches"},"pallet_weight":{"type":"number","example":1200,"description":"Pounds"},"container":{"type":"string","enum":["container_20ft","container_40ft","container_40ft_hc","trailer_53ft"],"description":"Defaults to trailer_53ft"}}}}}},"responses":{"200":{"description":"Pallets per floor + stacked + utilization"},"400":{"description":"BAD_INPUT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"summary":"Container load via query params","operationId":"containerLoadCalcGet","tags":["Tools"],"parameters":[{"name":"pallet_length","in":"query","required":true,"schema":{"type":"number"}},{"name":"pallet_width","in":"query","required":true,"schema":{"type":"number"}},{"name":"pallet_height","in":"query","required":true,"schema":{"type":"number"}},{"name":"pallet_weight","in":"query","required":true,"schema":{"type":"number"}},{"name":"container","in":"query","required":false,"schema":{"type":"string","enum":["container_20ft","container_40ft","container_40ft_hc","trailer_53ft"]}}],"responses":{"200":{"description":"Container load analysis"},"400":{"description":"BAD_INPUT"},"429":{"description":"RATE_LIMITED"}}}}}}