Gamification
Gamification SDK: client integration
Embed the player's loyalty screen in an iframe. Your backend signs an authentication payload, and your frontend passes it to the iframe. The iframe handles authentication, API calls, and rendering.
1. Get integration details
Request these from the Wynta team:
Gamification UI URL — the base URL for the iframe.
client_id— your registered client identifier, linked to your site.client_secret— the signing secret. Keep it on your backend only.
Use HTTPS in production. You do not need to send site_id.
2. Backend: create a signed payload
Create an authenticated endpoint on your backend that returns { client_id, payload, hash }. Use the logged-in player's ID from your server session.
Encoding and signing flow
Run all five steps on your backend:
Player claims → JSON string → UTF-8 bytes → Base64 string = payload
│
client_secret + HMAC-SHA256
│
lowercase hex = hash
Return { client_id, payload, hash } to your frontendBuild the claims object. Include
user_id,timestamp(current Unix seconds), andtransaction_id(a new UUID for this attempt).Convert the object to a JSON string. Use
JSON.stringify(claims)in Node.js. For the fixed example below, the exact string is:Encode that string as Base64. Convert the JSON string to UTF-8 bytes, then encode those bytes using standard Base64, keeping any trailing
=padding and adding no line breaks. This produces thepayloadfield:Base64 is reversible encoding, not encryption. It does not hide the player's ID.
Sign the Base64 string. Use HMAC-SHA256 with your
client_secretas the key and the exactpayloadstring from step 3 as the message. Convert the resulting digest to lowercase hexadecimal to createhash. Do not sign the raw JSON, decode the payload before signing, or include the surrounding JSON quotes.Return the request body. Add your
client_idalongside the unchangedpayloadandhash. The frontend passes this object to the iframe without re-encoding it. The secret is never included in the body.
Node.js implementation
Example response using the dummy secret example_secret:
The payload decodes to:
The hash is HMAC-SHA256(example_secret, payload) in hex. These values are illustrative; use your registered credentials, the current timestamp, and a new transaction ID for actual requests.
Requirements:
Sign the Base64 string, using HMAC-SHA256, and return the hash as hex.
Generate the payload when requested; do not cache it. The default timestamp window is 60 seconds, so keep your server clock accurate.
Generate a new
transaction_idand timestamp for every attempt, including retries.Return only the signed body to the frontend; never return
client_secret.
3. Frontend: embed and authenticate
Register the message listener before loading the iframe. When it sends PAGE_LOADED, fetch a fresh signed body from your backend and reply with SDK_AUTH_PAYLOAD.
Do not put authentication data in the iframe URL. Always validate both event.origin and event.source, and send the reply to the exact iframe origin.
Iframe → your frontend
{ type: 'PAGE_LOADED' }
Your frontend → iframe
{ type: 'SDK_AUTH_PAYLOAD', body: { client_id, payload, hash } }
PAGE_LOADED means the iframe mounted; it does not confirm authentication or data loading. There is currently no ready/success message. The iframe displays its own loading and error states. Your client does not call the SDK auth endpoint or manage the player token.
Troubleshooting
If iframe authentication returns 401 Invalid request, check:
The client is active and
client_id/client_secretare correct.The HMAC signs the exact Base64 payload string.
The timestamp is in Unix seconds and within the allowed window (default 60 seconds).
The
transaction_idhas not already been used.
To retry, reload the iframe and let the handshake request a newly signed payload.
Last updated
Was this helpful?