Skip to content

Sandbox — test mode

After this page you will know how to test your integration without moving real money, what works today and what does not yet. Time: 5 minutes. You need: an app registered in the developer console and its test key.

Test keys

The key decides the environment: an intent created with a test key is livemode: false, and that key sees only test objects. Test and live data never mix — lists, GET and the webhook's livemode are all separate.

Key Client id Secret How to get it
API key (test) gk_test_… gks_test_… console → Keys → "New key", a name, a preset or scopes (POST /dev/apps/{id}/keys)
Default key (test) mapp_test_… gma_cs_… POST /dev/apps/{id}/credentials — every scope of its environment
Live gk_live_… / mapp_… gks_live_… / gma_cs_… from the console's «Keys» (or POST /dev/apps/{id}/credentials): miniapp.keys.live and a sign-in within the last ten minutes (on 403 fresh_sign_in_required sign in again and repeat); works only once the app is approved; never in a sandbox organisation

A test key works at once, even while the app is a draft and not approved. The secret is shown once.

export GEREGE_CLIENT_ID=gk_test_xxxxxxxxxxxxxxxxxxxx
export GEREGE_CLIENT_SECRET=gks_test_…

curl -s "https://geregeapp.mn/api/v1/miniapp/payment-intents?limit=5" \
  -u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET"

What is different in test mode

  • No money moves. Core banking is not called and no hold is placed; no payout account is needed.
  • The last two digits of the amount decide the outcome — Test amounts.
  • A capture is succeeded at once, and so is a refund (no ledger answer to wait for).
  • Time limits (expires_in, capture_within) work exactly as in live — an intent past its time becomes expired.
  • Webhooks arrive with the same types and shapes as in live, livemode: false. Endpoints are per environment — add a test endpoint (a tunnel, say) without touching live (Local webhooks). The app's original webhook URL (endpoint №1) serves both environments — there, tell them apart by livemode.
  • GET /settlements with a test key is always empty — settlements are for live money only.
  • A test key never gets a live-only scope (terminals:write, sub_merchants:write, payout_links:write, webhooks:write): it reads terminals, sub-merchants and payout links, but writing them is 403 live_only. The registry is one for both environments (a leaked sandbox secret must not change real machines), so register them with a live key or in the console. A test key may print the sticker PDF (POST /terminals/print-sheet).
  • One terminal may have a test basket and a live basket open at the same time (one open unclaimed intent per terminal per environment). Only the app's owner and its test users are offered the test basket; everybody else, and the public /pay/t/<code> page, see only the live one.

What can be tested end to end today

Flow Today Notes
Claimless intents (qr, redirect, terminal): create, replay, list, cancel, unclaim, capture, refund ✓ with the test key; pay_url comes in the answer
Paying a claimless intent with a phone — Gerege App's QR button, "Scan NFC", a /pay/… link from the camera (Universal Link), touching the sticker ✓ Gerege App iOS build 122+ (TestFlight); a test user or the app's owner; Face ID on a test intent moves no money
The https://geregeapp.mn/pay/<token> QR page and the /pay/t/<code> terminal page on a computer ✓ the terminal page shows only the live basket
Playing the person without a phone (claim, pay, cancel, expire, touch the sticker) ✓ Testing without a phone
Mini app intents (presentment: "app") — the console's test intents, or a test user opening the app in Gerege App and paying ✓ a draft app shows in its test users' launcher
Reading terminals, sub-merchants and payout links; the sticker PDF ✓ writing is a live key's or the console's
Webhook endpoints (≤ 5 per environment), deliveries, "send again", test sends; the events API ✓ Local webhooks, Events API
App Clip coming soon App Clip
A sandbox organisation for people without a legal entity ✓ «Sandbox organisations» below

Testing with a phone

Only the app's owner and its test users can claim a test claimless intent; to anybody else it does not exist (404). So whoever tests with a phone must be a member of your organisation added as a test user. Make the QR from pay_url, or use your terminal's sticker (Testing NFC).

A developer without a company opens one sandbox organisation from their profile (Profile → Organisations → «Open a sandbox») — «Mini apps and payments» arrives installed in it. It is an ordinary organisation: the same console, team and permissions, and test mode in full (test keys, endpoints, simulation, terminals, sub-merchants, test intents).

  • Test users are you (the app's owner) and the members you invite to the sandbox (Test users).
  • An app's slug begins with sbx- (sbx-myshop; ^sbx-[a-z0-9-]{3,27}$, otherwise 400 sandbox_slug) — real names belong to real organisations, and no organisation that is not a sandbox may use sbx-.
  • Nothing live: a live key, a live secret, review, an agreement signature, a payout link or the app's payout is 409 sandbox_only.
  • To go live, open your organisation (a legal entity) and register the app there anew — nothing moves over.

From test to live

Going live changes only the key: swap the client id/secret for a live key and set up the live environment's webhook endpoint (with its own secret). Code, routes and shapes are the same. Test data does not move to live; terminals and sub-merchants are already one registry, so nothing is registered again. Before going live, go through the Go-live checklist. The concept: Test and live.