Most WooCommerce shipping API failures trace back to one of four things: credentials without write access, the Legacy API switched off, a server that blocks PUT requests, or carrier data in the wrong format. None of these are WooCommerce bugs. That is exactly why support tickets bounce between your store and your carrier for days while neither side finds anything wrong.
Here is how to work out which one you have hit, and how a managed shipping API connection removes most of them.
A WooCommerce support thread shows the pattern well. A merchant found orders marked Completed while the same parcels sat undispatched in their carrier panel. The carrier blamed WooCommerce, WooCommerce blamed the carrier, and the merchant was stuck in the middle for two weeks. The log settled it. Every status change traced to the same place:
woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php → update_itemWooCommerce does not update its own orders through its REST API. If a status change arrives through update_item, an external system sent it. Every write to the WooCommerce REST API is an authenticated request from outside the store, so the question is never "is WooCommerce broken" but "which integration sent this, and why." Check your provider's outgoing webhook logs first and you will usually have the answer in minutes.
Run these in order. In most cases the failure is gone by step three.
WooCommerce > Settings > Advanced > Legacy API. This has to be enabled by an admin account.
WooCommerce > Settings > API > Keys/Apps. Open the existing key and change the permission.
Many hosts permit GET and POST but block PUT. Shipping integrations need all three to write tracking data back.
Confirm webhooks are active under WooCommerce > Settings > Advanced > WebHooks, and enter the base URL as https://www.yourstore.com.
If you are on WooCommerce version 9, you need WooCommerce's official Legacy REST API extension before the connection will work. Note that this extension is not compatible with HPOS, so check which order storage your store uses before you install it.
Cloudflare and server firewalls often blacklist integration traffic without returning a useful error. Because ShippyPro's IPs are dynamic, there is no fixed list to allow. Create a firewall rule that permits traffic with the User Agent set to "ShippyPro" instead.
Product & Resources
Import WooCommerce orders, generate labels and push tracking back from one dashboard.
Explore the platform →Retry failed orders, correct recipient data and reassign carriers without touching anything.
See automation →Keep tracking consistent across every carrier so order status and reality stay in sync.
See Track & Trace →Authentication, endpoints and webhook events for connecting your own systems directly.
View the docs →Connect your store once and let a managed integration handle credentials, retries and tracking.
Separate the two failure types before you change anything. A 401 means the credentials were rejected. A 403 means they are valid but the associated user cannot perform that action. Treating a permissions problem as a credentials problem is how teams end up generating key after key that changes nothing.
| Error | What is actually happening | Fix |
|---|---|---|
| The consumer key is not valid (HTTP 401) | Credentials rejected or revoked | Create a new WooCommerce connection with the "Use Consumer and Secret Keys" option enabled |
| CURL error 28: operation timed out after 60001 ms | Your host reached ShippyPro but got no response inside 60 seconds | Try the connection again later |
| Params.from_address.country: must be at most 2 characters long | Origin country saved as a full name instead of a code | Set it to ISO format (IT, ES, DE) under WooCommerce > Shipping > ShippyPro Live Shipping Rates |
| Missing parameter app_name | The authorisation URL does not include your app_name | Rebuild the connection so app_name is present in the URL |
| /wc-auth/v1/authorize was not found on this server | The store address is wrong | Check the address of the store saved in your WooCommerce profile |
| Orders import with the wrong address | The shipping address field is empty | ShippyPro imports the WooCommerce shipping address, and only falls back to billing when shipping is blank |
ShippyPro sorts every carrier error message into five error types and attaches a description and solution to each, so a failed label tells you what to do rather than just that something went wrong. If you call the API directly, the API section of your account keeps a history of failed calls under View API Errors, and a Status of 2 in a Ship response means the call went out but the label was not created.
Shipping requests that end in a timeout return a 500 even when the label was created. Send the Ship call with the Async parameter set to true to avoid this. You get an immediate OK response with an order number, then retrieve the label with GetLabelURL or through the Order Shipped webhook once the carrier has generated it.
Both approaches work, and WooCommerce exposes a shipping method API for plugins that add their own rates. They fail differently, which is the part worth knowing before you commit engineering time.
| Criteria | Direct carrier API calls | Managed connection |
|---|---|---|
| Authentication | Separate credentials and refresh logic per carrier | One connection, credentials handled centrally |
| Failed label recovery | Manual, once someone notices | Auto-Retry, or a workflow triggered by "Order in error" |
| Bad recipient data | Fix and resubmit by hand, per order | Autofix recipient info corrects and retries the label |
| Adding a carrier | New integration project each time | Activate from the integration library |
| Where failures surface | Your logs, if you are watching them | A dedicated Errors view with documented fixes |
The cost of a raw integration is rarely the first build. It is the maintenance: a carrier changes a required field, an address exceeds a character limit, a timeout drops a batch of labels at 11pm. A managed connection absorbs that class of problem, and you can still call the API directly for anything custom.
When a call fails, record the status code and the message, and leave the consumer secret out of it. Never pass secrets in the URL and never widen a user's permissions just to make an error disappear. If a broader role fixes it, you have confirmed a permissions problem, not solved it.
WooCommerce does not do this itself. An external integration is sending a REST API write. Check your shipping provider's outgoing webhook logs to find the request.
An invalid or revoked consumer key, or an Authorization header that never arrives because the request is not travelling over HTTPS.
Usually the Legacy API is off, the API key is read-only, or the server blocks PUT. Check all three before looking at your code.
A CURL error 28 means no response arrived inside 60 seconds, so try connecting again later. For label requests sent through the API, use the Ship call with the Async parameter set to true so the request does not time out.
Related Articles
What changes when every carrier, channel and tracking feed lives in one dashboard.
Read more →Five automations to build now, including order retry for carrier downtime.
Read more →How the main platforms differ on automation depth, API access and pricing.
Read more →Practical guides on carrier management, automation and post-purchase operations.
Browse resources →Try ShippyPro free for 14 days. No credit card required.