Back to Genius hub

Order Lookup architecture

How we access the Genius API

Order Lookup uses server-side PHP cURL on HandiRamp's WPEngine site to call Genius ERP's REST API over HTTPS. The browser never receives Genius credentials or a Genius token. The public page talks only to our PHP endpoint, and that endpoint performs the Genius login, data fetches, result shaping, and logout.

Tool used PHP cURL running on the web server
Genius endpoint https://handiproducts.geniuserpcloud.com:53215
Authentication POST /api/auth, token passed as query param
Main resolver SalesOrderHeaderEntity.Code

System diagram

Genius is the identity spine. Order Lookup turns whatever the user has into a Genius sales order number, then fans out from that sales order to invoice, shipping, customer, freight, and tracking data.

User browser order-lookup-poc.html No Genius credentials WPEngine PHP endpoint /genius/order-lookup.php PHP cURL, server-side only Genius ERP REST API /api/auth /api/data/fetch/{Entity} fetch q=HR263803 POST /api/auth session token Accepted inputs Woo order: HR263803 Genius SO: 10538619 Genius invoice: 10646061 Shipping header: 00050138 Amazon or vendor PO FreightPop ShipmentID Carrier tracking number Resolver logic 1. Normalize user input 2. Search candidate Genius keys 3. Score exact matches 4. If ambiguous, return picker 5. Resolve one SO code Canonical key SalesOrderHeader.Code Example: 10538619 normalize Genius entities fetched SalesOrderHeaderEntity CustomerInvoiceHeaderEntity ShippingHeaderEntity ShippingDetailEntity CustomerEntity CustomerInvoiceDetailEntity Result: invoice, ship-to, carrier, tracking, freight GET fetch sanitized JSON response to browser Browser -> PHP endpoint -> Genius auth -> entity fetches -> PHP result shaping -> browser

What tool do we use?

In production

The live Order Lookup tool uses PHP cURL. That is the tool making the HTTPS calls to Genius. It runs inside order-lookup.php on WPEngine.

The browser calls our endpoint with a normal JavaScript fetch(). The browser does not call Genius directly.

From a terminal

For testing, we use the standard curl command plus jq to inspect JSON. This is equivalent to what PHP cURL is doing server-side.

The public Order Lookup page can be tested with curl against our endpoint without exposing Genius credentials.

Need the slower version? See PHP cURL and REST over HTTPS Explained for a plain-English diagram of what PHP, cURL, REST, and HTTPS each do.

Exact API sequence

Browser submits a lookup The UI calls /genius/order-lookup.php?q=HR263803.
PHP normalizes the input Example: HR263803 becomes candidate keys HR263803, WEB-263803, and related numeric variants.
PHP logs into Genius The server posts company code, username, and password to /api/auth. Genius returns a short-lived token.
PHP fetches Genius entities Every data read is a GET to /api/data/fetch/{Entity} with TOKEN, fields, filter, limit, and page.
PHP resolves one canonical sales order The target key is SalesOrderHeaderEntity.Code. Once that is known, the rest of the order information hangs off it.
PHP shapes a sanitized JSON response The browser receives order status, invoice, shipping header, customer, tracking, and freight fields. It never receives the Genius token.
PHP logs out of Genius The endpoint calls DELETE /api/auth?TOKEN=... in a finally block.

Terminal commands

These are the commands an engineer can run from a shell. They use placeholders; the real credentials stay server-side.

1. Log in and capture the Genius token

export GENIUS_BASE="https://handiproducts.geniuserpcloud.com:53215"
export GENIUS_COMPANY="HANDIP"
export GENIUS_USER="<server-held username>"
export GENIUS_PASS="<server-held password>"

TOKEN="$(
  jq -n \
    --arg company "$GENIUS_COMPANY" \
    --arg user "$GENIUS_USER" \
    --arg pass "$GENIUS_PASS" \
    '{CompanyCode:$company, Username:$user, Password:$pass}' |
  curl -sS -X POST "$GENIUS_BASE/api/auth" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    --data-binary @- |
  jq -r '.Result'
)"

printf '%s\n' "$TOKEN"

2. Fetch a sales order by Genius SO number

curl -sS "$GENIUS_BASE/api/data/fetch/SalesOrderHeaderEntity?$( \
  jq -nr \
    --arg TOKEN "$TOKEN" \
    --arg fields "Code,PoNumber,BillToCustomerCode,ShipToCustomerCode,TerritoryCode" \
    --arg filter 'Code="10538619"' \
    '$ARGS.named | to_entries | map("\(.key)=\(.value|@uri)") | join("&")'
)" | jq '.Result[0]'

3. Resolve a WooCommerce order through the Genius PO field

