Wire it up once, earn everywhere.

Load the wall in an iframe or a mobile WebView with your App ID and a user ID. We verify every reward, credit the balance, and can notify your own server too.

<iframe
  src="https://wall.goolarr.com/?app_id=YOUR_APP_ID&user_id=USER_ID"
  width="100%"
  height="800"
  frameborder="0"
  style="border:0;border-radius:8px"
/>

Three pieces, one flow.

Your App ID, the wall, and your postback endpoint all work together without any extra plumbing.

STEP 01

Get your App ID

Create a project in the dashboard. Each one gets its own App ID and Server Key.

STEP 02

Load the wall

Point an iframe or WebView at wall.goolarr.com with your App ID and a stable user ID.

STEP 03

Verify and credit

We credit the Goolarr balance automatically. If you want your own currency updated too, verify the signed postback we send your server.

Embed it in one tag.

Point an iframe at the wall with your App ID and a user ID. Branding, currency, and layout all come from your project settings automatically.

ParamDescription
app_id

Your project's App ID, from the dashboard. Required.

user_id

A stable, unique ID for the signed-in user on your platform. Required.

index.html
<iframe
  src="https://wall.goolarr.com/?app_id=YOUR_APP_ID&user_id=USER_ID"
  width="100%"
  height="800"
  frameborder="0"
  style="border:0;border-radius:8px"
  allow="payment; fullscreen"
></iframe>
responsive.html
<div style="position:relative;width:100%;padding-bottom:75%;height:0">
  <iframe
    src="https://wall.goolarr.com/?app_id=YOUR_APP_ID&user_id=USER_ID"
    style="position:absolute;inset:0;width:100%;height:100%"
    frameborder="0"
    allow="payment; fullscreen"
  ></iframe>
</div>

Same URL, native shell.

The wall is just a signed URL, so any platform that can render a WebView can host it.

Keep JavaScript and DOM storage enabled
Let the WebView handle its own navigation and back button
Use a stable user ID, not a session token that changes on login
HTTPS only — no special network exceptions needed
Web iframe
<iframe
  src="https://wall.goolarr.com/?app_id=YOUR_APP_ID&user_id=USER_ID"
  width="100%"
  height="800"
  frameborder="0"
  style="border:0;border-radius:8px"
  allow="payment; fullscreen"
></iframe>

Every reward, verified.

We credit the Goolarr balance the moment a reward is verified, whether or not you set anything up here. If you also want to update your own in-app currency, set a callback URL in your project's Integrations tab and we'll forward a signed copy of every event to it.

Reward Callback URL

Called on COMPLETE and SCREENOUT, so you always know a session finished, credited or not.

Reconciliation Callback URL

Called on RECONCILIATION, when an earlier reward is adjusted after the fact — a refund or chargeback.

Server Key

Signs every callback we send you. Find it next to your callback URLs in the Integrations tab.

Example request your server receives

GET /reward-callback?uid=YOUR_APP_ID--user_42&val=2.50&raw=2.00&tx=tx_9f27a1&type=COMPLETE&rat=4&loi=8&hash=3f1a9c…
ParamDescriptionIncluded on
uid

Your user's ID, formatted as YOUR_APP_ID--user_id. Split on the double hyphen to get back the ID you passed in.

Every event
tx

Unique transaction ID. Store it — a retried postback should never credit twice.

Every event
type

COMPLETE, SCREENOUT, or RECONCILIATION.

Every event
val

Reward amount in your app's currency. Zero on a screenout.

COMPLETE, RECONCILIATION
raw

Raw USD value before your currency conversion.

COMPLETE, RECONCILIATION
reason

Why the user didn't qualify.

SCREENOUT only
ref

The original transaction ID being adjusted.

RECONCILIATION only
rat, loi, cat, country

Survey rating, length, category, and user country.

COMPLETE only

How the signature works

We take the full callback URL with every parameter set, sign it with your Server Key using HMAC-SHA1, and append the result as hash. To verify it, rebuild the same URL from what you received, strip the hash param, sign it yourself, and compare.

Always verify the signature before crediting anything
Compare hashes with a constant-time check, never ===
Store the tx ID and ignore duplicates — postbacks can be retried
Keep your Server Key in an environment variable, never in client code
Only credit on type === COMPLETE
import crypto from 'crypto';

function isValidCallback(fullUrl: string, serverKey: string): boolean {
  const url = new URL(fullUrl);
  const receivedHash = url.searchParams.get('hash');
  if (!receivedHash) return false;

  url.searchParams.delete('hash');
  const expected = crypto
    .createHmac('sha1', serverKey)
    .update(url.toString())
    .digest('hex');

  const a = Buffer.from(receivedHash);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// Express handler for your Reward Callback URL
app.get('/reward-callback', (req, res) => {
  const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;

  if (!isValidCallback(fullUrl, process.env.GOOLARR_SERVER_KEY!)) {
    return res.status(401).send('INVALID_HASH');
  }

  const { uid, tx, type, val } = req.query;
  const [appId, userId] = String(uid).split('--');

  if (await alreadyProcessed(tx as string)) {
    return res.status(200).send('OK'); // already credited, ignore
  }

  if (type === 'COMPLETE') {
    await creditUser(userId, Number(val));
  }

  await recordTransaction(tx as string);
  res.status(200).send('OK');
});

Got a stack we didn't cover? We'll help you wire it up.