Docs Home Support Get started

BitsOffers Documentation

Everything you need to monetize your website, faucet or app with the BitsOffers offerwall: embed code, real-time postbacks, security and API. Integration takes only a few minutes.

1 Add your websiteGet your API key and secret key.
2 Embed the offerwallOne iframe with your user ID.
3 Receive postbacksCredit your users automatically.
You need a free BitsOffers account to use any of our tools. Create your account or sign in.

Add your website

To integrate the offerwall you first have to add your website. Once it is added you will receive an API KEY and a SECRET KEY.

  1. Sign in to your BitsOffers account.
  2. Click Add Website (top bar or sidebar).
  3. Enter your website name, domain and platform type.
  4. Set your currency name in plural (Points, Coins, Tokens…), the number of decimals (up to 2) and the exchange rate: how many of your currency units a user earns for every 1 USD.
  5. Set your Postback URL. We call it every time a user completes an offer so you can credit the reward (see Postbacks).
  6. Done! Our team reviews your website. Meanwhile you can continue with the integration.

Offerwall integration

The offerwall adapts to any screen and shows your users offers, surveys, games, PTC ads, shortlinks and more — all in one place. Your API key is in Websites → your site → API keys.

Offerwall code

Paste this code where you want to show the offerwall:

HTML
<iframe src="https://bitsoffers.com/offerwall?userid=[USER_ID]&key=[API_KEY]"
        style="width:100%;height:800px;border:0;padding:0;margin:0;"
        scrolling="yes" frameborder="0"></iframe>

Or open it as a full page / new tab:

DIRECT LINK
https://bitsoffers.com/offerwall?userid=[USER_ID]&key=[API_KEY]
Replace [API_KEY] with your website API key and [USER_ID] with the unique ID of the user who is viewing the wall.

Parameters

ParameterDescriptionType
keyYour website API key.varchar(32)
useridUnique identifier of the user on your site. It is returned to you in the postback.varchar(32)
tab (optional)Open only one category: ptc, offers, surveys, links, faucet…string

Postbacks

Every time a user completes an offer we make an HTTP GET request to the Postback URL of your website with all the information you need to credit your user. Build your Postback URL with the macros below, for example:

POSTBACK URL EXAMPLE
https://yourdomain.com/postback.php?subId={{userId}}&transId={{transactionId}}&reward={{rewardValue}}&currency={{rewardCurrency}}&payout={{payout}}&status={{status}}&userIp={{userIp}}&country={{countryCode}}&type={{type}}&signature={{secret}}

Macros

MacroDescriptionExample
{{userId}}Unique ID of the user who completed the action.user123
{{transactionId}}Unique ID of the transaction. Use it to avoid crediting twice.XX-12345678
{{rewardValue}}Amount of your virtual currency to credit.1.25
{{rewardCurrency}}Your currency name.Coins
{{payout}}Your earnings for this lead in USD.0.100000
{{userIp}}IP address of the user.192.168.1.10
{{countryCode}}Country of the user (ISO-2).US
{{status}}1 = credit, 2 = chargeback (subtract the reward).1
{{type}}Kind of lead: offers, ptc, shortlink, faucet, game, article…offers
{{secret}}Signature to verify the request comes from us (see Security).17b4e2a7…a9f9ab

Security

Always verify the signature. It is the MD5 of userId + transactionId + rewardValue + your SECRET KEY:

PHP
<?php
$secret    = "YOUR_SECRET_KEY"; // from BitsOffers > Websites > API keys
$subId     = $_GET['subId']     ?? '';
$transId   = $_GET['transId']   ?? '';
$reward    = $_GET['reward']    ?? '';
$signature = $_GET['signature'] ?? '';

if (md5($subId . $transId . $reward . $secret) !== $signature) {
    echo "ERROR: Signature doesn't match";
    exit;
}

Postbacks are sent from these IP addresses. Whitelist them if your server filters requests:

109.123.243.168

Respond "ok"

Your postback must answer with the text ok. Any other answer marks the postback as failed (you can resend it later from Website Reports). We wait up to 60 seconds for your answer.

Always check that the transactionId is not already in your database before crediting. If a postback is resent you will not pay twice.

Full example

PHP · postback.php
<?php
$secret = "YOUR_SECRET_KEY"; // from BitsOffers