curl -sS "$GENIUS_BASE/api/data/fetch/SalesOrderHeaderEntity?$( \
  jq -nr \
    --arg TOKEN "$TOKEN" \
    --arg fields "Code,PoNumber,BillToCustomerCode,ShipToCustomerCode,TerritoryCode" \
    --arg filter 'PoNumber="WEB-263803"' \
    '$ARGS.named | to_entries | map("\(.key)=\(.value|@uri)") | join("&")'
)" | jq '.Result[] | {Code, PoNumber, ShipToCustomerCode, BillToCustomerCode}'

4. Fetch invoice records for the resolved sales order

curl -sS "$GENIUS_BASE/api/data/fetch/CustomerInvoiceHeaderEntity?$( \
  jq -nr \
    --arg TOKEN "$TOKEN" \
    --arg fields "CustomerInvoiceHeaderCode,CustomerOrder,ShippingOrder,ShippingHeaderLink,AmountTotal,Status" \
    --arg filter 'CustomerOrder="10538619"' \
    '$ARGS.named | to_entries | map("\(.key)=\(.value|@uri)") | join("&")'
)" | jq '.Result[]'

5. Fetch shipping details for a Genius shipping header

curl -sS "$GENIUS_BASE/api/data/fetch/ShippingDetailEntity?$( \
  jq -nr \
    --arg TOKEN "$TOKEN" \
    --arg fields "ShippingHeaderCode,SalesOrderHeaderCode,CustomerInvoiceHeaderCode,ItemCode,ShippingDate" \
    --arg filter 'ShippingHeaderCode="00050138"' \
    '$ARGS.named | to_entries | map("\(.key)=\(.value|@uri)") | join("&")'
)" | jq '.Result[]'

6. Log out

curl -sS -X DELETE "$GENIUS_BASE/api/auth?$(jq -nr --arg TOKEN "$TOKEN" '$ARGS.named | to_entries | map("\(.key)=\(.value|@uri)") | join("&")')"
Do not put real credentials in public examples. The live Order Lookup tool currently keeps Genius access server-side. The right production hardening move is to load credentials from WPEngine environment or secret storage, not from client-side JavaScript and not from public documentation.

PHP implementation pattern

This is the simplified shape of the live endpoint. The actual file also handles FreightPop, Zoho, ambiguous matches, and response formatting.

function curl_json(string $method, string $url, ?array $body = null): array {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 35,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($body !== null) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Accept: application/json',
            'Content-Type: application/json',
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    }
    $raw = curl_exec($ch);
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return ['status' => $status, 'json' => json_decode($raw, true)];
}

function genius_login(): string {
    $res = curl_json('POST', GENIUS_BASE . '/api/auth', [
        'CompanyCode' => GENIUS_COMPANY,
        'Username' => GENIUS_USER,
        'Password' => GENIUS_PASS,
    ]);
    return (string) $res['json']['Result'];
}

function genius_fetch(string $token, string $entity, array $params): array {
    $params = array_merge(['TOKEN' => $token, 'limit' => 20, 'page' => 1], $params);
    $url = GENIUS_BASE . '/api/data/fetch/' . rawurlencode($entity) . '?' . http_build_query($params);
    return curl_json('GET', $url)['json']['Result'] ?? [];
}

Genius entities used by Order Lookup

Entity Why we call it Key fields
SalesOrderHeaderEntity Master order resolver. This is where external references become a Genius SO. Code, PoNumber, bill-to and ship-to fields
CustomerInvoiceHeaderEntity Finds invoice records and pivots invoice number back to a sales order. CustomerInvoiceHeaderCode, CustomerOrder, ShippingHeaderLink
ShippingHeaderEntity Gets the shipment header and parses package JSON from the note field. Code, CarrierCode, ShippingModeCode, Note
ShippingDetailEntity Resolves a shipping header to the SO and item lines. ShippingHeaderCode, SalesOrderHeaderCode, ItemCode
CustomerEntity Fallback customer phone lookup when the sales order does not expose enough phone data. Code, Phone
CustomerInvoiceDetailEntity Finds customer-billed freight by summing invoice detail lines where item code is FREIGHT. CustomerInvoiceHeaderCode, ItemCode, AmountTotal

Live Order Lookup verification command

This calls our public endpoint, not Genius directly. It proves the whole chain is working: browser-facing PHP endpoint, Genius auth, Genius entity fetches, FreightPop enrichment, and JSON response formatting.

curl -sS 'https://handiproducts.com/genius/order-lookup.php?q=HR263803' |
  jq '{
    ok,
    matched,
    salesOrder: .record.salesOrder,
    invoice: .record.invoice,
    shippingHeader: .record.shippingHeader,
    tracking: .record.tracking,
    delivery: .record.delivery,
    freightpop: .record.freightpop
  }'
Known verified example: HR263803 normalizes to WEB-263803 and resolves to Genius SO 10538619, invoice 10646061, shipping header 00050138, and FedEx tracking 382574195198.

Related Zapier automation path

Order Lookup uses PHP cURL on WPEngine. The shipping automation Zaps use a different path: Zapier calls a private Genius ERP app action that authenticates to Genius and performs a bulk shipping lookup. See How Zapier Uses the Genius API for Shipping Updates.