Skip to main content

Bulk Import

The import endpoint allows you to add multiple URLs for monitoring in a single request. This is ideal for initial setup or bulk migrations.

Import Watches

POST
endpoint
/api/v1/import
Import a list of URLs with optional shared configuration.

Request Body

The request body should be plain text with one URL per line:
https://example.com
https://example.org
https://example.net

Query Parameters

Special Parameters

tag
string
Tag name to apply to all imported watches
tag_uuids
string
Comma-separated tag UUIDs to apply to imported watches
proxy
string
Proxy configuration key to use for all imported watches
dedupe
boolean
default:true
Skip URLs that already exist in the system

Configuration Parameters

You can pass any watch configuration field as a query parameter. All parameters from the Watch schema are supported:
processor
string
Processor mode: text_json_diff or restock_diff
fetch_backend
string
Fetcher: system, html_requests, html_webdriver, extra_browser_*
paused
boolean
Import watches in paused state
notification_urls
string
Comma-separated notification URLs or JSON array format
time_between_check
string
JSON object with check interval: {"hours":1,"minutes":30}
include_filters
string
Comma-separated CSS/XPath selectors or JSON array

Type Conversion

Query parameters are automatically converted to the correct type:
TypeFormatExample
Booleantrue, false, 1, 0, yes, nopaused=true
ArrayComma-separated or JSONnotification_urls=url1,url2 or ["url1","url2"]
ObjectJSON formattime_between_check={"hours":1}
NumberInteger or floatwebdriver_delay=5
StringPlain texttitle=My+Watch

Examples

# Simple import with no configuration
curl -X POST "http://localhost:5000/api/v1/import" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  -d $'https://example.com\nhttps://example.org\nhttps://example.net'

Response

Small imports (< 20 URLs): Returns 200 OK with array of created UUIDs
[
  "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
  "7c9e6b8d-f2a1-4e5c-9d3b-8a7f6e4c2d1a",
  "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
]
Large imports (≥ 20 URLs): Returns 202 Accepted for background processing
{
  "status": "Importing 50 URLs in background",
  "count": 50
}
Imports with 20 or more URLs are processed in the background to avoid blocking the API. You’ll receive a 202 status immediately.

Advanced Import Scenarios

Import with JSON Configuration

For complex configurations, use JSON objects in query parameters:
curl -X POST "http://localhost:5000/api/v1/import" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  --data-urlencode 'time_between_check={"hours":2,"minutes":30}' \
  --data-urlencode 'headers={"Authorization":"Bearer token"}' \
  --data-urlencode 'notification_urls=["mailto:[email protected]","discord://webhook/token"]' \
  -d $'https://example.com'

Import from File

# Import URLs from a text file
curl -X POST "http://localhost:5000/api/v1/import?tag=production" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @urls.txt

Import with Multiple Tags

import requests

headers = {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'text/plain'
}

# Use tag_uuids for multiple tags
params = {
    'tag_uuids': '550e8400-e29b-41d4-a716-446655440000,330e8400-e29b-41d4-a716-446655440001',
    'processor': 'text_json_diff'
}

urls = 'https://example.com\nhttps://example.org'

response = requests.post(
    'http://localhost:5000/api/v1/import',
    headers=headers,
    params=params,
    data=urls
)

Import Product Monitors

For e-commerce/product monitoring with the restock_diff processor:
curl -X POST "http://localhost:5000/api/v1/import?processor=restock_diff&fetch_backend=html_webdriver" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  -d $'https://shop.example.com/product1\nhttps://shop.example.com/product2'

Deduplication

By default, the import endpoint skips URLs that already exist (dedupe=true).

Disable Deduplication

curl -X POST "http://localhost:5000/api/v1/import?dedupe=false" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  -d $'https://example.com\nhttps://example.com'  # Will create 2 watches
Disabling deduplication allows importing the same URL multiple times, which can be useful for monitoring the same URL with different configurations.

Validation

All URLs are validated before import:
  • Must use http://, https://, or ftp:// protocol
  • Must be a valid URL format
  • Must not be empty or whitespace-only

Invalid URLs

# This will fail with 400 error
curl -X POST "http://localhost:5000/api/v1/import" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: text/plain" \
  -d $'invalid-url\nfile:///etc/passwd\n'
Error Response:
Invalid or unsupported URL - invalid-url

Configuration Options

You can pass any of these watch configuration options as query parameters:
  • processor - Change detection processor
  • fetch_backend - Content fetcher
  • paused - Import in paused state
  • notification_muted - Mute notifications
  • method - HTTP method (GET, POST, etc.)
  • notification_urls - Notification endpoints
  • notification_title - Custom notification title
  • notification_body - Custom notification body
  • notification_format - Format (text, html, etc.)
  • notification_screenshot - Include screenshots
  • include_filters - CSS/XPath to extract
  • subtractive_selectors - CSS/XPath to remove
  • ignore_text - Text patterns to ignore
  • trigger_text - Required trigger patterns
  • text_should_not_be_present - Alert if found
  • time_between_check - Check interval
  • headers - Custom HTTP headers
  • body - HTTP request body
  • proxy - Proxy configuration
  • browser_steps - Browser automation steps
  • webdriver_delay - Browser wait time

Best Practices

Use Tags

Always assign imported watches to tags for easier management:
?tag=imported-2024-01

Start Paused

Import in paused state to review before activating:
?paused=true

Batch Size

For very large imports (100+ URLs), split into smaller batches to monitor progress.

Validate URLs

Clean and validate your URL list before import to avoid errors mid-import.

Import from CSV

If you have URLs in CSV format, extract the URL column first:
import csv
import requests

# Read URLs from CSV
with open('websites.csv', 'r') as f:
    reader = csv.DictReader(f)
    urls = [row['url'] for row in reader]

# Import
headers = {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'text/plain'
}

response = requests.post(
    'http://localhost:5000/api/v1/import',
    headers=headers,
    params={'tag': 'csv-import'},
    data='\n'.join(urls)
)

print(f"Imported {len(response.json())} watches")

Build docs developers (and LLMs) love