Work/Vinoshipper for WooCommerce
Selling wine into every US state from a normal WooCommerce store, without a licence in each one.
US wineries can only ship direct to consumers in states where they hold a licence. Vinoshipper covers the rest, but it wants to own the checkout. I built a WooCommerce plugin that keeps the winery's own store and payment gateway, and quietly routes the right orders to Vinoshipper after payment.
- Product
- Vinoshipper for WooCommerce (WordPress plugin)
- Industry
- Wine, direct-to-consumer shipping
- Services
- Plugin development, API integration
- Stack
- PHP 8, WooCommerce, React, Tailwind, shadcn/ui
- Timeline
- December 2025 to January 2026

The problem
In the US, a winery shipping straight to a customer needs a licence for the state the wine is going to. Most small wineries hold a handful. Vinoshipper holds the licences and handles the compliance for the rest, but its standard setup assumes you sell through its checkout.
A winery that already runs WooCommerce, with its own payment gateway, wine club and design, doesn't want two checkouts. It wants one store, where an order to a licensed state ships as normal and an order anywhere else goes to Vinoshipper without anyone retyping it. I first built it for a family winery in Sonoma that was turning away orders from states it wasn't licensed for, and now offer it to other wineries in the same spot.
What I built
A WooCommerce plugin with a React admin inside wp-admin. Payment happens through whatever gateway the store already uses (Square, Stripe or anything else). Once it clears, the plugin checks the shipping state against the winery's list and, if it matches, submits the order to Vinoshipper's API as already paid, matched to Vinoshipper's catalogue by SKU.
Vinoshipper then runs its compliance checks and ships. Its webhooks come back to the store: tracking numbers land on the order and in the customer's account, delivered orders are marked complete, and a compliance rejection puts the order on hold and emails the winery.
- 1State routing: pick any of the 50 states plus DC, grouped by region, and only those orders go to Vinoshipper.
- 2A Vinoshipper shipping method for checkout that shows live carrier rates and delivery estimates, cached for 15 minutes per address and basket.
- 3Carrier mapping for the store's other methods (flat rate, free shipping, local pickup) across UPS, FedEx, GLS and self-delivery, with 12 service levels.
- 4An orders table and an order meta box showing sync status, the Vinoshipper ID, tracking and errors, with retry built into WooCommerce's own order actions.
- 5A webhook log that keeps every incoming event and its raw payload, so a missing tracking number can be traced in minutes.

The hard part
Two systems each think they own the order, so the work is in keeping them from disagreeing. WooCommerce can fire both its payment complete and processing hooks for the same order, so submission is guarded twice: a unique key on the WooCommerce order ID in the sync table, and a status check that skips anything already submitted, processing, shipped or delivered. An order goes to Vinoshipper once, however many hooks fire.
Vinoshipper's webhooks aren't signed, and the event names and payload shapes aren't consistent. The handler accepts eleven event names across six handlers, reads tracking from three different payload shapes, and only ever acts on an order already in its own sync table, so a stray or replayed request can't touch an order it didn't send. Everything is logged with the source IP.
Outbound calls retry with exponential backoff on rate limits, server errors and dropped connections, but not on validation errors, which go straight to the winery as a readable message (usually a product without a SKU). The API secret is stored encrypted with AES-256 using the site's own salts, not as plain text in the options table.

How it went
The customer sees one store. They pick a shipping rate, pay with the store's usual gateway, and get tracking in their account like any other order. The winery sees Vinoshipper orders alongside the rest in WooCommerce, with problems flagged rather than discovered. For that first winery, it opened up 39 more states without a second checkout, routed more than 400 orders to Vinoshipper in its first three months, and saved its team around five hours a week of retyping orders.
It's built on the WooCommerce plugin template I use for my own products, with PSR-4 classes, a small dependency container and HPOS-compatible order screens, so it's ready for a paid licence and more wineries.

More work
All case studiesPlugin, WooCommerce and Square
Square Sync for Woo
My WordPress plugin that keeps products, stock, orders and customers in step between WooCommerce and Square, both directions. It comes with its own webhook relay and licensing platform, and has shipped 416 releases.
SaaS, wine club management
OnCloudWine
Wine club software for wineries: members, clubs, releases, card payments and shipping in one place. It started as a WordPress plugin and grew into a multi-tenant platform with its own member portal and seven provider integrations.