# Amazon Connect to Shopify order lookup (Lambda handler)

Companion to the post [Connect + Shopify (Oct 2026)](/blog/amazon-connect-shopify-integration-2026/).

A Node 24 ESM Lambda with no npm dependencies. It reads the caller's phone (`CustomerEndpoint.Address`, E.164) or an `orderNumber` flow parameter, queries the Shopify Admin GraphQL API, and returns a flat map of strings for an **Invoke AWS Lambda function** block set to `STRING_MAP` response validation.

> **Verify before you speak.** Neither the caller ID nor an order number proves who is calling: order numbers are printed on confirmation emails and packing slips. This handler does not verify identity. Before the flow reads any order detail aloud, check a second factor the caller gives you (for example the email or billing postcode on the order) in a separate step.

| Key | Meaning |
| --- | --- |
| `found` | `"true"` or `"false"` |
| `lookupStatus` | `ok`, `not_found`, `ambiguous` (two customers share the phone), `timeout`, `throttled` (HTTP 429 or GraphQL `THROTTLED`), `auth` (401/403), `not_configured`, `error`, `no_identifier` |
| `customerFirstName`, `lastOrderName`, `lastOrderStatus`, `fulfillmentStatus`, `carrier` | Present only when `found` is `"true"` |

Route on `lookupStatus`, not only on `found`. `found = false` with `lookupStatus = timeout` means "we could not check", which the flow must not say as "no order".

## Configuration (environment variables)

| Variable | Default | Note |
| --- | --- | --- |
| `SHOPIFY_SHOP` | none | `your-store.myshopify.com` |
| `SHOPIFY_API_VERSION` | `2026-10` | Pin it; re-test when you change it |
| `SHOPIFY_SECRET_ID` | none | Secrets Manager secret: `{"accessToken":"..."}` or `{"clientId":"...","clientSecret":"..."}` |
| `LOOKUP_BUDGET_MS` | `4500` | One `AbortController` covers the token fetch and the query. Keep it under the flow block timeout (max 8 s) |
| `SHOPIFY_ACCESS_TOKEN` | none | Local testing only. Do not set in Lambda |

Lambda function timeout: set it a little above `LOOKUP_BUDGET_MS` (for example 6 s), and the flow block timeout above that (for example 7 s).

## Run the test

```bash
node --test
```

The test mocks `fetch`. It checks the response shape, the query variables, each fallback status, that a hung query or hung token fetch aborts at the budget and returns a fallback instead of throwing, and that the one JSON log line per call never contains the phone number. It does not call Shopify, so it proves nothing about live field names or your store's data.

## Not included

Webhook receiver, Customer Profiles ingestion, retries (Connect already retries a thrown error, which is why this handler returns a fallback instead), and the IAM policy. The handler needs `secretsmanager:GetSecretValue` on one secret only.
