LootHQ

Publisher docs

Integrate your app with LootHQ

The same integration guide publishers see inside the dashboard.

Quickstart

Five steps to a live hosted wall, with the exact things to copy.

Quickstart: your first wall

Five steps to a live hosted wall, with the exact things to copy. The only thing you need up front is a placement id, and step 1 gets you one.

  1. 1Create a placement. Dashboard → Placements → New placement → integration type Hosted Wall. Copy its placement id; the snippets below call it YOUR_PLACEMENT_ID.
  2. 2Embed the wall. Paste this where the wall should render, filling in both placeholders:
    Script embed (recommended)
    <div id="loothq-wall"></div>
    <script
      src="https://www.loothq.com/wall.js"
      data-placement-id="YOUR_PLACEMENT_ID"
      data-sub-id="{USER_ID}"
      data-container="loothq-wall"
    ></script>
    <!-- Replace YOUR_PLACEMENT_ID with the id from Dashboard → Placements, and
         render {USER_ID} server-side as the signed-in user's STABLE id. -->

    data-sub-id must be a stable id for the signed-in user, unique across all your placements. It is the id your postback will echo back as {user_id}, so it decides who you credit. An iFrame or a hosted link works identically. The script tag just wires the resize and click plumbing for you.

  3. 3Save your postback template. In Settings → Publisher Settings, save this as your Postback URL (swap in your own domain, path and a real secret for YOUR_SECRET; the {macros} stay exactly as written; we fill them in):
    Default postback template
    https://your-site.com/postback?key=YOUR_SECRET&user_id={user_id}&tx={transaction_id}&points={points}&payout={payout}&currency={currency}&offer_id={offer_id}&offer_name={offer_name}&status={status}&event={event_id}

    Your endpoint credits the user {points} (already in your currency) and returns HTTP 200. Saving warns you, without blocking, if the template is missing {status} or {offer_id}, or if you have no reversal URL yet. Full handler samples are in Postbacks.

  4. 4Run the Integration check. Open Dashboard → Integration check and press Run. One click verifies your saved URLs, the attribution macros, and a real delivery to each endpoint that writes no delivery, conversion, stat or ledger row. Every failing row comes with the concrete fix.
  5. 5Fire a test. On the same Settings page, run Test delivery in the Postback Tester and confirm your endpoint answers 200. Run it twice: it reuses the same {transaction_id} on purpose, so the second run proves your duplicate check works. Then go live and watch clicks, conversions and revenue in the dashboard.

Answer 200 first, then validate

The delivery test sends a {user_id} and {transaction_id} that do not exist in your database yet. That is deliberate: it is the only way to prove your endpoint is reachable without inventing a real conversion. If your handler looks the user up and returns 400 or 500 when it cannot find them, the test fails even though your server is working perfectly.

Return HTTP 200 for anything you have decided about, including "unknown user" and "already processed". Reserve non-2xx for the cases you want us to retry, such as your database being briefly unreachable. The full handler samples in Postbacks do this already:

const user = await db.Users.findById(user_id);
  if (!user) {
    return res.status(200).send("unknown user");   // not 404
  }

When you are ready for reversal handling in code (recommended before launch), add the separate reversal URL; see Handling reversals. To render offers in your own UI instead of embedding the wall, start at the Offers API quickstart.