Deep Link Auth
Overview
When a player opens the webshop directly in a browser (not from inside the game), they can click Link to game. The browser opens the game app via a deep link, the game silently authorizes the player, then redirects the browser back to the webshop — where the player lands authenticated. The flow uses OAuth 2.0 Authorization Code + PKCE to protect against interception.
Before this flow works, configure the Game Authorize URL in Terminal3 Merchant Area → Store Settings. This is the deep link or Universal Link endpoint in your game app that handles the incoming auth request (e.g. https://yourgame.com/oauth/authorize or yourgame://authorize). Once set, the webshop automatically shows a Link to game button to players.
Flow
- Player clicks Link to game in the webshop browser.
- Webshop generates PKCE parameters and opens the game app via the configured Game Authorize URL with query params:
redirect_uri, state, code_challenge, code_challenge_method=S256, store_id.
- OS opens the game app. The player is already authenticated in the game — no login prompt appears.
- Game app reads the deep link params, generates a one-time
auth_code, and registers it with Terminal3 by calling POST /stores/{store_id}/auth/auth-code.
- Game app redirects the browser back to the
redirect_uri with ?code={auth_code}&state={state}.
- The webshop handles the rest — it verifies the code and the player lands authenticated.
Endpoint: Register Auth Code
POST /stores/{store_id}/auth/auth-code
Called by the game app after receiving the deep link. Registers a one-time auth code with Terminal3. Requires API key authentication.
Path Parameters
| Name |
Description |
store_id required string |
Your store identifier. |
| Name |
Description |
X-API-Key required |
Your integration API key. |
Content-Type required |
Must be set to application/json |
Request Body
| Name |
Description |
auth_code required string |
A cryptographically random one-time code generated by the game app. Any format is acceptable (UUID v4, hex, base64url). Max length: 255 characters. Valid for 5 minutes, single use only. |
redirect_uri required string |
The webshop callback URL received in the deep link params. Must be a Terminal3 domain. Pass through unchanged. |
client_reference_id required string |
The player’s unique identifier in your system. Max length: 255 characters. |
code_challenge required string |
The PKCE code challenge received in the deep link params. Pass through unchanged. |
state required string |
The state parameter received in the deep link params. Pass through unchanged. |
first_name string |
Optional. Player’s first name. Max length: 255 characters. |
last_name string |
Optional. Player’s last name. Max length: 255 characters. |
language string |
Optional. ISO 639-1 language code for the player’s preferred language. Example: en, de, ja Max length: 10 characters. |
currency string |
Optional. ISO 4217 currency code for the player’s preferred currency. Example: USD, EUR Max length: 3 characters. |
country string |
Optional. ISO 3166-1 alpha-2 country code for the player’s country. Example: US, DE Max length: 2 characters. |
timezone string |
Optional. IANA timezone identifier for the player’s timezone. Example: America/New_York, Europe/London Max length: 64 characters. |
Response
200 OK
{
"data": { "status": "ok" }
}
Game App Integration Guide
Step 1: Configure Game Authorize URL
In Terminal3 Merchant Area → Store Settings, set your Game Authorize URL:
- Recommended (Universal Link / App Link):
https://yourgame.com/oauth/authorize
- Alternative (custom URL scheme, simpler but less secure):
yourgame://authorize
Step 2: Register the deep link handler
Universal Links (iOS) — host at https://yourgame.com/.well-known/apple-app-site-association:
{
"applinks": {
"apps": [],
"details": [{"appID": "TEAMID.com.yourgame.app", "paths": ["/oauth/authorize"]}]
}
}
App Links (Android) — host at https://yourgame.com/.well-known/assetlinks.json:
[{"relation": ["delegate_permission/common.handle_all_urls"], "target": {"namespace": "android_app", "package_name": "com.yourgame.app", "sha256_cert_fingerprints": ["YOUR_SIGNING_CERT_SHA256"]}}]
Custom URL scheme — iOS: register in Info.plist under CFBundleURLTypes. Android: add <intent-filter> in AndroidManifest.xml.
Step 3: Handle the incoming deep link
Your app receives these query parameters:
| Parameter |
Description |
| redirect_uri |
Webshop callback URL. You will receive this value percent-encoded — decode it first to get the raw URL, then use the decoded value when calling /auth/auth-code and when building the redirect in Step 6. |
| state |
CSRF token. Pass through unchanged. |
| code_challenge |
PKCE challenge. Pass through unchanged. |
| code_challenge_method |
Always S256. |
| store_id |
Terminal3 store UUID. |
Step 4: Generate a one-time auth code
Generate a cryptographically random string in any format (UUID v4, hex, base64url), with at least 32 bytes of entropy.
Step 5: Call POST /stores/{store_id}/auth/auth-code
Pass the auth_code, redirect_uri, client_reference_id, code_challenge, state, and any optional player fields.
If the call fails, do not redirect the player back to the webshop — show an in-app error instead.
Step 6: Redirect the browser back
{redirect_uri}?code={auth_code}&state={state}
iOS: UIApplication.shared.open(URL(string: callbackUrl)!)
Android: startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(callbackUrl)))
Error Reference
| Error |
Likely cause |
401 on /auth/auth-code |
Invalid or missing X-API-Key |
404 on /auth/auth-code |
store_id not found |
422 on /auth/auth-code |
Required field missing or invalid |
400 on /auth/auth-code |
redirect_uri is not a Terminal3 domain |
503 on /auth/auth-code |
Service temporarily unavailable. Retry the request. |