Authenticating with the Preads API, and the limits that apply.
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 |
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. |
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.
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.
| 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.
apiSecret server-side. Never in client-side code.429 with backoff.userId you generate — it becomes a key in your conversion
records, and an unescaped value breaks tracking.