as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
Docs
Resources
Ecommerce Plug-ins
Publish
Connect
感谢您的访问。此页面目前仅提供英语版本。我们正在开发中文版本。谢谢您的理解。

Verify Identity Keys Test Cases

Disclaimer: This document contains sample content for illustrative purposes only. Organizations should follow their own established best practices, security requirements, and compliance standards to ensure solutions are production-ready.

Verify Identity Keys API Test Cases

Overview

These test cases validate the VerifyIdentityKeys API (POST /v1/identity/identity-keys), which Amazon calls whenever a shopper scans their Scan Key Code at the JWO gate. The API is the retailer's Identity Connector — it receives the shopper's identity key and returns an authorization decision that determines whether the gate opens or remains closed.


1. Successful Authorization (200)

1.1 Shopper Entry — Valid Identity Key

Objective: Verify a valid shopper is authorized and the gate opens

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfc2hvcHBlcl9rZXk=",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T17:53:57Z",
    "location": "ENTRY"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "shopper-uuid-001",
    "type": "SHOPPER"
  }
}

Expected Result: Gate opens. Shopper is allowed to enter the store.

1.2 Associate Entry

Objective: Verify a store associate is authorized with type ASSOCIATE

Request:

{
  "requestId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "identityKey": "YXNzb2NpYXRlX2tleQ==",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "22222222-3333-4444-5555-666666666666",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "associate-uuid-001",
    "type": "ASSOCIATE"
  }
}

Expected Result: Gate opens. Associate entry is tracked separately from shopper entry.

1.3 Cash Shopper Entry

Objective: Verify a cash shopper is authorized with type CASH_SHOPPER (store must support this type)

Request:

{
  "requestId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "identityKey": "Y2FzaF9zaG9wcGVyX2tleQ==",
  "storeId": "CASH-ENABLED-STORE-001",
  "authEvent": {
    "id": "33333333-4444-5555-6666-777777777777",
    "timestamp": "2024-02-09T18:05:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "cash-shopper-uuid-001",
    "type": "CASH_SHOPPER"
  }
}

Expected Result: Gate opens. Confirm CASH_SHOPPER type is only returned for stores that support it.

1.4 Entry with Optional shopperDeviceId

Objective: Verify response includes shopperDeviceId when the shopper's mobile device is identified

Request: Same as test 1.1

Expected Response (200):

{
  "visitorDetails": {
    "id": "shopper-uuid-001",
    "type": "SHOPPER"
  },
  "shopperDeviceId": "device-abc-123"
}

Expected Result: Gate opens. shopperDeviceId is present and correctly identifies the shopper's device.

1.5 Exit Gate Scan

Objective: Verify identity key validation at the EXIT gate location

Request:

{
  "requestId": "d4e5f6a7-b8c9-0123-defa-234567890123",
  "identityKey": "dmFsaWRfc2hvcHBlcl9rZXk=",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "44444444-5555-6666-7777-888888888888",
    "timestamp": "2024-02-09T18:30:00Z",
    "location": "EXIT"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "shopper-uuid-001",
    "type": "SHOPPER"
  }
}

Expected Result: Exit gate processes the scan correctly.

1.6 RADIO Key Channel

Objective: Verify identity key validation when keyChannel is RADIO (e.g., badge scan)

Request:

{
  "requestId": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "identityKey": "cmFkaW9fYmFkZ2Vfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "55555555-6666-7777-8888-999999999999",
    "timestamp": "2024-02-09T18:10:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "RADIO"
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "badge-shopper-uuid-001",
    "type": "SHOPPER"
  }
}

Expected Result: Gate opens. RADIO channel scan is processed correctly.

1.7 keyChannel Omitted

Objective: Verify the API handles requests without the optional keyChannel field

Request:

{
  "requestId": "f6a7b8c9-d0e1-2345-fabc-456789012345",
  "identityKey": "dmFsaWRfc2hvcHBlcl9rZXk=",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "66666666-7777-8888-9999-aaaaaaaaaaaa",
    "timestamp": "2024-02-09T18:15:00Z",
    "location": "ENTRY"
  }
}

Expected Response (200):

{
  "visitorDetails": {
    "id": "shopper-uuid-001",
    "type": "SHOPPER"
  }
}

