FreshBooks and ShipStation integration
FreshBooks tracks invoices, expenses, and clients. ShipStation manages orders and shipments for e-commerce. Connecting the two keeps your customer list aligned and your fulfillment costs posted into your accounting records. New orders in ShipStation pull customer data from FreshBooks, and each shipment creates an expense or cost allocation in FreshBooks so your landed-goods and fulfillment costs stay visible in your accounting close. ml-connector handles the different authentication models and bridges the gap between FreshBooks' user-delegated OAuth and ShipStation's API Key scheme.
What moves between them
Orders and customers flow from ShipStation into FreshBooks. When a new order arrives in ShipStation, ml-connector reads the order and customer data (polling V1 with modifyDate to catch updates), maps the customer to a FreshBooks client, and optionally creates an expense or invoice line item. When a shipment event fires, ml-connector polls ShipStation to fetch the full shipment details (following the webhook pointer), calculates fulfillment cost by carrier, and posts that as an expense in FreshBooks. Costs are tagged with the original order reference so they can be reconciled to invoices and matched to revenue. The sync runs on a polling cadence for ShipStation (since webhooks are pointer-only and order updates are not pushed) and consumes FreshBooks webhooks where possible to accelerate the reverse flow (e.g., invoice cancellations that trigger shipment refunds).
How ml-connector handles it
ml-connector stores the FreshBooks OAuth credential (user-delegated token refresh on 401) and the ShipStation API Key (V1 and V2 credentials if using both). On the ShipStation side it makes authenticated calls to V1 endpoints with modifyDate filters to detect order and shipment changes, and it follows webhook pointers with authenticated GET requests since the webhook payload is a URL, not the full record. When webhook timestamp is in PST/PDT, ml-connector converts to UTC for consistent internal time handling. On the FreshBooks side it accepts OAuth token refresh transparently (no re-authorization needed) and presents HMAC-SHA256 signatures on outbound webhook registrations. Orders are keyed by ShipStation orderKey; shipments are keyed by shipmentId. ml-connector handles V1's rate limit (40 req/min) with exponential backoff and jitter. Because ShipStation orders cannot be updated after shipping or cancellation, ml-connector treats them as immutable once in that state and gates subsequent cost posts to immutable shipments only. Customers are created implicitly in ShipStation via orderUsername in the order payload, so ml-connector does not attempt direct customer creation; instead it maps existing FreshBooks clients to ShipStation orders at order-ingest time.
A real-world example
A small e-commerce business uses FreshBooks to manage invoicing and expense tracking, and ships orders through ShipStation, which aggregates orders from Shopify, Amazon, and their own website. Before integration, the fulfillment team packed and shipped orders in ShipStation while the accounting team manually logged shipping costs and carrier fees in FreshBooks at month end, leading to month-end close delays and cost mismatches. With FreshBooks and ShipStation connected, each shipment automatically posts its carrier cost into FreshBooks as an expense, tagged with the originating order and linked to the invoice. The accounting team now has real-time shipment cost visibility, month-end close runs faster, and landed-goods calculations are accurate.
What you can do
- Map ShipStation orders and customers to FreshBooks clients and expense records, keeping customer lists aligned across both systems.
- Read ShipStation order updates via polling with modifyDate filters and follow webhook pointers to fetch full shipment details.
- Post shipment costs and carrier fees from ShipStation into FreshBooks as expenses, tagged with order and invoice references.
- Handle OAuth 2.0 user-delegated tokens for FreshBooks and API Key authentication for ShipStation, including V1 rate limits and PST/PDT to UTC timezone conversion.
- Treat shipped and cancelled orders as immutable, preventing cost overwrites and double-posting to FreshBooks.
Questions
- Why does ml-connector poll ShipStation if it has webhooks?
- ShipStation webhooks deliver only a resource URL and type, not the full order or shipment data - ml-connector must fetch the actual record with an authenticated GET. Additionally, ShipStation does not push webhook events when orders are updated; only new order creation triggers ORDER_NOTIFY. ml-connector polls V1 with modifyDate filters to catch updates that webhooks miss.
- How does ml-connector handle the difference between FreshBooks OAuth and ShipStation API Key?
- FreshBooks uses user-delegated OAuth 2.0 without a Client Credentials flow, so ml-connector stores and refreshes the user token on 401 responses. ShipStation uses API Key authentication (header-based in V2, HTTP Basic in V1), which does not expire. ml-connector manages both credential types and their respective refresh/retry logic independently.
- What happens to ShipStation orders after they ship or are cancelled?
- Once a ShipStation order is shipped or cancelled, the API treats it as immutable and will not accept updates. ml-connector recognizes this state and gates all downstream cost posts and expense creation to immutable shipments only, preventing duplicate or conflicting postings to FreshBooks when orders are reprocessed.
Related integrations
More FreshBooks integrations
Other systems that connect to ShipStation
Connect FreshBooks and ShipStation
Free to use. Add your credentials, ping your real systems, and see if we fit.
Get started