RideKit
Docs/Using the product/Why your admin only shows your country

Why your admin only shows your country

One codebase ships to buyers in 37 countries, so it carries every payment rail and every tax authority those countries use. Shown all at once, that is 22 credential groups and 64 input fields — of which, in India, ten and twenty-nine are reachable. The rest asked an operator in Mumbai for a Safaricom paybill, a Brazilian CNPJ and a Saudi ZATCA token, and looked for all the world like setup that had been left undone.

So the admin scopes itself to the country the installation runs in.

How your country is worked out

At first boot, before anyone has signed in:

  1. DEFAULT_COUNTRY in the environment, if you set one. An explicit decision always wins.
  2. The server's timezone. Asia/Kolkata means India. A box is almost always configured for the market it serves, and this needs no network call — it works on a firewalled or air-gapped network.
  3. Nothing conclusive → nothing changes. The install keeps the country it has rather than guessing.

Then it stops. Detection only ever runs while the install is not yet onboarded; the moment you confirm a country in Settings, your choice is final and detection becomes a no-op. It never silently overwrites a decision you made.

This is not geo-IP, and that is deliberate. Geo-IP would add a third-party dependency to your boot sequence, be wrong for a VPS you rent in another country, and leak your server's address. It also would not survive the obvious case: you, on a VPN, opening your own admin. Because the country comes from the server and is decided once, browsing from anywhere in the world changes nothing.

What gets scoped

Screen Behaviour
Providers → Payment gateways Cards for the rails your market uses. Others are listed by name under "Also supported in other countries".
Providers → Credentials Fields for the rails your market uses, plus your tax authority. Everything else sits behind Show.
Markets Opens on your own market and any you have switched on. A toggle shows all 37.
Settings → Country picker Not scoped, on purpose — this is where you choose a country.
Language switcher Already follows your market's own language list, served from /branding.

Nothing is deleted, and nothing is locked. Every screen keeps a way through to the full set, because launching a second country is a thing operators do.

Two rules that override the scoping

A provider holding credentials is always shown. If M-Pesa has keys stored, M-Pesa appears on an Indian install, tagged Configured. A stored secret you cannot see is one you cannot rotate or clear, which is worse than clutter.

A failure shows everything. If the scope request fails, every screen renders its full, unscoped self — exactly as it did before scoping existed. A side request that times out must never make a credential field disappear.

Multi-country gateways stay put

Stripe is listed by all 37 markets, so it is in scope everywhere with no special case. What disappears from a given install are the rails that are genuinely national: M-Pesa, Moyasar, Tap, Xendit, PayMongo, Mercado Pago, Asaas. They come back the moment your country is one they serve.

For developers

The relevance is derived, never listed — there is no country→provider table to maintain:

market.config.payment.gateways   (falls back to the shipped preset)
    → GATEWAY_TO_PROVIDER        (payments/topup-rail.resolver.ts)
    → the credential group
market.config.tax.engine         → the e-invoicing group, if that engine files
                                   with anyone ('vat' and 'none' do not)

Adding a country to backend/src/markets/country-presets.ts scopes it correctly with no second edit. backend/src/settings/country-scope.spec.ts enforces both directions: that a country is not shown another's rails, and that no credential group becomes unreachable from every market — a field no buyer can reach is a worse failure than the clutter this replaced. It also re-derives the two rails whose keys live under another name (gcash reads PayMongo's, oxxo reads your Stripe account's) from the provider sources, so that mapping cannot drift silently.

The endpoint is GET /settings/scope.

source: docs/admin-guide/country-scoping.md (ships identically in the product zip)