ICON Developer Center

API reference

Affiliate API overview

Three calls: search with a lead, poll for results, submit the result the consumer chose.

#The three legs

  1. Search. POST /api/v1/engine/search with the lead, icon_campaign_id and icon_affiliate_id. ICON searches every active offer on that campaign (its own offers and the partner offers it calls), runs its duplicate, cap, eligibility and requirement checks, and answers with icon_lead_id (your search id) and the first results.
  2. Results. GET /api/v1/engine/results/{icon_lead_id} until processing_done is true. More results arrive while partner offers answer; wait poll_after_ms (about a second) between polls. A search stays open for up to 45 seconds.
  3. Submit. POST /api/v1/engine/leads with the icon_result_id the consumer chose, search_lead_id, the program, the answers to the result's form_fields and the consumer's consent. No need to send the lead again: ICON builds the submit on the lead of the search.
LegEndpointPage
1. SearchPOST /api/v1/engine/searchSearch
2. ResultsGET /api/v1/engine/results/{icon_lead_id}Results
3. SubmitPOST /api/v1/engine/leadsSubmit a lead
Optional pre-checkPOST /api/v1/engine/dupe-checkDuplicate pre-check
text
your server                                 ICON
    │  POST /engine/search (lead, campaign) ──▶  searches every active offer on the campaign
    │  ◀── icon_lead_id + first results ──────   duplicate, cap, eligibility, consent checks
    │  GET /engine/results/{icon_lead_id} ────▶  (repeat until processing_done)
    │  ◀── all results so far ────────────────
    │  POST /engine/leads (icon_result_id) ───▶  full checks again, then delivery
    │  ◀── status, reason, code, payout ──────

#What every result carries

The same core fields, whether the result is an ICON-hosted offer or a partner offer ICON calls: the result id to submit, the offer and its school (name and logo), the consent statement to show, the programs, the questions to ask (form_fields), your payout and an expiry. The full schema is on Results.

#Your payout

payout is your own payout for the result, per program where programs differ (programs[].payout). ICON never returns the offer's own price or anyone else's terms.

  • No payout is configured for your campaign: the payout key is absent.
  • A refused submit answers payout: 0.
  • An accepted submit answers the payout booked for that lead.

#Exclusivity

offer.offer_typeWhat an accepted submit means
sharedThe lead can be sold to up to max_accepted_submissions offers (3 today). Submit to several shared results if the consumer chose several.
exclusiveSold as an exclusive offer for its school. Unlike true exclusive, it does not end the lead's other sales.
true_exclusiveAn accepted submit ends the lead's other sales: later submits for the same search are refused.

Every search and results answer also carries accepted_count, max_accepted_submissions and true_exclusive_accepted so you can tell what can still be sold.

#Reposts and corrections

  • Sending a lead to an offer that already accepted it answers DUPLICATE (Duplicate - Offer). This is recognised when the repost carries the same search_lead_id (or, for a direct post, the icon_lead_id ICON returned).
  • Once a lead has been submitted, a request with your key that would change its data is refused (403, FORBIDDEN) and nothing is saved.
  • To correct a submitted lead, contact your ICON contact with its icon_lead_id.

#Conventions

  • JSON in, JSON out, UTF-8. Send Content-Type: application/json.
  • Ids are UUIDs unless stated. Times are ISO 8601 in UTC.
  • Additive changes: ICON adds fields to answers without notice. Ignore keys you do not use. Removals and renames are announced in the changelog.
  • Every answer carries status, reason and code (Standard responses).

Generated 2026-09-28 from ICON's API definitions. Every page is also available as Markdown; the index is llms.txt.