Getting Started
Testing & Sandbox

Testing

The test environment is the same as live — same endpoints, same field contract, same error envelope, same webhook mechanism. What differs is that no real money moves and the bank side is simulated.

There is one base URL; your key decides the environment.

https://api-gateway.lunixi.com/api/v1

The only thing that changes in your code is the key you use. There is no test-specific base URL, no separate client, no different call shape — code that works live works in test.

Environments are separated by key

For testing you generate a separate Ed25519 key pair and register the public key against the TEST environment. Its key id looks like mk_test_sk_…, and tokens minted with it come back prefixed at_test_.

EnvironmentKey idToken prefix
Testmk_test_sk_…at_test_…
Livemk_live_sk_…at_live_…
⚠️

Keys do not cross environments. A token minted with your test key cannot reach live data — the environment is resolved from the key you signed the token request with. That is deliberate protection: it stops you triggering real money movement by accident.

Publishable keys carry the environment too: mk_test_pk_… / mk_live_pk_…. A Web SDK talks to whichever environment its key belongs to. → Web SDK Overview

TestBank — the built-in test bank

You do not need a real bank to test payments. TestBank runs inside the platform and makes no outbound HTTP calls at all; every response is synthesised in-process.

The important part: TestBank replies in the classic PSP response shape. So the handler → parse → normalise → decline classification chain flows down exactly the same path as a real bank. Your test exercises the code that will run in production.

Scenarios

You pick the scenario on the 3DS simulator screen; the finalize result is produced from it.

ScenarioOutcomeDecline code
SUCCESSApproved—
AUTH_FAILED3D authentication failedTB_3D_AUTH_FAILED
INSUFFICIENT_FUNDSInsufficient funds51
DO_NOT_HONORBank declined05
EXPIRED_CARDCard expired54
STOLEN_CARDLost or stolen card43
LIMIT_EXCEEDEDLimit exceeded61
TIMEOUTBank does not respond—

In every scenario except AUTH_FAILED, 3D authentication succeeds (mdStatus=1) and the failure comes back at the charge stage — the same ordering as real life.

To exercise the meal card flow, TestMealCard works on the same pattern.

No randomness

🚫

Randomness is forbidden in TestBank — the same input always produces the same outcome. That keeps your tests from being flaky. If you see "sometimes passes, sometimes fails", TestBank is not the cause.

The wallet side

Wallet test simulators are registered as integrations — they run down the same path as a real bank integration rather than through a separate code branch.

⚠️

In an inbound transfer simulation, omitting senderName means the money is not credited — the transaction drops into third-party review. That is not a bug but a real money-safety gate, and it applies in the test environment too.

The fraud side

Fraud decisions in the test environment are produced by the flow you published, exactly as in live. There are no magic test values.

🚫

Publish no rules in the test environment and you will not get allow. An unconfigured merchant gets the policy default (typically review) with code fraud.decision.unconfigured — the same behaviour as live. The test environment does not loosen that gate. → Flows and Resolution

To exercise history-based rules you must feed events in the test environment as well; without POST /api/v1/fraud/events/transactions, velocity rules never fire.

Testing webhooks

Test environment webhooks use the same signature scheme, the same retry policy and the same x-lunixi-* headers as live. For local development your endpoint has to be reachable from the public internet — use a tunnel (ngrok or similar).

⚠️

The delivery service rejects private network addresses: localhost, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16. That rule applies in the test environment too. → Webhooks

Moving to live

  1. Generate and register a new key pair for the live environment
  2. Configure your application to sign with the live key — the base URL does not change
  3. Publish your fraud flow in live scope — a publication in test does not carry over
  4. Create your webhook endpoint separately for the live environment
  5. Watch it in shadow mode for a while, then start enforcing decisions

→ Integration Guide

Related