API Reference
Complete API documentation with request/response examples and error handling.
Authentication & Security
InjectAPI uses API keys for authentication. All API requests must include your API key in the X-API-Key header.
API Key Format
API keys follow the format: ik_ followed by 32 alphanumeric characters.
# Example API key
ik_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6pYou can generate and manage your API keys from the Dashboard.
Using Your API Key
Include your API key in the X-API-Key header with every request:
curl -X POST https://api.injectapi.com/api/extract \
-H "X-API-Key: ik_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "mode": "product"}'Security Best Practices
1. Never Hardcode API Keys
Always use environment variables to store your API keys:
// ✅ Good - Use environment variables
const apiKey = process.env.INJECTAPI_KEY;
// ❌ Bad - Never commit API keys to version control
const apiKey = 'ik_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p';2. Use Different Keys for Different Environments
Generate separate API keys for development, staging, and production environments. This allows you to:
- Isolate usage and costs per environment
- Rotate production keys without affecting development
- Revoke compromised keys without disrupting other environments
3. Rotate Keys Regularly
Regenerate your API keys periodically (e.g., every 90 days) to minimize the impact of potential key exposure. InjectAPI allows you to have multiple active keys during rotation.
4. Restrict Key Usage
Monitor your API key usage in the dashboard and set up alerts for:
- Unusual traffic patterns
- Unexpected geographic locations
- Quota threshold warnings (80%, 90%, 100%)
5. Server-Side Only
⚠️ Important: Never expose your API keys in client-side code (JavaScript running in the browser). Always make API requests from your backend server.
// ✅ Good - Backend (Node.js server)
app.post('/api/scrape', async (req, res) => {
const response = await fetch('https://api.injectapi.com/api/extract', {
headers: { 'X-API-Key': process.env.INJECTAPI_KEY }
});
res.json(await response.json());
});
// ❌ Bad - Frontend (exposed in browser)
fetch('https://api.injectapi.com/api/extract', {
headers: { 'X-API-Key': 'ik_exposed_key_visible_to_users' } // DO NOT DO THIS!
});6. Revoke Compromised Keys Immediately
If you suspect your API key has been compromised, revoke it immediately from the dashboard and generate a new one.
POST /api/compare-prices
RecommendedCompare product prices across multiple retailers with a single API call. Ultra-fast with Redis caching.
POST https://api.injectapi.com/api/compare-pricesRequest Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
product | string | Yes | - | Product search query |
retailers | string[] | No | ["target", "ebay"] | Retailers to search |
maxResults | number | No | 10 | Max products per retailer (1-100) |
offset | number | No | 0 | Skip first N products (for incremental loading) |
includeAIAnalysis | boolean | No | false | Include AI-generated summary |
format | string | No | "grouped" | "grouped" or "flat" (use "flat" for per-product cache metadata) |
cacheCategory | string | No | "general" | Cache namespace ("general", "comparison", "wishlist", or custom) |
Incremental Loading Pattern
Use the offset parameter to load products in batches for better UX:
// Load first 10 products (3-4s)
const batch1 = await fetch('/api/compare-prices', {
method: 'POST',
body: JSON.stringify({
product: 'wireless headphones',
maxResults: 10,
offset: 0
})
});
// Load next 10 products (3-4s)
const batch2 = await fetch('/api/compare-prices', {
method: 'POST',
body: JSON.stringify({
product: 'wireless headphones',
maxResults: 10,
offset: 10 // Skip first 10
})
});Response Format
{
"success": true,
"query": "nintendo switch",
"results": [
{
"title": "Nintendo Switch OLED Model",
"price": 349.99,
"currency": "USD",
"url": "https://www.target.com/...",
"image": "https://...",
"availability": "In Stock",
"rating": 4.8,
"review_count": 1234,
"retailer": "target",
"product_id": "A-12345678",
"normalized_title": "Nintendo Switch OLED Model"
}
],
"metadata": {
"total_products": 8,
"retailers_searched": 2,
"retailers_successful": ["target", "ebay"],
"retailers_failed": [],
"response_time_ms": 3542,
"from_cache": false,
"cache_age_seconds": 0,
"cache_fresh": true
}
}Cache Headers
Every price comparison response includes cache status headers:
| Header | Values | Description |
|---|---|---|
X-Cache | HIT | MISS | Whether result was served from cache |
X-Cache-Age | number | Age of cached result in seconds |
X-Cache-Fresh | true | false | Whether cache is within freshness window (5 min) |
Examples
Target Only (Fastest - 3-4s)
curl -X POST https://api.injectapi.com/api/compare-prices \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"product": "ps5",
"retailers": ["target"]
}'All Retailers with Flat Format
const response = await fetch('https://api.injectapi.com/api/compare-prices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'YOUR_API_KEY'
},
body: JSON.stringify({
product: 'nintendo switch',
retailers: ['target', 'ebay'],
format: 'flat'
})
});
const data = await response.json();
// Check cache status
const cacheStatus = response.headers.get('X-Cache'); // 'HIT' or 'MISS'
const cacheAge = response.headers.get('X-Cache-Age'); // seconds
if (data.metadata.from_cache) {
console.log(`Cached result (${data.metadata.cache_age_seconds}s old)`);
}Performance
| Retailer | Response Time | Method |
|---|---|---|
| Target | 3-4s | DOM extraction (no AI) |
| eBay | 6-7s | AI extraction (Llama 3.1 8B) |
| Cached | <50ms | Redis (15min TTL) |
POST /api/extract
Extract structured data from any webpage using AI.
POST https://api.injectapi.com/api/extractHeaders
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | - | URL to scrape |
extract | boolean | No | true | Enable AI extraction (true = 5-10s, false = 1-2s) |
mode | string | No | general | Extraction mode (see below) |
waitFor | number | No | 0 | Wait time in ms for dynamic content |
customSchema | string | No | - | Custom extraction instructions |
Extraction Modes
general- Extract any structured dataproduct- E-commerce product pagesarticle- Blog posts and news articlesprofile- Social media profilescontact- Contact information pagessearch- Search results pages
Response Schemas by Mode
Each extraction mode returns different fields optimized for that content type.
Product Mode
Extracts structured product data from e-commerce pages:
{
"success": true,
"data": {
"title": "Apple AirPods Pro (2nd Generation)",
"price": 24999, // Price in cents
"currency": "USD",
"original_price": 29999, // Optional: original price if on sale
"discount_percentage": 17, // Optional: discount percentage
"availability": "In Stock",
"sku": "MTJV3AM/A",
"brand": "Apple",
"rating": 4.7,
"review_count": 50234,
"images": [
"https://m.media-amazon.com/images/I/61f1YfTkTDL.jpg"
],
"description": "Active Noise Cancellation...",
"features": [
"Active Noise Cancellation",
"Transparency mode",
"Adaptive Audio"
],
"variants": [ // Optional: product variants
{
"name": "Color",
"options": ["White"]
}
],
"shipping": { // Optional: shipping info
"free": true,
"estimated_delivery": "2-3 days"
}
},
"metadata": {
"url": "https://amazon.com/dp/B0CHWRXH8B",
"mode": "product",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 5234
}
}Article Mode
Extracts content from blog posts and news articles:
{
"success": true,
"data": {
"title": "The Future of Web Scraping in 2025",
"author": "Jane Smith",
"published_date": "2025-01-15T09:00:00Z",
"modified_date": "2025-01-16T14:30:00Z", // Optional
"content": "Full article text content...",
"excerpt": "A brief summary or excerpt...", // Optional
"image": "https://example.com/featured-image.jpg",
"tags": ["web scraping", "AI", "technology"],
"category": "Technology", // Optional
"reading_time_minutes": 8, // Optional
"word_count": 1850, // Optional
"language": "en" // Optional
},
"metadata": {
"url": "https://techcrunch.com/article-slug",
"mode": "article",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 4567
}
}Profile Mode
Extracts information from social media profiles and bio pages:
{
"success": true,
"data": {
"name": "John Doe",
"username": "johndoe",
"bio": "Software engineer and tech enthusiast...",
"avatar": "https://example.com/avatar.jpg",
"location": "San Francisco, CA",
"website": "https://johndoe.com",
"followers": 12500, // Optional
"following": 340, // Optional
"verified": true, // Optional
"social_links": { // Optional
"twitter": "https://twitter.com/johndoe",
"linkedin": "https://linkedin.com/in/johndoe",
"github": "https://github.com/johndoe"
}
},
"metadata": {
"url": "https://twitter.com/johndoe",
"mode": "profile",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 3890
}
}Contact Mode
Extracts contact information from business pages:
{
"success": true,
"data": {
"name": "Acme Corporation",
"emails": [
"contact@acme.com",
"support@acme.com"
],
"phones": [
"+1 (555) 123-4567",
"+1 (555) 987-6543"
],
"address": {
"street": "123 Main Street",
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"country": "USA"
},
"social_media": { // Optional
"facebook": "https://facebook.com/acme",
"twitter": "https://twitter.com/acme",
"linkedin": "https://linkedin.com/company/acme"
},
"hours": { // Optional
"monday": "9:00 AM - 5:00 PM",
"tuesday": "9:00 AM - 5:00 PM",
"friday": "9:00 AM - 3:00 PM"
}
},
"metadata": {
"url": "https://acme.com/contact",
"mode": "contact",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 4123
}
}Search Mode
Extracts results from search result pages:
{
"success": true,
"data": {
"query": "web scraping tools",
"results_count": 15,
"results": [
{
"title": "Top 10 Web Scraping Tools in 2025",
"url": "https://example.com/article",
"snippet": "Discover the best web scraping tools...",
"position": 1
},
{
"title": "Web Scraping with Python Tutorial",
"url": "https://example.com/tutorial",
"snippet": "Learn how to scrape websites using Python...",
"position": 2
}
],
"related_searches": [ // Optional
"python web scraping",
"beautiful soup tutorial"
],
"pagination": { // Optional
"current_page": 1,
"total_pages": 10
}
},
"metadata": {
"url": "https://google.com/search?q=web+scraping+tools",
"mode": "search",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 5678
}
}General Mode
Flexible extraction for any type of content. Returns dynamic fields based on page structure:
{
"success": true,
"data": {
// Dynamic fields based on page content
// Use customSchema for specific extraction requirements
"extracted_fields": {
"field1": "value1",
"field2": "value2"
}
},
"metadata": {
"url": "https://example.com",
"mode": "general",
"extracted": true,
"timestamp": "2025-01-21T10:30:00Z",
"processingTime": 4456
}
}Response Format
Success Response
{
"success": true,
"data": {
// Extracted data structure varies by mode
},
"metadata": {
"url": "string",
"mode": "string",
"extracted": boolean,
"timestamp": "ISO 8601",
"processingTime": number
}
}Error Response
{
"success": false,
"error": "Error message",
"metadata": {
"timestamp": "ISO 8601"
}
}Examples
Product Extraction
const response = await fetch('https://api.injectapi.com/api/extract', {
method: 'POST',
headers: {
'X-API-Key': 'ik_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://amazon.com/dp/B08N5WRWNW',
mode: 'product',
extract: true
})
});
const data = await response.json();
// {
// "success": true,
// "data": {
// "title": "Apple AirPods Pro",
// "price": 24900,
// "currency": "USD",
// "rating": 4.7,
// "reviews_count": 50234,
// ...
// }
// }Article Extraction
const response = await fetch('https://api.injectapi.com/api/extract', {
method: 'POST',
headers: {
'X-API-Key': 'ik_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://techcrunch.com/article-slug',
mode: 'article',
extract: true
})
});
const data = await response.json();
// {
// "data": {
// "title": "Article Title",
// "author": "Jane Doe",
// "published_date": "2025-01-15",
// "content": "Full article text...",
// "image": "https://...",
// ...
// }
// }Raw HTML (No Extraction)
const response = await fetch('https://api.injectapi.com/api/extract', {
method: 'POST',
headers: {
'X-API-Key': 'ik_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
extract: false // Faster, returns raw HTML
})
});
const data = await response.json();
console.log(data.data.html); // Raw HTML stringGET /api/compare-prices/retailers
Get a list of all supported retailers for price comparison.
GET https://api.injectapi.com/api/compare-prices/retailersResponse
{
"success": true,
"retailers": [
{ "id": "target", "name": "Target" },
{ "id": "ebay", "name": "eBay" }
]
}GET /api/scrape
Scrape HTML from a URL without AI extraction (faster, cheaper). Supports retailer-specific presets.
GET https://api.injectapi.com/api/scrape?url={url}&preset={preset}Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | URL to scrape |
preset | string | No | Scraping preset: target, ebay, walmart, bestbuy, default |
Response
{
"success": true,
"url": "https://www.target.com/...",
"html": "<html>...</html>",
"metadata": {
"preset": "target",
"response_time_ms": 1234
}
}GET /api/presets
Get all available extraction presets and their descriptions.
GET https://api.injectapi.com/api/presetsResponse
{
"success": true,
"presets": [
{
"id": "product",
"name": "Product",
"description": "Extract product information (title, price, rating, etc.)"
},
{
"id": "article",
"name": "Article",
"description": "Extract article content (title, author, publish date, content)"
},
{
"id": "profile",
"name": "Profile",
"description": "Extract social media profile information"
},
{
"id": "contact",
"name": "Contact",
"description": "Extract contact information (email, phone, address)"
},
{
"id": "search",
"name": "Search",
"description": "Extract search results"
}
]
}GET /api/health
Public - No Auth RequiredHealth check endpoint for monitoring system status and uptime.
GET https://api.injectapi.com/api/healthResponse
{
"status": "ok",
"timestamp": "2025-01-19T12:34:56.789Z",
"uptime": 12345,
"memory": {
"used": 123456789,
"total": 1073741824
}
}Error Handling
Understanding errors and how to handle them effectively.
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
200 | Success | Request successful, data extracted |
400 | Bad Request | Invalid parameters or malformed URL |
401 | Unauthorized | Invalid or missing API key |
402 | Payment Required | Insufficient credits |
429 | Rate Limit Exceeded | Too many requests |
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Target website failed to respond |
503 | Service Unavailable | OpenAI quota exceeded |
504 | Gateway Timeout | Request timed out (30s limit) |
Error Response Format
All error responses follow this format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"field": "parameter_name", // Optional, for validation errors
"retry_after_seconds": 45 // Optional, for rate limits
},
"metadata": {
"timestamp": "2025-01-15T10:30:00Z"
}
}Common Errors
401 Unauthorized
Invalid or missing API key:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}Solution: Check that you're passing X-API-Key header with a valid key.
429 Rate Limit Exceeded
You've exceeded your plan's rate limit:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please wait before making more requests",
"retry_after_seconds": 45,
"limit": 60,
"window": "1 minute"
}
}Solution: Wait for retry_after_seconds before retrying, or upgrade your plan.
402 Payment Required
Monthly credit limit exhausted:
{
"success": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "You have used all available credits for this billing period",
"credits_remaining": 0,
"next_reset": "2025-02-01T00:00:00Z"
}
}Solution: Upgrade plan or wait for monthly reset.
502 Bad Gateway
Target website failed to respond:
{
"success": false,
"error": {
"code": "UPSTREAM_ERROR",
"message": "Failed to fetch the requested URL",
"url": "https://example.com/product",
"status_code": 503
}
}Solution: The target website may be down or blocking requests. Try again later.
Retry Logic Best Practices
1. Check Status Code
const response = await fetch('https://api.injectapi.com/api/extract', options);
if (!response.ok) {
const error = await response.json();
console.error('API Error:', error);
throw new Error(error.error.message);
}
const data = await response.json();2. Implement Retry with Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
// Success
if (response.ok) {
return response.json();
}
// Rate limit - wait and retry
if (response.status === 429) {
const error = await response.json();
const waitTime = error.error.retry_after_seconds || 60;
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
continue;
}
// Server error - exponential backoff
if (response.status >= 500) {
const waitTime = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
// Client error - don't retry
throw new Error(`Request failed: ${response.status}`);
}
throw new Error('Max retries exceeded');
}3. Handle Specific Errors
try {
const response = await fetch('https://api.injectapi.com/api/extract', options);
const data = await response.json();
if (!response.ok) {
switch (response.status) {
case 401:
console.error('Invalid API key');
break;
case 402:
console.error('Insufficient credits - upgrade plan');
break;
case 429:
console.error('Rate limit exceeded - slow down');
break;
case 502:
case 504:
console.error('Target website unreachable - try later');
break;
default:
console.error('Unexpected error:', data.error.message);
}
}
} catch (error) {
console.error('Network error:', error);
}Rate Limits
Understanding request limits and quotas.
Limits by Plan
| Plan | Requests/Minute | Monthly Credits | Overage |
|---|---|---|---|
| Free | 10 RPM | 1,000 | Hard limit |
| Starter | 60 RPM | 25,000 | $3.00/1k |
| Professional | 300 RPM | 100,000 | $2.50/1k |
| Enterprise | Custom | Unlimited | Custom |
Rate Limit Headers
Every API response includes headers with your current rate limit status:
| Header | Description |
|---|---|
X-RateLimit-Limit | Your plan's rate limit (requests per minute) |
X-RateLimit-Remaining | Remaining requests in current window |
X-RateLimit-Reset | Unix timestamp when limit resets |
X-Credits-Remaining | Monthly credits remaining |
X-Credits-Reset | ISO 8601 timestamp when credits reset |
HTTP/2 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705334400
X-Credits-Remaining: 23450
X-Credits-Reset: 2025-02-01T00:00:00ZHandling Rate Limits
Monitor Headers
const response = await fetch('https://api.injectapi.com/api/extract', options);
// Check rate limit headers
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
console.log(`Requests remaining: ${remaining}`);
if (remaining < 5) {
console.warn('Approaching rate limit!');
}Request Queuing
class RateLimitedQueue {
constructor(requestsPerMinute) {
this.limit = requestsPerMinute;
this.requestTimes = [];
}
async enqueue(fn) {
// Wait if at limit
while (this.requestTimes.length >= this.limit) {
const oldestRequest = this.requestTimes[0];
const timeSinceOldest = Date.now() - oldestRequest;
if (timeSinceOldest < 60000) {
await new Promise(resolve =>
setTimeout(resolve, 60000 - timeSinceOldest)
);
}
// Remove requests older than 1 minute
this.requestTimes = this.requestTimes.filter(
time => Date.now() - time < 60000
);
}
this.requestTimes.push(Date.now());
return fn();
}
}
// Usage
const queue = new RateLimitedQueue(60); // 60 RPM for Starter plan
const results = await Promise.all(
urls.map(url => queue.enqueue(() => fetchData(url)))
);Historical Price Tracking
InjectAPI automatically stores every scraped product in PostgreSQL/TimescaleDB for historical price tracking, trend analysis, and competitive intelligence.
Overview
Every API call performs a dual-write to both Redis (ephemeral cache) and PostgreSQL (persistent storage). This enables you to build price tracking SaaS, market research dashboards, and arbitrage tools without additional storage infrastructure.
- Auto-Storage: Every scraped product is automatically stored with price, availability, rating, etc.
- 70-80% Data Completeness: High capture rate for price, availability, title, image, rating, reviews
- Daily Aggregates: Pre-computed min/max/avg prices per day
- Price Change Detection: Identify 24h price drops/increases for alerts
GET /api/price-history
Get full price history for a specific product URL.
GET https://api.injectapi.com/api/price-history?url=PRODUCT_URL&limit=100Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Full product URL |
limit | number | No | Max observations to return (default: 100) |
Example Request
curl "https://api.injectapi.com/api/price-history?url=https://www.target.com/p/nintendo-switch/A-12345&limit=100" \
-H "X-API-Key: YOUR_API_KEY"Response
{
"success": true,
"product": {
"id": 12345,
"url": "https://www.target.com/p/nintendo-switch/A-12345",
"title": "Nintendo Switch OLED Model",
"retailer": "target",
"first_seen_at": "2025-11-01T10:30:00Z",
"last_seen_at": "2025-11-19T15:45:00Z",
"times_scraped": 847
},
"price_history": [
{
"id": 98765,
"price": 349.99,
"currency": "USD",
"availability": "In Stock",
"rating": 4.8,
"review_count": 5234,
"scraped_at": "2025-11-19T10:30:00Z"
}
],
"metadata": {
"total_observations": 847,
"returned_observations": 100,
"earliest_observation": "2025-11-01T10:30:00Z",
"latest_observation": "2025-11-19T15:45:00Z"
}
}GET /api/price-history/daily
Get daily price aggregates (min/max/avg) for a product over the past N days.
GET https://api.injectapi.com/api/price-history/daily?url=PRODUCT_URL&days=30Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Full product URL |
days | number | No | Number of days to retrieve (default: 30) |
Response
{
"success": true,
"daily_stats": [
{
"day": "2025-11-19",
"min_price": 299.99,
"max_price": 349.99,
"avg_price": 324.99,
"closing_price": 299.99,
"sample_count": 8,
"last_availability": "in_stock"
}
]
}GET /api/price-history/latest
Get the most recent price observation for a product.
GET https://api.injectapi.com/api/price-history/latest?url=PRODUCT_URLResponse
{
"success": true,
"latest_price": {
"price": 299.99,
"currency": "USD",
"availability": "In Stock",
"rating": 4.8,
"review_count": 5234,
"scraped_at": "2025-11-19T15:45:00Z"
}
}GET /api/price-history/changes
Get recent price changes (24h drops/increases) across all tracked products.
GET https://api.injectapi.com/api/price-history/changes?retailer=target&limit=50Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
retailer | string | No | Filter by retailer |
limit | number | No | Max products to return (default: 50) |
Use Case: Price Drop Alerts
// Daily cron job: Check for price changes
const response = await fetch('/api/price-history/changes?retailer=amazon&limit=100');
const { data } = await response.json();
// Filter for significant drops (10%+)
const bigDrops = data.filter(product => product.price_change_pct < -10);
// Send alerts to users
bigDrops.forEach(product => {
sendPriceAlert(user, {
title: product.title,
oldPrice: product.price_24h_ago,
newPrice: product.current_price,
savings: product.price_change_amount
});
});GET /api/price-history/search
Search for products in the historical database.
GET https://api.injectapi.com/api/price-history/search?q=nintendo+switch&retailer=targetQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Yes | Search query (title search) |
retailer | string | No | Filter by retailer |
GET /api/price-history/stats
Get database statistics (total products, price observations, retailer breakdown).
GET https://api.injectapi.com/api/price-history/statsResponse
{
"success": true,
"stats": {
"totalProducts": 12453,
"totalPriceObservations": 45621,
"retailerBreakdown": {
"target": 5234,
"ebay": 4123,
"amazon": 3096
},
"oldestData": "2025-11-01T10:30:00Z",
"newestData": "2025-11-19T15:45:00Z"
}
}Use Cases
1. Price Tracking SaaS
Build a JungleScout or Keepa competitor with historical price data:
- Show 30-day price charts with min/max/avg
- Send price drop alerts when products hit target prices
- Track competitor pricing strategies
2. Market Research Dashboard
Analyze pricing trends across retailers:
- Compare average prices by retailer
- Identify seasonal pricing patterns
- Track availability changes
3. Arbitrage Tool
Find profitable arbitrage opportunities:
- Detect products with recent 20%+ price drops
- Cross-reference with other marketplaces
- Alert users to buying opportunities