Expected Result: Gate opens. Missing optional keyChannel does not cause a failure.


2. Unauthorized — Invalid or Unknown Key (401)

2.1 Invalid Identity Key

Objective: Verify gate remains closed when the identity key is invalid

Request:

{
  "requestId": "a1111111-1111-1111-1111-111111111111",
  "identityKey": "aW52YWxpZF9rZXk=",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "timestamp": "2024-02-09T18:20:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (401):

{
  "message": "Invalid identity key"
}

Expected Result: Gate remains closed.

2.2 Identity Key Not Found

Objective: Verify gate remains closed when the identity key does not map to any known shopper

Request:

{
  "requestId": "b2222222-2222-2222-2222-222222222222",
  "identityKey": "dW5rbm93bl9rZXk=",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "bbbbbbbb-cccc-dddd-eeee-ffffffffffff",
    "timestamp": "2024-02-09T18:25:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "OPTICAL"
}

Expected Response (401):

{
  "message": "Identity key not found"
}

Expected Result: Gate remains closed.

2.3 Expired Identity Key

Objective: Verify gate remains closed when the identity key (e.g., QR code) has expired

Test Steps:

  1. Generate a Scan Key Code
  2. Wait beyond the configured expiry window (e.g., 30–90 seconds)
  3. Submit the expired key to the API

Expected Response (401):

{
  "message": "Identity key expired"
}

Expected Result: Gate remains closed. Shopper must generate a new Scan Key Code.

2.4 Flagged Shopper Account

Objective: Verify gate remains closed when the shopper's account has been flagged (e.g., fraud, outstanding balance)

Request: Use an identity key mapped to a flagged account

Expected Response (401):

{
  "message": "Shopper account flagged"
}

Expected Result: Gate remains closed.

2.5 Expired Payment Method

Objective: Verify gate remains closed when the shopper's associated payment method has expired

Request: Use an identity key mapped to a shopper with an expired card

Expected Response (401):

{
  "message": "Payment method expired"
}

Expected Result: Gate remains closed.


3. Bad Request — Validation Errors (400)

3.1 Missing requestId

Objective: Verify 400 when requestId is omitted

Request:

{
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Missing required field: requestId"
}

3.2 Invalid requestId Format

Objective: Verify 400 when requestId does not match UUID format

Request:

{
  "requestId": "not-a-valid-uuid",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Invalid requestId format"
}

3.3 Missing identityKey

Objective: Verify 400 when identityKey is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Missing required field: identityKey"
}

3.4 identityKey Exceeds 1000 Characters

Objective: Verify 400 when identityKey exceeds the maximum length

Request: Submit a request with an identityKey longer than 1000 characters

Expected Response (400):

{
  "message": "identityKey exceeds maximum length of 1000 characters"
}

3.5 identityKey Not Valid Base64

Objective: Verify 400 when identityKey is not a valid Base64-encoded string

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "!!!not-base64!!!",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Invalid identityKey encoding"
}

3.6 Missing storeId

Objective: Verify 400 when storeId is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Missing required field: storeId"
}

3.7 storeId Exceeds 255 Characters

Objective: Verify 400 when storeId exceeds the maximum length

Request: Submit a request with a storeId longer than 255 characters

Expected Response (400):

{
  "message": "storeId exceeds maximum length of 255 characters"
}

3.8 Invalid storeId

Objective: Verify 400 when storeId does not match any known store

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "NONEXISTENT-STORE",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Invalid storeId"
}

3.9 Missing authEvent

Objective: Verify 400 when the entire authEvent object is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001"
}

Expected Response (400):

{
  "message": "Missing required field: authEvent"
}

3.10 Missing authEvent.id

Objective: Verify 400 when authEvent.id is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Missing required field: authEvent.id"
}

3.11 Invalid authEvent.id Format

Objective: Verify 400 when authEvent.id does not match UUID format

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "not-a-uuid",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Invalid authEvent.id format"
}

3.12 Missing authEvent.timestamp

Objective: Verify 400 when authEvent.timestamp is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Missing required field: authEvent.timestamp"
}

3.13 Invalid authEvent.timestamp Format

