Skip to main content

POS Partner API — Authentication Contract

Supported auth path: x-partner-key

The Trident Phase 1 integration uses a single shared API key delivered via the x-partner-key HTTP header.

HeaderValueSource
x-partner-keyHMAC-compared against POS_PARTNER_API_KEY env varInfisical /pos/partner-api

All v1/pos/partners/* endpoints require this header. Missing or invalid keys return:

{"message":"Invalid partner API key","error":"Forbidden","statusCode":403}

Legacy compatibility auth path

The /pos/* and /transactional/* routes use LegacyPartnerApiKeyGuard, which accepts two auth modes:

Mode 1 — modern key on legacy routes:

InputSourceChecked against
x-partner-key headerHTTP headerPOS_PARTNER_API_KEY
x-data-source headerHTTP headerMCA_API_DATA_SOURCE

Both must be present and valid. This allows the modern partner key to work on legacy routes when the data source matches.

Mode 2 — legacy token:

InputSourceChecked against
tokenQuery string or request bodyMCA_API_KEY
x-data-source headerHTTP headerMCA_API_DATA_SOURCE

Both must be present and valid.

Note: This is NOT Authorization: Bearer. The legacy path reads token from the query string or JSON body, not from an Authorization header.

Status: The legacy auth path is wired but is not the supported path for Trident Phase 1. See the auth hardening issue for the deprecation/retention decision.

Unauthenticated endpoints

Health endpoints (/api/health/ready, /api/health/live) are not guarded and require no authentication.

Gateway smoke

A repeatable smoke test is available at tools/scripts/smoke/pos-partner-api.sh:

POS_BASE_URL=https://pos-partner-api.uat.digiwedge.com \
POS_PARTNER_KEY=<key> \
bash tools/scripts/smoke/pos-partner-api.sh

Smoke matrix

TestMethodPathExpected
HealthGET/api/health/ready200, ok=true
No authPOST/api/v1/pos/partners/members/lookup403
Wrong keyPOST/api/v1/pos/partners/members/lookup403
Valid key, disabled clubPOST/api/v1/pos/partners/members/lookup200, reasonCode=club_pos_disabled
Balance, disabled clubGET/api/v1/pos/partners/balance403

Note on HTTP semantics

Member lookup returns 200 with status=BLOCKED for disabled clubs. Balance returns 403. This is the current behavior and is documented here for contract stability. If uniform semantics are required, open a consistency review.