Idealo API: Get Merchant Offers Without Enriching Every Search Result

Published October 17, 2026

offers_count: 512 looks like enough data for a merchant-comparison screen. In the observed Idealo keyword result, that field sat beside offers: []. Request budgeting starts with understanding why those two fields can coexist, not with collecting every product's details.

512 offers counted does not mean 512 offer rows

The German iphone 16 search returned 36 found listing rows. The first listing, 204736899, counted 512 offers but supplied no individual merchant rows. This is intentional: search-by-term discovers products through IDs, names, images, minimum prices and offer counts. It does not populate shop-level offers.

To get merchant offers from search results, select a listing and submit its country and exact ID to search-by-id, then retrieve the new job. This Idealo API reads competitor-price observations. It does not upload your shop's offers; Idealo's official merchant API manages a shop's own listings instead. Neither a data lookup nor its completion changes shop prices or purchases anything.

Search once, enrich three IDs: at least eight calls

Every lookup has two necessary network actions: create the job, then retrieve its result. For one keyword search and N selected IDs, the lower bound is 2 × (1 + N) calls.

Selection policyCreate callsMinimum result readsMinimum total
Discovery only112
Discovery plus three selected IDs448
Discovery plus all 36 observed listings373774

These are network-call lower bounds, not credit quotations or latency guarantees. They assume the first retrieval sees a terminal result. Pending jobs require additional polls, and retries consume more calls. Check platform pricing separately; do not convert the table into a billing promise.

Choose an application-wide call budget that leaves room for pending results. If only three variants belong on a watchlist, enriching 33 other listings cannot improve that watchlist. An existing approved country-and-ID mapping can also avoid repeating keyword discovery at every refresh, provided you revalidate the returned product identity.

Choose country-and-ID pairs before requesting details

Keep country with the selected ID. The schemas accept only de and at; successful live observations covered Germany, not Austria. A similar product name across countries is not an identity join. Listing IDs are strings with their own validation: neither 0 nor a leading-zero ID is valid.

For the first discovery request, obtain your authorized platform key from the dashboard. Replace YOUR_API_KEY deliberately. The keyword below is a documented example, not a guarantee of today's matches. The key travels in the URL: keep full request URLs out of shared logs, screenshots and client-side bundles. Opening this guide, expanding a form or copying a command sends no request; running it does.

All four lookup POSTs expose one required string parameter named body. The gateway request wraps serialized JSON text, rather than sending country and values as separate top-level fields:

curl -X POST 'https://api.opendata-api.com/api/project/idealo/search-by-term?key=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data '{"body":"{\"country\":\"de\",\"values\":[\"iphone 16\"]}"}'

For a selected-ID job, use search-by-id and replace the inner phrase with that selected listing's ID. values must contain exactly one string; it is not a batch queue. Submitting the POST uses a request and creates a temporary collection job, not immediate product details.

The observed 20-offer ID lookup used 204771161, the 128GB black variant included in discovery, not the first listing 204736899. Its discovery row counted 82 offers. Those 20 returned rows establish neither complete merchant coverage nor a fixed response limit; they do not verify the first listing's 512 offers.

Let terminal job results release the next stage

Save the fresh job_id from creation and pass it to get-job. This retrieval remains a request even if the job is pending:

curl --get 'https://api.opendata-api.com/api/project/idealo/get-job?key=YOUR_API_KEY' \
  --data-urlencode 'job_id=FRESH_JOB_ID_FROM_CREATE'

Replace that placeholder with the current creation response, never a historical sample. Space polls, for example starting around five seconds, apply backoff, and stop at a deadline or total-call budget. Count creation, every poll and any resubmission against the workflow budget. Persist active IDs if a worker must resume rather than creating duplicate jobs.

Check HTTP status separately from the gateway's code, message and data business result. Gateway code 200 indicates gateway business success, but does not establish product success inside data. There are three distinct checkpoints:

  • error=false plus a job_id: the request was accepted.
  • Job pending, completed or failed: the collection lifecycle.
  • Each result's found, not_found or error: whether that row has usable product data.

A deliberately nonexistent phrase was accepted and later completed with summary.found=0, one not_found row and result:null. Completion did not find a product. Only reviewed found discovery rows should release ID-enrichment jobs. Fix a documented invalid_query item error instead of blindly resubmitting it; bound other retries.

The observed search had done=1 and total=1 but 36 found listing rows. Those counters describe the submitted work, not the output listing count or merchant coverage.

Compare delivered totals only after checking the product match

An EAN/GTIN lookup can start from a catalog barcode instead of a keyword. Keep its 8–14 digits as a string, preserving leading zeros. That formatting rule differs from the listing-ID rule, and a barcode match still needs product review.

The observed Nutella lookup for EAN 4008400401621 returned nine offers, including a 15 × 450g multipack despite classification:product_page_match and confidence:high. Those labels did not guarantee a single 450g jar. Check returned identity, variant and quantity before comparing anything monetary.

Then compare currency, price, shipping and delivered total, alongside condition and availability. Preserve null shipping rather than treating it as free delivery. Do not divide a multipack total into a unit price until its quantity is independently verified. A supplied low price is not a stock reservation or a checkout guarantee.

A known product URL is another documented input, but its country must match the request. search-by-url was not live-probed; successful ID and barcode jobs do not verify that separate route.

Keep fetched_at snapshots instead of assuming price history

Job output is temporary: collect it within one hour after completion. There is no built-in historical-price query here. For a price-monitoring application, store repeated approved snapshots with country, selected listing ID, query, operation and the product's fetched_at. Retain available offer identity and nullable fields. Keep job created_at separately; it is not the product observation time.

Refresh frequency is your own budget decision. Repeated readings can build a dated series, but gaps remain gaps, and missing products are negative observations rather than zero-priced stock. Returned rows are not guaranteed exhaustive. A passing ping would only mean liveness, not working collection or fresh prices; ping itself was not live-probed. No Idealo health check is enabled, and expired saved job IDs cannot serve as reusable collection controls.

Request-budget mistakes that produce misleading comparisons

  • Enriching all 36 listings by default: choose relevant country-and-ID pairs first; eight versus 74 calls is the lower-bound difference for three selections.
  • Equating offer counts with offer payloads: keyword offers=[] is expected, and detailed output need not contain every counted merchant.
  • Treating acceptance or completion as a match: require a usable found result; keep not_found, item errors and failed jobs distinct.
  • Batching several values or flattening the body: submit one serialized JSON string under body, containing exactly one value.
  • Ranking unlike products or unknown delivery costs together: check variants, multipacks, currency and null fields before comparing totals.
  • Budgeting only creations: reserve calls for spaced polling and collect the final snapshot before its one-hour retention window closes.