API Access

Authenticating with the Preads API, and the limits that apply.

Base URL

JSON endpoints live under /api/v1. Two further endpoints sit directly under /api and are part of the integration surface:

https://preads.hansaldev.com/api/v1
Path What it is Credentials
/api/v1/* The JSON API. See below
/api/track Click tracking. Redirects rather than returning JSON. apiKey only
/api/postback Inbound endpoint for offer networks. Not for publishers — it is unauthenticated by design. None

Authentication

Credentials come from an approved app. Find them on the app's detail page in the publisher area.

Endpoint Credentials required
GET /api/v1/offers apiKey and apiSecret
GET /api/track apiKey, plus userId and offerId
POST /api/v1/fingerprint* None. These are anonymous — see Fingerprinting.
Keep your API secret on the server. A request without valid credentials is rejected with 401. Never place apiSecret in HTML, JavaScript or any client-side code — anyone who reads it can read your whole offer feed. Call the API from your backend and proxy what you need.

Your app must also be approved. A pending app has credentials but they will not authenticate.

The API key alone is semi-public — it appears in every tracking URL the platform hands out — so treat the key as identifier-level information and the secret as a credential.

Example request

curl "https://preads.hansaldev.com/api/v1/offers?apiKey=YOUR_API_KEY&apiSecret=YOUR_API_SECRET&userId=user_8812&country=US&platform=web&limit=10&sort=payout_desc"

Using PHP:

$response = Http::get('https://preads.hansaldev.com/api/v1/offers', [
    'apiKey'    => env('PREADS_API_KEY'),
    'apiSecret' => env('PREADS_API_SECRET'),
    'userId'    => $endUser->id,
    'limit'     => 20,
]);

if ($response->successful()) {
    $offers = $response->json('data');
} elseif ($response->status() === 401) {
    // wrong key or secret, or the app is not approved
} elseif ($response->status() === 422) {
    // $response->json('error.message') holds the per-field errors
}

Store the secret in your environment or secrets manager, never in your repository.

Rate limits

Scope Limit Counted by
JSON API (/api/v1/*) 60 per minute User ID if signed in, otherwise IP
Inbound network postback 300 per minute IP

Exceeding a limit returns 429. Cache responses rather than retrying immediately — offer lists change slowly and the API already caches internally for short periods.

Note that the offerwall iframe endpoints and /api/track are not rate limited. Do not build a server-side proxy that calls them per visitor; embed the wall directly instead.

Security checklist

  • Keep apiSecret server-side. Never in client-side code.
  • Serve your own pages over HTTPS.
  • Call the API from your backend with a short timeout and handle 429 with backoff.
  • Validate and cap the userId you generate — it becomes a key in your conversion records, and an unescaped value breaks tracking.
  • Do not treat postbacks as authenticated. See Postback Setup.
  • Rotate credentials by creating a new app if a secret is ever exposed, and update your tracking URLs — the API key changes with it.

Related documentation