Documentation

Integration guide

A practical guide to embedding the survey wall, receiving verified callbacks, testing your integration and requesting launch.

Quick start

You integrate with Omer Insight once. We connect the survey providers and send their confirmed events to your App. You supply the user identity, embed the wall and maintain your own user ledger. Your users do not need an Omer Insight Publisher account.

  1. Your user opens the wall

    Your site passes the App code and the signed-in user ID to the iframe.

  2. Omer Insight confirms the event

    The survey provider notifies our server; we associate the event with your App and user.

  3. Your server handles the callback

    Verify the signature, process the event once and acknowledge with HTTP 2xx.

The browser displays the survey; the server callback confirms the event. A success page, redirect or message in the browser is not proof for updating a ledger.
  1. Create your App

    Register and verify your Publisher account, then open Apps → Create App. Every new App starts in test mode, including Apps created by an approved account.

  2. Collect the credentials

    Open the App → General settings. Copy App code, App secret and the security hash. The Integration information tab contains examples, not a second set of credentials.

  3. Save your settings

    Set the App name and user-facing currency in the editor. In Postback settings, save a public receiving URL. A main URL is required even if you configure separate event URLs.

  4. Build the two connections

    Embed the wall for your signed-in users and implement a server endpoint for callbacks. These are separate connections: showing the wall does not automatically update your database.

  5. Test before launch

    First test the receiving endpoint with Send test postback. Then add your test user ID or IP in General settings and verify the wall with that identity.

  6. Request launch

    Save all changes, finish the checks below and click Request launch in the App editor. Only an administrator can change the App to live.

App code and secrets

Find these values in App → General settings. Use the credentials for the same App at both ends of the integration.

ValuePurpose and handling
App codePublic identifier used as app_id in the wall URL. It is not a secret.
App secretServer-only secret used for the iframe secure_hash and the X-Omer-Signature HMAC. Never put it in browser JavaScript, a mobile bundle or the callback URL.
Security hashSeparate server-side value for the optional callback hash placeholder: MD5 of trans_id, a hyphen and this value. It is not App secret. Prefer the HMAC header because it also covers the event fields.

Embed the surveywall

Load the wall in an iframe on your authenticated user page. Use a stable ID from your own system; the same ID returns as user_id in callbacks. Do not generate a new ID on each visit.

Privacy before loading the survey wall

Disclose Omer Insight, CPX Research and PrimeSurvey (Prime Earn) in your privacy notice. Loading the iframe starts server-side survey matching and shares the user ID, IP address and browser information with enabled partners. Where applicable law requires prior consent for that sharing, obtain it before assigning the iframe src. Our cookie controls do not replace your own disclosure or consent requirements.

HTML
<iframe
  src="https://offers.omerinsight.com/wall/en?app_id=YOUR_APP_CODE&ext_user_id=USER_123&secure_hash=SERVER_GENERATED_HASH"
  title="Omer Insight"
  style="width:100%;height:720px;border:0"
  allow="clipboard-write"
></iframe>

Replace YOUR_APP_CODE, USER_123 and SERVER_GENERATED_HASH. The PHP example builds and URL-encodes the link on your server; replace authenticatedUserId with your own session identity. The browser receives only the final URL. If your page uses a Content Security Policy, allow https://offers.omerinsight.com in frame-src. Verify survey navigation on the browsers or WebViews you support.

PHP · iframe
<?php
// In your authenticated page/controller. Never accept the user ID from a form.
$appCode = getenv('OMER_APP_CODE');
$appSecret = getenv('OMER_APP_SECRET');
if (!$appCode || !$appSecret) {
    throw new RuntimeException('Configure OMER_APP_CODE and OMER_APP_SECRET');
}
// Replace this with the ID from YOUR authenticated server-side session.
$userId = (string) $authenticatedUserId;
$query = http_build_query([
    'app_id' => $appCode,
    'ext_user_id' => $userId,
    'secure_hash' => md5($userId . '-' . $appSecret),
], '', '&', PHP_QUERY_RFC3986);
$wallUrl = 'https://offers.omerinsight.com/wall/en?' . $query;
?>
<iframe
  src="<?= htmlspecialchars($wallUrl, ENT_QUOTES, 'UTF-8') ?>"
  title="Omer Insight"
  style="width:100%;height:720px;border:0"
  allow="clipboard-write"
