Skip to content

Go-live checklist

A printable list to walk through once as a team, ticking it off, before taking live payments. Time: 1–2 hours (after running every flow once in test mode). You need: an integration working in test mode (Sandbox) and access to the console.

Technical

Webhooks

  • The live environment's webhook endpoint is https://, public, with no redirect and its own secret (separate from test); the endpoint's «Send test» (…/webhook-endpoints/{eid}/test) says ok: true. Its event filter (event_types) includes every type your handler expects.
  • The signature is checked over the raw body, against every v1, within ±300 seconds (Verifying signatures).
  • Duplicates are dropped by Gerege-Event-Id; an event arriving twice never hands goods over twice.
  • 2xx is answered within 10 seconds (slow work is queued).
  • Ordering is not guaranteed: an old event arriving late does not move a state backwards — re-read with GET and decide (Idempotent handler).
  • Unknown types are answered 2xx and ignored.
  • It works even when a webhook never comes: a regular reconcile — the Events API (GET /events, 30 days) or GET /payment-intents?status=… / ?reference=… — checks every pending order (Reconciliation). An endpoint failing for 5 days becomes auto_disabled — it is agreed who receives the admins' notifications.

Payments

  • The amount and description come from your server; description ≤ 80, a short order summary (Security checklist).
  • One order = one intent = one Idempotency-Key; network errors, 429 and 5xx are retried with the same key.
  • After a redirect, return_url?pi= is not trusted: the server matches status, amount and reference with GET /payment-intents/{id}.
  • Every status is handled: requires_confirmation, processing (a 202 answer — wait and read again), requires_capture, succeeded, partially_refunded, refunded, canceled, expired, failed (payable again — do not close the order) (Payment intent).
  • The right behaviour for error codes: in_progress (wait, read again), idempotency_conflict, terminal_busy (cancel the open intent, then retry), expired, not_capturable, payouts_not_configured, payments_unavailable (Error codes).
  • Manual capture: capture when dispensed, cancel when not, within capture_within; partly dispensed means a full capture plus a refund.
  • Refunds: their own Idempotency-Key; a 202 / pending is finished by refund.succeeded / refund.failed; the 90-day limit (Refunds).

Credentials

  • The live secret is only on servers, in a secret manager / environment variables; switching from test to live changes only the credentials — code and URLs stay the same.
  • One named key per server with the fewest scopes; test keys no longer needed are revoked.
  • The team knows the rotation procedure: API keys roll with an overlap, the default key (POST …/credentials — today the only way to a live secret) is replaced at once, with no overlap (Security checklist).

Business and registration

  • The organisation and the app (kind: merchant or a mini app) are registered in the console.
  • Submission requirements are met: the privacy policy (privacy_url), terms of service (terms_url) and support (support_url) links — when https://, each answers 200 without a redirect; the app's webhook URL (endpoint №1, POST …/webhook) is set; a live secret issued with the default key. For a mini app, a checked manifest (512×512 PNG icon) (Review requirements).
  • For a merchant, the return hosts (return_hosts, ≤ 5, exact hosts) are registered before review (changing them after approval means another review).
  • The app is approved (before that, the live credential is 401 invalid_client).
  • The payout account that receives the takings is set — by the admin to the organisation's own account in the console, or by the operator (otherwise a live intent is 409 payouts_not_configured) (Payout accounts).
  • Each sub-merchant's payout link is approved by its holder in Gerege App.
  • Fees and the settlement schedule are agreed with the operator (Fees).
  • The organisation's representative has signed the merchant agreement with eID (console → Agreements; the miniapp.agreements.sign permission, a representative listed in eID). Submission and live keys do not require it yet, but the operator checks.
  • The business profile (KYB) is filled in, proved and submitted (console → Business profile, 1.14.0): trade name, logo (512×512 PNG), MCC, website, support/technical/finance e-mail and the support phone (each proved with a code), owners of 25 % or more, the registration certificate (and a licence when the MCC needs one). The legal name and register come from what was registered when the organisation was opened with eID. Only an admin submits, after signing in again; the operator approves.
  • The go-live checklist is green on the server: GET /api/v1/miniapp/dev/account (organisation) and GET /api/v1/miniapp/dev/apps/{id}/go-live (app) — every step done.
  • You know your limits: a new merchant (new) ≤ 1,000,000₮ per payment and ≤ 10,000,000₮ a day; standard 10M / 200M; ask for more in the console. Where the installation enforces going live (MINIAPP_GO_LIVE=on), a live intent without the agreement, an approved profile or within the limits is a 409 (agreement_required, business_profile_required, business_limit_exceeded …).

User experience

  • A clear «Pay with Gerege App» button, with a loading state when pressed.
  • QR / terminal: when payment_intent.claimed arrives, show «Confirm on your phone»; show how long is left (expires_at).
  • A cancel button (cancel), and clear Mongolian messages with a retry for expiry (expired) and declines (failed).
  • On success, show a receipt / the order number (reference); the refund policy is visible before paying.
  • Every path of a redirect checkout has been walked through on both a computer and a phone.

The first day live

  • One real payment of a small amount (say 100₮) → webhook → fulfilment → refund.
  • No failed events in the console's «Deliveries» (live endpoint); the dashboard's payment list matches your orders.
  • The team knows how to reach Support.