// Only accept requests from BitsOffers
$allowed = ['109.123.243.168'];
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'];
if (!in_array($ip, $allowed)) { echo "ERROR: Invalid source"; exit; }

$userId    = $_GET['subId']     ?? null;
$transId   = $_GET['transId']   ?? null;
$reward    = $_GET['reward']    ?? 0;
$payout    = $_GET['payout']    ?? 0;
$status    = $_GET['status']    ?? 1;
$signature = $_GET['signature'] ?? null;

if (md5($userId . $transId . $reward . $secret) !== $signature) {
    echo "ERROR: Signature doesn't match"; exit;
}

if ($status == 2) {             // chargeback
    $reward = -abs($reward);
}

if (isNewTransaction($transId)) {             // your function
    processTransaction($userId, $reward, $transId); // your function
}

echo "ok"; // Important!

Faucet scripts

Ready-to-paste integrations for the most popular faucet scripts. Replace YOUR_SECRET_KEY and YOUR_API_KEY with the keys of your website.

VieFaucet 4.x

1. Open application/controllers/Wh.php and paste this function before the last closing bracket }:

PHP · application/controllers/Wh.php
public function bitsoffers()
{
    $secret  = "YOUR_SECRET_KEY"; // BitsOffers secret key
    $holdDays = 1;                // days on hold (0 = no hold)
    $minHold  = 0.1;              // rewards lower than this are not held

    $userId        = $this->db->escape_str($_GET['subId'] ?? '');
    $transactionId = $this->db->escape_str($_GET['transId'] ?? '');
    $reward        = $this->db->escape_str($_GET['reward'] ?? 0);
    $userIp        = $this->db->escape_str($_GET['userIp'] ?? '0.0.0.0');
    $signature     = $this->db->escape_str($_GET['signature'] ?? '');
    $status        = $this->db->escape_str($_GET['status'] ?? 1);

    if (md5($userId . $transactionId . $reward . $secret) != $signature) {
        echo "ERROR: Signature doesn't match"; return;
    }
    $reward = $reward * $this->data['settings']['currency_rate'];
    if ($this->m_offerwall->getTransaction($transactionId, 'bitsoffers')) { echo "DUP"; return; }

    if ($status == 2) {
        $this->m_offerwall->reduceUserBalance($userId, abs($reward));
        $this->m_offerwall->insertTransaction($userId, 'bitsoffers', $userIp, $reward, $transactionId, 1, time());
        echo "ok"; return;
    }
    if ($reward <= $minHold || $holdDays == 0) {
        $offerId = $this->m_offerwall->insertTransaction($userId, 'bitsoffers', $userIp, $reward, $transactionId, 2, time());
        $this->m_offerwall->updateUserBalance($userId, $reward);
        $this->m_core->addNotification($userId, currencyDisplay($reward, $this->data['settings']) . " from BitsOffers offer #" . $offerId . " was credited.", 1);
    } else {
        $offerId = $this->m_offerwall->insertTransaction($userId, 'bitsoffers', $userIp, $reward, $transactionId, 0, time() + $holdDays * 86400);
        $this->m_core->addNotification($userId, "Your BitsOffers offer #" . $offerId . " is pending approval.", 0);
    }
    echo "ok";
}

2. Open application/controllers/Offerwall.php and add before the last }:

PHP · application/controllers/Offerwall.php
public function bitsoffers()
{
    $api_key = "YOUR_API_KEY";
    $this->data['page']   = 'BitsOffers Offerwall';
    $this->data['iframe'] = '<iframe style="width:100%;height:800px;border:0" scrolling="yes" src="https://bitsoffers.com/offerwall?userid=' . $this->data['user']['id'] . '&key=' . $api_key . '"></iframe>';
    $this->data['wait']   = 3;
    $this->render('offerwall', $this->data);
}

3. Add the menu link in application/views/user_template/template.php:

HTML
<li><a href="<?= site_url('offerwall/bitsoffers') ?>">BitsOffers</a></li>

4. In application/config/config.php add \'wh/bitsoffers\', to $config['csrf_exclude_uris'].

Postback URL to set in BitsOffers:

POSTBACK URL
https://yourdomain.com/wh/bitsoffers?subId={{userId}}&transId={{transactionId}}&reward={{rewardValue}}&payout={{payout}}&status={{status}}&userIp={{userIp}}&type={{type}}&signature={{secret}}
ClaimBits / CryptoFaucet