></iframe>

URL parameters

ParameterTypeDescription
app_idRequiredstringYour app code, shown in the Portal.
ext_user_idRequiredstringYour user's unique, stable id. Returned to you as {user_id}.
secure_hashRecommendedstringRecommended: md5(ext_user_id + '-' + app_secret), generated on your server. A supplied hash is validated; a missing hash is currently accepted, so this is not mandatory identity authentication.
langOptionalstringUse /wall/en, /wall/zh-CN or another supported locale for an explicit language. The /wall entry also accepts lang; otherwise it uses the browser language, then English.
subid_1OptionalstringOptional tracking value. Returned when supported by the upstream provider; it may be empty. Do not use it as the sole user or App identifier.
subid_2OptionalstringOptional second tracking value. Provider support varies; it may be empty.

Receive postbacks

A postback is a server-to-server notification. Omer Insight sends an HTTP GET request to the URL saved in your App. Values replace the placeholders before sending. Your endpoint must work without a browser session or login cookie.

publisher.example.com below is a placeholder for YOUR receiving server, not an Omer Insight endpoint. Replace it with your public HTTPS domain and handler path. Keep the placeholder tokens in the saved template. Configure the final URL directly: no localhost, private IP, login page, CAPTCHA or redirect.

GET · Postback URL
https://publisher.example.com/omer/postback?status={status}&trans_id={trans_id}&original_trans_id={original_trans_id}&user_id={user_id}&amount_usd={amount_usd}&amount_local={amount_local}&type={type}&test={test}&subid_1={subid_1}&subid_2={subid_2}&hash={secure_hash}

Placeholders

ParameterDescription
{status}1 = credited, 2 = reversed.
{trans_id}Unique transaction id. Use it to de-duplicate.
{user_id}The ext_user_id you passed to the wall.
{subid_1}subid_1 you passed to the wall.
{subid_2}subid_2 you passed to the wall.
{amount_local}The number of units in your App currency. Use the received value when updating the user ledger; do not calculate it again.
{amount_usd}The USD value of this event for your Publisher account. This is not the user currency unit.
{ip_click}User IP at click time.
{type}complete, screenout, bonus or reversal.
{secure_hash}md5(trans_id + '-' + app_security_hash).
{original_trans_id}Original transaction ID for a reversal; empty for other events. Keep the full ID including its prefix.
{test}1 = test delivery, 0 = real delivery. Test events must never change real user balances.

Postback types

All four event types are enabled. The main URL is required. Separate screenout, bonus and reversal URLs are optional; an empty separate URL uses the main URL. This lets you implement one endpoint that routes by type and status.

typeDescription
completeA confirmed completion. Apply the received user currency units once.
screenoutThe user started a survey but did not qualify. Handle the received reward event.
bonusA reward event, such as an eligible survey rating. Process separately from a completion.
reversalAn earlier event was revoked. status=2; original_trans_id identifies the original transaction.

Verify the signature

Every callback includes X-Omer-Signature. Current App callbacks use GET: calculate HMAC-SHA256 with App secret over the exact full public URL, including the unchanged path and query string. Compare the lowercase hexadecimal digest using a constant-time comparison. Never sort, decode or rebuild the query before verification.

These examples show URL construction and signature verification. They are not a complete wallet SDK. process_omer_event_atomically is a function you must implement using your own database and user model. The current App editor sends GET callbacks; the PHP POST branch is only for compatibility.