Objective: Verify 400 when authEvent.timestamp is not valid UTC format

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "not-a-timestamp",
    "location": "ENTRY"
  }
}

Expected Response (400):

{
  "message": "Invalid authEvent.timestamp format"
}

3.14 Missing authEvent.location

Objective: Verify 400 when authEvent.location is omitted

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z"
  }
}

Expected Response (400):

{
  "message": "Missing required field: authEvent.location"
}

3.15 Invalid authEvent.location Value

Objective: Verify 400 when authEvent.location is not ENTRY or EXIT

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "INVALID"
  }
}

Expected Response (400):

{
  "message": "Invalid authEvent.location value"
}

3.16 Invalid keyChannel Value

Objective: Verify 400 when keyChannel is not OPTICAL or RADIO

Request:

{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "identityKey": "dmFsaWRfa2V5",
  "storeId": "STORE-001",
  "authEvent": {
    "id": "11111111-2222-3333-4444-555555555555",
    "timestamp": "2024-02-09T18:00:00Z",
    "location": "ENTRY"
  },
  "keyChannel": "BLUETOOTH"
}

Expected Response (400):

{
  "message": "Invalid keyChannel value"
}

3.17 Empty Request Body

Objective: Verify 400 when the request body is empty

Request:

{}

Expected Response (400):

{
  "message": "Invalid request body"
}

4. Rate Limiting (429)

4.1 Exceed Rate Limit

Objective: Trigger "Too Many Requests" by exceeding the API rate limit

Test Method: Send rapid concurrent requests to the API endpoint beyond the configured rate limit

Expected Response (429):

{
  "message": "Too Many Requests"
}

Expected Result: Gate remains closed. Subsequent requests within the rate window are rejected.


5. Internal Server Error (500)

5.1 Server Error — Default Gate Decision

Objective: Verify the gate follows the store's default gate decision when a 500 error occurs

Test Method: Simulate an internal server error (e.g., identity backend unavailable)

Expected Response (500):

{
  "message": "Internal server error"
}

Expected Result: Gate follows the configured default gate decision for the store (open or closed depending on store configuration).


6. Idempotency

6.1 Duplicate Request — Same authEvent.id

Objective: Verify the API returns the same response when called multiple times with the same authEvent.id

Test Steps:

  1. Send a valid request with authEvent.id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
  2. Confirm 200 response with visitorDetails
  3. Send the exact same request again with the same authEvent.id
  4. Confirm the response is identical to step 2

Expected Result: Both responses are identical. No duplicate shopper sessions are created.

6.2 Duplicate Request — Same authEvent.id, Different requestId

Objective: Verify idempotency is keyed on authEvent.id, not requestId

Test Steps:

  1. Send a valid request with authEvent.id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee and requestId 11111111-...
  2. Send the same request but with a new requestId 22222222-... and the same authEvent.id
  3. Confirm both responses are identical

Expected Result: The authEvent.id drives idempotency. Different requestIds with the same authEvent.id produce the same result.

6.3 Rapid Retries — Same Scan Event

Objective: Simulate Amazon retrying the same scan event multiple times in quick succession

Test Steps:

  1. Send 5 identical requests with the same authEvent.id within 1 second
  2. Verify all responses are identical
  3. Verify only one shopper session is created

Expected Result: All responses are consistent. No side effects from repeated calls.


7. QR Code / Scan Key Code Validation

7.1 Valid Scan Key Code

Objective: Verify a properly formatted Scan Key Code is accepted

Test Steps:

  1. Generate a Scan Key Code with valid prefix (JWO), customer prefix, recognition token (32 chars), and timestamp
  2. Base64-encode the payload and submit as identityKey
  3. Confirm 200 response

Expected Result: Gate opens.

7.2 Scan Key Code with Invalid Prefix

Objective: Verify rejection when the Scan Key Code does not start with JWO

Test Steps:

  1. Generate a Scan Key Code with prefix "ABC" instead of "JWO"
  2. Base64-encode and submit

Expected Result: 401 response. Gate remains closed.

7.3 Scan Key Code Below Minimum Length

Objective: Verify rejection when the decoded Scan Key Code is shorter than 49 characters