1. Create system/gateways/bitsoffers.php with:

PHP · system/gateways/bitsoffers.php
<?php
define('BASEPATH', true);
require('../init.php');
$secret = "YOUR_SECRET_KEY"; // BitsOffers secret key

$userId  = $db->EscapeString($_GET['subId'] ?? '');
$survey  = $db->EscapeString($_GET['transId'] ?? '');
$reward  = $db->EscapeString($_GET['reward'] ?? 0);
$payout  = $db->EscapeString($_GET['payout'] ?? 0);
$userIP  = $db->EscapeString($_GET['userIp'] ?? '0.0.0.0');
$country = $db->EscapeString($_GET['country'] ?? '');

if (md5($userId . $survey . $reward . $secret) != ($_GET['signature'] ?? '')) {
    echo "ERROR: Signature doesn't match"; return;
}
if ($userId !== '' && $db->QueryGetNumRows("SELECT 1 FROM `completed_offers` WHERE `survey_id`='$survey' LIMIT 1") == 0) {
    $user = $db->QueryFetchArray("SELECT `id` FROM `users` WHERE `id`='$userId'");
    if (!empty($user['id'])) {
        $tc = max(1, (int)round(0.10 * ($payout * 100)));
        $db->Query("UPDATE `users` SET `ow_credits`=`ow_credits`+'$reward', `tasks_contest`=`tasks_contest`+'$tc' WHERE `id`='{$user['id']}'");
        $db->Query("INSERT INTO `completed_offers` (`user_id`,`survey_id`,`user_country`,`user_ip`,`revenue`,`reward`,`method`,`timestamp`) VALUES ('{$user['id']}','$survey','$country','" . ip2long($userIP) . "','$payout','$reward','BitsOffers','" . time() . "')");
    }
}
echo 'ok';

2. In template/default/pages/offers.php add a new case:

PHP
case 'bitsoffers':
    $title = 'BitsOffers';
    $offer_wall = '<iframe src="https://bitsoffers.com/offerwall?userid=' . $data['id'] . '&key=YOUR_API_KEY" style="width:100%;height:690px;border:0;border-radius:5px;"></iframe>';
    break;

3. Add the button to the offerwall list:

HTML
<a href="<?php echo GenerateURL('offers&x=bitsoffers'); ?>" class="btn btn-secondary mb-1<?php echo ($method == 'bitsoffers' ? ' active' : ''); ?>">BitsOffers</a>
Set your currency in BitsOffers as credits. Postback URL: https://yourdomain.com/system/gateways/bitsoffers.php?subId={{userId}}&transId={{transactionId}}&reward={{rewardValue}}&payout={{payout}}&status={{status}}&userIp={{userIp}}&country={{countryCode}}&signature={{secret}}
AutoFaucet (NGB Solutions)

Same steps as ClaimBits. The only difference: the payout is converted with the current BTC price. Create system/gateways/bitsoffers.php:

PHP · system/gateways/bitsoffers.php
<?php
define('BASEPATH', true);
require('../init.php');
$secret = "YOUR_SECRET_KEY"; // BitsOffers secret key

$userId  = $db->EscapeString($_GET['subId'] ?? '');
$survey  = $db->EscapeString($_GET['transId'] ?? '');
$reward  = $db->EscapeString($_GET['reward'] ?? 0);
$payout  = $db->EscapeString($_GET['payout'] ?? 0);
$userIP  = $db->EscapeString($_GET['userIp'] ?? '0.0.0.0');
$country = $db->EscapeString($_GET['country'] ?? '');

if (md5($userId . $survey . $reward . $secret) != ($_GET['signature'] ?? '')) {
    echo "ERROR: Signature doesn't match"; return;
}
if ($userId !== '' && $db->QueryGetNumRows("SELECT 1 FROM `completed_offers` WHERE `survey_id`='$survey' LIMIT 1") == 0) {
    $user = $db->QueryFetchArray("SELECT `id` FROM `users` WHERE `id`='$userId'");
    if (!empty($user['id'])) {
        $price = $db->QueryFetchArray("SELECT `value` FROM `bitcoin_price` ORDER BY `time` DESC LIMIT 1");
        $usd   = $price['value'] * $payout;
        $tc    = max(1, (int)round(0.10 * $usd));
        $db->Query("UPDATE `users` SET `ow_credits`=`ow_credits`+'$reward', `tasks_contest`=`tasks_contest`+'$tc' WHERE `id`='{$user['id']}'");
        $db->Query("INSERT INTO `completed_offers` (`user_id`,`survey_id`,`user_country`,`user_ip`,`revenue`,`reward`,`method`,`timestamp`) VALUES ('{$user['id']}','$survey','$country','" . ip2long($userIP) . "','$usd','$reward','BitsOffers','" . time() . "')");
    }
}
echo 'ok';

