Sandbox environment & fixtures

Audience: integrations that ship against https://api.hiobuy.com (Workers gateway) — same base URL as production.

Plans: Free plans include self-service documentation and Sandbox access. Dedicated integration and fulfillment support are available on paid plans.

Auth: deterministic fixtures apply only to API keys prefixed with hio_test_* (key_type: test). hio_live_* production keys never read this page’s rules — they always hit upstream marketplaces / warehouses normally.

Related docs: Authentication · Response format · Errors · Rate limits · Products · Orders · Fulfillment · Webhooks

Important: Warehouse Fulfillment Testing

The Sandbox API (hio_test_*) is intended for mock and fixture-based integration testing.

If HIOBuy has provided your application with a WH-DEV Warehouse Developer Code, do not use the Sandbox API key to test your assigned warehouse configuration.

Use:

Production API Key (hio_live_*) + WH-DEV

WH-DEV is still a test warehouse configuration. Using a Production API key with WH-DEV does not mean that your application is performing live warehouse fulfillment.

ConfigurationPurpose
hio_test_*Mock / fixture API testing
hio_live_* + WH-DEVAssigned warehouse integration testing with test warehouse data
hio_live_* + Production warehouse authorizationLive warehouse fulfillment

Sandbox Fulfillment endpoints return predefined or simulated data. For example, sandbox warehouse locations, balances, packages, shipping routes, and package statuses may differ from the WH-DEV configuration assigned to your application.

If you are validating a WH-DEV integration, always use your Production API key.

Public API coverage (summary)

