Skip to content

REST API

Order status lookup (Dixa MIM Tools)

POST /wp-json/dixa/v1/order-status

Used by Dixa's MIM Actions to answer "where is my order"-style questions. Deliberately lives outside the wc/v3 namespace and outside WooCommerce's own REST authentication — see Architecture if you're adding a similar endpoint.

Authentication

HTTP Basic Auth, checked independently of WordPress users and WooCommerce's Consumer Key/Secret REST auth:

Authorization: Basic base64(DIXA_MIM_TOOLS_API_KEY:DIXA_MIM_TOOLS_API_SECRET)

The credentials are set in the site's .env file — see Configuration. Requests over plain HTTP are always rejected (401). Repeated failed authentication or lookup attempts from the same API key (or IP, if no credentials are supplied at all) are throttled — see Errors.

Other plugins (WordPress core's Application Passwords, some security plugins, Basic-Auth dev plugins) can also read Authorization: Basic credentials globally, for every REST request site-wide, and reject an unrecognized API key as an invalid WP username before this route is even reached. This endpoint clears any such conflicting global auth error for its own path so its own auth logic always gets the final say — see Architecture.

Request body (JSON)

POST is used instead of GET specifically so the verification data below never ends up in a URL query string (and therefore never in web server access logs, proxy logs, etc.).

This is enforced, not just a convention: order_number, email and phone are only ever read from the JSON body. If any of them are sent as query-string parameters instead — e.g. because a MIM Action tool was configured with "query" params rather than "body" — the request is rejected with 400 params_must_be_in_body rather than silently accepted, so a misconfiguration on the caller's side can't quietly reintroduce PII into request logs. When setting up the tool in Dixa, make sure order_number/email/phone are added under the request body, not under query parameters.

Field Required Description
order_number Yes The order's number (its WooCommerce order ID, unless a sequential order numbering plugin is active)
email One of email/phone Billing email on the order
phone One of email/phone Billing phone on the order. Normalized before comparison, so country code presence, spaces and dashes don't matter (e.g. +45 12 34 56 78, 004512345678, and 12345678 can all match the same order)

order_number plus at least one of email/phone is required. If both are supplied, matching either one is enough — a customer's email on file can go stale while their phone stays current, or vice versa, so requiring every supplied field to match would only lock out legitimate customers. An order number alone is never sufficient to look up an order.

Phone number normalization on multi-market shops

A phone number typed without an explicit country code (e.g. 12345678) needs a default country to be interpreted correctly — 12345678 is a different number in Denmark than in the US. For shops that sell into more than one country, the shop's own base country is not a safe assumption, so the order's own billing/shipping country is tried first:

  1. The order's billing country
  2. The order's shipping country (if different)
  3. The shop's base country, as a fallback
  4. No default country at all — a number that already includes its own country code (e.g. +45...) still matches even if none of the above is set or resolvable

This means an order can still be validated even when its country field is empty or wrong, as long as the phone number supplied is fully-qualified.

Example

curl -u <api-key>:<api-secret> \
  -X POST "https://example.com/wp-json/dixa/v1/order-status" \
  -H "Content-Type: application/json" \
  -d '{"order_number":"1234","phone":"+45 12 34 56 78"}'

Response

{
  "order_number": "1234",
  "status": "processing",
  "date_created": "2026-08-01T10:00:00+00:00",
  "date_paid": "2026-08-01T10:05:00+00:00",
  "date_completed": null,
  "needs_payment": false,
  "payment_method_title": "Credit card",
  "total": "499.00",
  "currency": "DKK",
  "item_count": 3,
  "shipping_method": "GLS Parcel Shop",
  "shipping_country": "DK",
  "is_refunded": false,
  "estimated_delivery": null,
  "tracking": {
    "tracking_url": "https://..."
  }
}

tracking is only populated when a shipping-label plugin providing dao_get_latest_shipping_label_from_order() is active and a label exists for the order.

Dixa's MIM Actions let the tool config narrow this down further with JMESPath on their side, so this endpoint intentionally returns the full flat object rather than supporting its own field-filtering query parameter.

dixa_order_status_data filter

A site can add, edit or remove fields on this response from its own theme/mu-plugin — e.g. to expose a custom field, rename a value, or drop something that shouldn't leave the site:

add_filter( 'dixa_order_status_data', function ( array $data, WC_Order $order ) {
    $data['loyalty_points'] = get_user_meta( $order->get_customer_id(), 'loyalty_points', true );

    return $data;
}, 10, 2 );
Param Type Description
$data array The response fields, keyed by field name (everything shown in the example response above, after estimated_delivery has already been computed)
$order WC_Order The order being looked up

Runs last, after every field this package computes — a callback sees (and can override) this package's own values, not just append new ones.

Estimated delivery

estimated_delivery is null unless the order both has a base date to count from and ships with one of the carriers below, identified by the order's shipping item method id (e.g. dao, dhl, bladkompagniet — as registered by barberklingen/package-dao-shipping, if active). When both conditions hold, business days (Mon–Fri) are added to the base date:

Carrier Business days added Condition
DAO 2
DHL 7 Shipping country (fallback: billing country) is not DK
DHL 3 Shipping country (fallback: billing country) is DK
Bladkompagniet 6

The base date is the order's completed date (date_completed) if set, falling back to the paid date (date_paid) if the order hasn't been marked completed yet.

Any other/unknown shipping method (or an order with neither a completed nor a paid date) leaves estimated_delivery as null.

dixa_order_status_estimated_delivery filter

The computed value above is only a default — a site can override or extend it (e.g. to add cut-off times, or handle a carrier not listed here) by hooking this filter from its own theme/mu-plugin:

add_filter( 'dixa_order_status_estimated_delivery', function ( $estimated, WC_Order $order ) {
    // $estimated already holds this package's computed default (or null).
    // Return an ISO 8601 date string, or null to leave it unset.
    return $estimated;
}, 10, 2 );
Param Type Description
$estimated string\|null This package's computed default (see table above), or null
$order WC_Order The order being looked up

Return value must be a non-empty string (used as-is) or null.

Errors

Standard WordPress REST error shape ({code, message, data: {status}}):

Status Code Meaning
400 params_must_be_in_body order_number, email or phone was sent as a query-string parameter instead of in the JSON body
400 missing_params order_number was supplied but neither email nor phone was
401 unauthorized Missing/invalid Basic Auth credentials, or a non-HTTPS request
404 order_not_found Generic — covers both "no such order" and "verification mismatch", by design, so a caller can't tell them apart
429 rate_limited Too many failed attempts from this API key/IP; try again later

Customer lookup

GET /wp-json/wc/v3/dixa/v1/list

Returns WooCommerce customer data formatted for Dixa. Requires manage_woocommerce capability.

Query parameters

Parameter Type Description
email string Look up customer by email address
phone string Look up customer by billing phone number (country prefix stripped)

Exactly one parameter must be supplied. If neither matches a customer, an empty object {} is returned.

Example

curl -u admin:password \
  "https://example.com/wp-json/wc/v3/dixa/v1/list?email=customer@example.com"

Response

The response shape is produced by DixaDataGenerator and mirrors the Dixa End User structure (name, email, phone, orders, subscriptions).