Server side
Authentication
Your backend never talks to the shell directly. It talks to Shoppingate — the platform API — using a per-mini-app API key, and it receives outbound webhooks for every order state change.
Every server-to-server call is authenticated with a per-mini-app Vendor API Key plus the X-Mini-App-Id header. Get the key from the developer portal → your mini app → API keys. Rotate anytime; the previous key stays valid for 24 hours to give you a clean cutover.
# Every request carries these two headers
X-Vendor-Api-Key: sg_live_v2_<your-key>
X-Mini-App-Id: 42
Keep the key server-side. Never ship it inside the mini-app bundle or expose it in a page. If a key leaks, rotate it from the developer portal immediately — the old key stays valid for 24 hours so nothing breaks in the wild.
User authentication flow
The API key above authenticates your server to Shoppingate. To identify the user in front of the mini app, follow this three-step flow — the mini app mints a token via a host bridge, your backend verifies it against the platform, and from there you mint your own session token.
01
Mint a token in the mini app, forward it to your backend
Inside the mini app, call getUserToken on the host bridge. It returns a signed identity JWT for the signed-in Shoppingate user. Send that JWT to your backend the same way you send any other authenticated request — typically an Authorization: Bearer <token> header. Do not try to parse it in the mini app; treat it as an opaque credential.
02
Verify the token with the Identity API and register the profile
Your backend calls POST /s2s/v1/identity/verify with the same JWT (see the endpoint below). You always get back user_id, mini_app_id, and consent_status. When consent_status === "granted", the response also includes name, email, phone_number, and phone_code; otherwise those fields are null. Upsert your profile row keyed on user_id so the same user always resolves to the same account. Reject the token if mini_app_id does not match your X-Mini-App-Id. If consent is not granted, either proceed with a minimal registration (just user_id) or bounce the user back into the mini app to grant consent.
03
Mint your own session token and use it inside the mini app
Once the profile is registered, mint your own session token (whatever your backend already uses — a JWT, an opaque cookie, an OAuth access token) and return it to the mini app. From here on, every mini-app → your-backend call uses your token. Only re-run steps 1 & 2 when your token expires or the user relaunches the mini app fresh — the SG identity JWT is short-lived (~10 min by default) and is intended for handshake, not for every request.
What consent controls
POST /s2s/v1/identity/verify confirms the user's Shoppingate identity unconditionally — the user_id comes back on every successful verify. What consent gates is PII disclosure: name, email, phone_number, and phone_code are only returned when consent_status === "granted". In every other state (revoked, not_set) those fields are null and users-service is never even queried.
The user grants, revokes, or re-grants consent from inside the mini app — the SG super app renders a consent sheet the first time your mini app calls getUserToken, and the user can flip it anytime from their profile. Consent is re-checked at every verify call, so a revoke between token mint and token verify blocks disclosure immediately without you having to invalidate anything on your side.
Only ask for consent when you actually need the PII. If your mini-app registration flow can run on user_id alone, prefer that — an unnecessary consent prompt is friction the user will remember. When you do need name/phone/email, treat consent_status !== "granted" as a first-class UX state: keep the user inside the mini app and show a screen that explains what you'll do with the data before nudging them to the consent sheet.