AreaSandbox
Globalresponse_format: upstream rejected (standard only). currency body field rejected as in prod. sandbox_trigger allowed for test keys (platform fixtures). Channel OAuth treated as authorized for hio_test_*. Quotas & rate limits skipped for test keys.
/v1/products/*Search, detail, parse, upload-image, search-by-image, freight estimate, batch-check, 1688 analytics endpoints mocked as documented below. OpenAPI-only extensions not in this site’s handoff set are not mocked.
/v1/orders/*Preview, create, detail, pay, cancel, logistics trace, list, purchase query mocked with magic / dynamic ids.
/v1/fulfillment/*Balance, quotes, shipments, inbounds, packages, unclaimed, returns, locations, VAS, service-requests, finance mocked with magic / dynamic ids (see below).
/v1/support/ticketsList/detail/reply mocked with tkt_* fixtures.
WebhooksSandbox resources do not auto-emit webhooks. Use portal Send test (livemode: false) to verify your receiver and signature.

Design goals

GoalMeaning
RepeatableSame request → same response (no randomness in outcomes).
DocumentedEvery scenario has a stable id or keyword you can grep in this page.
Contract alignedJSON matches standard schema fields from production; values differ.
Happy path defaultUnknown ids fall back to generic success mocks.
Explicit failureUse sb_* ids or sandbox_trigger to force errors / edge states.

Naming: sb_\{domain\}_\{scenario\}

SegmentRuleExamples
PrefixAlways sb_sb_prod_not_found
domainLowercase noun (prod, search, ord, shp, pkg, plat, …)
scenariosnake_casenot_found, pay_declined

Characters: [a-z0-9_], length ≤ ~48. Do not prefix real upstream ids with sb_ unless you intend the fixture. Some fulfillment resources also use stable non-sb_ ids (ret_*, ucp_*, svc_*, tkt_*, inv_*).

Two failure layers

Distinguish transport/API errors from HTTP 200 business states:

  • API failure → HTTP 4xx/5xx + error.code (e.g. NOT_FOUND, PAYMENT_DECLINED).
  • HTTP 200 with state → e.g. variants[].stock = 0, status: wait_payment.

Product fixtures (high level)

POST /v1/products/detail

See Product detail. upstream format is unsupported in sandbox.

Trigger when product_id, parsed url, mi_id, or tao_password resolves to a sb_* id.

Fixture idResultHTTP
(any non-sb_ id)Standard mock product200
sb_prod_not_foundNOT_FOUND404
sb_prod_offlinePRODUCT_UNAVAILABLE422
sb_prod_no_stockDetail ok, stock: 0200
curl https://api.hiobuy.com/v1/products/detail \
  -H "Authorization: Bearer hio_test_..." \
  -H "Content-Type: application/json" \
  -d '{"channel":"1688","product_id":"sb_prod_not_found","language":"en"}'

POST /v1/products/search

channel, keyword, page, page_size, language apply. 1688 filter / sort / price filters are accepted but ignored for mock rows.

keyword (exact)Result
ordinary textMock list with hits
sb_search_emptyitems: [], total: 0
sb_search_not_foundAlias of empty

Parse / upload-image / search-by-image / freight / analytics

EndpointSandbox note
Parse URLURL query/path containing sb_* mirrors detail behavior.
Upload imageAlways { "image_id": "img_sandbox_mock" } after validations pass.
Image searchOptional keyword: sb_search_empty yields empty list; pair with upload-image for flow tests.
Advanced — freight estimateDefault domestic freight mock 800 minor units aligned with preview.
Advanced — batch-checkReturns upstream-style envelope with mock mpProducts; use sb_prod_not_found in mi_id/item_id to populate exclusion lists.
Advanced — top keywords/list / daily-sales-trendUse sb_search_empty on category_id / rank_id where documented to empty lists or 404 detail cases.

Order & payment fixtures (magic ids)

POST /v1/orders/detail

order_idTypical statusNotes
sb_ord_unpaidwait_payment
sb_ord_paidwait_shipment
sb_ord_shippedwait_receive
sb_ord_completedcompleted
sb_ord_cancelledcancelled
sb_ord_refundingwait_shipment (refund_status in progress)
sb_ord_not_found404

POST /v1/orders/pay

order_idResultHTTP
sb_ord_unpaidPays successfully → logical paid state200
sb_ord_pay_declinedPAYMENT_DECLINED402
sb_ord_pay_insufficientPAYMENT_INSUFFICIENT_FUNDS402
sb_ord_paidORDER_ALREADY_PAID409
sb_ord_cancelledORDER_CANCELLED409
sb_ord_upstream_timeoutCHANNEL_UPSTREAM_ERROR502

Preview / create

Preview returns fixed illustrative totals (sample line ~4500 + freight ~800 in minor units). Create emits dynamic order_id values prefixed sbo_* persisted in sandbox storage — lines referencing offer_id: sb_prod_offline / sb_prod_no_stock return 422 like production semantics.

Cancel / logistics / list / purchase query

Per cancel, trace, detail list: unpaid sb_ord_* and dynamic sbo_* unpaid orders cancel; paid/shipped/etc. fixtures return ORDER_NOT_CANCELLABLE. Logistics returns packages for sb_ord_shipped / completed mocks; unpaid/paid-await-shipment return packages: []. Buyer list respects product_name: sb_ord_list_empty for empty mocks. Purchase query returns upstream envelopes; omit not-found pseudo ids accordingly.

Fulfillment fixtures

Note: The fixtures below are for Sandbox API testing only. They do not represent your application’s WH-DEV warehouse configuration. For WH-DEV testing, use a Production API key (hio_live_*).

All endpoints below require a hio_test_* key. Dynamic ids from create (pkg_*, sbs_*, sbi_*, …) are persisted in sandbox storage for the key.

Balance · quotes · locations · VAS catalog

EndpointSandbox note
GET /v1/fulfillment/balanceMock available balance 500000 CNY minor units.
POST /v1/fulfillment/shipping/quotesNeeds destination.country_code + weight or dimensions; legacy …/shipments/freight/estimate still works.
GET /v1/fulfillment/locationsSandbox: loc_wh_001 (Weihai), loc_sz_001 (Shenzhen, paused), loc_yw_001 (Yiwu). Live uses warehouse numeric id (e.g. "1") and Chinese country.
GET /v1/fulfillment/value-added-servicesSandbox: PHOTO / WOODEN_FRAME etc. Live uses warehouse numeric code as a string (e.g. "1").

Shipments

Live warehouse Public id is the numeric PK as a string (e.g. "115"); order_sn is the warehouse order number. Sandbox create returns sbs_*; fixtures below use sb_shp_*.

Fixture / idBehavior
sb_shp_unpaidList + detail PENDING; intercept → SHIPMENT_NOT_INTERCEPTABLE
sb_shp_shippedShipped detail: split boxes, first/last-mile legs, packing files; plus international tracking events. Intercept → REQUESTED
sb_shp_not_foundDetail 404
sb_shp_pay_insufficientPOST …/shipments/sb_shp_pay_insufficient/payINSUFFICIENT_BALANCE
sb_shp_not_cancellableCancel → SHIPMENT_NOT_CANCELLABLE; intercept is allowed (WAIT_SHIP)
sb_shp_signedSigned; intercept → SHIPMENT_NOT_INTERCEPTABLE
sb_shp_interceptedDetail SHIPPED + interception.status: INTERCEPTED; intercept again → SHIPMENT_INTERCEPTION_ALREADY_REQUESTED
Dynamic sbs_*Create / pay / list / detail / cancel / intercept against sandbox storage
sb_parcel_not_foundCreate → 422 PARCEL_NOT_FOUND

List path: GET /v1/fulfillment/shipments. Tracking path: GET /v1/fulfillment/shipments/{id}/tracking (language query).

Inbounds (create / cancel)

Create returns dynamic package_id (pkg_*) — there is no separate inbound_id.

Trigger valueFieldHTTPerror.code
sb_inbound_shippedtracking_number409INBOUND_TRACKING_ALREADY_SHIPPED
sb_inbound_existstracking_number409INBOUND_TRACKING_ALREADY_EXISTS
sb_inbound_bad_trackingtracking_number422INVALID_TRACKING_NUMBER
sb_inbound_external_existsexternal_order_id409EXTERNAL_ORDER_ID_ALREADY_EXISTS
sb_vas_missingservices[].service_code422VALUE_ADDED_SERVICE_NOT_FOUND
sb_vas_unavailableservices[].service_code422VALUE_ADDED_SERVICE_UNAVAILABLE
sb_vas_outboundservices[].service_code422VALUE_ADDED_SERVICE_INVALID_STAGE
Cancel idHTTPerror.code
Dynamic sbi_* (after create)200Cancelled; related package discarded
Same sbi_* again409INBOUND_NOT_EDITABLE
sb_inb_not_found404INBOUND_NOT_FOUND
sb_inb_received409INBOUND_ALREADY_RECEIVED
sb_inb_shipped / sb_inb_consolidated / sb_inb_cancelled409INBOUND_NOT_EDITABLE

Packages · tracking · list

package_idDetail / tracking
Dynamic pkg_*PENDING; tracking starts at INBOUND_CREATED
sb_pkg_pendingPENDING
sb_pkg_receivedRECEIVED + PHOTO timeline
sb_pkg_exceptionRECEIVED + condition.EXCEPTION
sb_pkg_shippedSHIPPED full outbound timeline
sb_pkg_not_found404 PACKAGE_NOT_FOUND

Unclaimed packages

Id / triggerBehavior
ucp_01K2ABCDEF1234567890Claimable; claim with SF123456789012 (list masked)
ucp_01K2ABCDEF9876543210Claimable; YT738800001148
Unknown tracking404 UNCLAIMED_PACKAGE_NOT_FOUND
SF000ALREADY01409 PACKAGE_ALREADY_CLAIMED
SF000NOTCLAIM1409 PACKAGE_NOT_CLAIMABLE

Returns

IdBehavior
ret_pending_001PENDING; fee=18; confirm succeeds
ret_pending_002PENDING; fee=20; confirm with 18 → RETURN_FEE_CHANGED
ret_returned_001RETURNED + tracking
ret_cancelled_001CANCELLED
sb_ret_not_found404 RETURN_NOT_FOUND
sb_ret_fee_not_readyConfirm → RETURN_FEE_NOT_READY
sb_ret_insufficientConfirm → INSUFFICIENT_BALANCE
Create on sb_pkg_shipped409 PACKAGE_NOT_RETURNABLE

Service requests

IdBehavior
svc_photo_completedPHOTO COMPLETED + images
svc_inspection_failedBASIC_INSPECTION FAILED
svc_video_processingVIDEO PROCESSING
svc_reinforce_pendingPACKAGE_REINFORCEMENT PENDING
svc_wooden_awaitingWOODEN_FRAME awaiting confirmation
sb_svc_not_found404
sb_svc_fee_not_ready / sb_svc_insufficientConfirm edge cases

Finance (transactions / invoices)

FixtureNote
txn_01K2ABC001006TOP_UP / VAS / RETURN / SHIPPING / REFUND / STORAGE
inv_01K2ABC001ISSUED (downloadable)
inv_01K2ABC002PENDING
inv_01K2ABC003REJECTED

See Fulfillment finance.

Support ticket fixtures

Fixture idScenario
tkt_01K2ABCDEF1234567890PACKAGE · NORMAL · WAITING_FOR_HIOBUY
tkt_01K2ABCDEF9876543210RETURN · URGENT · WAITING_FOR_CUSTOMER
tkt_01K2ABCDEFAPIRESOLVEDAPI · NORMAL · RESOLVED
tkt_01K2ABCDEFSHIPCLOSEDSHIPMENT · NORMAL · CLOSED (no replies)
tkt_not_found404 TICKET_NOT_FOUND

See Support tickets.

Platform triggers: sandbox_trigger

Allowed only on hio_test_*; production keys ignore the field quietly.

sandbox_triggerHTTPerror.code
sb_plat_quota_exceeded429QUOTA_EXCEEDED
sb_plat_rate_limited429RATE_LIMIT_EXCEEDED
sb_plat_upstream_error502CHANNEL_UPSTREAM_ERROR

Combine with benign ids so realistic bodies still validate:

{
  "channel": "1688",
  "product_id": "123456",
  "language": "en",
  "sandbox_trigger": "sb_plat_quota_exceeded"
}

Special auth fixture sb_auth_channel_required paired with triggers can produce CHANNEL_AUTH_REQUIRED (403) for UI regressions despite the normal “authorized by default” rule.

Implementation status snapshot

PhaseCoverageNotes
ShippedProducts, procurement orders, fulfillment (balance/quotes/shipments/inbounds/packages/unclaimed/returns/locations/VAS/service-requests/finance), support ticketsMirrors Public API subset on this site.
Not yetAuto-emitted sandbox webhooks; unpublished OpenAPI-only catalogue extensionsPrefer portal Send test for webhook CI; do not assume all live events are enabled until announced.

Quick copy cheat sheet

sb_prod_not_found          → 404 product missing
sb_prod_offline            → 422 unavailable
sb_prod_no_stock           → 200 detail with zero stock

sb_search_empty            → empty search/items
sb_ord_list_empty          → empty buyer order list filter
img_sandbox_mock           → stable upload-image id

sb_ord_unpaid              → detail wait_payment • pay succeeds • cancel ok
sb_ord_pay_declined        → pay 402 PAYMENT_DECLINED
sb_ord_paid                → pay 409 ALREADY_PAID • trace maybe empty until shipped fixtures
sb_ord_shipped             → detail wait_receive • trace populated
sb_ord_cancelled           → cancelled state • pay conflicts

sb_shp_unpaid / sb_shp_shipped / sb_shp_signed / sb_shp_intercepted → shipment list / detail / intercept
sb_pkg_received / sb_pkg_shipped → package detail / fulfillment timeline
sb_inbound_exists          → inbound create 409 tracking exists
ret_pending_001            → return confirm happy path
ucp_01K2ABCDEF1234567890   → unclaimed claimable
svc_photo_completed        → VAS request completed
tkt_01K2ABCDEF1234567890   → support ticket open

sb_plat_quota_exceeded     → sandbox_trigger → 429 QUOTA_EXCEEDED

When you add fixtures internally, mirror this numbering scheme in regression tests — never mutate standard JSON shapes inside mocks.

Get Support

Need integration help? Contact Developer Support at support@hiobuy.com · Response within 1–2 business days

Email support