Static Offer API
General Concept
The static offer API is designed to be called by a backend/server. This API returns you the inventory of all currently available offers. The feed can be used to extend your existing offer inventory or build your own offer system.
It is to be noted that the static offer API was not designed to be used in combination with any of the user-based offer APIs that we provide.
Target Group or Use Case: Use this API to grab our inventory and insert the offers in your existing offer management system.
Calling the API
You have to enable Offers for the App via our Publisher Dashboard
By calling the Get Offers for Publishers Endpoint, you will get all the offers available in the BitLabs network. You are then free to use your own yield management.
Example response
{
"data": {
"offers": [
{
"advertiser_id": 103082,
"anchor": "Get Paid To Play!",
"app_metadata": {
"app_id": "1621328561",
"categories": [
"Games",
"Family",
"Board",
"Entertainment"
],
"screenshot_urls": [],
"video_urls": []
},
"arpu_goals": [
{
"day": 7,
"goal": "1.3"
}
],
"categories": [
"CPE",
"iPad",
"iPhone"
],
"click_url": "https://bitlabs.link/vc/naeXr2c/offers/671309?source_type=offer_api&s1=",
"country_stats": [
{
"country_code": "GB",
"desktop_rank": 4,
"mobile_rank": 5
}
],
"creatives": {
"icon": "https://main-p.agmcdn.com/pb1dKAtX.jpg",
"images": {
"1080x1920": "https://main-p.agmcdn.com/0gLB5EbI.jpg",
"120x60": "https://main-p.agmcdn.com/cdn-cgi/image/width=120,height=60/https://main-p.agmcdn.com/Ks12k9xK.jpg",
"275x275": "https://main-p.agmcdn.com/cdn-cgi/image/width=275,height=275/https://main-p.agmcdn.com/mZJAlAUU.jpg",
"400x400": "https://main-p.agmcdn.com/cdn-cgi/image/width=400,height=400/https://main-p.agmcdn.com/mZJAlAUU.jpg",
"580x580": "https://main-p.agmcdn.com/cdn-cgi/image/width=580,height=580/https://main-p.agmcdn.com/mZJAlAUU.jpg",
"600x200": "https://main-p.agmcdn.com/cdn-cgi/image/width=600,height=200/https://main-p.agmcdn.com/gDrogW5X.jpg",
"600x300": "https://main-p.agmcdn.com/cdn-cgi/image/width=600,height=300/https://main-p.agmcdn.com/Ks12k9xK.jpg",
"630x315": "https://main-p.agmcdn.com/cdn-cgi/image/width=630,height=315/https://main-p.agmcdn.com/Ks12k9xK.jpg"
}
},
"demographic_targeting": {},
"description": "Release your inner property tycoon and earn a HUGE by playing Monopoly! Reach the board levels below to earn!",
"device_targeting": {
"browsers": [],
"devices": [],
"operating_systems": [
{
"name": "ios"
}
],
"platforms": [
{
"name": "smartphone"
},
{
"name": "tablet"
}
]
},
"disclaimer": "Must reach board 19 and level 101 within a certain timeframe. will appear as Pending for 5 days. Each person may redeem this offer only ONCE (1 time). This offer is presented to you by website or app on behalf of a third party merchant or sponsor (\"Merchant\"), which advises us when the offer is completed and a reward should be issued. website or app has not evaluated and does not endorse Merchant's views, policies, products or services, which you are encouraged to evaluate for yourself. Have questions? Please contact the website or app Help Center.",
"epc": "1.43",
"events": [
{
"hash": "c2bfaaf2b3eca424b68d3d4b9583a677",
"id": "8b00bb5c-2a9f-11f0-be1f-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Install",
"payout": "13",
"payout_type": "flat",
"points": "0",
"translations": {},
"ttc_minutes": 0,
"type_id": 1
},
{
"hash": "1d251194295ee9c9a092a0b50b7bd7df",
"id": "8b00db82-2a9f-11f0-96d2-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "*BONUS REWARD: Reach Board 19. Complete within 3 days",
"payout": "0",
"payout_type": "flat",
"points": "5000",
"translations": {},
"ttc_minutes": 4320,
"type_id": 2
},
{
"hash": "bf61784a4b73f4f3bc0320c2771756c9",
"id": "8b00fc48-2a9f-11f0-b5ee-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "*BONUS REWARD: Reach Board 71. Complete within 5 days",
"payout": "0",
"payout_type": "flat",
"points": "25000",
"translations": {},
"ttc_minutes": 7200,
"type_id": 2
},
{
"hash": "ba2dd36eacd2c8847da41b4b448f638b",
"id": "8b01185e-2a9f-11f0-a390-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "*BONUS REWARD: Reach Board 101. Complete within 8 days",
"payout": "0",
"payout_type": "flat",
"points": "36000",
"translations": {},
"ttc_minutes": 11520,
"type_id": 2
},
{
"hash": "ce314170b31b5f1ffa6ceb05bb078875",
"id": "8b0136fe-2a9f-11f0-9729-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 3. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "50",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "89211e2260ffb5648a5d434eab28acd8",
"id": "8b0156f2-2a9f-11f0-9c23-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 5. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "80",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "9a1dc9f9b1e67604ffc378c19452122f",
"id": "8b01798e-2a9f-11f0-badb-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 8. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "120",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "72cbf7b3a617972134240b1817e98170",
"id": "8b019d7e-2a9f-11f0-84b8-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 10. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "160",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "28ebfebab6a479ee114b5f7443fe4882",
"id": "8b01c330-2a9f-11f0-9779-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 12. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "200",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "ab4b21cb17595d9607c4b6b7bfe616f4",
"id": "8b01eaf4-2a9f-11f0-9d7c-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 19 Base. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "240",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "73fd62fa5f0a2783bfa747e26226c8e7",
"id": "8b0215a6-2a9f-11f0-9815-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 42. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "800",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "c17a2e88c6cbd39f1ca7c4a6e66562d4",
"id": "8b024102-2a9f-11f0-be18-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 56",
"payout": "0",
"payout_type": "flat",
"points": "1000",
"translations": {},
"ttc_minutes": 0,
"type_id": 11
},
{
"hash": "80afce69a94587a8c3daeea8b0496648",
"id": "8b026e84-2a9f-11f0-8a84-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 86. Complete within 30 days",
"payout": "0",
"payout_type": "flat",
"points": "1200",
"translations": {},
"ttc_minutes": 43200,
"type_id": 11
},
{
"hash": "82f97b0a5d12b2078e3772bd8f3f1d9c",
"id": "8b029d00-2a9f-11f0-81bf-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 126 within 60 days",
"payout": "0",
"payout_type": "flat",
"points": "4000",
"translations": {},
"ttc_minutes": 0,
"type_id": 11
},
{
"hash": "2f175e6ad4d2946c52aaf1937136aceb",
"id": "8b02ce9c-2a9f-11f0-b69e-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 176 within 60 days",
"payout": "0",
"payout_type": "flat",
"points": "15000",
"translations": {},
"ttc_minutes": 0,
"type_id": 11
},
{
"hash": "2e6c594e4e21f79592dcb476ea3de5e4",
"id": "8b030092-2a9f-11f0-97fb-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 251 within 60 days",
"payout": "0",
"payout_type": "flat",
"points": "50000",
"translations": {},
"ttc_minutes": 0,
"type_id": 11
},
{
"hash": "02956fa0489095b86f4181e84584daa8",
"id": "8b033530-2a9f-11f0-adfa-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Reach Board 301 within 60 days",
"payout": "0",
"payout_type": "flat",
"points": "100000",
"translations": {},
"ttc_minutes": 0,
"type_id": 11
},
{
"hash": "eb2e6d2097926b591a563579a6ef9273",
"id": "8b036c3a-2a9f-11f0-b386-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Any Purchase (1 per day, max 5 total)",
"payout": "0",
"payout_type": "flat",
"points": "2000",
"translations": {},
"ttc_minutes": 0,
"type_id": 3
},
{
"hash": "5e5467753119b91df90b3bb063dac0a5",
"id": "ba9a91e9-3094-4caa-b514-3fb4fa53b86b",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Make a $1.99 Purchase",
"payout": "0",
"payout_type": "flat",
"points": "2000",
"translations": {},
"ttc_minutes": 0,
"type_id": 3
},
{
"hash": "bded2c55b68f68d844487d0abad43619",
"id": "77baf172-65b3-48b2-8eae-c9b22196a703",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Make a $4.99 Purchase",
"payout": "0",
"payout_type": "flat",
"points": "5000",
"translations": {},
"ttc_minutes": 0,
"type_id": 3
},
{
"hash": "f04b1eab413a97b0a1329340432b0551",
"id": "84aeaa94-915e-4ec6-a0c0-78d698207216",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "Make a $9.99 Purchase. Complete within 3 days",
"payout": "0",
"payout_type": "flat",
"points": "12000",
"translations": {},
"ttc_minutes": 4320,
"type_id": 3
},
{
"hash": "f4ea9e2726c4e9a8b79559509f3ac8ed",
"id": "6df7e263-a92c-4beb-91a3-0c61fab1ea39",
"is_cpc": false,
"multiple_conversions_allowed": false,
"name": "*Bonus Reward: Make a $19.99 Purchase. Complete within 10 days",
"payout": "0",
"payout_type": "flat",
"points": "25000",
"translations": {},
"ttc_minutes": 14400,
"type_id": 3
},
{
"hash": "5f6b3c1b8aec80b377e18fc8f66ea652",
"id": "8b03a93e-2a9f-11f0-82c9-069eb31df495",
"is_cpc": false,
"multiple_conversions_allowed": true,
"multiple_conversions_rules": {
"every_y_seconds": 0,
"rule_type": "unlimited",
"x_conversions": 0
},
"name": "Earn when you play at least 2 minutes daily!",
"payout": "0",
"payout_type": "flat",
"points": "10",
"translations": {},
"ttc_minutes": 0,
"type_id": 4
}
],
"geo_targeting": {
"cities": [],
"countries": [
{
"country_code": "GB"
}
],
"postal_codes": [],
"states": []
},
"icon": "https://main-p.agmcdn.com/pb1dKAtX.jpg",
"id": 671309,
"is_game": true,
"is_sensitive": true,
"lowest_cap_left": null,
"name": "Monopoly Go! iOS (UK) (OS2ID 22095)",
"pending_time": 7200,
"preview_url": "https://apps.apple.com/app/id1621328561?mt=8",
"product_id": "01JEEDNAFAXGZJQ5PRSFFQZGP7",
"product_name": "MONOPOLY GO!",
"requirements": "Hint: in-app purchases help you complete levels faster. Must be installing Monopoly Go for the first time to receive rewards. You must click \"Allow\" if tracking permission is requested within the app. Confirms Instantly",
"session_hours": 1608,
"support_url": "https://wall.adgaterewards.com/offer/contact/naeXr2c/671309?s1=",
"things_to_know": [
"Hint: in-app purchases help you complete levels faster.",
"Must be installing Monopoly Go for the first time to receive rewards.",
"You must click \"Allow\" if tracking permission is requested within the app.",
"Confirms Instantly"
],
"total_points": 284860,
"total_promotional_points": 0,
"translations": null
}
]
},
"status": "success",
"trace_id": "72b27669a61d9888"
}Details about the response
You can find all the details about the query and response parameters of the API in the documentation page here.
Recommended API Fields for a Better User Experience
We highly recommend reading this quick guide, which explains which API fields help create a smooth user experience and minimize customer complaints.
Tracking link parameters
Once you get a response from the API, you will see a tracking link for each offer. Some additional information needs to be provided in these links. The s1 parameter should include the ID of the user accessing the offer. The ID can be any string up to 255 characters long. The s4 parameter can include custom subparameters you want to receive in callbacks. Learn more about it here.
All other s parameters are used internally and should not be overwritten.
Common Practices
Here are some common practices we recommend to our partners when using the static offer API.
Fetching offers
To have an updated inventory of our offers, we recommend fetching the offer list every 10 to 15 minutes. There is no indicator of which offer changed or which offer disappeared. Because of this, it is advised to compare the newly fetched list with the current one and then change offer descriptions, events, and other data or take offers offline, if they do not appear in the new list.
Storing clicks & continue playing
When using the static API, it is important to note that you have to store the user's clicks and the events they have completed. This is important for two reasons:
- When an offer changes (details, events, ...) the user should still see all the details at the time of the click. Otherwise, it can be irritating for the user, if they see new events all of a sudden.
- You have to store the events that the user has completed, otherwise they will not know what the progress is. You will receive the completed events via the callbacks.
- Stored clicks should expire if they do not lead to an install within 24 hours. In that case, the game should be removed from the “continue playing” section (in case there is a continue playing section), as the user either did not install or can no longer install (e.g. due to temporary or permanent restrictions). Keeping such entries may result in repeated, non-converting clicks and a degraded user experience.
For games, once a click is stored, it is advised to no longer expose the tracking link to the user and instead use a direct link to the Google Play Store or Apple App Store.
click_url→ for new users who haven’t installed the game (tracks installs, subject to caps).preview_url→ for returning users who have already installed the game (avoids caps and ensures a smooth experience).
Generating a support URL
The API returns a support URL for each offer when fetching the offer list. You are free to use this, but two things have to be noted:
- You have to attach the user ID in the s1 parameter of the URL
- The supported URL will only work once a click is recognized by us. Therefore you can add a logic to show the URL only once a user has clicked on the offer. A click for games means that the user saw the Google Play or the App Store page.
How do I filter the response to only see games?
The API currently does not support a query parameter to filter for games. However, we added a parameter called is_game. If this parameter is true, then the offer is a gaming offer.
How do I filter the response by country?
The API currently does not support a query parameter to filter the response by country. However, we added a field in the response called country_stats which contains a country code. This can be used to filter by country on your end.
How do I filter the response by device?
You can find the device_targeting field in the response for each offer. This will include information about the operating system of an offer, for exampleios or android. The offer is available for all devices if no information is provided in the device_targeting field.
How do I set up custom offer rewards?
Custom rewards can be an effective way to tailor reward structures for individual users or to run A/B tests aimed at optimizing performance.
If you wish to implement custom offer rewards, please be aware of the following limitations:
- You must work with the events available through the API.
- While you can define the reward amount for each event, you are responsible for storing these custom reward values in your system. We strongly recommend implementing a fallback mechanism in case a new event is introduced.
To set up custom rewards:
- Store a custom reward value in your system for each event.
- Map each reward to the corresponding event ID (or task ID) returned in the API and in callbacks.
- When a callback is received, look up the event ID in your system to determine the appropriate custom reward.
- Avoid relying on the event name for mapping, as it is subject to change and may break your reward logic.
Having a robust fallback ensures your system continues to function smoothly even if new events are introduced without prior notice.
How do I handle translations?
Some offers may not include translations for all fields, such as descriptions or event names. In these cases, English is used as the default language.
If a translation is available, it will be structured as follows:
"translations": {
"de": {
"anchor": "Magnet Miner",
"description": "Graben Sie in der tiefsten Mine, die möglich ist, und greifen Sie nach den im Boden verborgenen Schätzen! Verdienen Sie Gold und verbessern Sie Ihren Einkaufswagen und Magnet-Drop.",
"requirements": "Erstbenutzer: Erreichen Sie 5.000 Meter, um RIESIGE Belohnungen zu erhalten. Sie müssen auf \"Zulassen\" klicken, wenn in der App eine Tracking-Berechtigung angefordert wird."
}
}How do I handle country stats?
Offer country targeting typically includes the country code indicating where the offer is available (e.g., US for the United States).
In some cases, offers may also include a list of specific states or regions within a country. This is used when an offer is limited to certain sub-regions.
Example:
"states": [
{
"geoname_id": 5101760,
"name": "New Jersey"
}
]ZIP codes are no longer being used; instead, the state list should be used.
Age and Gender Targeting
Some offers are restricted to users within specific age ranges and/or genders. To ensure compliance with advertiser requirements and avoid a poor user experience, you should only display these offers to users who match the defined targeting criteria.
Offer Targeting Information
The Offer API response may include age and gender targeting objects.
Age Targeting
"age": {
"exclude": false,
"unknown_allowed": false,
"options": [
{
"min_age": 18,
"max_age": 25
},
{
"min_age": 60,
"max_age": null
}
]
}| Field | Description |
|---|---|
exclude | Indicates whether the listed criteria should be excluded rather than included. |
unknown_allowed | Specifies whether users with an unknown age are eligible for the offer. |
options | List of eligible age ranges for the offer. |
In the example above, the offer is available to users who are:
- Between 18 and 25 years old (inclusive), or
- 60 years old and above (
max_age: nullindicates no upper limit).
Gender Targeting
"gender": {
"exclude": false,
"unknown_allowed": true,
"options": [
"male",
"female"
]
}| Field | Description |
|---|---|
exclude | Indicates whether the listed genders should be excluded rather than included. |
unknown_allowed | Specifies whether users with an unknown gender are eligible for the offer. |
options | List of eligible genders for the offer. Supported values are male and female. |
Displaying Targeted Offers
If you do not collect age and gender information from your users, we recommend not displaying offers that require this targeting information.
Before showing an offer to a user, evaluate the targeting requirements returned by the Offer API and determine whether the user is eligible.
Example
If an offer contains the following targeting configuration:
"age": {
"exclude": false,
"unknown_allowed": false,
"options": [
{
"min_age": 18,
"max_age": 25
}
]
},
"gender": {
"exclude": false,
"unknown_allowed": false,
"options": [
"female"
]
}Only users who are female and between 18 and 25 years old should be shown the offer.
Passing Age and Gender on Click
For offers that include age and/or gender targeting, you must provide the corresponding user information when redirecting the user to the offer. This allows us to verify that the user meets the advertiser's targeting requirements.
Pass these values as query parameters in the click URL:
| Parameter | Type | Description |
|---|---|---|
age | Number | The user's age in years. |
gender | String | The user's gender. Supported values: male, female. |
Query Parameter Example
&age=25&gender=maleExample Click URL
https://bitlabs.link/vc/naeXr2c/offers/1675037?source_type=offer_api&s1=testuser&age=25&gender=maleImportant: If your integration supports age and gender collection, ensure that the values passed in the click URL accurately reflect the user's information. Providing incorrect values may result in users being rejected from offers or advertisers flagging the traffic as invalid.
Handling multi-conversion events
Multi-conversion events are events that a user can complete multiple times, depending on specific rules that define how frequently and how often conversions are allowed.
To determine if an event supports multiple conversions, check the events.#.multiple_conversions_allowed field.
The configuration for multi-conversion rules is defined in the multiple_conversions_rules object, as shown below:
"multiple_conversions_rules": {
"every_y_seconds": 2678400,
"rule_type": "INTERVAL",
"x_conversions": 5
}The rule_type field determines how multiple conversions are handled. The following values are supported:
- UNLIMITED: The user can complete the event an unlimited number of times.
- TOTAL_CONVERSIONS: The user can complete the event up to
x_conversionstimes in total. - INTERVAL: The user can complete the event up to
x_conversionstimes everyevery_y_secondsinterval.
Note: The every_y_seconds field is only applicable when rule_type is set to INTERVAL.
How do I identify if an offer pays on Install (CPI)?
To determine if an offer includes an install-based payout, follow these steps:
- Check the event type Look for an event where
type_id= 1 (INSTALL). - Verify the payout value Inspect the payout field of this install event.
- Determine payout eligibility If
payout> 0, the offer pays on install.
This will inform you whether you receive payment on install or not. Note that for most CPI campaigns, the regular progression events will not have a payout amount.
Appending Additional Tracking Parameters
To improve tracking accuracy and attribution reliability, the Static Offer API supports a set of optional query parameters that can be manually appended to each offer’s click_url.
Unlike the User-Based Offer API, these parameters are not automatically handled. Publishers are responsible for appending them when rendering or redirecting users to the offer.
Overview
When these parameters are appended to the click_url:
- They are forwarded to downstream partners for improved tracking and attribution
- They provide additional device and user context
- They remain fully optional and do not affect existing integrations
Publishers are already appending the user_id using the s1 parameter. Additional parameters can be appended in the same way.
Supported Query Parameters
| Parameter | Description | Platform |
|---|---|---|
ios_id | Apple Identifier for Advertisers (IDFA). Only available if ATT is granted. | iOS |
android_advertiser_id | Google Advertising ID (GAID) | Android |
idfv | Apple Identifier for Vendors | iOS |
u_ip | User IPv4 address from the native network call | All |
device_name | Device model (e.g., iPhone17,2) | All |
os_version | Operating system version (e.g., 18.3.1) | All |
ua | User Agent string | All |
Example Click URL
Base click URL:
https://bitlabs.link/vc/naeXr2c/offers/1453636?source_type=offer_api&s1={user_id}With additional parameters:
https://bitlabs.link/vc/naeXr2c/offers/1453636?source_type=offer_api&s1={user_id}&ios_id={IDFA}&android_advertiser_id={GAID}&idfv={IDFV}&u_ip={IPV4_ADDRESS}&device_name={MODEL}&os_version={VERSION}&ua={USER_AGENT}Implementation Notes
- All parameters are optional
- Parameters must be appended as standard query parameters using
& - Existing parameters (e.g.,
s1) must not be modified or removed - All values should be properly URL-encoded before appending
Platform-Specific Notes
ios_idshould only be sent for iOS devices and when App Tracking Transparency (ATT) permission is grantedandroid_advertiser_idshould only be sent for Android devicesidfvis specific to iOS devicesu_ipmust be a valid IPv4 address