PHP · HMAC-SHA256
<?php
// Configure your PUBLIC origin, including scheme and non-default port.
// Do not trust a client-supplied Host or X-Forwarded-Proto header.
$publicOrigin = 'https://publisher.example.com';
$secret = getenv('OMER_APP_SECRET');
if (!$secret) {
    http_response_code(503);
    exit('Receiver not configured');
}
$method = $_SERVER['REQUEST_METHOD'];
$raw = file_get_contents('php://input');
$signed = $method === 'GET'
    ? $publicOrigin . $_SERVER['REQUEST_URI'] // exact path + query, no re-encoding
    : $raw;
$expected = hash_hmac('sha256', $signed, $secret);
$signature = $_SERVER['HTTP_X_OMER_SIGNATURE'] ?? '';
if (!hash_equals($expected, $signature)) {
    http_response_code(403);
    exit;
}
$event = $method === 'GET' ? $_GET : json_decode($raw, true);
// Implement this function using a DATABASE TRANSACTION:
// 1. INSERT event.trans_id with a UNIQUE constraint; duplicate = return success.
// 2. Validate user_id, status and the non-negative integer amount_local.
// 3. status=1: credit amount_local; status=2: debit amount_local.
//    Link a reversal using original_trans_id; allow it to arrive before the credit.
// 4. test=1: use a TEST ledger, not real balances. Never infer mode from the ID.
// 5. Commit the ledger change and the event together; failures return HTTP 500.
// Return 2xx only after durable processing. Never credit from a browser redirect.
process_omer_event_atomically($event); // Your own persistence implementation.
http_response_code(200);
echo 'OK';
Node.js · HMAC-SHA256
import { createHmac, timingSafeEqual } from "node:crypto";