Test Steps:

  1. Create a payload shorter than 49 characters
  2. Base64-encode and submit

Expected Result: 401 response. Gate remains closed.

7.4 Scan Key Code Exceeds Maximum Length

Objective: Verify rejection when the decoded Scan Key Code exceeds 154 characters

Test Steps:

  1. Create a payload longer than 154 characters
  2. Base64-encode and submit

Expected Result: 401 response. Gate remains closed.

7.5 Scan Key Code with Expired Timestamp

Objective: Verify rejection when the Scan Key Code timestamp is older than the configured expiry window plus buffer

Test Steps:

  1. Generate a Scan Key Code with a timestamp older than authEvent.timestamp - expiry window - 15 second buffer
  2. Base64-encode and submit

Expected Result: 401 response. Gate remains closed.

7.6 Scan Key Code with Non-Alphanumeric Characters

Objective: Verify rejection when the decoded Scan Key Code contains non-alphanumeric characters

Test Steps:

  1. Create a payload containing special characters (e.g., @, #, spaces)
  2. Base64-encode and submit

Expected Result: 401 response. Gate remains closed.


8. Gate Behavior Validation

8.1 Gate Remains Closed on 400

Objective: Confirm the gate does not open when the API returns 400

Test Steps:

  1. Send a request with missing required fields
  2. Confirm 400 response
  3. Verify gate remains closed

Expected Result: Gate remains closed.

8.2 Gate Remains Closed on 401

Objective: Confirm the gate does not open when the API returns 401

Test Steps:

  1. Send a request with an invalid identity key
  2. Confirm 401 response
  3. Verify gate remains closed

Expected Result: Gate remains closed.

8.3 Gate Follows Default Decision on 500

Objective: Confirm the gate follows the store's default gate decision on 500

Test Steps:

  1. Simulate a 500 error
  2. Verify gate behavior matches the store's configured default (open or closed)

Expected Result: Gate follows default gate decision.

8.4 Gate Remains Closed During Retries

Objective: Confirm the gate does not open while Amazon is retrying a failed request

Test Steps:

  1. Simulate a transient failure that triggers retries
  2. Verify the gate remains closed until a definitive 200 or rejection is received

Expected Result: Gate remains closed until a final authorization decision is made.


9. Performance

9.1 Response Time Under 2 Seconds

Objective: Verify the Identity Connector responds within the 2-second SLA

Test Steps:

  1. Send 100 valid requests sequentially
  2. Measure response time for each
  3. Verify p99 response time is under 2 seconds

Expected Result: All responses return within 2 seconds.

9.2 Concurrent Load

Objective: Verify performance under peak concurrent scan volume

Test Steps:

  1. Send 50 concurrent valid requests
  2. Measure response times and success rates
  3. Verify no timeouts or dropped requests

Expected Result: All requests succeed within the 2-second SLA.


Test Data Requirements

Data Item Description
Valid shopper identity key Base64-encoded key mapped to a known SHOPPER
Valid associate identity key Base64-encoded key mapped to a known ASSOCIATE
Valid cash shopper identity key Base64-encoded key mapped to a known CASH_SHOPPER (cash-enabled store only)
Invalid identity key Base64-encoded key that does not map to any shopper
Expired identity key Base64-encoded Scan Key Code with an expired timestamp
Flagged shopper identity key Base64-encoded key mapped to a flagged account
Valid store IDs At least 2 store IDs assigned during onboarding
Invalid store ID A store ID that does not exist
Cash-enabled store ID A store ID that supports CASH_SHOPPER type

Test Execution Notes

  1. Base64 Encoding: All identityKey values must be Base64-encoded before submission. Decode before performing validation logic.
  2. UUID Format: Both requestId and authEvent.id must follow the pattern [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}
  3. Idempotency: Coordinate with your team to verify that repeated calls with the same authEvent.id do not create duplicate sessions.
  4. CASH_SHOPPER: Confirm with the Amazon team whether your store supports the CASH_SHOPPER visitor type before running test 1.3.
  5. Default Gate Decision: Confirm your store's default gate decision configuration before running test 8.3.
  6. Latency Buffer: When testing Scan Key Code timestamp validation, account for the recommended 15-second buffer for network delays.