Orders & fulfilment
Carrier integrations (UPS, FedEx, DHL, USPS)
Indicative price, not an offer: €29–79/month per carrier
Generated from docs/plan/paid/carrier-integrations-2/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Provides read-only APIs for UPS, FedEx, DHL, and USPS carriers integrated into AstroBaaS. Supports live rate quotes, tracking, and label generation. Does not include shipping-label-generation or tracking-number-sync (separate features).
The problem
No carrier integrations exist. I have accounts with UPS and FedEx but cannot fetch live rates, generate labels, or sync tracking without third-party software.
What it does
- Carrier adapter interface: abstract class for rate queries, label generation, tracking queries; concrete implementations for UPS, FedEx, DHL, USPS
- API key storage: settings store carrier account credentials (API key, shipper ID, etc.); encryption at rest
- Connection testing: test endpoint validates credentials and connectivity to each carrier
- Rate quote: adapter queries carrier with weight, destination, service level; returns rate in USD (or carrier’s native currency)
- Label generation: adapter generates PDF or ZPL; stores response blob
- Tracking query: adapter queries carrier with tracking number; returns events array
- Error handling: adapter returns structured errors (e.g., ‘account_not_found’, ‘invalid_zip’); system translates to user-friendly messages
- Retry logic: if carrier API times out, retry up to 2 times with exponential backoff
- Rate limiting: respect carrier rate limits (queries per minute); queue requests if needed
- Webhook: carrier.integration_status_changed when adapter health changes (up/down)
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- UPS Quantum View (real-time shipment visibility): out of scope—polling API only. Reason: WebSocket requires separate contract.
- FedEx Ground vs Express rate differences: out of scope—adapter returns rate for requested service. Reason: merchant selects service; adapter doesn’t differentiate.
- DHL Express customs broker integration: out of scope. Reason: outside carrier API scope.
- USPS Informed Delivery (consumer notifications): out of scope. Reason: only USPS’s service, not part of shipping API.
- Carrier surcharges per region (fuel, zone): out of scope—returned in rate as single value. Reason: carrier applies surcharges; system receives net rate.
- International shipment additional declarations: out of scope. Reason: handled by label generation; no separate entity.
Data model
No new entities (CarrierAccount is defined in live-carrier-rate-apis). CarrierIntegrationLog table/collection for debugging: log_id, carrier, request_type (rate|label|tracking), request_body, response_status, response_body, error (if any), created_at. Assumption: settings key/value store exists.
API
- POST /carrier-integrations/test (staff, body: {carrier, api_key, shipper_id?}) → {success: true | false, error?: string}
- GET /carrier-integrations/status → [{carrier, is_healthy, last_check, last_error?}]
- POST /carrier-integrations/:carrier/rate (internal, body: {origin_zip, dest_zip, weight_g, service_level}) → {rate_usd, delivery_days, carrier_name}
- POST /carrier-integrations/:carrier/label (internal, body: {tracking_number, from_address, to_address, weight_g, service_level}) → {label_blob_id, label_format}
- POST /carrier-integrations/:carrier/tracking (internal, body: {tracking_number}) → {status, events: [{status, timestamp, location}]}
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Carrier Integrations section in settings. List UPS, FedEx, DHL, USPS with connection status (green/red indicator). Test button for each. API key field (masked input). Error log showing recent failures with timestamp and reason.
The seam — why this is paid
Core owns carrier adapter interface and base implementations for UPS, FedEx, DHL, USPS. Paid pack owns: custom carrier integrations (regional carriers), complex rate rule overrides, carrier-specific billing models. Why: core provides honest read-only API access to four major carriers; custom carriers and billing logic are paid.
Requires carrier credentials and rate agreements. Needs support for API maintenance and troubleshooting.
Dependencies
- settings (carrier credentials stored as key/value)
- live-carrier-rate-apis (rate queries use carrier-integrations adapter)
- shipping-label-generation (label generation calls adapter)
- tracking-number-sync (tracking queries call adapter)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- CarrierAccount created with carrier_name=‘ups’, api_key=‘test_abc123’; POST /carrier-integrations/test returns {success: true}
- Invalid api_key returns {success: false, error: ‘ups.invalid_credentials’}
- POST /carrier-integrations/ups/rate with weight=500, dest_zip=‘90210’ returns {rate_usd: 18.99, delivery_days: 2}
- POST /carrier-integrations/fedex/label returns label_blob_id and label_format=‘pdf’
- POST /carrier-integrations/usps/tracking with tracking_number=‘1234567890’ returns status and events array
- Carrier API timeout: retry twice with 1s and 2s delay; if all fail, return 503 with ‘carrier.timeout’
- GET /carrier-integrations/status shows all four carriers; one shows is_healthy=false with last_error=‘rate_limit_exceeded’
- Webhook carrier.integration_status_changed fires when UPS status changes from healthy to unhealthy
- Invalid request (e.g., missing dest_zip) returns 400 with validation error, not carrier API error
- Carrier integration log records every request/response for debugging; accessible to staff in admin
Risks
Credentials: API keys stored in settings; if leaked, attacker can generate labels and queries on merchant’s account (and bill them). Rate limits: if many customers check rates at once, carrier API rate limit is hit; merchant sees no rates (fallback to manual rates). Timeout: if carrier API is slow (10+ seconds), checkout hangs; must timeout early (5s) and fallback. Error messages: if carrier returns raw error (e.g., ‘Account 1234 not found’), staff sees merchant account number in logs; sanitize.
Commercial context
| Suggested price | €29–79/month per carrier |
| Rival anchor | Magento Open Source: UPS, USPS, DHL, FedEx bundled free with live rates and PDF labels. |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.