Testing
Test scenarios
Run each scenario in the sandbox. Compare the result with the expected result, and check what your system recorded.
Authentication#
| Scenario | How to test | Expected result |
|---|---|---|
| No key | Send a request without Authorization. |
401 with AuthenticationRequired and a WWW-Authenticate: Bearer header. |
| Wrong environment | Use a live key where you expect sandbox data, or read a sandbox ID with a live key. | The IDs of one environment do not exist in the other. A read returns 404. |
| Malformed or revoked key | Change one character of the key. | 401 with AuthenticationRequired. |
| Missing scope | Use a key without payments:refund and request a refund. |
403 with InsufficientScope. The message names the scope. |
See Authentication.
Hosted checkout#
| Scenario | How to test | Expected result |
|---|---|---|
| Successful payment | Create a session, open its url, and pay with sandbox test payment details. |
The buyer returns to successUrl. You receive payment.succeeded, checkout.completed, and transaction.completed, in any order. Your system fulfils once. |
| Failed payment | Pay with sandbox test payment details that are refused. | You receive payment.failed. The session returns to open and the buyer can try again on the page. |
| Buyer cancels | Cancel on the hosted page. | The buyer returns to cancelUrl. You receive checkout.expired with status cancelled. |
| Session expiry | Create a session with expiresAt 30 minutes ahead, or call Expire a checkout session. |
You receive checkout.expired. The page no longer accepts payment. |
| Return without payment | Open your successUrl directly. |
Your system does not fulfil. |
Webhooks#
| Scenario | How to test | Expected result |
|---|---|---|
| Valid signature | Receive any sandbox event. | Your endpoint verifies Merxian-Signature and returns 2xx quickly. |
| Bad signature | Send a stored request body to your own endpoint with a changed signature. | Your endpoint refuses the request and does not process it. |
| Duplicate delivery | Send a stored request body to your own endpoint a second time. For a local test, sign it again with your sandbox secret and a new timestamp. | Your endpoint returns 2xx and does not process the event id a second time. |
| Events out of order | Send payment.succeeded before payment.processing to your own endpoint. |
The final state in your system is still paid. |
| Endpoint down | Stop your endpoint during a sandbox payment, then start it. | Merxian retries the delivery. Your system catches up. See Delivery and retries. |
Refunds#
| Scenario | How to test | Expected result |
|---|---|---|
| Full refund | Refund a succeeded payment without amount. |
202 with requested. Then refund.succeeded and transaction.refunded. |
| Partial refund | Refund part of the amount, for example 5000 (€50.00) of 14280. |
refund.succeeded and transaction.partially_refunded. |
| Over-refund | Refund more than the amount that is not yet refunded. | 422 with refundValidationFailed. |
| Refund of an unpaid payment | Refund a payment that did not succeed. | 422 with refundValidationFailed. |
Idempotency#
| Scenario | How to test | Expected result |
|---|---|---|
| Replay | Send the same create request twice with the same Idempotency-Key. |
The second response is the first result. Only one resource exists. |
| Conflict | Send a different body with a key that you used before. | 409 with idempotency_conflict, idempotencyConflict, or StaleIdempotencyKey, by endpoint. |
| Missing key | Send a create request without Idempotency-Key. |
400 with ValidationFailed. |
See Idempotency.
Lists and limits#
| Scenario | How to test | Expected result |
|---|---|---|
| Pagination | Create more transactions than limit, then list with limit=2. |
Each page has pagination.nextCursor until the last page. Your code reads every page once. |
| Rate limit | Handle a 429 response in your client. |
Your client waits for the seconds in Retry-After and retries. |
Do not load-test the sandbox to trigger a 429. Test the handling in your own code with a stubbed response.
Disputes#
The sandbox cannot simulate a dispute yet. Test your dispute.opened handler with a stored or hand-made request body against your own endpoint. See Disputes.