Skip to content

Test and live

Two environments inside one app. The credential's environment sets the intent's livemode; the data never mix.

1. What decides the environment

test live
Key (client id) gk_test_… (or the default mapp_test_…) gk_live_… (or the default mapp_…)
Intent livemode: false livemode: true
Money does not move — the amount decides the outcome a hold on the person's Gerege Wallet account → capture
Works from registration (even for a draft app) the app's approval only (before it, 401 invalid_client)
Who can pay the person who registered the app, its test users anyone (subject to the app's min_age / requires_verified)
Payout account, core banking not needed needed (409 payouts_not_configured, 503 payments_unavailable)
Webhook endpoints separate per environment (≤ 5), livemode: false separate per environment (≤ 5), livemode: true
Settlements (/settlements) empty / 404 ✓

A key sees only its own environment's intents and events: reading a live intent with a test key is 404. A test key never gets the registry's write scopes (terminals:write, sub_merchants:write, payout_links:write, webhooks:write).

2. Test amounts

The last two digits of the amount decide the outcome of confirm:

Amount Outcome
…01 (e.g. 3501) failed, failure_code: "test_declined"
…02 (e.g. 3502) canceled
anything else, automatic succeeded
anything else, manual requires_capture → your capture / cancel

Refunds succeed at once in test. Test users (≤ 50, active members of your organisation), the console's test intents, and webhook deliveries / resend / webhook.test: Developer sandbox.

3. One registry for both environments

The app, its terminals and sub-merchants are one registry for both environments — there is no separate «test terminal». So:

  • Writing to the registry (creating or editing terminals and sub-merchants, requesting payout links) takes a live key or the console; a test key only reads — 403 live_only. A leaked sandbox secret must not change a real machine's owner and send live money elsewhere. In the sandbox, register from the console.
  • A terminal has one open basket per environment: a test basket never blocks a live machine.
  • Intents, refunds, events and settlements are separate per environment.

4. The app's state and going live

Two separate states: review (draft → in_review → approved | rejected, suspended) and status (draft, active ⇄ maintenance, disabled).

draft ──submit──▶ in_review ──approve──▶ approved      (live keys work, people see it)
  ▲                   │
  └──── fix ◀──── rejected                approved ──suspend (operator)──▶ suspended (everything stops)
  • Submit (POST /dev/apps/{id}/submit): legal pages (privacy, terms, support — 200 when https), a live secret, a webhook URL (with payments), and for a mini app a checked manifest. Anything missing: 400 not_ready + details[]. During review the app is frozen (409 locked_for_review).
  • The operator checks the business (today the agreement and KYB documents by hand), approves it and sets the payout account.
  • Every state change sends an app.status_changed webhook.
  • suspended — nothing opens, every token is revoked, credentials are refused.

The self-service steps to live from the dashboard — the organisation's representative signing the agreement with eID, the business profile (KYB), a go-live checklist, limits (tiers), live keys from the new API (behind a fresh sign-in; today through POST /dev/apps/{id}/credentials) — are «удахгүй». An individual without a legal entity uses the whole of test mode (a sandbox organisation — «удахгүй»); live needs an organisation.