Then add the iframe case and button exactly like in ClaimBits.


API

Show BitsOffers PTC ads, shortlinks and articles with your own design. The API returns JSON; each item includes a url to open when the user clicks.

API access must be enabled for your website. Contact us on Telegram: @bitsoffersco.
REQUEST
GET https://bitsoffers.com/api?type=ptc&apiKey=YOUR_PUBLIC_KEY&userId=USER_ID&device=desktop&country=us
Secret: YOUR_PRIVATE_KEY
Accept: application/json
ParameterDescription
typeptc, shortlink or article
apiKeyYour website API (public) key
userIdUser ID on your site
devicedesktop, mobile or tablet
countryISO-2 country of the user (e.g. us)
Secret (header)Your private key

Errors

MessageMeaning
Invaid Api keyThe apiKey does not exist.
Website Is PendingYour website has not been approved yet.
Access deniedAPI access or this category is not enabled for your website.
Access to this resource is deniedMissing parameters or wrong Secret header.

PTC

PHP
<?php
function bitsoffers_api($type, $country = 'us', $userId = 1) {
    $ua = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
    $device = strpos($ua, 'mobile') !== false ? 'mobile' : (strpos($ua, 'tablet') !== false ? 'tablet' : 'desktop');

    $query = http_build_query([
        'type'    => $type,               // ptc | shortlink | article
        'apiKey'  => 'YOUR_PUBLIC_KEY',
        'userId'  => $userId,
        'device'  => $device,
        'country' => strtolower($country),
    ]);
    $ch = curl_init('https://bitsoffers.com/api?' . $query);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_HTTPHEADER     => ['Secret: YOUR_PRIVATE_KEY', 'Accept: application/json'],
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    return json_decode($res, true);
}

$ptc = bitsoffers_api('ptc', 'us', $currentUserId);

Response:

RESPONSE
{
  "status": "success",
  "msg": "Request completed successfully",
  "total_reward": "12.5",
  "total_duration": 90,
  "total_ads": 3,
  "data": [
    { "id": 14, "name": "Visit CryptoSite", "description": "Stay 30 seconds",
      "reward": "5", "timer": 30, "adtype": "surfads",
      "url": "https://bitsoffers.com/offerwall/sptcview?token=...", "currency_name": "Coins" }
  ]
}
FieldDescription
rewardReward in your currency (your exchange rate is already applied).
timerSeconds the user must stay on the ad.
adtypesurfads (opens in our viewer) or windowads (opens in a new window).
urlOpen this URL when the user clicks. The reward is sent to your Postback URL with type=ptc.

Shortlinks

Same function, just change the type:

PHP
$links = bitsoffers_api('shortlink', 'us', $currentUserId);
RESPONSE
{
  "status": "success",
  "msg": "Request completed successfully",
  "total_reward": "20",
  "available": 6,
  "total_links": 3,
  "data": [
    { "id": 7, "name": "EarnLinks", "reward": "4", "view_per_day": 2, "remain_views": 2,
      "url": "https://bitsoffers.com/offerwall/linkgenerate?token=...", "currency_name": "Coins" }
  ]
}

Show only links with remain_views > 0. The reward arrives in your postback with type=shortlink.

Read articles

Returns the daily article cards of the user. Each card can be completed once per day: limit: "1/1" is available and "0/1" is already used (disabled: 1).

PHP
$articles = bitsoffers_api('article', 'us', $currentUserId);
RESPONSE
{
  "status": "success",
  "daily_limit": 10,
  "completed_today": 2,
  "available": 8,
  "data": [
    { "id": 3, "name": "Read Article #3", "reward": "1", "timer": 30,
      "limit": "1/1", "completed": 0, "disabled": 0,
      "url": "https://bitsoffers.com/offerwall/article_continue?...", "currency_name": "Coins" }
  ]
}

Support