All endpoints (except /health) require Bearer authentication using the Authorization header:
Authorization: Bearer <your-api-key>
All shop-related endpoints support dual identifier access:
550e8400-e29b-41d4-a716-446655440000)cf1a0652-d4cd-4e6f-85a0-87d203578c35)You can use either identifier in any shop endpoint URL parameter. Custom UUIDs are optional and must be in valid UUID format if provided.
Check the health status of the application.
Endpoint: GET /health
Authentication: Not required
Response:
{
"status": "ok",
"timestamp": "2025-01-01T12:00:00.000Z",
"queue_stats": {
"total": 10,
"pending": 2,
"running": 1,
"completed": 6,
"failed": 1
}
}
Create a new scraping job for a webshop.
Endpoint: POST /api/jobs
Request Body:
{
"url": "https://example-shop.com",
"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35"
}
Fields:
url (required) - The main URL of the webshop to scrapecustom_id (optional) - Custom UUID identifier for the shop (must be unique)Response: 201 Created
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"shop_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "Job created successfully"
}
Error Responses:
400 Bad Request - Missing or invalid URL, or invalid custom_id format409 Conflict - custom_id is already in use500 Internal Server Error - Server errorExample:
curl -X POST http://localhost:3000/api/jobs \
-H "Authorization: Bearer your-secret-key" \
-H "Content-Type: application/json" \
-d '{"url": "https://example-shop.com"}'
Get the status and result of a specific job.
Endpoint: GET /api/jobs/:id
URL Parameters:
id - Job UUIDResponse:
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"created_at": "2025-01-01T12:00:00.000Z",
"updated_at": "2025-01-01T12:05:00.000Z",
"result": {
"initial_sitemap": "https://example-shop.com/sitemap.xml",
"shipping_informations": [
{
"url": "https://example-shop.com/shipping",
"content": "# Shipping Information\n\n..."
}
],
"contacts": [
{
"url": "https://example-shop.com/contact",
"content": "# Contact Us\n\n..."
}
],
"terms_of_conditions": [
{
"url": "https://example-shop.com/terms",
"content": "# Terms and Conditions\n\n..."
}
],
"faq": [
{
"url": "https://example-shop.com/faq",
"content": "# FAQ\n\n..."
}
]
}
}
Status Values:
pending - Job is waiting in queuerunning - Job is currently being processedcompleted - Job finished successfullyfailed - Job failed (includes error field)Error Responses:
404 Not Found - Job not found500 Internal Server Error - Server errorExample:
curl http://localhost:3000/api/jobs/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer your-secret-key"
Get a list of all jobs with queue statistics.
Endpoint: GET /api/jobs
Response:
{
"stats": {
"total": 10,
"pending": 2,
"running": 1,
"completed": 6,
"failed": 1
},
"jobs": [
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"sitemap_url": "https://example-shop.com",
"created_at": "2025-01-01T12:00:00.000Z",
"updated_at": "2025-01-01T12:05:00.000Z"
}
]
}
Example:
curl http://localhost:3000/api/jobs \
-H "Authorization: Bearer your-secret-key"
Get a list of all shops with their analytics.
Endpoint: GET /api/shops
Response:
{
"shops": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35",
"url": "https://example-shop.com",
"sitemap_url": "https://example-shop.com/sitemap.xml",
"webshop_type": "shopify",
"created_at": "2025-01-01T10:00:00.000Z",
"updated_at": "2025-01-01T12:00:00.000Z",
"analytics": {
"total_scrapes": 5,
"last_scraped_at": "2025-01-01T12:00:00.000Z",
"next_scrape_at": "2025-01-02T12:00:00.000Z",
"total_urls_found": 42,
"average_scrape_time": 5432.5,
"average_page_scrape_time": 234.8
}
}
]
}
Error Responses:
503 Service Unavailable - Database not available500 Internal Server Error - Server errorExample:
curl http://localhost:3000/api/shops \
-H "Authorization: Bearer your-secret-key"
Get detailed information about a specific shop including analytics, content metadata, scrape history, and scheduled jobs.
Endpoint: GET /api/shops/:id
URL Parameters:
id - Shop identifier (can use either internal UUID or custom_id)Response:
{
"shop": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35",
"url": "https://example-shop.com",
"sitemap_url": "https://example-shop.com/sitemap.xml",
"webshop_type": "shopify",
"created_at": "2025-01-01T10:00:00.000Z",
"updated_at": "2025-01-01T12:00:00.000Z"
},
"analytics": {
"total_scrapes": 5,
"last_scraped_at": "2025-01-01T12:00:00.000Z",
"next_scrape_at": "2025-01-02T12:00:00.000Z",
"total_urls_found": 42,
"average_scrape_time": 5432.5,
"average_page_scrape_time": 234.8
},
"content_metadata": {
"shipping_informations": [
{
"url": "https://example-shop.com/shipping",
"changed": false,
"last_updated": "2025-01-01T12:00:00.000Z"
}
],
"contacts": [
{
"url": "https://example-shop.com/contact",
"changed": true,
"last_updated": "2025-01-01T12:00:00.000Z"
}
],
"terms_of_conditions": [],
"faq": []
},
"scrape_history": [
{
"id": "history-uuid-1",
"job_id": "job-uuid-1",
"started_at": "2025-01-01T12:00:00.000Z",
"completed_at": "2025-01-01T12:05:00.000Z",
"status": "completed",
"error": null,
"scrape_time_ms": 5432,
"urls_found": 42
}
],
"scheduled_jobs": [
{
"id": "schedule-uuid-1",
"next_run_at": "2025-01-02T12:00:00.000Z",
"frequency": "daily",
"last_modified": "2025-01-01T10:00:00.000Z",
"status": "pending",
"enabled": true,
"created_at": "2025-01-01T10:00:00.000Z"
}
]
}
Notes:
/api/shops/:id/results endpointchanged flag indicates if content has changed since the previous scrapeError Responses:
404 Not Found - Shop not found503 Service Unavailable - Database not available500 Internal Server Error - Server errorExample:
curl http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer your-secret-key"
Get shop scraping results with full content. Supports filtering by date range, content type, and limit.
Endpoint: GET /api/shops/:id/results
URL Parameters:
id - Shop identifier (can use either internal UUID or custom_id)Query Parameters:
limit (optional) - Maximum number of results to returndate_from (optional) - Filter results from this date (ISO 8601 format)date_to (optional) - Filter results to this date (ISO 8601 format)content_type (optional) - Filter by content type: shipping, contacts, terms, or faqResponse:
{
"shop_id": "550e8400-e29b-41d4-a716-446655440000",
"filters": {
"limit": 10,
"date_from": "2025-01-01",
"date_to": null,
"content_type": null
},
"results": {
"shipping_informations": [
{
"url": "https://example-shop.com/shipping",
"content": "# Shipping Information\n\nDetailed shipping content...",
"changed": false,
"last_updated": "2025-01-01T12:00:00.000Z"
},
{
"url": "https://example-shop.com/delivery-info",
"content": "# Delivery Information\n\nDetailed delivery content...",
"changed": true,
"last_updated": "2025-01-01T12:00:00.000Z"
}
],
"contacts": [
{
"url": "https://example-shop.com/contact",
"content": "# Contact Us\n\nEmail: contact@example.com\nPhone: +1234567890",
"changed": true,
"last_updated": "2025-01-01T12:00:00.000Z"
}
],
"terms_of_conditions": [
{
"url": "https://example-shop.com/terms",
"content": "# Terms and Conditions\n\nDetailed terms...",
"changed": false,
"last_updated": "2025-01-01T12:00:00.000Z"
}
],
"faq": [
{
"url": "https://example-shop.com/faq",
"content": "# Frequently Asked Questions\n\nQ: Question 1?\nA: Answer 1...",
"changed": false,
"last_updated": "2025-01-01T12:00:00.000Z"
}
]
}
}
Notes:
changed flag indicates if content has changed since the previous scrapeError Responses:
404 Not Found - Shop not found503 Service Unavailable - Database not available500 Internal Server Error - Server errorExamples:
Get all results:
curl "http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/results" \
-H "Authorization: Bearer your-secret-key"
Get limited results:
curl "http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/results?limit=10" \
-H "Authorization: Bearer your-secret-key"
Get results from a specific date:
curl "http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/results?date_from=2025-01-01" \
-H "Authorization: Bearer your-secret-key"
Get only shipping information:
curl "http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/results?content_type=shipping" \
-H "Authorization: Bearer your-secret-key"
Get results with date range and limit:
curl "http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/results?date_from=2025-01-01&date_to=2025-01-31&limit=50" \
-H "Authorization: Bearer your-secret-key"
Set or update the custom ID for a shop.
Endpoint: PATCH /api/shops/:id/custom-id
URL Parameters:
id - Shop identifier (can use either internal UUID or custom_id)Request Body:
{
"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35"
}
Fields:
custom_id - Custom UUID identifier for the shop (set to null to remove)Response:
{
"shop_id": "550e8400-e29b-41d4-a716-446655440000",
"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35",
"message": "Custom ID set to cf1a0652-d4cd-4e6f-85a0-87d203578c35"
}
Error Responses:
400 Bad Request - Invalid custom_id format404 Not Found - Shop not found409 Conflict - custom_id is already in use503 Service Unavailable - Database not available500 Internal Server Error - Server errorExample:
curl -X PATCH http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/custom-id \
-H "Authorization: Bearer your-secret-key" \
-H "Content-Type: application/json" \
-d '{"custom_id": "cf1a0652-d4cd-4e6f-85a0-87d203578c35"}'
Enable or disable scheduled scraping for a shop.
Endpoint: PATCH /api/shops/:id/schedule
URL Parameters:
id - Shop identifier (can use either internal UUID or custom_id)Request Body:
{
"enabled": true
}
Response:
{
"shop_id": "550e8400-e29b-41d4-a716-446655440000",
"schedule_enabled": true,
"message": "Schedule enabled successfully"
}
Error Responses:
400 Bad Request - Missing or invalid enabled field404 Not Found - Shop not found503 Service Unavailable - Database not available500 Internal Server Error - Server errorExamples:
Enable scheduling:
curl -X PATCH http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/schedule \
-H "Authorization: Bearer your-secret-key" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'
Disable scheduling:
curl -X PATCH http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000/schedule \
-H "Authorization: Bearer your-secret-key" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
Delete a shop and all related data (analytics, scrape history, content, scheduled jobs).
Endpoint: DELETE /api/shops/:id
URL Parameters:
id - Shop identifier (can use either internal UUID or custom_id)Response:
{
"message": "Shop and all related data deleted successfully",
"shop_id": "550e8400-e29b-41d4-a716-446655440000"
}
Notes:
Error Responses:
404 Not Found - Shop not found503 Service Unavailable - Database not available500 Internal Server Error - Server errorExample:
curl -X DELETE http://localhost:3000/api/shops/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer your-secret-key"
All endpoints return standard HTTP status codes:
200 OK - Request successful201 Created - Resource created successfully400 Bad Request - Invalid request parameters404 Not Found - Resource not found500 Internal Server Error - Server error503 Service Unavailable - Service (e.g., database) unavailableError responses include a JSON body with an error field:
{
"error": "Description of the error"
}
The scraper categorizes content into four types:
Each category can contain multiple pages (returned as arrays).
The application automatically schedules scraping based on sitemap rules:
always, hourly, daily, weekly, monthly, yearlyThe system uses MD5 hashing to detect content changes:
changed flag set to true if hashes differ