// GET: signed = configuredPublicOrigin + req.originalUrl (exact raw path + query).
// POST: signed = raw request body bytes, before JSON parsing.
export function verify(signed, header, secret) {
  if (!secret || typeof header !== "string") return false;
  const expected = createHmac("sha256", secret).update(signed).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(header ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

Process a callback reliably

Keep signature verification, event validation and durable processing on your server. A successful HTTP response tells us you have safely accepted this event.

  1. Verify before trusting fields

    Use the App secret and the configured public origin, not an untrusted Host header. Behind a reverse proxy, preserve the exact raw request path and query.

  2. Validate the identity and event

    Check user_id against your users; allow the documented type and status values. Treat all query values as strings until validated. Preserve the full trans_id, including cpx:, prime: and reversal suffixes.

  3. Separate test and live processing

    test=1 belongs only in your test ledger. test=0 is live. Do not infer the mode from the transaction ID prefix.

  4. Commit once in a database transaction

    Use a unique event key and commit the event record and ledger update atomically. For a duplicate already committed event, make no change and return 2xx. A reversal has its own trans_id and references the credit through original_trans_id.

  5. Acknowledge after durable acceptance

    Return 200 OK after committing, or after storing the event in a durable queue you will process reliably. A memory-only task is not enough. Return 5xx for a temporary failure. Respond within 15 seconds.

Callbacks can arrive out of order. If a reversal arrives before its original event, store it durably as pending and reconcile when the original arrives. Never silently discard it or attach it to a different transaction.

Retries & idempotency

The first delivery is immediate. Network failures, 408, 429 and 5xx are retried at the intervals below. Other 3xx and 4xx stop automatic retries; redirects are not followed. After fixing the endpoint, contact support with the transaction ID to arrange a replay.

AttemptDelay after previous
1—
23 min
310 min
430 min
52 h
624 h

Delivery may repeat after a timeout or recovery, even if your first processing succeeded. Keep a unique key on App + test mode + full trans_id, and return 2xx for an already committed event without applying it again.

Testing

Use Send test postback to verify your receiving endpoint: these events have test-* IDs. Allowlisted users can also test the wall while the app is in test mode; those callbacks keep provider-prefixed IDs. Always isolate events using test=1, not the ID prefix. Test callbacks must never change real balances. Passing the send test does not validate the upstream API, real survey completion or return redirect.

In App → Postback settings, enter a user ID that exists in your test system. Start with the main callback, record the returned transId, then test the other types. The button saves the visible callback settings before sending and calls your real URL.

CheckExpected result
Main callbackYour endpoint receives a signed GET, recognizes the user and records one event in the test ledger.
Screenout and bonusTest each separately. A dedicated URL receives its type; without one, the main URL receives it.
ReversalUse the transId of the earlier main test for the same App and user. The callback has status=2 and the correct original_trans_id.
Duplicate deliveryIn your own integration harness, resend the same signed event without modifying its URL. It is acknowledged without a second ledger change.
Invalid signature / temporary failureAn invalid signature is rejected. Test transient failures and recovery in your harness; the manual send button is a one-shot delivery and does not exercise the production retry queue.
Wall accessThe allowlisted identity can open the test wall. A non-allowlisted identity sees the not-live notice. If the test completion limit is reached, new surveys stop.
Check both logsCompare the Portal → Statistics → Postbacks log with your server log using the same full transaction ID. HTTP 2xx alone does not prove your ledger code is correct.

The test wall uses real upstream surveys. Test mode isolates Omer Insight records and sets test=1; it is not a simulated provider sandbox. Use only provider-approved testing and do not fabricate completions. End-to-end acceptance includes survey navigation, return navigation, the provider event and your server processing.

Request launch

  • Your main URL is saved, reachable and verifies the HMAC header.
  • All event types, duplicate handling, reversal handling and test isolation have passed your checks.
  • Your iframe uses stable user IDs and server-generated links; you have checked your supported browsers.
  • Save every edited tab, then click Request launch. Keep the saved configuration unchanged while it is being reviewed.

Saving changes while a request is pending withdraws that request; finish editing and submit again. Account approval does not automatically publish Apps. After approval, start a fresh wall session and verify live callbacks before gradually increasing traffic.

Troubleshooting

The test wall does not open

Check the App status, saved user/IP allowlist and test completion limit. The user ID must exactly match ext_user_id in your link. A supplied invalid secure_hash is rejected even in test mode.

The wall opens but has no surveys

Availability depends on the user, location, device and provider inventory. An empty list alone does not prove the integration is broken. Test from an eligible real connection; a proxy or VPN can be blocked.

No callback arrives

First check the Portal postback log. If a delivery exists, inspect its HTTP status and your firewall/server log. If no event exists, contact support with the App code, user ID and time so the upstream event can be checked.

The HMAC signature does not match

Check App secret, the public HTTPS origin and the exact raw URL. Query parameter order, percent encoding, a rewritten path or an HTTP/HTTPS mismatch changes the signature. Do not use the security hash as the HMAC key.

The log says success but my user was not updated

2xx confirms only that your endpoint accepted the request. Check the user mapping, test ledger, unique event key and transaction commit. Do not return success before the event is stored.

A failed callback needs to be sent again

Fix the endpoint first, then contact support with the App code and full transaction ID. Replaying must preserve the original event ID; creating a new manual test is not a replay of the failed event.

When contacting support, include App code, full trans_id if available, UTC time, HTTP status and a redacted error message. Never send App secret, security hash or live user credentials.

OMER INSIGHT

Essential

Always active

Sign-in sessions, security, your language preference and this privacy choice. These are needed to provide the requested features.

Analytics

Not used

We do not currently load optional website analytics cookies or scripts.

Advertising

Not used

We do not currently load advertising cookies, retargeting pixels or cross-site marketing trackers.

Survey partners

Our survey partners are CPX Research and PrimeSurvey (Prime Earn). When a survey wall loads, our server sends enabled partners the user identifier, IP address and browser information to match surveys. CPX may also receive publisher-supplied tracking references.

These settings apply to Omer Insight storage in this browser on this site. They do not control partner websites or stop the server processing required to deliver requested surveys. Partner sites provide their own privacy notices and consent controls.