CompSniper Docs

Bulk Search API

Stream up to 20 independent eBay searches through one authenticated CompSniper request.

POST /v1/bulk-search accepts up to 20 unique keywords and streams each independent result as soon as it finishes. The server runs at most three searches concurrently.

Start a stream

cURL
curl -N --fail-with-body \
  -X POST "https://api.compsniper.com/v1/bulk-search" \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -H "Idempotency-Key: inventory-price-run-2026-09-02" \
  -d '{
    "keywords": [
      "Apple iPhone 14 128GB",
      "Shure SM7B",
      "Garmin 8612xsv"
    ],
    "options": {
      "count": 60,
      "ebaySite": "ebay.com",
      "relevance": true,
      "exactMatch": false
    }
  }'

Keywords are trimmed and deduplicated case-insensitively. Every keyword searches page 1 using the same options. Supported options match the main search endpoint except page, because each streamed result is one independently metered page.

Stream events

The response uses Content-Type: text/event-stream and emits:

  • start: run ID, total unique keywords, effective concurrency, replay state, combined CSV URL, and billing behavior.
  • result: one success or failure with its original input index and keyword. Successful rows include a per-keyword CSV URL.
  • complete: run ID, terminal status, total, succeeded and failed counts, replay state, and combined CSV URL.

Results can finish out of order. Use index to restore the submitted order.

SSE example
event: start
data: {"runId":"RUN_ID","total":3,"allocated":3,"quotaSkipped":0,"concurrency":3,"replayed":false,"combinedCsvUrl":"/v1/bulk-search/RUN_ID/download.csv"}

event: result
data: {"index":1,"keyword":"Shure SM7B","ok":true,"status":200,"response":{"totalItems":60},"csvUrl":"/v1/bulk-search/RUN_ID/download.csv?index=1"}

event: complete
data: {"runId":"RUN_ID","total":3,"succeeded":3,"failed":0,"status":"done","replayed":false}

Billing and failures

Before starting, the endpoint determines how many keywords fit the account's selected monthly and credit balance. If at least one fits, those first keywords run and every remaining keyword receives its own 429 quota_exceeded result event. The start event reports allocated and quotaSkipped. If none fit, the HTTP request returns 429 without creating a run.

Each successful allocated keyword uses monthly quota first, then one purchased credit, and includes remaining monthly and credit balances in the result event. Add X-Credit-Source: credits to fund the entire run from purchased credits. A failed keyword uses the same error contract as GET /v1/scrape and is not charged.

Allocation always follows input order. A later keyword is never run ahead of an earlier keyword merely because results complete out of order. Quota-skipped keywords are persisted with the run, replay with the same Idempotency-Key, and are excluded from CSV exports like other failed results.

Reuse the same Idempotency-Key and identical JSON body after a disconnect. Once the original run is terminal, CompSniper replays the stored start, result, and complete events without repeating searches or consuming quota. Reusing the key with a different body returns 409. Retrying while the original run is still active also returns 409, so wait briefly and retry the same key.

Run results and CSV exports remain available for 30 days.

Download CSV

The start and complete events include the combined CSV URL. Each successful result event includes a URL for only that keyword. Send the same account's bearer credential when downloading:

Combined CSV
curl --fail-with-body \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/bulk-search/RUN_ID/download.csv" \
  -o compsniper-bulk.csv
One keyword CSV
curl --fail-with-body \
  -H "Authorization: Bearer cs_live_REPLACEWITHYOURKEY" \
  "https://api.compsniper.com/v1/bulk-search/RUN_ID/download.csv?index=1" \
  -o shure-sm7b.csv

Sold and active bulk searches receive the appropriate CSV columns. Failed keywords are excluded from the combined export.

Node.js event reader

Node.js
const response = await fetch("https://api.compsniper.com/v1/bulk-search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.COMPSNIPER_API_KEY}`,
    "Content-Type": "application/json",
    Accept: "text/event-stream",
  },
  body: JSON.stringify({
    keywords: ["Apple iPhone 14 128GB", "Shure SM7B"],
    options: { count: 60, relevance: true },
  }),
});

if (!response.ok) throw new Error(await response.text());

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  const frames = buffer.split("\n\n");
  buffer = frames.pop() ?? "";
  for (const frame of frames) {
    const type = frame.match(/^event: (.+)$/m)?.[1];
    const raw = frame.match(/^data: (.+)$/m)?.[1];
    if (type && raw) console.log(type, JSON.parse(raw));
  }
}

On this page