PAN is recognized but is no longer valid returns panNoLongerValid
PAN is recognized but the card account has been closed returns cardAccountClosed
PAN is not eligible returns cardIneligible decline
PAN invalid format returns invalidFieldValue error
Expiration date mismatch returns incorrectExpiration decline
Red-path PAN* returns riskDeclined decline
Externally-managed terms of service not accepted by user returns
tosNotAccepted decline
Externally-managed terms of service acceptance timestamp out of date returns
tosAcceptanceOutdated decline
Idempotency - Same requestId + same PAN returns success
Idempotency - Same requestId + different PAN returns idempotencyViolation
Different requestId + same PAN returns success
(2nd enrollment)
This can happen if the same PAN is registered by multiple users (different
hashedEmailAddress) or a single user (same hashedEmailAddress) with
multiple payment profiles
for example if the send OTP limit is 3, OTP timeout is 10 min, and the
challenge option timeout is 15 min, the user could timeout the first OTP at
10 min but then timeout the whole challenge at 15 min
Red path* returns riskDeclined
Idempotency - Same requestId + same contents returns same response
Too many** sendOtps returns sendLimitExceeded decline
enrollmentRequestId has been unenrolled returns challengeOptionExpired
for example, if (1) retrieveVirtualCardNumber returns challengeRequired,
(2) the card is unenrolled in virtual cards, and then (3) sendOtp is called.
challengeOptionId not found returns invalidIdentifier error
Idempotency - Same requestId + same contents returns same response
Does not cause sendLimitExceeded for multiple retries (send count only
incremented once)
Does not resend SMS OTP if it was already sent
Does not change expiration result (example w/ 30 min expiration timer: first
attempt at 29 minutes, retry (same request ID) at 31 minutes. It should return
the same result from the first attempt, not challengeOptionExpired)
Idempotency - same requestId + different contents returns idempotencyViolation
enrollmentRequestId not found returns invalidIdentifier error
GetTransactions
getTransactions without transactionListContinuationToken returns all
transactions for the maximum period prior to the request
getTransactions with transactionListContinuationToken returns all
transactions added or updated since the request represented by the token
transactionListContinuationToken not found returns
unknownTransactionListContinuationToken (not an ErrorResponse with
invalidIdentifier like other APIs)
Idempotency - Same requestId + same contents returns same transaction list
and transactionListContinuationToken in response
Idempotency - Same requestId + different contents returns idempotencyViolation
enrollmentRequestId not found returns unknownEnrollment (not an
ErrorResponse with invalidIdentifier like other APIs)
Unenroll
Happy Path
Idempotency - enrollmentRequestId that has already been unenrolled returns success
Inbound tests
Inbound tests refer to flow direction Integrator -> Google.
TransactionEventNotification
Happy Path
All rights reserved. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2024-10-16 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2024-10-16 UTC."],[[["\u003cp\u003eThe Google Pay Virtual Cards API requires testing after implementation, with Google providing test cases to assist in this process.\u003c/p\u003e\n"],["\u003cp\u003eTest cases are categorized into outbound (Google to Integrator) and inbound (Integrator to Google) scenarios for different API endpoints.\u003c/p\u003e\n"],["\u003cp\u003eOutbound tests cover various scenarios, including request validation, successful and failed enrollment attempts, card retrieval with challenge flows, transaction retrieval, and unenrollment.\u003c/p\u003e\n"],["\u003cp\u003eInbound tests focus on the \u003ccode\u003eTransactionEventNotification\u003c/code\u003e endpoint to confirm successful transaction event communication.\u003c/p\u003e\n"],["\u003cp\u003eIntegrators can configure sandbox environments to simulate specific card enrollment and retrieval behaviors, including risk declines and challenge requirements.\u003c/p\u003e\n"]]],["After implementing Virtual Cards APIs, testing is crucial. Outbound tests (Google to Integrator) validate various scenarios: common errors like invalid encryption or timestamps, and specific flows for Echo, Enroll, RetrieveVirtualCardNumber, SendOTP, GetTransactions, and Unenroll. These include happy paths, declines due to PAN issues, risk assessments, idempotency, and challenge handling. Inbound tests (Integrator to Google) ensure TransactionEventNotification functions correctly. Sandbox PANs are used for testing different behaviors. Limits and expiration times for challenges are integrator-defined.\n"],null,["# Testing\n\nOnce the\n[Virtual Cards APIs](/pay/virtual-cards-v1/reference/vcn-sequence-diagrams)\nhave been implemented, it's time to test them. Google provides\n[test cases](/pay/virtual-cards-v1/guides/testing-and-launch/testing#test_cases)\nthat may aid you in this process.\n\nTest cases\n----------\n\nThis section outlines the test cases expected to be executed to validate your\nVirtual Cards APIs implementation.\n\n### Outbound tests\n\nOutbound tests refer to flow direction **Google -\\\u003e Integrator**.\n\n#### Common (applies to all outbound endpoints)\n\n1. Invalid encryption returns `invalidPayloadEncryption`\n2. Invalid signature returns `invalidPayloadSignature`\n3. Invalid JSON returns `invalidDecryptedRequest`\n4. Timestamp not within +/- 60 seconds returns `requestTimestampOutOfRange` (this requirement helps protect against replay attacks)\n5. RequestId missing returns `missingRequiredField`\n6. Invalid [PIAID (paymentIntegratorAccountId)](/pay/virtual-cards-v1/reference/glossary#payment_integrator_account_id) returns `invalidIdentifier`\n\n#### Echo\n\n1. Happy Path (clientMessage is echoed in response)\n\n#### Enroll\n\n1. Happy Path\n2. PAN is not found returns `unknownPan` decline\n3. PAN is recognized but is no longer valid returns `panNoLongerValid`\n4. PAN is recognized but the card account has been closed returns `cardAccountClosed`\n5. PAN is not eligible returns `cardIneligible` decline\n6. PAN invalid format returns `invalidFieldValue` error\n7. Expiration date mismatch returns `incorrectExpiration` decline\n8. Red-path PAN\\* returns `riskDeclined` decline\n9. Externally-managed terms of service not accepted by user returns `tosNotAccepted` decline\n10. Externally-managed terms of service acceptance timestamp out of date returns `tosAcceptanceOutdated` decline\n11. Idempotency - Same `requestId` + same PAN returns `success`\n12. Idempotency - Same `requestId` + different PAN returns `idempotencyViolation`\n13. Different `requestId` + same PAN returns `success` (2nd enrollment)\n - This can happen if the same PAN is registered by multiple users (different `hashedEmailAddress`) or a single user (same `hashedEmailAddress`) with [multiple payment profiles](https://support.google.com/googlepay/answer/7644003?visit_id=638253754129670000-3896145703&rd=2#multiple-profiles)\n\n#### RetrieveVirtualCardNumber\n\n1. Green path\\* returns success\n2. Yellow path\\* returns `challengeRequired` decline\n3. Yellow path\\* (including valid challenge result) returns success\n4. Yellow path\\* (including INVALID challenge result) returns `challengeResultInvalid` decline\n5. Yellow path\\* (too many\\*\\* attempts at challenge result) returns `challengeResultVerificationLimitExceeded` decline\n6. Yellow path\\* (including expired\\*\\* OTP challenge result) returns `challengeResultExpired` decline\n7. Yellow path\\* (including expired\\*\\* challenge option) returns `challengeResultExpired` decline\n - for example if the send OTP limit is 3, OTP timeout is 10 min, and the challenge option timeout is 15 min, the user could timeout the first OTP at 10 min but then timeout the whole challenge at 15 min\n8. Red path\\* returns `riskDeclined`\n9. Idempotency - Same `requestId` + same contents returns same response\n - Green path returns `success`\n - Yellow path returns `challengeRequired` decline\n - Yellow path (including valid challenge result) returns `success`\n10. Idempotency - Same `requestId` + different contents returns `idempotencyViolation`\n11. `enrollmentRequestId` not found returns `invalidIdentifier` error\n12. `enrollmentRequestId` that has been unenrolled returns `invalidIdentifier` error\n\n#### SendOTP\n\n1. Happy Path\n2. Expired\\*\\* challenge option returns `challengeOptionExpired` decline\n3. Too many\\*\\* sendOtps returns `sendLimitExceeded` decline\n4. `enrollmentRequestId` has been unenrolled returns `challengeOptionExpired`\n - for example, if (1) `retrieveVirtualCardNumber` returns `challengeRequired`, (2) the card is unenrolled in virtual cards, and then (3) `sendOtp` is called.\n5. `challengeOptionId` not found returns `invalidIdentifier` error\n6. Idempotency - Same `requestId` + same contents returns same response\n - Does not cause `sendLimitExceeded` for multiple retries (send count only incremented once)\n - Does not resend SMS OTP if it was already sent\n - Does not change expiration result (example w/ 30 min expiration timer: first attempt at 29 minutes, retry (same request ID) at 31 minutes. It should return the same result from the first attempt, not `challengeOptionExpired`)\n7. Idempotency - same `requestId` + different contents returns `idempotencyViolation`\n8. `enrollmentRequestId` not found returns `invalidIdentifier` error\n\n#### GetTransactions\n\n1. `getTransactions` without `transactionListContinuationToken` returns all transactions for the maximum period prior to the request\n2. `getTransactions` with `transactionListContinuationToken` returns all transactions added or updated since the request represented by the token\n3. `transactionListContinuationToken` not found returns `unknownTransactionListContinuationToken` (not an `ErrorResponse` with `invalidIdentifier` like other APIs)\n4. Idempotency - Same `requestId` + same contents returns same transaction list and `transactionListContinuationToken` in response\n5. Idempotency - Same `requestId` + different contents returns `idempotencyViolation`\n6. `enrollmentRequestId` not found returns `unknownEnrollment` (not an `ErrorResponse` with `invalidIdentifier` like other APIs)\n\n#### Unenroll\n\n1. Happy Path\n2. Idempotency - `enrollmentRequestId` that has already been unenrolled returns success\n\n| **Note:** \\* Sandbox PANs can be mapped to certain **Enroll** and **Retrieve** behaviors by the Integrator: **Enroll** : green (always success), red (always risk decline), card ineligible. There is no yellow path. **Retrieve**: green (always success), yellow (always challenge), red (always risk decline). For yellow path, IDV options can be configured, for instance SMS OTP only, or SMS OTP + CVV2.\n| **Note:** \\*\\* Challenge retry or verification limit, send OTP limit, OTP expiration time, and challenge option expiration time are defined by the Integrator.\n\n### Inbound tests\n\nInbound tests refer to flow direction **Integrator -\\\u003e Google**.\n\n#### TransactionEventNotification\n\n1. Happy Path"]]