Skip to main content
Fetch personalized offers via direct HTTP requests. Full control over when and how ads appear in your application. Base URL: https://zeroclick.dev

Authentication

All requests to /api/v2/offers require an API key:
x-zc-api-key: your-api-key
Get your API key from the Developer Dashboard.
The impressions endpoint (/api/v2/impressions) does not require authentication.

Integration Flow

1. Fetch offers     →  POST /api/v2/offers
2. Render in UI     →  Display offers to users
3. Track impressions →  POST /api/v2/impressions

Improving Offer Relevance

The query parameter helps match offers to user intent. ZeroClick will always return offers, but query quality directly impacts relevance. Best: Keywords
query: "running shoes marathon training"
Parse keywords from the user’s message for optimal relevance. Good: Full Message
query: "I'm running a marathon this fall and looking for new training shoes."
The full user message works but may be less precise than keywords. Foundation: Null
query: null
When there’s no relevant query, ZeroClick uses default context (including information about your product) and Signal Collection data to match offers. You’ll still get ads, just with broader targeting.
Better query = more relevant ads. Spend time extracting meaningful keywords from user messages when possible.

Server-Side Example

When calling from your backend, use method: "server" and forward the client’s IP and User-Agent.
// 1. Fetch offers
const response = await fetch("https://zeroclick.dev/api/v2/offers", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-zc-api-key": "your-api-key"
  },
  body: JSON.stringify({
    method: "server",
    ipAddress: clientIpAddress, // required
    userAgent: clientUserAgent, // recommended
    query: "best running shoes",
    limit: 3
  })
});

const offers = await response.json();

// 2. Render offers in your UI
offers.forEach(offer => {
  console.log(offer.title, offer.clickUrl, offer.price);
});

// 3. Track impressions (must be called from the client device)
await fetch("https://zeroclick.dev/api/v2/impressions", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    ids: offers.map(offer => offer.id)
  })
});
When calling from the browser, use method: "client". IP and User-Agent are extracted automatically from request headers.
Using method: "client" requires a public API key, since the key will be exposed in client-side code. Create a public key in the Developer Dashboard.
const response = await fetch("https://zeroclick.dev/api/v2/offers", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-zc-api-key": "your-public-api-key"
  },
  body: JSON.stringify({
    method: "client",
    query: "best running shoes",
    limit: 3
  })
});
Impression requests must originate from the end user’s device, not your server. Requests will be rate limited per IP.

Optional Parameters

Pass additional context for better personalization:
ParameterDescription
groupingIdSegment analytics by site or app
userIdStable user identifier for per-user tracking. Can be a hash — does not need to be your internal ID, just deterministic per user
userSessionIdStable session identifier. Can be a hash — does not need to be your internal session ID, just deterministic per session
userLocaleUser locale (e.g., en-US)
userEmailSha256SHA-256 hashed email for identity matching
userPhoneNumberSha256SHA-256 hashed phone for identity matching
signalsArray of real-time signals about the user’s current context

Real-Time Signals

You can pass signals directly in the offer request to describe what the user is currently engaging with. This provides additional context for offer matching and is stored for future personalization. Real-time signals are ideal for passing structured contextual data such as IAB Content Taxonomy categories, page-level context, or parsed user intent from your application.
const response = await fetch("https://zeroclick.dev/api/v2/offers", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-zc-api-key": "your-api-key"
  },
  body: JSON.stringify({
    method: "server",
    ipAddress: clientIpAddress,
    query: "best running shoes",
    limit: 3,
    signals: [
      {
        category: "interest",
        confidence: 0.85,
        subject: "Running & Jogging",
        relatedSubjects: ["Athletic Shoes", "Fitness Equipment"],
        sentiment: "positive",
        iab: {
          type: "content",
          version: "2.2",
          ids: ["607", "606", "604"]
        }
      }
    ]
  })
});
Each signal requires category, confidence, and subject. See the Signal Collection docs for the full field reference and more examples.
For standalone signal collection (without fetching offers), use the dedicated Signals API endpoint.

Next Steps