Manifest — /.well-known/gerege-miniapp.json¶
Every mini app MUST publish a manifest on its own origin:
https://<origin>/.well-known/gerege-miniapp.json ← tried first
https://<origin>/.well-known/openpay-miniapp.json ← the OMAS name, if the first is absent
Content-Type: application/json, ≤ 64 KB, no redirects (the platform does not follow redirects). The platform
connects only to public IP addresses (checked after DNS) — a manifest hosted on an internal network cannot be read.
http://localhost is allowed only on installations that are not production. If manifest_url is set explicitly in
the developer console, only that address is read (it must end in one of these two paths and have the same origin as
entry).
The manifest is proof of origin ownership: only someone who can publish the verification token issued at
registration on that origin owns that origin. JSON Schema: schemas/manifest.schema.json.
Example¶
{
"omas_version": "1.0",
"slug": "esim",
"client_id": "mapp_7Qk2c9Xv0bR1aB3dE5fG7hJ9",
"version": "1.0.0",
"name": { "mn": "Аяллын eSIM", "en": "Travel eSIM" },
"subtitle": { "mn": "200+ улсад дата" },
"category": "travel",
"developer": { "name": "Жишээ ХХК", "email": "support@example.mn", "url": "https://example.mn" },
"entry": "https://esim.example.mn/app",
"origins": ["https://esim.example.mn"],
"icons": [{ "src": "https://esim.example.mn/icon-512.png", "size": 512 }],
"accent_color": "#3B82F6",
"scopes": ["profile.basic", "payments"],
"bridge": { "min_version": 1, "methods": ["getContext", "getLaunchCode", "requestPayment", "openExternal", "copy", "share", "haptic", "setTitle", "close"] },
"external_urls": ["https://esimsetup.apple.com/"],
"channels": ["ios", "android"],
"webhook_url": "https://esim.example.mn/webhooks/gerege",
"legal": { "privacy_url": "https://example.mn/privacy", "terms_url": "https://example.mn/terms", "support_url": "https://example.mn/help" },
"verification": "omas-verify=3f9c1e7a2b4d6f80a1c3e5f7"
}
Fields¶
| Field | Required | Rule |
|---|---|---|
omas_version |
✓ | "1.0" |
slug |
✓ | ^[a-z0-9-]{2,32}$, matches the registry, never changes |
client_id |
✓ | mapp_… or mapp_test_… — the app's live or test id |
version |
✓ | semver (1.2.3, 1.2.3-beta.1) — kept in the review history |
name.mn |
✓ | 1–24 characters; name.en optional |
subtitle.mn |
≤ 40 characters | |
category |
✓ | travel · shopping · finance · games · services · food · transport · utilities |
developer |
✓ | name (1–80), email, url (https, optional) |
entry |
✓ | https, within one of origins, exactly equal to the registry's entry_url. The host appends ?launch=<code>&path=<path> |
origins |
✓ | 1–3 origins (https://host[:port], no path). The origin the manifest was fetched from and every origin in the registry are listed here |
icons |
✓ | ≥ 1; size ∈ 128/256/512/1024; 512 required. PNG, opaque, no rounded corners |
accent_color |
✓ | #RRGGBB |
scopes |
✓ | profile.basic required. Every scope in the registry is declared here (auth.md §4) |
bridge.min_version |
✓ | ≥ 1 |
bridge.methods |
✓ | Names from bridge.md §3. Applied to the registry when the check passes |
external_urls |
≤ 20 https prefixes — opened with openExternal. Applied to the registry by the check |
|
requires_verified |
boolean. When true, a person not verified with eID cannot open the app (403 verification_required) — auth.md §1.1 |
|
min_age |
13–21 or null. Under age → 403 age_restricted; not verified → 403 verification_required |
|
channels |
✓ | ios, android, web (android added over OMAS). The host that works today is iOS |
webhook_url |
https. REQUIRED with the payments scope. The URL and secret are set in the console (webhooks.md) |
|
legal.* |
✓ | privacy_url, terms_url, support_url — https, in Mongolian |
verification |
✓ | The omas-verify=… issued at registration |
An unknown field → an error (Үл мэдэгдэх талбар, "unknown field"). Every error comes with a JSON-pointer path
(/icons/0/size).
Cross-checking with the registry¶
«Manifest шалгах» ("Check manifest", POST /api/v1/miniapp/dev/apps/{id}/manifest/check), beyond the schema:
slug,client_id,verificationandentrymatch the registry;entryand the origin the manifest was fetched from are withinorigins; every registry origin and scope is in the manifest;- the 512 icon is fetched and checked: PNG, exactly 512×512;
legal.privacy_url,terms_urlandsupport_urleach answer200(redirects are not followed — a redirect is an error);- an approved app may narrow
bridge.methodsandexternal_urlsbut not widen them — that needs a new review; it may tightenrequires_verified/min_agebut not loosen them.
The icon and the legal pages are fetched with the same SSRF-guarded client as the manifest (public addresses only).
Response: {ok, fetched_from, errors: [{path, message}], manifest}. On success manifest_checked_at,
manifest_version, the bridge methods, external links, requires_verified and min_age are written to the
registry. The host works from the registry — it does not fetch the manifest at runtime.