Home / Technical Reference / Transportation API Architecture

Transportation Developer Guide & Integration Patterns

Transportation API & Integration Architecture Library

An engineering reference for freight software engineers, logistics IT directors, and integration teams. Explore standard REST request/response schemas, event-driven webhook patterns, ELD telematics ingestion, and hybrid EDI-to-REST pipelines.

1. Modern Freight Integration Architecture: EDI & REST Coexistence

Enterprise logistics requires supporting both asynchronous batch B2B protocols (ANSI ASC X12 EDI) and low-latency, event-driven HTTP REST APIs. Rather than forcing shippers or motor carriers into a single standard, modern Transportation Management Systems deploy an API translation gateway that normalizes incoming loads regardless of origin.

Unified Shipment State Machine

Whether a shipment arrives via EDI 204 from a retail distribution network or via JSON REST API from a 3PL customer portal, the payload is parsed into an immutable domain entity.

EDI 204 / REST Ingest → Tender Validation → Fast Dispatch Grid → CheckPoint GPS / ELD → Sage/QBO Billing

2. Standard Freight Load Tender Ingestion (POST /api/v1/shipments/tender)

Allows shippers, 3PL brokers, and ERP systems (SAP, Oracle, NetSuite) to programmatically tender loads directly to the TMS. Mirrors the informational payload of an ANSI X12 204 transaction with clean JSON semantics.

Field Type Requirement Description
tender_id String Required Unique shipper-assigned tender identification code (B204).
action String Required TENDER_NEW, TENDER_UPDATE, or TENDER_CANCEL.
stops Array<Stop> Required Ordered collection of origin, intermediate, and destination facilities.
rate Object Optional Agreed linehaul, FSC calculation method, and accessorial commitments.
// Example Conceptual JSON Request: POST /api/v1/shipments/tender { "tender_id": "TND-984214-MN", "timestamp": "2026-10-06T14:32:00Z", "action": "TENDER_NEW", "equipment_type": "53FT_DRY_VAN", "billing_currency": "USD", "agreed_linehaul": 2450.00, "fsc_index": "DOE_WEEKLY_DIESEL_NATIONAL", "stops": [ { "sequence": 1, "type": "PICKUP", "facility_name": "Minneapolis Distribution Hub", "address": { "street": "400 S 4th St", "city": "Minneapolis", "state": "MN", "postal_code": "55415", "country": "USA" }, "appointment_window": { "start": "2026-10-07T08:00:00Z", "end": "2026-10-07T12:00:00Z" }, "commodities": [ { "description": "Consumer Electronics", "weight_lbs": 38400, "pallet_count": 24 } ] }, { "sequence": 2, "type": "DELIVERY", "facility_name": "Chicago Logistics Terminal", "address": { "street": "1800 S Western Ave", "city": "Chicago", "state": "IL", "postal_code": "60608", "country": "USA" }, "appointment_window": { "start": "2026-10-08T06:00:00Z", "end": "2026-10-08T10:00:00Z" } } ] }

3. Event-Driven Webhooks: Real-Time Shipment Status Updates

Instead of continuous polling, shippers and partner brokers subscribe to webhook endpoints. Whenever a driver triggers a milestone in the TMS (via ELD, CheckPoint GPS, or driver app), an HTTP POST is emitted with an HMAC SHA-256 signature.

// Example Conceptual JSON Webhook Delivery: POST https://shipper.com/webhooks/freight // Header: X-Exspeedite-Signature: sha256=d3b07384d113edec49eaa6238ad5ff00... { "event_id": "evt_81923058102", "event_type": "shipment.status_updated", "shipment_id": "EXP-2026-88194", "shipper_ref": "PO-49102-WALMART", "status_code": "X6", "status_description": "En Route to Delivery Location", "geo_telematics": { "latitude": 41.8781, "longitude": -87.6298, "speed_mph": 62, "city": "Joliet", "state": "IL", "estimated_eta": "2026-10-08T07:15:00Z" }, "hos_remaining_drive_hours": 4.8 }

4. Webhook Reliability: Exponential Backoff with Jitter

In freight transportation, network outages and receiving server downtime must not cause lost milestones. Exspeedite implements idempotent message delivery with exponential backoff and jitter algorithms across 5 retry attempts over a 24-hour cycle.

// Standard Exponential Backoff Formula with Decorrelated Jitter: function calculateNextRetry(attempt, baseDelay = 5, maxDelay = 1800) { const exponential = Math.min(maxDelay, baseDelay * Math.pow(2, attempt)); const jitter = Math.random() * (exponential * 0.2); // 20% random spread to prevent thundering herd return Math.round(exponential + jitter); } // Attempt 1: ~10 seconds // Attempt 2: ~20 seconds // Attempt 3: ~40 seconds // Attempt 4: ~80 seconds // Attempt 5: ~160 seconds