Release Notes
Mailhub Release Notes
Production changes that affect developers integrating with Mailhub — the API and Mailhub MCP alike. Updates to this portal’s wording, examples, or downloads are not releases and are not listed here.
Shopify integration, draft Orders, and warehouse management#
This release connects Mailhub to Shopify, adds draft Order management, Order export, warehouse management and PrintNode printing, and extends Mailhub MCP with drafts and Shopify.
Shopify integration
- Connect a Shopify store to Mailhub.
- Existing Orders are pulled in automatically when a store is connected.
- Shopify Orders are imported into Mailhub as drafts.
- Order edits sync both ways between Mailhub and Shopify.
- Tracking numbers are sent back to Shopify once a Label is purchased.
What’s new
- Direct Label printing through PrintNode.
- Order export.
- Draft Order management.
- Warehouse management: add, edit, assign users to, and remove warehouses.
- Mailhub MCP gained draft Order management and Shopify functionality.
What changed
- The expected shipping date is no longer shown for carrier aggregators that do not return one.
- Package size now has enforced limits.
- Rates from the same carrier and service level are merged into one.
- The last payment method on an account can no longer be removed.
- Registration now includes a phone number field.
- Registration details are now used as the default sender.
Action required
Handle a Rate list that may be shorter than before, and a Rate without an expected shipping date. Packages outside the size limits are now rejected, so check your package values if a request that used to succeed is refused.
Existing integrations otherwise require no change.
Breaking
Orders, Rates, and Labels integration improvements#
This release improves consistency across Orders, Rates, and Labels, tightens several workflow rules, and makes integrations more predictable.
What changed
- Improved Order and Sub-account handling, so an Order request made in a Sub-account context stays within that Sub-account.
- Added Order source information and filtering, so you can tell manual, API and Shopify Orders apart and list them separately.
- Improved Label download and retry handling, so a client waiting on a Label file knows when to try again.
- Tightened Order status rules to prevent invalid state changes, and to stop an Order being cancelled in a way that left its Label live at the carrier.
- Improved Rate correctness, so a Rate Mailhub cannot price accurately is no longer offered for purchase.
- Updated the public API contract to match production behavior more closely.
Action required
Breaking API changes included
Some API request and response types changed to align the public contract with production behavior. If you generate a client from the Mailhub OpenAPI contract, or depend on Order, Rate or Label fields that changed, review the migration details before updating your integration.
Existing integrations that do not depend on the affected fields or behaviors continue to work unchanged.
View API migration details
What changed on the wire, and what to do about it. Field-level reference material lives in the API Reference; this covers only what an existing integration may have to change. Previously The three selectedRate money fields were quoted strings: "rate": "8.42". Now They are JSON numbers: "rate": 8.42. What the fields mean, and the currency fields, are unchanged. Developer action Update any client that reads selectedRate.rate as a string, and regenerate a generated client. Rate quotes on the rates operations were already numbers and do not change. Affected operation CreateShipmentLabel Previously POST /api/v1/orders returned a quoted name: "status": "Created". Now It returns the numeric OrderStatus value the rest of the API already used: "status": 0. POST /api/v2/orders changes the same way on data.order.status only; that response’s own top-level data.status is a different field and is unchanged. Developer action Compare the status against the number rather than the name, and regenerate a generated client. The codes and their meanings are unchanged. Affected operation CreateOrder, CreateOrderV2 · Order status values Previously Each order in GET /api/v1/orders carried a labelStatus field. Now The field is absent. Nothing else about the List Orders response changed. Developer action Read the label state from Get Order, which still returns it and is unchanged. Affected operation ListOrders · Use instead GetOrder Previously The contract marked almost nothing as required, on requests or responses. Now Requiredness is declared. Every one of these was already true at runtime, so nothing changed on the wire. Required means the key is always present, not that it has a value — a required field can still be null. Developer action Requests that already work keep working. Regenerate a generated client and expect field types and optionality to change even though no endpoint behavior did. Affected operation CreateAuthToken, RefreshAuthToken, RevokeAuthToken, CreateOrder, UpdateOrderStatus, CreateShipmentLabel · API Reference Previously A caller could set LabelCreated or Error by hand, and could move an Order straight from LabelCreated to Cancelled — which left a paid-for Label live at the carrier, because changing an Order’s status has never voided or refunded anything. Now A status that is the consequence of an operation is reachable only by performing that operation. A caller-supplied LabelCreated is rejected, a caller-supplied Error is rejected, and the direct LabelCreated to Cancelled transition no longer exists. Both statuses are still returned and readable. Developer action Buy a Label to reach LabelCreated. To undo one, cancel the Label rather than moving the Order status — that voids it with the carrier and returns the Order to Packed. Affected operation UpdateOrderStatus · Use instead CancelLabel Previously GET /api/v1/orders/{orderId} ignored the X-SubAccount-Id header: the Order was looked up by account alone, whichever Sub-account you named. Now The lookup is restricted to the Sub-account you send, so an Order belonging to a different Sub-account answers 404 where it was previously returned. Callers that never send the header are unaffected. Developer action If you send the header, send the Sub-account that owns the Order, or omit it to look up Orders across the account. Affected operation GetOrder · Work with Sub-accounts Previously A Rate quoted in a currency Mailhub cannot represent was stored and returned as though it were USD, and could be bought at a price whose currency was wrong. Now Such a Rate is skipped. A shipment may come back with fewer Rates; if none remain, the operation behaves as it always has when there are no Rates. The optional retailRate and listRate comparison amounts may be absent for the same reason. Developer action Read currency alongside rate, and handle a shorter result set. A client that assumes a particular carrier, service or comparison amount is always present should handle its absence. Affected operation GetShipmentRates, CreateOrderV2 Previously The contract described Label values the API does not produce: an Epl2 format, single labelZplUrl and labelEpl2Url fields, and Label asset format values written as Pdf, Zpl203Dpi, Zpl300Dpi and Zpl600Dpi. Now The published contract matches the runtime. The service itself never changed: it returns PDF or ZPL bytes only, one Label URL per ZPL resolution, and the Label asset format values PDF, ZPL203DPI, ZPL300DPI and ZPL600DPI it has always sent. Developer action Nothing changed on the wire, so a client that already matched the values it received keeps working. Regenerate a generated client: one built from the old contract expected format values and field names no response ever carried. Affected operation CreateShipmentLabel, DownloadLabel, GetOrder Previously The API already accepted the header and already replayed a repeated request, but the published contract did not declare it — so a generated client had no way to send it and the documentation described no safe repeat for Order creation. Now The contract declares what the service was already doing: both Create Order operations publish an optional Idempotency-Key request header. Repeating a request with the same value returns the Order the first attempt created rather than creating a second one. The key is scoped to the account rather than the Sub-account, and is limited to 200 characters. Developer action Optional. To make a timed-out Order creation safe to repeat, send your own key and reuse it for the retry; choose a new value for a genuinely new Order. Affected operation CreateOrder, CreateOrderV2Buy Label returns selectedRate amounts as numbers, not stringsBreaking
Create Order returns the order status as a number, not a nameBreaking
List Orders no longer returns labelStatusBreaking
The contract declares which fields are always sent, and which you must sendBreaking
Update Order Status rejects system-managed statusesBreaking
Get Order applies the Sub-account context
Rates in an unsupported currency are no longer offered
The published Label contract matches what the API returns
The contract declares the Idempotency-Key header Create Order accepts
Beta
Public API beta and Mailhub MCP#
Mailhub became available in Production for beta integrations, and introduced Mailhub MCP. Beta behavior can still change, so review an operation before you depend on it.
What’s new
- The Mailhub public API became available for Production beta integrations.
- Mailhub MCP became available for supported AI-assisted workflows. It works under the signed-in user’s own permissions, and access is not self-service.
- Get Order gained improved Label asset access, so a current download link can be fetched without buying the Label again.
What changed
- Label download links became temporary rather than permanent.
- Logout and authentication behavior was tightened for Production use.
Action required
Treat direct Label links as temporary. Request a fresh link, or use Download Label, when one is needed.
Existing integrations otherwise require no change unless they relied on the previous Label link or logout behavior.