API Integration (Advanced)

Get Personalized API - Migrate from User-Level Offer API

This guide covers migrating from the legacy User-Level Offer API (/hotoffers_api.php, versions 1 and 2) to the new Get Personalized API.

Both return an on-demand, per-user, ranked list of offers. Get Personalized keeps that model but standardizes the response, renames fields to match the Get Offers API, moves to a clean REST URL, and adds server-side ban enforcement and richer offer detail.

No API key is required, the same as the legacy endpoint. You identify the request with your wall and the user's uid.

At a glance


User-Level Offer (legacy)

Get Personalized

Endpoint

/hotoffers_api.php (query: wall, uid, numoffers, version)

/api/v1/users/{uid}/personalized (uid in the path)

Protocol

HTTP/HTTPS

HTTPS required

Version selection

version=1 or version=2

none — the response is the current format

Response

bare list of offers

enveloped: status, publisher_id, wall_id, support_id, total, offset, limit, offers[]

Rewards

currency_award (+ tier fields in v2)

events[] with total_user_reward and per-event payout

Tier progress

tiers_url (per-event status)

offer-level in_progress / user_completed, plus the Get Progress API

Ban handling

none

structured 403 (USER_BANNED / IP_BANNED)

1. Endpoint and request

Before

curl "http://publishers.revenueuniverse.com/hotoffers_api.php?wall=WALL_ID&uid=USER_ID&numoffers=25&version=2"
curl "http://publishers.revenueuniverse.com/hotoffers_api.php?wall=WALL_ID&uid=USER_ID&numoffers=25&version=2"
curl "http://publishers.revenueuniverse.com/hotoffers_api.php?wall=WALL_ID&uid=USER_ID&numoffers=25&version=2"

After

curl "https://publishers.revenueuniverse.com/api/v1/users/USER_ID/personalized?wall=WALL_ID&numoffers=25&device=ios"
curl "https://publishers.revenueuniverse.com/api/v1/users/USER_ID/personalized?wall=WALL_ID&numoffers=25&device=ios"
curl "https://publishers.revenueuniverse.com/api/v1/users/USER_ID/personalized?wall=WALL_ID&numoffers=25&device=ios"

What changed:

  • uid moves out of the query string and into the URL path: /api/v1/users/{uid}/personalized.

  • wall and numoffers are unchanged query parameters.

  • version is removed — there is a single current response format.

  • HTTPS is required.

Parameter mapping

User-Level Offer (legacy)

Get Personalized

Notes

wall (query)

wall (query)

unchanged

uid (query)

uid (path)

now part of the URL path

numoffers (query)

numoffers (query)

unchanged (1–500, top-N ranked)

version (query)

removed

device (query)

device (query)

unchanged; mobile is no longer accepted (desktop/ios/android)

ip (query)

ip (query)

unchanged

sid3

New: session token embedded in click_url, returned on the postback

os_version

New: requesting device OS version

bid_floor

New: exclude offers below a price floor

As before, calling client-side lets RevU auto-detect device and IP; pass device and ip if you call server-side.

2. Response shape

The legacy API returned a bare list of offers. Get Personalized wraps them in an envelope:

{
  "status": "success",
  "publisher_id": 45,
  "wall_id": 123,
  "support_id": 567890,
  "total": 120,
  "offset": 0,
  "limit": 25,
  "offers": [  ]
}
{
  "status": "success",
  "publisher_id": 45,
  "wall_id": 123,
  "support_id": 567890,
  "total": 120,
  "offset": 0,
  "limit": 25,
  "offers": [  ]
}
{
  "status": "success",
  "publisher_id": 45,
  "wall_id": 123,
  "support_id": 567890,
  "total": 120,
  "offset": 0,
  "limit": 25,
  "offers": [  ]
}
  • total is the number of eligible offers for the user before the numoffers cut.

  • offset is always 0 — this endpoint returns the top N, it is not a paged feed.

  • support_id is a per-request reference to quote when contacting support.

Update your client to read offers from the envelope rather than treating the response as a top-level array.

3. Field mapping

User-Level Offer (legacy)

Get Personalized

Notes

cid

offer_id


name

offer_name


description

description

unchanged

terms

offer_terms


reporting

reporting

unchanged (Instant / Hourly / 2-3 Days)

currency_award

total_user_reward

Total user reward; per-step amounts are in events[].user_reward.

offer_url

click_url

Still a ready-to-use per-user URL — serve as-is, do not edit.

image_url

creatives[].url

A single square image becomes an array of creatives (url, width, height).

New fields with no legacy equivalent: headline, offer_type, offer_category, offer_conversion_window, mobile_package_id, tag, events[], total_payout, hot_offers_order, epc, and the per-user fields user_eligible, in_progress, user_completed, recommended_score, and attributed_click_time (returned when available).

4. Tiers → events, and tracking progress

Rewards (v2 tiers). The legacy v2 tier fields are replaced by the standard events[] array used across RevU's APIs:

Legacy (v2)

Get Personalized

tiers: true

An offer simply has more than one entry in events[].

currency_award_with_tiers

total_user_reward (sum of events[].user_reward).

per-tier reward

events[].user_reward (user) and events[].payout (your USD payout).

Each event also carries event_id (the step's tracking identifier — the base step is base_<offer_id>), conversion_type, event_conversion_window, event_order (false for an independent step, or a 1-based integer for sequential steps), and non_linear.

Progress tracking. The legacy tiers_url (which returned per-event status — blank / Completed / Revoked) is replaced by:

  • Offer-level in_progress and user_completed flags on each offer (returned when available), and

  • The Get Progress API for detailed per-event completion status.

Postback attribution by step continues to use the event identifier (the value formerly tracked via sid4), now surfaced as events[].event_id.

5. Ban enforcement (new)

The legacy API had no ban concept. Get Personalized enforces UID, wildcard-UID, and IP bans server-side and returns a structured 403:

{ "status": "error", "error": { "code": "USER_BANNED", "message": "User is banned from accessing offers" } }
{ "status": "error", "error": { "code": "USER_BANNED", "message": "User is banned from accessing offers" } }
{ "status": "error", "error": { "code": "USER_BANNED", "message": "User is banned from accessing offers" } }

error.code is USER_BANNED or IP_BANNED. Treat a 403 with either code as "do not serve this user." This also makes the endpoint usable as a ban check in support tooling.

6. Error handling

Validation and not-found errors use { "status": "failure", "message": "…" } (e.g. Invalid Wall ID, Invalid Number of Offers (min is 1, max is 500), Missing UID, Wall not found, No offers available). Ban rejections use the 403 error shape above. Update your handling to read status and branch on message or error.code accordingly.

Migration checklist

  • Move uid into the path: /api/v1/users/{uid}/personalized, and call over HTTPS.

  • Drop the version parameter.

  • Read offers from the response envelope instead of a top-level array.

  • Apply the field renames in §3 (cidoffer_id, nameoffer_name, termsoffer_terms, currency_awardtotal_user_reward, offer_urlclick_url, image_urlcreatives[].url).

  • Replace v2 tier handling with events[] + total_user_reward.

  • Move per-event progress from tiers_url to in_progress / user_completed and the Get Progress API.

  • Add 403 ban handling on error.code.

  • Keep serving click_url unmodified; optionally pass sid3 for postback round-trip.

  • Stop sending device=mobile (use desktop / ios / android).

Support

For help with your migration, contact your account manager or sales contact, and include the support_id from a response when reporting an issue.

Share feedback on this documentation