DEVELOPERS / MERCHANT API V1
One contract from warehouse receipt to delivery.
WooliiPorter, operated by WOOLII, LLC of Newark, Delaware, provides China warehouse receiving, parcel consolidation and international forwarding for individuals, and fulfillment services for merchants. Forwarding customers and merchants buy from their own suppliers; the separate personal purchase concierge can buy supported products after a confirmed quote and payment. Merchant API V1 is that operation, callable: direct forwarding, optional merchant-owned inventory, warehouse fulfillment, unified shipments, packed quotes, line-item settlement and signed event delivery, behind one stable contract. Every operation in this reference is reconciled against the implemented V1 route surface.
Read the whole contract now, without an account. Merchant signup, business details, human review, online agreement signing, then sandbox and production key management from the active merchant console.Start with a sandbox key, where an integration can create orders, run the lifecycle and settle them without moving real funds.
OpenAPI 3.1 JSONMCP serverApply for API access
- Contract release · V1
- 2.2.0
- HTTP operations
- 51
- Webhook events
- 13
- MCP tools
- 26
- Documentation revision
- 2026-10-28.1
Contract principles
Reliable order automation from one API
Merchant API V1 rests on four properties: idempotent writes with stored-response replay, HMAC-signed webhooks with immutable event IDs delivered at least once, estimates typed separately from packed quotes, and per-merchant keys carrying explicit scopes and a visible execution mode. Each one removes a repeatable path from order submission to settlement and shipment updates.
| Property | Integration benefit |
|---|---|
| Idempotent writes with stored-response replay | Repeat an eligible request with the same key and payload to retrieve its original response and continue the same order. |
| HMAC signature over the raw body, immutable event IDs, at-least-once delivery | Verify the raw-body signature and deduplicate by event ID to keep your order status synchronized through retries. |
| Estimates typed separately from packed quotes | Plan with an estimate, then pay against the quote produced from packed measurements and applicable fees. |
| Per-merchant keys with explicit scopes and a visible execution mode | Run a scoped integration for your account and test order workflows in the key’s sandbox environment. |
Merchant control
Clear products, quotes and fulfillment actions
Select a shipping product or save a store default. Review the complete itemized settlement and authorize payment through your approved workflow. When an order combines stocked and supplier-forwarded lines, the fulfillment intent presents the actions needed to proceed. Inventory reservation, warehouse work and shipment updates then follow the same business record.
Payment-required handling
What a short wallet balance returns
Warehouse-service intake can return HTTP 402 with the wallet shortfall. A stocked fulfillment order or commerce intent can instead remain on hold with a balance reason. Show the returned action, open the merchant finance workspace for top-up, then retry the documented confirmation or re-evaluation action.
Overview
Base URL: https://api.woolii.com. All endpoints live under /v1/merchant, accept and return JSON, and are bounded to the authenticated merchant account — a resource id alone is never sufficient to read data. Most responses carry an X-Request-Id header; include it when you contact us about a request. Requests are rate-limited per key; a 429 includes a Retry-After header. Webhook endpoints must be public https URLs — loopback, private and cloud-metadata addresses are rejected.
The API covers three connected workflows, and in all of them you (or your supplier) buy and own the goods. The forwarding workflow is pass-through: parcels arrive at the assigned Woolii China warehouse, and WooliiPorter operates receiving, optional inspection, value-added services (relabeling, repacking, FBA prep), consolidation, the packed quote, line-item settlement, dispatch and WooliiPorter tracking. The optional stocking workflow adds merchant-owned inventory on top: register SKUs, pre-alert inbound shipments, and dispatch fulfillment orders from stock — with live ledger-computed inventory, warehouse transfers and a monthly statement that reconciles line by line. The commerce-order workflow lets an enabled WooCommerce store submit one order snapshot and receive a stocked, forwarding or merchant-review outcome, with the selected public product carried through execution. Prefer to let an agent drive it? See the MCP server.
Read shipping products first. A product’s fixed country assignment defines its transport service; quote checks validate cargo, postcode, weight and dimensions. Customer responses carry public product names, sell quotes and stable WooliiPorter tracking identities. Direct estimate/order endpoints use the account default; commerce intents also resolve the registered store default. Pass productCode explicitly to keep the same selection across calls.
Versions & changes
The URL /v1/merchant identifies the API major version. OpenAPI info.version identifies the Merchant API contract release; 3.1.0 is the OpenAPI document format. The documentation revision is a separate audit marker.
We use semantic versions: patches correct compatible defects or documentation; minor versions add compatible capabilities. Incompatible fields, states, payment semantics or webhook payloads require a major version and a documented migration. Published releases are immutable. Deprecation notices specify the replacement and retirement date before an old contract is retired.
Shopify and WordPress/WooCommerce connectors keep their own versions. Each coordinated release records their supported API contract, upgrade instructions and verification results. A new plugin version does not by itself change the API major version.
2.2.0 — changes
2.2.0 is an additive minor release over 2.1.0. Requests and existing fields keep their meaning. A declined value-added service now says why in services[].declineReason; the order object stays open in the OpenAPI, so additional response fields are not a validation change.
- Value-added servicesA services[] entry whose state is declined adds declineReason: customer_declined (you declined it), expired (the approval window closed without a decision) or withdrawn (WooliiPorter operations withdrew it, for example after you asked by phone). state stays declined and no fee is charged in any case. Treat an unknown declineReason as declined.
- OpenAPICreate, retrieve, cancel, simulate and list order responses now reference MerchantOrderResponse / MerchantOrderPage, with services[] typed as MerchantOrderService. The order object remains open (additionalProperties: true); only the service entries are described in detail.
2.1.0 — changes
2.1.0 is an additive minor release over 2.0.0. Existing requests keep their meaning and the new endpoints and webhook event are opt-in. Shipment detail gains the always-present actionRequired array: if you validate responses against the 2.0.0 OpenAPI with additionalProperties: false, regenerate from the 2.1.0 document before upgrading.
- US CPSC certificatesGET, PUT and DELETE /skus/{skuCode}/cpsc maintain the Children's Product Certificate or General Certificate of Conformity of a SKU, with the same data and validation as the merchant console. The response reports a single filing status for the key environment; WooliiPorter operations file with the carrier. Certificates are account data shared with production, so sandbox keys can read them and changes need a live key (403 merchant_sandbox_read_only). SKU reads add cpscRegulated.
- Action-required holdsShipment detail adds actionRequired. A not-yet-booked US shipment with a regulated SKU that is not cleared lists code cpsc_filing_required and, per SKU, the reason and whether you must act. The shipment stays in the warehouse and is not charged or booked until the list is empty.
- Webhooksshipment.action_required is sent once per distinct hold; a hold that changes and returns is sent again. Subscribe explicitly: existing endpoints do not receive it, and WooCommerce/Shopify store registration and reconnection never add it (an explicit subscription on a store endpoint is kept). After the hold clears the shipment continues with the usual quote, payment and dispatch events.
2.0.0 — changes
2.0.0 is a major release over 1.3.0 on the same /v1 path. Items marked Migration required change published 1.3.0 behaviour; update an existing integration before relying on them.
- Wallet paymentMigration requiredMerchant orders are paid with the explicit finance:pay wallet payment, which requires the current settlement version and an Idempotency-Key. The 1.3.0 card payment entry (POST /orders/{id}/pay) now returns merchant_payment_unavailable and never debits a wallet. Existing keys gain no spending power until finance:pay is granted.
- DeclarationsMigration requiredSupplied per-unit declaration values must be at least USD 1 (1.3.0 accepted zero). Validate before submitting; existing frozen declarations are not rewritten.
- SettlementMigration requiredSettlement reads merchant fee rows, bills and wallet refund evidence instead of the 1.3.0 payment projection. validForDispatch is a current settlement check; stage paid alone is not dispatch authorization or proof of physical handover.
- Delivery trackingMigration requiredFulfillment intent delivery projects every current WooliiPorter parcel. complete is true only when all child orders and shipments are handed over and delivered: do not complete an order on a single parcel event, and refresh the intent after callbacks.
- Fulfillment cancellationMigration requiredHTTP 202 from fulfillment-order cancellation means the request was accepted for warehouse or operations action. It is not final cancellation, inventory release or refund; keep reading cancellationStatus and the order.
- Forwarding cancellationMigration requiredAn order that is partially received can no longer be cancelled directly and returns HTTP 409; it goes to review. Channel-linked orders cancel through their fulfillment-intent endpoint.
- Amazon FBA inboundMigration requiredAMAZON_FBA inbound requires fba.destinationPostalCode (the fulfillment-center postal code) and fba.inboundPlanId (wf…) in addition to fulfillmentCenter and shipmentId. The booked carrier delivers from the China warehouse to the fulfillment center, and WooliiPorter sends the final-leg tracking to Amazon.
- Inbound shipmentsMigration requiredfirstMile.trackingNumber (the upstream carrier number) is removed; use WooliiPorter public shipment tracking. Stored-inventory replenishment cartons report null receipt counts and dispatchUnits; do not read null as zero received.
- OnboardingMigration requiredNew accounts complete business review, the approved service scope and online signing before inbound and fulfilment access; endpoints return a specific 403 envelope until then. Eligible existing accounts keep access without re-signing.
- After-salesshipment.exception also fires when the carrier returns a parcel to sender and carries trackingStatus (EXCEPTION or RETURNED). Each post-handover incident opens an after-sales review instead of blocking warehouse work.
- Product identifiersSKUs accept manufacturerPartNumber (model / part number, up to 50 characters) and a check-digit validated gtin for the EU product identifiers required on customs declarations from 1 November 2026. Both are optional, returned on SKU reads, and frozen into the parcel declaration at packing.
- Tracking eventstracking.updated, shipment.exception and shipment.delivered are emitted the same way whether a carrier scan arrives by polling or by tracking-provider push.
- Receiving exceptionsClosed and cancelled receiving reviews have terminal messages; the structured exception state, resolution and customerActionRequired fields remain authoritative.
- WooCommerceWooCommerce snapshots preserve empty checkout regions (for example France). Re-evaluation reports repairable product/routing configuration conflicts with HTTP 409 and allows retry after configuration is corrected.
- Tax and IOSSTax documentation follows per-order IOSS verification and frozen settlement snapshots.
- DocumentationEndpoint-specific error envelopes are documented, and the console plugin package is distinguished from the WordPress directory release.
Authentication
Authenticate with a Bearer key. Keys belong to one account, carry a sandbox or production execution mode, and grant explicit scopes. New merchants complete business review and online signing before activation, then create either a wp_sk_test_… (sandbox) or wp_sk_live_… (production) key in the developer console. Start in sandbox and move to production only after the workflow is validated and the applicable account terms are accepted. Each key carries explicit scopes: orders:read, orders:write, tracking:read, finance:read, finance:pay (explicit wallet-payment permission), webhooks:write, console:sso.
Keys can be rotated and revoked without losing the request audit trail. Store them like passwords.
Sandbox
Orders created with a wp_sk_test_… key are sandbox orders: they carry"sandbox": true, and they never enter real fulfilment — no warehouse receiving, no live tracking, no dispatch. They share your account's data space, so use a distinctexternalOrderId range (e.g. a test- prefix) to keep them recognizable.
Because there is no warehouse behind a sandbox order, advance its lifecycle yourself to exercise your webhook receiver end to end:
Simulation is rejected (409 merchant_not_sandbox) for production orders — those advance from real warehouse events only.
Idempotency
Operations explicitly marked requires Idempotency-Key accept any stable unique string up to 200 characters. Retrying one of those operations with the same key and body returns the original stored response; the same key with a different body returns 409 merchant_idempotency_conflict. The direct forwarding create/cancel operations and every fulfillment-intent mutation use this stored-response contract.
Other writes are not interchangeable: SKU and Store registration are natural upserts, fulfillment creation deduplicates by externalOrderId, while payment, sandbox simulation, inbound, transfer and webhook creation have endpoint-specific behavior. Unless an endpoint says it is replay-safe, reconcile with a GET before retrying after an ambiguous timeout.
Errors
The standard error envelope is shown alongside. Endpoint-specific responses take precedence:
PUT /transport-productsvalidation errors (422) use a top-level stringerror, withcodeorissueswhen supplied.POST /inbound-shipmentsreturns a top-level stringerrorandcode: merchant_agreement_required(403) when the signed agreement does not cover the service. This response does not include a request ID.
Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | merchant_invalid_json / merchant_idempotency_required | The body is not valid JSON, or this operation requires a missing/invalid Idempotency-Key. |
| 402 | merchant_insufficient_balance | Available wallet balance cannot cover the pre-checked warehouse service amount. Top up before retrying. |
| 401 | merchant_auth_missing / merchant_auth_invalid | Missing or unknown API key. |
| 401 | merchant_key_revoked / merchant_key_expired | The key was revoked or has passed its expiry. |
| 403 | merchant_scope_missing | The key lacks the scope this endpoint requires. |
| 403 | merchant_account_inactive | The merchant account is not active; complete the required business review and signing, or contact support if access is suspended. |
| 403 | overseas_warehouse_unavailable | Overseas warehouse services (warehouse transfers) are not open yet. Use the China warehouse for inbound and fulfillment. |
| 403 | merchant_agreement_required | The requested service is not enabled under the merchant agreement. Complete signing or contact support to review the agreed service scope. |
| 403 | merchant_smart_routing_disabled / merchant_store_not_registered | Fulfillment-intent access is not enabled, or the Store is not registered in this key environment. |
| 404 | merchant_order_not_found | No such resource in your account. Cross-account ids also return 404. |
| 404 | merchant_intent_not_found | No such fulfillment intent exists in the authenticated merchant account. |
| 404 | merchant_shipment_not_found | No such shipment exists in the authenticated merchant account. Cross-account shipment numbers also return 404. |
| 409 | merchant_idempotency_conflict | The Idempotency-Key was already used with a different request body. |
| 409 | merchant_request_in_progress | A matching idempotent request still owns the processing lease. Retry after a short delay with the same key and body. |
| 409 | merchant_external_order_exists | externalOrderId already maps to an order (id included in details). |
| 409 | merchant_parcel_conflict | A tracking number already belongs to an active order. |
| 409 | customs_consent_required | International orders need the account owner to accept the current customs declaration and IOSS/VOEC consent in the merchant console (details.consoleUrl). Sandbox keys are not affected. |
| 409 | merchant_order_conflict | The order is past the stage this action allows. |
| 409 | merchant_not_sandbox | Sandbox simulation was attempted against a production order. |
| 409 | merchant_intent_version_conflict / merchant_intent_state_conflict | The fulfillment projection changed or its state is no longer eligible. Read the current intent before retrying. |
| 409 | merchant_intent_already_executed / merchant_supplier_parcels_locked | A child order or submitted parcel makes automatic re-routing unsafe. Human review is required. |
| 409 | merchant_intent_warehouse_missing | The routed fulfillment work has no warehouse assignment, so cancellation requires an authorized data-repair review. |
| 409 | merchant_not_payable / merchant_already_paid / merchant_nothing_due | Pay was called before the final packed quote, after payment, or with a zero balance. |
| 402 | merchant_insufficient_balance | Top up the merchant wallet, reread settlement and retry with a new Idempotency-Key. |
| 409 | merchant_quote_changed | Read and confirm the current settlement version before paying. |
| 409 | merchant_settlement_review_required | Resolve the pending settlement, refund or declaration review before payment. |
| 409 | merchant_amount_basis_mismatch | Settlement and the order payable amount disagree. Contact support to reconcile the bill before paying. |
| 409 | merchant_fo_state | The fulfillment order is not in a state that allows this action (e.g. confirm on a dispatched order); the current state is named in the message. |
| 409 | merchant_no_receiving_workflow | No active stocking warehouse is currently available for inbound shipments. |
| 409 | merchant_endpoint_limit | The account already has the maximum five active webhook endpoints. |
| 422 | merchant_validation_failed | Field validation failed; details.issues lists each problem. |
| 422 | merchant_vas_incomplete | A value-added service request is missing instructions, illustrations or printable label files; details.issues lists every gap at once. |
| 422 | merchant_fba_details_required / merchant_fba_prep_required / merchant_fba_prep_quantity_invalid | AMAZON_FBA workflows need fba details plus explicit prep services covering every declared unit. |
| 422 | merchant_estimate_unavailable | No shipping route is configured for the requested destination. |
| 410 | merchant_transport_rules_retired | Delivery-rule writes have migrated to productCode and the explicit account/store default at /transport-products. |
| 422 | merchant_routing_retired | Direct forwarding no longer accepts transitBandId, bandPreference or maxTransitDays; select productCode. |
| 409 | transport_product_required / transport_product_unavailable | A fulfillment intent needs an explicit/default product that supports its destination, cargo and purpose. The estimate endpoint reports these failures as 422 merchant_estimate_unavailable. |
| 404 | merchant_sku_not_found | The SKU in the path is not registered for this account. |
| 403 | merchant_sandbox_read_only | Sandbox keys can read but not change account data that production depends on, such as a SKU CPSC certificate. Use a live key. |
| 409 | merchant_cpsc_version_conflict / merchant_cpsc_already_filed | The CPSC certificate changed since expectedVersion, or a filed certificate cannot be deleted. Re-read it and update instead. |
| 422 | merchant_sku_unregistered | An inbound shipment or fulfillment order references SKU codes that are not registered; details.missing lists every one. Register them via POST /skus first. |
| 422 | merchant_cursor_invalid | The inbound pagination cursor is malformed or uses an unsupported version. Restart from the first page instead of sending a database ID. |
| 422 | merchant_supplier_parcels_incomplete / merchant_supplier_parcel_overallocated | Supplier parcel line allocations do not exactly cover the forwarding intent or exceed a line quantity. |
| 422 | merchant_store_id_invalid / merchant_https_required | The connector Store identity is invalid or a production Store URL is not HTTPS. |
| 422 | merchant_warehouse_invalid | The requested transfer destination is not an active overseas warehouse. |
| 422 | merchant_webhook_url_rejected | The webhook URL is not https or resolves to a private/loopback/metadata address. |
| 404 | merchant_inbound_not_found | The inbound IB number does not exist in the authenticated merchant account. |
| 429 | merchant_rate_limited | Per-key request budget exceeded. Honor the Retry-After header. |
| 429 | merchant_sandbox_cap | Daily sandbox order limit reached for this account. |
| 500 | merchant_intent_cancellation_failed | The cancellation request could not be applied. Reconcile with GET fulfillment intent before retrying. |
Check the API connection
GET/v1/merchant/connection
Validates the key and returns the merchant account, environment, granted scopes and enabled features. Call this before registering a store and enabling automatic order submission. The legacy smartRouting flag controls commerce fulfillment-intent access; shipping uses your selected product and its configured destination coverage.
mcp: false means no hosted remote MCP endpoint is enabled. mcpStdioPreview: true identifies the optional standalone stdio adapter, which uses this same API key and scopes.
Register a WooCommerce store
PUT/v1/merchant/stores/{externalStoreId}
Creates or updates one WooCommerce installation in the API-key environment. The operation is naturally idempotent because the account, environment, platform and externalStoreId form the upsert key. The official plugin generates the Store identity once and keeps it stable across reconnects.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalStoreId | path string | Required | A stable wcstore_<UUID> generated by the plugin. |
platform | literal | Required | WOOCOMMERCE. |
storeUrl | URL | Required | Canonical storefront URL, up to 500 characters. |
pluginVersion | string | Required | Installed connector version, up to 40 characters. |
webhookUrl | URL | Required | The plugin receiver at /wp-json/wooliiporter/v1/webhook. |
Production storeUrl and webhookUrl values must use HTTPS. Explicit loopback URLs are accepted only by the isolated local release harness.
Read the store onboarding checklist
GET/v1/merchant/stores/{externalStoreId}/onboarding
Returns the same seven-step onboarding snapshot as the merchant console: account, channel services, product sync, SKU links, inbound stocking, shipping product and first-order validation, plus wallet funding. The official plugin uses this response to show the next setup action.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalStoreId | path string | Required | A registered wcstore_<UUID> in the API-key environment. |
Warehouse work is gated on wallet funds (ON_HOLD_BALANCE). The wizard should route merchants to the console finance workspace through the console-sso handoff rather than collecting payment details inside WordPress.
Sync the WooCommerce catalog and link SKUs
POST/v1/merchant/stores/{externalStoreId}/catalog
Registers up to 250 WooCommerce products or variations per call and links them to warehouse SKUs. A row with an explicit skuCode is linked to that SKU; a row whose channel sku exactly matches one active warehouse SKU is linked automatically; every other row is returned as unmatched for a manual decision. The sync never creates warehouse SKUs and never guesses a link. A successful call records the catalog sync evidence used by onboarding step 3.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalStoreId | path string | Required | A registered wcstore_<UUID> in the API-key environment. |
products | array | Required | 1-250 rows of {externalProductId, externalVariationId, name, sku?, skuCode?}. |
An invalid or inactive explicit skuCode rejects the whole batch with merchant_sku_code_invalid so a typo never half-links a catalog.
Open the Woolii merchant console
POST/v1/merchant/console-sso
Creates a 60-second, single-use merchant-console handoff for one registered WooCommerce Store. The official plugin calls this endpoint from WordPress after a manage_woocommerce nonce check; the API key never enters the browser or handoff URL. The returned URL must be opened immediately and must never be logged, cached, emailed or persisted.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalStoreId | string | Required | A registered wcstore_<UUID> in the API-key environment. |
returnPath | enum | Optional | One of the bounded merchant-console paths. Unknown values fall back to /merchant. |
This is a connector handoff, not a general authentication API. It requires an active member linked to the Store account and rejects expiry or replay.
Submit a commerce order for fulfillment
POST/v1/merchant/fulfillment-intents
Submits a versioned WooCommerce order snapshot. WooliiPorter resolves productCode, then the registered store default, then the account default, and validates the product against destination, cargo and purpose. Stocked lines reserve inventory; forwarding lines await domestic supplier parcels; mixed orders return the merchant actions needed to proceed. Access requires a registered store and features.smartRouting=true.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
platform | literal | Required | WOOCOMMERCE. |
externalStoreId | string | Required | A Store registered in the current API environment. |
externalOrderId | string | Required | Stable WooCommerce database order ID and intent idempotency identity, up to 120 characters. |
externalOrderName | string | Optional | Merchant-facing value from WC_Order::get_order_number(), including sequential-order-number extensions, up to 120 characters. |
externalOrderVersion | string | Required | Stable content hash/version for this exact order snapshot. |
destination | object | Required | recipientName, phone, country, province, city, street and postalCode. For this WooCommerce snapshot, province may be an empty string when checkout has no region field (for example France); do not invent a region. Carrier-specific address requirements still apply before booking. |
lines | array | Required | 1–100 unique externalLineId entries with productName, qty and optional productId, variationId, skuCode and fulfillmentPreference. |
fulfillmentPreference | enum | Optional per line | AUTO (default) | FORWARDING. FORWARDING never consumes stocked inventory. |
productCode | string | Optional | Shipping product code; defaults to the saved store/account selection. Legacy serviceType is compatibility input only and must identify a unique product. |
checkoutShippingMethod | string | Optional | The buyer’s checkout shipping method, recorded as an observation; it does not select or change the shipping product. |
currency / orderTotal | string / number | Optional | Three-letter order currency and non-negative order total for diagnostics. |
Possible statuses include MAPPING_REQUIRED, WAITING_SUPPLIER_TRACKING, MIXED_REVIEW_REQUIRED, ROUTED_FULFILLMENT, ROUTED_FORWARDING, ON_HOLD_BALANCE, STALE, ROUTING_BLOCKED and CANCELLED. Follow requiredActions and the optional cancellation projection rather than inferring the next action from status text.
A changed externalOrderVersion may replace only an intent with no child order and no submitted supplier parcel. Otherwise the intent becomes STALE for human review.
The official WooCommerce plugin always sends externalOrderName for display and search. externalOrderId remains the stable identity used for idempotent intent upserts.
Retrieve a fulfillment intent
GET/v1/merchant/fulfillment-intents/{id}
Returns the selected public product, inventory/forwarding decisions per line, routingVersion, requiredActions, editable supplier parcels, child orders, complete public parcel delivery facts and any cancellation lifecycle. routingVersion is an optimistic concurrency token for fulfillment decisions; refresh it before every mutation.
delivery contains complete (boolean) and shipments[]. Each shipment contains shipmentNumber, status, handedOverAt and parcels[] with parcelNumber, trackingNumber, trackingUrl and trackingStatus. Cancelled replacement shipments are omitted. No upstream carrier identifiers are exposed.
Use delivery.complete for whole-order delivery. A delivered child, a carrier scan before warehouse handover, or a split route whose other child is not created is not complete. Re-read the intent for the current state after every callback or missed callback; older releases may omit delivery.
cancellation is omitted until a cancellation has been requested. Its status is the durable lifecycle projection: WAREHOUSE_STOPPED and WAREHOUSE_RETURNED require operational follow-up, ADMIN_REVIEW requires an authorized recall or after-sales decision, and CANCELLED is terminal.
Cancel a fulfillment intent
POST/v1/merchant/fulfillment-intents/{id}/cancel
Requests cancellation against the unified commerce fulfillment intent, so the API evaluates its stocked-fulfillment or supplier-forwarding child and the real physical execution stage. A 200 response means every linked operation was safely cancelled. A 202 response means the request was accepted but warehouse return or authorized admin review must finish before the intent is terminal.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
routingVersion | integer | Required | The latest routingVersion returned by the fulfillment-intent projection. |
reason | string | Required | Non-empty merchant-facing reason, up to 500 characters. |
200 outcome CANCELLED: the intent and its safe linked work are terminally cancelled; cancellation.status is CANCELLED and resolvedAt is populated.
202 outcome WAREHOUSE_REVIEW_REQUIRED: warehouse work was stopped and the cancellation projection advances through WAREHOUSE_STOPPED and WAREHOUSE_RETURNED before an authorized operator closes settlement.
202 outcome ADMIN_REVIEW_REQUIRED: transport or another protected stage requires an authorized recall or after-sales decision; cancellation.status is ADMIN_REVIEW.
The response repeats cancellation at the top level for immediate disposition handling and inside fulfillmentIntent as the canonical status projection. A terminal 200 response replays unchanged; a request first accepted with 202 keeps the same request identity but later retries project the current lifecycle, including eventual 200 CANCELLED after authorized closure.
Cancellation and retry projections preserve externalOrderName so operators can continue reconciling the WooCommerce order while externalOrderId remains unchanged.
Save supplier parcel drafts
PUT/v1/merchant/fulfillment-intents/{id}/supplier-parcels
Replaces the complete editable supplier-parcel draft for an intent that is waiting for forwarding. Each real China domestic tracking number carries one or more externalLineId quantity allocations. Draft allocations may be partial, but cannot over-allocate a line or reuse a tracking number.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
routingVersion | integer | Required | The latest value returned by GET fulfillment intent. |
parcels | array | Required | 0–50 supplier parcels. Each has trackingNumber and 1–100 line allocations; carrier, supplierName and notes are optional. |
lines | array | Required per parcel | externalLineId plus positive integer qty. |
A routingVersion mismatch returns 409 merchant_intent_version_conflict. Submitted or received parcels are locked and cannot be replaced.
Submit supplier forwarding
POST/v1/merchant/fulfillment-intents/{id}/submit-forwarding
Locks the supplier parcels and atomically creates the forwarding child order. Submission succeeds only when the saved parcel allocations exactly cover every forwarding line. The plugin deliberately separates draft saving from this irreversible warehouse handoff.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
routingVersion | integer | Required | The latest routingVersion returned by the intent. |
Incomplete exact coverage returns 422 merchant_supplier_parcels_incomplete with expected and allocated quantities per line.
Choose how a mixed order proceeds
POST/v1/merchant/fulfillment-intents/{id}/select-route
Resolves an unexecuted mixed order. FORWARD_ALL moves every line to supplier forwarding. WAIT_FOR_STOCK records the merchant decision but leaves the intent in review until stock changes and the merchant explicitly re-evaluates. Automatic split fulfillment is intentionally disabled in this release.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
routingVersion | integer | Required | The latest routingVersion returned by the intent. |
selection | enum | Required | FORWARD_ALL | WAIT_FOR_STOCK. |
Re-evaluate stock and fulfillment readiness
POST/v1/merchant/fulfillment-intents/{id}/re-evaluate
Re-runs an unexecuted mixed, mapping-required or routing-blocked intent against current mappings, route configuration and inventory. It never re-routes an intent that already has a child order or submitted supplier parcel.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
routingVersion | integer | Required | The latest routingVersion returned by the intent. |
List shipping products and defaults
GET/v1/merchant/transport-products
Returns public shipping products, cargo types, fulfillment purposes, product families, country readiness and saved account/store defaults. stores contains only registrations in this API key environment; the account default is shared by the merchant account. Use countries[].available to check operational readiness, then estimate the selected product with actual destination and measurements.
Body parameters
| Parameter | Type | Required | Description |
|---|
Product codes and coverage come from this catalog; names shown here are illustrative. A listed country with available=false remains a configured destination but is not ready for a quote.
This endpoint returns the product catalog and defaults without an X-Request-Id success header. Authentication failures use the standard merchant error envelope.
Save a default shipping product
PUT/v1/merchant/transport-products
Saves an explicit product selection for new orders. Specify storeId to change that registered store, or omit it for the account default. Existing intents and shipments keep their selected product. Send null to clear a default.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productCode | string | null | Required | Product code from the catalog, or null to clear. |
storeId | string | Optional | Owned store ID returned by the catalog; scoped to the API key environment. |
storeId is the internal store resource ID returned by GET /transport-products, not externalStoreId. Store defaults are environment-scoped; omitting storeId updates the shared account default.
This endpoint currently returns validation errors as {error: string, issues: [...]}, or {error: string, code: "transport_product_unavailable" | "store_not_found"} with HTTP 422. Successful writes return {productCode} without an X-Request-Id header.
Read historical delivery rules
GET/v1/merchant/routing-rules
Historical records only. These rules no longer select a product for new orders.
Body parameters
| Parameter | Type | Required | Description |
|---|
Retired delivery-rule writes
PUT/v1/merchant/routing-rules
Returns HTTP 410. Use productCode on orders or save a default through /transport-products.
Body parameters
| Parameter | Type | Required | Description |
|---|
Estimate cost and transit
POST/v1/merchant/orders/estimate
Estimates freight and requested warehouse services for your selected product, destination and package measurements. The product has a fixed country assignment. The result uses current published prices, your merchant settlement policy and quote-time exchange rate. Final packed pricing uses warehouse measurements and adds applicable declaration-based taxes and fees.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productCode | string | Optional | Public product code. If omitted, use the account default; if neither is set, legacy AIR_CARGO compatibility must resolve to exactly one destination/cargo-compatible product. This endpoint has no store selector. |
destination | object | Required | Destination country code and postalCode. |
packages | array | Required | 1–20 packages with weight (kg), length, width and height (cm). PURE_BATTERY also requires batteryCount: the number of individual batteries in each physical package. |
packageTypeId | string | Optional | API cargo selectors: 1 (GENERAL, default) | 2 (BATTERY_COSMETIC: battery-powered, no liquids) | 3 (SENSITIVE: liquids, pastes, powders and cosmetics) | 4 (PURE_BATTERY). These are not database package-type IDs. |
services | array | Optional | Value-added service requests, validated with the same rules as order creation. |
This request accepts productCode, packageTypeId, destination, packages and services. Use the store-selected productCode explicitly when estimating for a store. A non-USD estimate returns totals.estimatedTotal=null because warehouse service lines are quoted in USD.
The estimate has no declaration or IOSS input, so it does not calculate VAT or the EU per-HS charge. Send the full customer declaration on the order/SKU and read final settlement after packing and HS review.
A missing or ambiguous WooliiPorter service, route, rate version, settlement policy, postal zone or FX snapshot returns 422 merchant_estimate_unavailable. No legacy tariff fallback is used. Value-added service requests are validated here with the same rules as order creation — incomplete label-class jobs return 422 merchant_vas_incomplete before any pricing runs.
Create an order pre-alert
POST/v1/merchant/orders
Registers a forwarding pre-alert with a destination, domestic supplier parcels and a selected shipping product. Each product uses its assigned full-service supplier for that country. Transit-band and price/speed overrides are retired. Returns the Woolii order, its receiving instructions and the recorded parcels. externalOrderId is unique per account.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productCode | string | Optional | Public product code saved on this pre-alert. Pass it explicitly for a stable store selection. When omitted, account-default or unambiguous legacy selection is resolved at pricing; direct orders have no store selector. |
externalOrderId | string | Required | Your own order id, unique per account. |
destination | object | Required | recipientName, phone, country, province, city, street, postalCode. |
parcels | array | Required | 1–50 domestic parcels: trackingNumber (4–64 chars), optional productName, quantity (default 1), declaredUnitPrice (full customer per-unit value in USD, minimum 1 when supplied), description and cargoType: General (default) | Electronics | PureBattery | Liquid | Branded. |
shipmentType | enum | Optional | SINGLE | CONSOLIDATED. Default CONSOLIDATED. |
checkoutShippingMethod | string | Optional | Checkout method as an observation only. It does not select the transport product. |
inspection | boolean | Optional | Request an inbound inspection. Default false. |
services | array | Optional | Value-added work for the warehouse to execute — see Value-added services below. |
destinationType | enum | Optional | CUSTOMER (default) | AMAZON_FBA — see Amazon FBA prep below. |
fba | object | Required for FBA | { region: US | EU | CA | MX, fulfillmentCenter, shipmentId? }. |
notes | string | Optional | Free-form note, up to 1000 characters. |
New forwarding creates return HTTP 201. The initial response confirms warehouse intake; a supplied product is fully checked against packed measurements at pricing. Quote readiness also requires complete declarations and confirmed HS classification.
Declare the complete customer value, at least USD 1 per unit when supplied. VAT uses quantity × declaredUnitPrice. New applicable EU non-IOSS quotes use the configured EUR 3 charge per distinct confirmed HS code per physical parcel. Read the final settlement lines rather than hard-coding fees; existing quote snapshots remain unchanged. IOSS treatment requires administrator verification for this order and a matching tax snapshot; an account tax number alone is insufficient. This request has no iossNumber or hsCode field; use the declaration and operations review workflows.
transitBandId, bandPreference and maxTransitDays return 422 merchant_routing_retired. serviceType is not an accepted field on this strict create schema. Use productCode.
Requires an Idempotency-Key header. Replaying the same key with the same body returns the stored response; a different body returns 409 merchant_idempotency_conflict.
A tracking number that already belongs to another active order returns 409 merchant_parcel_conflict.
Value-added services
services[] declares value-added work: RELABEL | REPACK | POLYBAG | BUNDLE | COMPLIANCE_STICKER | QC | PHOTO | PALLETIZE | REINFORCE | HANGTAG. The warehouse only executes unambiguous jobs: label-class services (RELABEL, COMPLIANCE_STICKER, HANGTAG) must carry instructionText, at least one illustrationImages entry and a printable labelFiles entry (PDF/PNG) — we print exactly what you upload, never a guess. BUNDLE and REPACK require instructionText. Anything missing returns 422 merchant_vas_incomplete with every gap listed in details.issues. In order responses, services[].state is requested | in_progress | done | skipped, plus draft (an extra job logged by the warehouse, being priced), awaiting_approval (waiting for your decision in the merchant console) and declined (not charged). A declined service also carries declineReason: customer_declined (you declined it), expired (the approval window closed) or withdrawn (WooliiPorter operations withdrew it); treat an unknown value as declined. services[].type is the type you declared, a catalog code in lower case for catalog services, or adhoc for an extra job. Orders with draft or awaiting_approval services are not packed or quoted until those are resolved.
Amazon FBA prep
destinationType: CUSTOMER (default) | AMAZON_FBA. FBA first-leg orders must include fba { region: US | EU | CA | MX, fulfillmentCenter, shipmentId? }, put the fulfillment-center address in destination, and explicitly declare the RELABEL + POLYBAG + PALLETIZE prep services (RELABEL with your printable FNSKU label files). Missing prep returns 422 merchant_fba_prep_required — prep is never added silently on your behalf.
List orders
GET/v1/merchant/orders
Cursor-paginated list of your orders, newest first. Filter by externalOrderId, state, or updatedSince (ISO 8601).
Pass nextCursor back as ?cursor= to fetch the next page. limit is capped at 100.
Retrieve an order
GET/v1/merchant/orders/{id}
Returns one order with its parcels, receiving instructions and the live progress of every value-added service you requested. Order ids from another account return 404 — resource existence is never disclosed across accounts.
Each services[] entry tracks one job: stage (receive | sort | pack) pins it to a warehouse step, state moves requested → done, and the fee line reappears verbatim in the settlement. A declined entry adds declineReason (customer_declined | expired | withdrawn) and is not charged.
Cancel an order
POST/v1/merchant/orders/{id}/cancel
Cancels a direct forwarding pre-alert only before any parcel has been received and before payment has settled. The aggregate awaiting_parcels state alone does not prove that no goods are in the warehouse. Receipt and cancellation share a transaction lock.
If any parcel has arrived, returns 409 merchant_order_conflict. Contact support for cancellation review; goods, photos and warehouse locations remain recorded.
Channel-linked orders return 409 with details.fulfillmentIntentId. Cancel through POST /fulfillment-intents/{id}/cancel so the channel and child order remain synchronized.
Retry an ambiguous response with the same Idempotency-Key. A different key is a new request and is checked against the current order state.
Simulate a sandbox lifecycle event
POST/v1/merchant/orders/{id}/simulate
Advances a sandbox forwarding order and emits the matching signed webhook without touching real warehouse, payment or carrier systems. Use the events in order when testing an end-to-end receiver. Production orders are always rejected.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
event | enum | Required | parcel.received | quote.ready | shipment.dispatched | shipment.delivered. |
Calling this endpoint for a production order returns 409 merchant_not_sandbox. The simulator does not require Idempotency-Key; do not retry it blindly after an ambiguous network failure.
List shippable countries
GET/v1/merchant/countries
Country-level candidates backed by a current published carrier buy-rate version and an executable published WooliiPorter route. This endpoint no longer reads legacy ShippingRate rows. Postal zone, cargo type, weight and dimension eligibility remain authoritative in the estimate endpoint.
Retrieve the quote state
GET/v1/merchant/orders/{id}/quote
Read packed freight, packaging, insurance and transit estimates for the selected product. New amounts come from each parcel’s current versioned sell quote; historical orders retain their legacy quote projection. For versioned quotes, amounts.total is the shipping/packaging/insurance subtotal. Read settlement for the complete itemized bill, including warehouse services and applicable taxes.
stage: pending_packed_quote | final_packed_quote | unavailable. The final versioned quote is visible after every packed parcel has a current quote in one currency.
For source=versioned_shipment_quote, amounts.total excludes VAS, VAT and per-HS fees. Use GET /settlement and its total to display the payment amount.
Retrieve the settlement
GET/v1/merchant/orders/{id}/settlement
Read the complete itemized bill from merchant FeeItems, the merchant wallet payment and refunded amounts. Total is the sum of the returned fee rows in the order currency. Lines remain empty before the final quote. Copy settlementVersion into an explicit wallet-payment request after confirming the current total.
stage retains pending_final_quote | payable | paid | cancelled. A historical paid stage does not prove current funds: inspect payment.status and validForDispatch, especially after a refund or declaration correction.
payment includes provider, status, amount, currency, paidAt and refundedAmount. Wallet status may be open, completed, refund_pending, partially_refunded, refunded or void. billId identifies the merchant ledger bill.
settlementVersion is null before final pricing. A changed price, parcel, address or discount produces another version. Never substitute a client-entered amount.
validForDispatch checks current settlement evidence; booking, labels, exceptions and physical PDA handover remain separate gates. Sandbox is never eligible for real dispatch.
Existing legacy aggregate-only fees require reconciliation before wallet payment; the candidate no longer invents aggregate rows absent from the merchant fee ledger. This difference requires compatibility review.
Pay from the merchant wallet
POST/v1/merchant/orders/{id}/wallet-payment
Pay the confirmed final quote from the merchant wallet using the same bill and debit transaction as the console. Requires explicit finance:pay, Idempotency-Key and settlementVersion. Sandbox simulates payment without spending wallet funds. No card secret is returned.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
settlementVersion | string | Required | 64-character version returned by GET /settlement. Confirm the current total before submitting. |
Create a payment-enabled key in the developer console as an authorized account owner. finance:pay is never added to existing or default keys automatically. Wallet funding uses the existing merchant console top-up flow.
402 merchant_insufficient_balance leaves the bill OPEN and moves no money. Top up, reread settlement and use a new Idempotency-Key. The original key continues replaying the original response.
409 merchant_quote_changed requires rereading and confirming the revised quote. Other payment blocks require the existing review workflow. Cancelled, refunded and under-review orders cannot be charged again here.
A replay is the original response snapshot; GET /settlement returns the current refund and dispatch eligibility. After a timeout retry the same key and version. The debit, order advancement, notification, webhook and replay response commit together. A different key for an already validly settled order returns its settlement without another debit.
payment.completed indicates settled funds; it is not a carrier booking or physical dispatch event.
Legacy card payment entry
POST/v1/merchant/orders/{id}/pay
Deprecated candidate behavior: production returns 503 merchant_payment_unavailable without collecting money because the personal Stripe completion rail rejects merchant orders. Use the merchant console or explicitly migrate to wallet-payment. Sandbox retains its simulated response. This is a compatibility-impacting safety change, not an automatic wallet debit.
Do not retry this production response automatically or expect a Stripe clientSecret. First upgrade the integration, obtain an explicitly authorized key and confirm a current quote. No JSON body is required here.
Existing sandbox simulation and pre-payment validation errors remain. Production rollout requires the migration and client-compatibility gate in the release plan; this candidate is not yet published.
Retrieve the timeline
GET/v1/merchant/orders/{id}/timeline
One time-ordered event stream for the whole journey: the China private leg (receiving, inspection, value-added services, packing, payment) merged with the international carrier leg. "Where is my order?" has a single answer from a single endpoint.
segment: cn (private China leg) | intl (carrier network). CN event types: order.created, parcel.received, inspection.completed, vas.completed, package.packed, payment.completed; carrier events are type carrier.event.
A carrier lookup failure never blocks the timeline — the China leg is always complete.
Retrieve tracking
GET/v1/merchant/orders/{id}/tracking
Order-keyed tracking projection for every outbound package on the order. It returns the stable WooliiPorter WP number and the same delivery timeline available on woolii.com/track.
List unified shipments
GET/v1/merchant/shipments
Lists the immutable outbound-shipment ledger across forwarding and stocked fulfillment. Use cursor pagination for continuous synchronization. The carrier is always WooliiPorter and each row uses the same stable public reference shown to the customer.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cursor | query string | Optional | Opaque cursor from nextCursor. |
limit | query integer | Optional | 1–100; default 20. |
updatedSince | query ISO 8601 | Optional | Only shipments updated at or after this timestamp. A timezone offset is required. |
externalOrderId | query string | Optional | Exact merchant/store order identity. |
trackingNumber | query string | Optional | Exact WooliiPorter public tracking number. |
sourceType | query enum | Optional | ORDER | FULFILLMENT_ORDER. |
status | query enum | Optional | PACKED | ROUTED | BOOKING_PENDING | BOOKING_UNKNOWN | BOOKED | HANDOVER_PENDING | HANDED_OVER | IN_TRANSIT | DELIVERED | CANCELLED | EXCEPTION. |
trackingStatus | query enum | Optional | UNKNOWN | INFO_RECEIVED | HANDED_OVER | IN_TRANSIT | OUT_FOR_DELIVERY | DELIVERED | EXCEPTION | RETURNED. |
Shipment creation is warehouse-controlled. Merchants create orders or fulfillment orders; after packing, WooliiPorter materializes and routes the shipment. This endpoint is read-only and never accepts a carrier choice.
The public service is a WooliiPorter transport product such as international small parcel or express. It is distinct from the warehouse fulfillment workflow selected for the order.
Collection rows are intentionally compact: parcel lines, measurements and event history are available from the shipment detail resource. This keeps high-volume incremental synchronization bounded.
BOOKING_UNKNOWN is a reconciliable technical state, not proof of failure. Continue reading the shipment or wait for webhook updates; do not submit a duplicate order.
Retrieve a unified shipment
GET/v1/merchant/shipments/{shipmentNumber}
Returns one outbound shipment by its WooliiPorter shipment number, including public parcel measurements, merchant-owned line snapshots, the latest merchant sell quote and the WooliiPorter delivery timeline. actionRequired lists holds that keep a not-yet-booked shipment in the warehouse; it is empty otherwise.
A held US shipment returns, for example, "actionRequired": [ { "code": "cpsc_filing_required", "message": "…", "skus": [ { "skuCode": "TOY-BLOCKS-50", "reason": "CERTIFICATE_REFERENCES_MISSING", "merchantAction": true, "message": "…" } ] } ].
Reasons: CERTIFICATE_REFERENCES_MISSING and FILING_REJECTED need you to update the certificate (merchantAction true); FILING_PENDING and SERVICE_UNSUPPORTED are handled by WooliiPorter operations. Treat unknown codes and reasons as holds you cannot clear yourself.
Retrieve shipment-native tracking
GET/v1/merchant/shipments/{shipmentNumber}/tracking
Returns the compact tracking projection for every parcel in one unified shipment. New integrations should prefer this shipment-native endpoint; the order-keyed endpoint is only an alternate projection of the same Shipment ledger.
Customer lookup is available without a merchant key at GET /public/tracking/{WP-number}; it is IP rate-limited and returns only carrier=WooliiPorter, status, public location and timestamps.
The authenticated tracking-publication feed is a separate partner contract and cannot be read with merchant keys.
Register a SKU
POST/v1/merchant/skus
Registers or updates a SKU in your catalog — an upsert keyed on skuCode, so replaying the same registration is safe without an Idempotency-Key. SKUs are the master data for stocking: inbound shipments and fulfillment orders reference skuCode and are rejected with 422 merchant_sku_unregistered until the SKU exists — stock is never put away against a guessed product. Re-registering reactivates an inactive SKU.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
skuCode | string | Required | Your SKU code, unique per account — the upsert key. Up to 80 characters. |
name | string | Required | Product name, up to 200 characters. |
imageUrl | string | Optional | Product image URL — shown to warehouse operators at putaway and picking. |
barcode | string | Optional | Scannable barcode, up to 64 characters. |
unitWeight | number | Optional | Weight per unit in kg. |
unitLength / unitWidth / unitHeight | number | Optional | Unit dimensions in cm. They also derive the per-unit volume used for the storage lines on your monthly statement. |
declaredValue | number | Optional at registration | Full customer customs value per unit in USD, minimum 1 when supplied. Required with customsNameEn and confirmed HS classification before international pricing and reservation can proceed. |
customsNameEn | string | Optional | English customs name. |
hsCode | string | Optional | HS code, up to 20 characters. |
manufacturerPartNumber | string | null | Optional | The manufacturer's model or part number, up to 50 characters — the non-standard product identifier EU customs declarations require from 1 November 2026. skuCode is sent as your merchant identifier. null clears it. |
gtin | string | null | Optional | GTIN-8, -12, -13 or -14 (EAN/UPC) with a valid check digit; required for EU declarations when the product has one. Kept separate from barcode, which may be a warehouse code. null clears it. |
routingTags | string[] | Optional | Up to 20 normalized historical tags; transport product selection uses productCode. |
lowStockThreshold | integer | null | Optional | 0–1,000,000; null clears the SKU low-stock threshold. |
List SKUs
GET/v1/merchant/skus
Your active SKUs, sorted by skuCode. Up to 500 entries are returned.
cpscRegulated is true when the SKU has a US CPSC certificate on file; read it with GET /skus/{skuCode}/cpsc.
Retrieve a SKU CPSC certificate
GET/v1/merchant/skus/{skuCode}/cpsc
Returns the US CPSC certificate (Children's Product Certificate or General Certificate of Conformity) kept for one SKU and the filing status for your key environment. certificate is null when the SKU is not regulated. A SKU with a certificate is held from US shipment until WooliiPorter has filed the current certificate for the selected service; the shipment's actionRequired list is authoritative for a specific shipment.
filing.status: NOT_FILED (nothing filed yet), ACCEPTED (the current certificate was accepted), REJECTED (the latest filing of the current certificate was rejected — review the data or contact support), UNCONFIRMED (the result was not confirmed; WooliiPorter files again) or OUTDATED (filed before the certificate last changed).
Carrier identities, filing request bodies and raw carrier responses are never returned.
Save a SKU CPSC certificate
PUT/v1/merchant/skus/{skuCode}/cpsc
Creates or replaces the US CPSC certificate of a registered SKU. Replaying the same content is a no-op, so the call is safe to retry without an Idempotency-Key. Any change to the content invalidates earlier filings: the SKU is held from US shipment until WooliiPorter files the new version. Send expectedVersion from your last read to avoid overwriting a concurrent edit.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
certificateType | string | Required | CHILDRENS_PRODUCT (CPC) or GENERAL_PRODUCT (GCC). |
certifierId / productId / versionId | string | null | Together | CPSC Product Registry references (up to 100, 100 and 19 characters). Send all three or none; without them US shipments stay held with CERTIFICATE_REFERENCES_MISSING. |
intendedUseCode | string | null | Optional | Product Registry intended-use code, up to 16 characters. |
fullDeclaration | object | null | Optional | Complete PGA data set (product, manufacturer, labs, certifier, point of contact) for a full filing. Field lengths follow the carrier eFiling table and are checked on save; see the OpenAPI CpscFullDeclaration schema. |
expectedVersion | integer | Optional | certificate.version from your last read. A mismatch returns 409 merchant_cpsc_version_conflict. |
404 merchant_sku_not_found when the SKU is not registered; register it with POST /skus first.
403 merchant_sandbox_read_only for sandbox keys: the certificate is shared with production, where a change re-holds live US shipments until it is filed again.
Remove a SKU CPSC certificate
DELETE/v1/merchant/skus/{skuCode}/cpsc
Removes a certificate entered by mistake, which also lifts the US CPSC hold for that SKU. A certificate that was already filed with a carrier is kept as evidence and returns 409 merchant_cpsc_already_filed; update it instead.
Create an inbound shipment
POST/v1/merchant/inbound-shipments
Creates stored-inventory intake or an enabled Amazon FBA prep/first-mile workflow. The compatibility MARKETPLACE_FBM input is normalized to STORED_FULFILLMENT for new stocking receipts. WooliiPorter returns a public IB number and assigned receiving address; place the IB number on every carton.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalRef | string | Optional | Your own reference for this inbound, up to 120 characters. |
origin | object | Optional | countryCode (2–3 letters), optional province and city; used by the warehouse intake assignment. |
businessType | enum | Optional | STORED_FULFILLMENT (default) | AMAZON_FBA. Legacy MARKETPLACE_FBM is accepted and normalized to STORED_FULFILLMENT. |
fba | object | Required for AMAZON_FBA | region, fulfillmentCenter, destinationPostalCode (the FC postal code), shipmentId and inboundPlanId (wf…, used to send final-leg tracking to Amazon) are required. Also accepts productCode, firstMileMode (EXPRESS | AIR | SEA, default AIR) and the actual destinationCountryCode. EU is a region, not a destination country. The booked carrier delivers from the China warehouse to the FC. |
marketplace | object | Optional compatibility metadata | platform and optional storeRef. New stocking intake is normalized to STORED_FULFILLMENT; marketplace origin belongs to outbound channel orders. |
cartonCount | integer | Required | Expected physical carton count, 1–1000. The warehouse records actual cartons, weight and volume at receipt. |
lines | array | Required | Declared contents: skuCode plus expectedQty. 1–200 entries. Every skuCode must already be registered. |
services | array | Optional | 0–40 value-added service requests. Label-class work requires complete instructions, illustrations and printable label files. FBA requires explicit prep coverage for every declared unit. |
notes | string | Optional | Free-form note, up to 1000 characters. |
Unregistered SKU codes return 422 merchant_sku_unregistered with every missing code in details.missing — register them via POST /skus first.
AMAZON_FBA requires fba.region, fulfillmentCenter and shipmentId plus explicit RELABEL, POLYBAG and PALLETIZE prep covering every declared unit. Use an available product supporting AMAZON_FBA and an actual destination country for an EU shipment. Activation also requires the dedicated FBA warehouse workflow.
WooliiPorter assigns the receiving warehouse from the enabled business route. If no active route exists, the API returns a 409 routing error instead of guessing a receiving address.
The returned IB number is the customer/PDA receiving identity. Do not invent a tracking number or send a supplier carrier number in this endpoint.
exceptions contains only WooliiPorter-branded status, type and customer-action flags. Internal warehouse providers, evidence paths, liability, supplier costs and payable records are never exposed.
Stored inventory follows expected → receiving → processing → putaway → stocked (or cancelled); sellable stock is available after putaway. FBA uses its dedicated prep/first-mile workflow. firstMile appears after recorded physical dispatch and contains WooliiPorter and dispatchedAt only; upstream carrier names and tracking/booking numbers are internal.
List inbound shipments
GET/v1/merchant/inbound-shipments
Your inbound shipments, newest first, with IB numbers, per-line quantities and customer-safe exceptions. source distinguishes inbound_delivery from stored_inventory replenishment. Replenishment has null declared/received cartons and no new receiving instructions; dispatchUnits reports actual carton and pallet counts. Cursor pagination returns up to 100 entries per page.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cursor | query string | Optional | Opaque versioned cursor returned as nextCursor. Database IDs are never accepted as cursors. |
limit | query integer | Optional | 1–100; default 100. |
Retrieve an inbound shipment
GET/v1/merchant/inbound-shipments/{inboundNumber}
Retrieves one tenant-scoped inbound by public IB number. Database IDs are internal and never become customer-facing references. The response uses the same projection as create/list and includes current customer-safe exception status.
A missing or cross-tenant IB number returns the same 404 merchant_inbound_not_found response.
Provider identities, quarantine bins, internal notes, evidence URLs, responsibility findings, customer receivable drafts and provider payables are excluded.
Retrieve inventory
GET/v1/merchant/inventory
Live stock levels per SKU per warehouse — onHand, reserved, available — plus stock aging (the receipt date of the oldest lot still holding stock). Every number is computed on read by summing the immutable stock-movement ledger, the same source the storage lines on your statement are computed from: inventory and billing can never disagree. Filter one SKU with ?sku=.
Create a fulfillment order
POST/v1/merchant/fulfillment-orders
Creates a dropship fulfillment order shipped from your stocked inventory — one destination address, one or more SKU lines. externalOrderId is the idempotency key: replaying an id that already exists returns the stored order with replayed: true instead of creating a duplicate. By default the order is confirmed automatically on creation; set draftOnly to hold it in draft for an explicit confirm call.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalOrderId | string | Required | Your own order id, unique per account — the idempotency key (e.g. wc-1042). |
destination | object | Required | recipientName, phone, country, province, city, street, postalCode. |
lines | array | Required | skuCode plus qty per line. 1–100 entries. Every skuCode must already be registered. |
productCode | string | Optional | Public shipping product code; direct fulfillment uses the account default when omitted. This endpoint has no store selector. Legacy serviceType defaults to AIR_CARGO and must identify an unambiguous product if no explicit/default selection exists. |
serviceType | enum | Optional compatibility field | AIR_CARGO (default) | EXPRESS | BULK_SHIPPING. New integrations select productCode. |
checkoutShippingMethod | string | Optional | The buyer’s checkout shipping method, recorded as an observation; it does not select or change the shipping product. |
draftOnly | boolean | Optional | Default false: attempts confirmation and reservation; unmet prerequisites leave the order on_hold. true stops at draft until you call confirm. |
notes | string | Optional | Free-form note, up to 1000 characters. |
Reservation is atomic and consumes stock oldest-first (FIFO) within the assigned warehouse. Product eligibility, a valid freight quote, full SKU declarations, confirmed HS classification and sufficient wallet funds are checked before reservation. When a prerequisite or stock is missing, the order is on_hold with holdReason; correct it, then call confirm.
Unregistered SKU codes return 422 merchant_sku_unregistered with the codes in details.missing.
state can be awaiting_payment, draft, confirmed, reserved, on_hold, picking, packed, dispatched, in_transit, delivered, cancelled or exception. Read holdReason and cancellation when present; do not treat an unfamiliar state as dispatch permission.
Fulfillment fees must be settled from the merchant wallet before dispatch. fees[] and monthly statements report ledger entries; neither is permission to ship before payment.
List fulfillment orders
GET/v1/merchant/fulfillment-orders
Your fulfillment orders in this API key environment, most recently updated first, with lines and fee items. Incremental polling uses updatedSince and cursor; continue until nextCursor is null.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
updatedSince | query string | Optional | ISO 8601 update timestamp. |
cursor | query string | Optional | Continuation value from nextCursor. |
limit | query integer | Optional | 1–100; default 100. |
Confirm a fulfillment order
POST/v1/merchant/fulfillment-orders/{id}/confirm
Confirms a draft order, or retries reservation on an on_hold order after restocking — the same atomic, FIFO, all-or-nothing reservation as auto-confirm. With default auto-confirm you only need this call for draftOnly orders and for releasing holds.
Only draft and on_hold orders can be confirmed; any other state returns 409 merchant_fo_state with the current state in the message.
Cancel a fulfillment order
POST/v1/merchant/fulfillment-orders/{id}/cancel
Requests cancellation. Returns HTTP 200 only when cancellation is complete. HTTP 202 means warehouse handling or administrative review is still required; inventory and any refund are finalized only after that workflow completes.
cancellationStatus is CANCELLED (200), or WAREHOUSE_STOPPED, WAREHOUSE_RETURNED or ADMIN_REVIEW (202). HTTP 202 is not confirmation of a refund or released stock. Read the order again to follow completion.
Before warehouse work or booking, cancellation can release reservations and refund prepaid fees automatically. After work has begun, warehouse handling and administrative cost review must finish first.
A standalone order already handed over returns 409 merchant_fo_state. A channel-linked order follows its fulfillment-intent cancellation workflow and may enter administrative review.
Repeating a completed cancellation returns HTTP 200. This endpoint does not use Idempotency-Key response replay; subsequent requests reflect the current cancellation state.
Retrieve the monthly statement
GET/v1/merchant/statements
The monthly stocking bill, computed live from the same ledger as inventory — never a stored snapshot, so the statement and your stock can never disagree. Storage is billed per lot: on-hand units × the lot’s unit volume (CBM) × the per-CBM-per-day price × billable days, where billing starts only after a free period from receipt. Fulfillment fees incurred in the month are listed line by line alongside. ?month=YYYY-MM; defaults to the current month.
freeDays and pricePerCbmDay are account-level billing parameters echoed in every response — read them from your statement rather than assuming fixed values; this page intentionally promises none.
Every line is explainable: a storage line names the SKU, the on-hand quantity and the billed days; a fulfillment line is exactly the fee recorded on the order it came from.
Create a warehouse transfer
POST/v1/merchant/transfer-orders
Requests a China-to-overseas-warehouse stock transfer. The source is the active China warehouse; the destination must be an active international warehouse supplied by operations. Dispatch and receiving remain warehouse-controlled actions, and the resulting quantities appear as in transit until receiving completes. Overseas warehouse services are not open yet: until they launch this endpoint returns 403 overseas_warehouse_unavailable.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
toWarehouseId | string | Required | Active overseas warehouse ID supplied by WooliiPorter operations. V1 does not yet expose warehouse discovery. |
lines | array | Required | 1–200 registered SKU lines with positive integer qty. |
notes | string | Optional | Transfer instructions, up to 1000 characters. |
Creation returns HTTP 201 with a frozen quote and OPEN bill; warehouse execution starts after payment. Fee amounts in this example are placeholders, not a rate promise. freightPending=true means freight still requires an operational quote; it is not free shipping. This strict V1 request accepts toWarehouseId, lines and notes only.
This POST is not protected by Idempotency-Key in V1. Do not retry it automatically after an ambiguous network failure; list transfers and reconcile before creating another request.
List warehouse transfers
GET/v1/merchant/transfer-orders
Returns up to 100 transfer orders plus an inTransit summary by SKU. Use the individual lines for audit and the aggregate to avoid double-counting stock that has left China but has not yet been received overseas. Overseas warehouse services are not open yet: until they launch this endpoint returns 403 overseas_warehouse_unavailable.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
cursor | query string | Optional | Continuation value from nextCursor. |
limit | query integer | Optional | 1–100; default 100. |
Create a webhook endpoint
POST/v1/merchant/webhook-endpoints
Registers an HTTPS endpoint for the event types you select. The signing secret is returned exactly once — store it immediately. Up to 5 active endpoints per account.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Required | Public https URL that receives deliveries. |
eventTypes | array | Required | Event types to deliver — see Webhook events below. |
List webhook endpoints
GET/v1/merchant/webhook-endpoints
Lists your endpoints with status and failure counters. Signing secrets are never returned again.
Disable a webhook endpoint
DELETE/v1/merchant/webhook-endpoints/{id}
Disables the endpoint. The delivery ledger is evidence and is retained; nothing is deleted.
Webhook events
Deliveries are at-least-once with bounded backoff (1 minute to 24 hours, 8 attempts); deduplicate by eventId. Sustained failures disable the endpoint, and the delivery ledger is always retained.
Event types
| Event | Meaning |
|---|---|
parcel.received | A domestic supplier parcel was scanned and recorded at the warehouse. |
inspection.completed | An inspection you requested finished. |
quote.ready | Packing and measurement produced the final packed quote; the order moved to payment. |
payment.completed | The shipment settlement was paid; the order moved on to dispatch. |
shipment.dispatched | Warehouse handover or the supported dispatch workflow confirmed physical dispatch. Booking confirmation remains a separate state. |
tracking.updated | A normalized WooliiPorter parcel tracking fact changed. The payload contains public shipment and parcel identifiers only. |
shipment.exception | The carrier reported a parcel exception after handover: loss, damage or failed delivery (trackingStatus EXCEPTION), or a return to sender (trackingStatus RETURNED). WooliiPorter opens an after-sales review; read the order for the outcome. |
shipment.delivered | Every outbound package on the order has a delivered carrier fact. |
shipment.action_required | A packed shipment is held in the warehouse before quoting and booking. data.actionRequired matches the shipment detail field (today: code cpsc_filing_required with per-SKU reasons). Sent once per distinct hold; a cleared hold continues with the usual shipment events. |
inbound.exception.opened | WooliiPorter opened an inbound receiving review. The payload contains the IB number and customer-safe exception projection only. |
inbound.exception.updated | The public state, customer-action requirement or resolution of an inbound receiving review changed. |
cancellation.updated | The interception state of a cancellation request changed — warehouse stop, stock return, review, final cancellation or rejection. The payload mirrors the cancellation object returned by GET fulfillment intent; once dispatched, orders can no longer be cancelled and the request resolves through review instead. |
account.balance_low | The merchant wallet is below the operating threshold. This account-level event has no order identity. |
Verifying signatures
Every delivery is signed with your endpoint's secret: an HMAC-SHA256 over `${timestamp}.${rawBody}`. Headers: X-Woolii-Event-Id, X-Woolii-Timestamp (unix seconds), X-Woolii-Signature (v1=<hex>). Verify against the raw body before parsing.
MCP server
Let your AI agent operate forwarding directly. The WooliiPorter MCP (Model Context Protocol) server exposes the Merchant API above as agent-callable tools, so Claude, Cursor or your own copilot can pre-alert orders, estimate costs, watch the timeline, settle shipments and run the optional stocking workflow — SKUs, inbound shipments, inventory, fulfillment orders and the monthly statement — without custom glue code. It is a single zero-dependency file — Node >= 18, no install step — and it uses your existing API key with the same scopes, sandbox behavior and fool-proof value-added-service rules as raw HTTP.
MCP tools
| Tool | What it does |
|---|---|
create_forwarding_order | Pre-alert an order: parcels, destination, value-added service requests. Idempotent per externalOrderId. |
estimate_shipping_cost | Estimate the selected public product with current prices and measurements; final packed pricing adds applicable declaration-based fees. |
get_order | Read one order, including value-added service progress. |
list_orders_updated_since | Incremental polling: orders changed since a timestamp. |
get_packed_quote | Final packed quote and transit ETA. |
get_settlement | The line-item bill — every charge explainable. |
pay_order | Legacy entry: production payment is unavailable; migrate explicitly. |
pay_order_from_wallet | Pay a confirmed quote with finance:pay, a settlement version and idempotency key. |
get_tracking | Normalized carrier tracking for every outbound package. |
get_timeline | Unified China-leg + carrier-leg event timeline. |
list_shipments | Cursor-paginated unified shipments, filterable by source, status, tracking and update time. |
get_shipment | One shipment with public service, parcels, merchant sell quote and normalized events. |
get_shipment_tracking | Shipment-native WooliiPorter tracking for every outbound parcel. |
cancel_order | Cancel while the order is still awaiting parcels. |
cancel_fulfillment_intent | Cancel one unified commerce fulfillment intent; the outcome distinguishes terminal cancellation from warehouse or admin review. |
register_sku | Register or update a merchant SKU (upsert by skuCode) — required before stocking or fulfillment. |
get_sku_cpsc | Read the US CPSC certificate of a SKU and its filing status. |
save_sku_cpsc | Create or replace the US CPSC certificate of a SKU; changes require a new filing before US shipment. |
create_inbound_shipment | Create a stocking/FBA/FBM inbound and receive an IB inbound number and address; no supplier tracking is required. |
get_inbound_shipment | Read one inbound by public IB number, including carton progress and customer-safe exception state. |
get_inventory | Live stock levels per SKU per warehouse plus aging, from the immutable movement ledger. |
create_fulfillment_order | Create a dropship order from stocked inventory — auto-confirms and reserves FIFO; ON_HOLD names any shortfall. |
confirm_fulfillment | Confirm a draft order, or retry reservation on an on-hold order after restocking. |
get_statement | Monthly statement: per-lot storage fees plus fulfillment fees, every line explainable. |
list_shipping_products | Public shipping products and saved account/store defaults. |
list_shippable_countries | Destinations with a live configured route. |
Start with a sandbox key: your agent can create orders, simulate the lifecycle and settle them without moving real funds. The same constraints apply as over HTTP — label-class services still require instructions, illustrations and printable label files, and pay only succeeds once the final packed quote exists.
The agent-facing page for this server — what it calls, where autonomy stops and how to get a key — is the MCP server page. Key issuance and scoping, webhook signature verification and staff access are described at Security.
Running WooCommerce? WooliiPorter Fulfillment for WooCommerce connects the store directly to fulfillment-intent endpoints. Use the standalone MCP server to connect an authorized assistant in your own runtime with the same merchant API key and scopes.
Running Shopify? The fulfillment-service app is listed on the Shopify App Store. Install it there to handle installation, product-to-SKU linking and assigned fulfillment orders inside Shopify itself. Shopify-managed authorization connects those assigned orders to the shared fulfillment backend and sends eligible shipment updates back to the store.
WooliiPorter Fulfillment for WooCommerce
Plugin version 0.9.0 connects one WooCommerce installation to Woolii-operated fulfillment in China. Test and connect validates the account, API-key environment, required scopes and compatibility smartRouting feature flag, then registers the store. When an eligible order reaches processing, the plugin sends a versioned snapshot through Action Scheduler—never in the checkout request—and stores the fulfillment intent, per-line route facts, required action and diagnostic request ID on the WooCommerce order.
Stock, supplier parcels and merchant review
Mapped lines with enough inventory reserve a warehouse fulfillment order. Forwarding lines wait for the merchant to enter real China domestic tracking numbers and allocate each product quantity; a forwarding child order is created only after those allocations exactly cover the intent. Mixed orders remain paused for Forward all, Wait for stock or Re-evaluate inventory. A product or variation marked Always forwardfollows supplier-parcel processing. Choose the store’s shipping product to define transport for each supported destination.
Replay, stale-order and webhook safety
The order snapshot hash is part of a stable Idempotency-Key. Duplicate hooks and retries replay the existing intent; a queued task exits safely when the order changed before execution. Lifecycle writes also carry routingVersion so a stale browser cannot overwrite a newer backend decision. Webhooks are accepted only when the HMAC timestamp is fresh and the Store and intent identities match. Event IDs are claimed atomically and retained for 90 days. A fulfillment intent completes the WooCommerce order only after the backend says every child fulfillment is delivered.
Settings
WooCommerce → WooliiPorter
| Setting | What it controls |
|---|---|
| API key & environment | Use wp_sk_test_… for sandbox and wp_sk_live_… for production. Test and connect verifies the real key environment and refuses a mismatch. |
| API base | Production is pinned to https://api.woolii.com/v1/merchant. Developer mode accepts only exact local hosts or code-allowlisted HTTPS origins, preventing credential exfiltration. |
| Order processing | The compatibility smartRouting setting enables fulfillment intents after features.smartRouting=true and Store registration. The shipping product is an explicit selection. |
| Automatic submission | Off by default. Can be enabled only after connection, environment, scope, Store, webhook-secret and Action Scheduler checks all pass. |
| Shipping product | Select productCode or save a store/account default. Each product has a fixed provider per country. Orders retain their selected product and public name snapshot. |
| Webhook signing secret | Required in every environment. The receiver verifies HMAC, Store identity, intent identity (when known), timestamp and eventId deduplication before writing order state. |
Install
- Active merchants can download the reviewed ZIP from the Integrations workspace. Upload it through Plugins → Add New → Upload Plugin, or upload the
wooliiporter-fulfillmentdirectory towp-content/plugins/. Requires WordPress 6.4+, PHP 7.4+ and WooCommerce 8.2+. - Activate WooliiPorter Fulfillment for WooCommerce on the Plugins screen.
- Open WooCommerce → WooliiPorter, paste a
wp_sk_test_…key, configure the webhook signing secret, then run Test and connect. - Map stocked products/variations to WooliiPorter SKU codes; mark supplier-direct products Always forward. Exercise stocked, forwarding and mixed outcomes in sandbox.
- Choose a shipping product, enable the order-processing setting, then enable automatic submission after the connection, Store, webhook secret and Action Scheduler release gates all pass.
The WordPress.org listing currently offers stable version 0.9.0 through standard WordPress updates. Active merchants can download the reviewed 0.9.0 package from the Integrations workspace for the latest product-selection workflow. WordPress.org publication of that package is tracked separately from the merchant download.
The connector synchronizes store identity, order snapshots, catalog/SKU links and supplier-parcel allocations with the shared WooliiPorter backend. Its privacy disclosure explains the operational data used for those workflows.
Get access
Create a merchant login, submit business details and expected order volume, then complete human review and online signing. Your offer specifies services, freight discount and settlement currency. Shopify, WooCommerce, Amazon and direct API merchants follow the same process. Signing activates the merchant console and API-key management.
While your application is under review or awaiting signature, you can sign in, view your application and agreements, and use the public shipping calculator. API-key creation stays closed until the account is active.
Eligible existing merchant accounts retain their access without retroactive signing; no signature record is created on their behalf.
Apply for API accessOpen the developer console
The developer console manages sandbox and production keys, webhook endpoints and one-time secrets. Store every revealed secret immediately; it is not shown again.
Questions
Is there a China 3PL with an API?
Yes. WooliiPorter publishes Merchant API V1 — 51 HTTP operations covering product selection, order creation, estimates, packed quotes, value-added services, tracking, settlement and inventory — with an OpenAPI 3.1 contract publicly available at /api/developers/openapi. Supported mutations use stored-response replay or resource-specific deduplication, and 13 webhook event types are HMAC-signed.
Does WooliiPorter publish an OpenAPI specification?
Yes. The OpenAPI 3.1 contract for Merchant API V1 is published at /api/developers/openapi and is readable without an account, before any application is submitted. The contract version is stated on the developers page and is reconciled against the deployed route surface rather than maintained by hand.
Why does a fulfillment API need idempotency?
Idempotency lets you safely retry a request after a timeout. Direct forwarding creation and fulfillment-intent mutations require a stable Idempotency-Key and replay the stored response. Stocked fulfillment deduplicates by account, environment and externalOrderId. Follow each endpoint’s contract so retries keep the same business record.
How do I verify a WooliiPorter webhook signature?
Verify HMAC-SHA256 over timestamp.rawBody before parsing the body, check timestamp freshness, then deduplicate the immutable event ID and process it. WooliiPorter delivers 13 signed event types at least once. Use the signature headers and receiver example below so accepted duplicate deliveries keep the same result.
How do I get a WooliiPorter API key?
API keys are managed from an active merchant console after review and signing. Start with a sandbox key, validate the workflow, then use production within your agreed service scope.
What can I evaluate before applying?
Everything that decides an integration: the OpenAPI 3.1 contract, all 51 operations with their parameters, the error table, the HMAC signature scheme, the idempotency contract, the 13 webhook event types and the 26 MCP tools. All of it is public, so the technical decision can be made before any conversation.
MCP server · Security · WooCommerce plugin · Webhooks guide · MCP for logistics