Skip to main content

Job Endpoints

Execute scrapes and retrieve results via HTTP.

Create job

Create a new scrape job using a strategy.
POST /v1/jobs

Request body

{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products"
}

Response

{
  "job_id": "660e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "created_at": "2025-01-15T10:30:00Z"
}

Example

curl -X POST https://api.meter.sh/v1/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/products"
  }'

Execute job (synchronous)

Create a job and wait for completion. Returns results directly without polling.
POST /v1/jobs/execute

Request body

{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products"
}

Response

{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "status": "completed",
  "results": [
    {"name": "Product A", "price": "$19.99"},
    {"name": "Product B", "price": "$29.99"}
  ],
  "item_count": 2,
  "error": null,
  "started_at": "2025-01-15T10:30:01Z",
  "completed_at": "2025-01-15T10:30:08Z",
  "created_at": "2025-01-15T10:30:00Z"
}
This endpoint blocks until the job completes (up to 1 hour timeout). Use the async POST /v1/jobs endpoint for long-running scrapes or when you don’t need immediate results.

Example

curl -X POST https://api.meter.sh/v1/jobs/execute \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/products"
  }'

Error handling

If the job fails, the response will include the error:
{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "results": null,
  "error": "Connection timeout: target site did not respond",
  "completed_at": "2025-01-15T10:30:15Z"
}

Get job

Get job status and results.
GET /v1/jobs/{job_id}

Response

{
  "job_id": "660e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "results": [
    {"name": "Product A", "price": "$19.99"},
    {"name": "Product B", "price": "$29.99"}
  ],
  "item_count": 2,
  "content_hash": "7f3d9a2b4c1e...",
  "structural_signature": {...},
  "started_at": "2025-01-15T10:30:05Z",
  "completed_at": "2025-01-15T10:30:12Z",
  "created_at": "2025-01-15T10:30:00Z"
}
Status values: pending, running, completed, failed

Example

curl https://api.meter.sh/v1/jobs/660e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_..."

List jobs

List jobs with optional filtering.
GET /v1/jobs?strategy_id={id}&status={status}&limit=20&offset=0

Query parameters

ParameterTypeRequiredDescription
strategy_idstringNoFilter by strategy UUID
statusstringNoFilter by status
limitintegerNoMax results (default: 20)
offsetintegerNoResults to skip (default: 0)

Response

Array of job objects (same format as Get job).

Example

# All jobs
curl https://api.meter.sh/v1/jobs \
  -H "Authorization: Bearer sk_live_..."

# Filter by strategy
curl https://api.meter.sh/v1/jobs?strategy_id=550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_..."

# Only failed jobs
curl https://api.meter.sh/v1/jobs?status=failed \
  -H "Authorization: Bearer sk_live_..."

Compare jobs

Compare two jobs to detect changes.
POST /v1/jobs/compare

Request body

{
  "job_id": "660e8400-e29b-41d4-a716-446655440000",
  "other_job_id": "770e8400-e29b-41d4-a716-446655440000"
}

Response

{
  "content_hash_match": false,
  "structural_match": true,
  "semantic_similarity": 0.95,
  "changes": [
    "Item count changed: 10 -> 12",
    "Field 'price' changed in 3 items"
  ]
}

Example

curl -X POST https://api.meter.sh/v1/jobs/compare \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "job_id": "660e8400-e29b-41d4-a716-446655440000",
    "other_job_id": "770e8400-e29b-41d4-a716-446655440000"
  }'

Get strategy history

Get timeline of all jobs for a strategy.
GET /v1/strategies/{strategy_id}/history

Response

[
  {
    "job_id": "660e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "item_count": 12,
    "has_changes": true,
    "created_at": "2025-01-15T10:30:00Z"
  },
  {
    "job_id": "770e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "item_count": 10,
    "has_changes": false,
    "created_at": "2025-01-15T09:30:00Z"
  }
]

Example

curl https://api.meter.sh/v1/strategies/550e8400-e29b-41d4-a716-446655440000/history \
  -H "Authorization: Bearer sk_live_..."

Polling for completion

Use POST /v1/jobs/execute instead if you want synchronous behavior without polling.
Since jobs created with POST /v1/jobs run asynchronously, poll the Get job endpoint until status is completed or failed:
async function waitForJob(jobId) {
  while (true) {
    const response = await fetch(`https://api.meter.sh/v1/jobs/${jobId}`, {
      headers: {
        'Authorization': `Bearer ${process.env.METER_API_KEY}`
      }
    });

    const job = await response.json();

    if (job.status === 'completed') {
      return job.results;
    } else if (job.status === 'failed') {
      throw new Error(job.error);
    }

    // Wait 2 seconds before next check
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

Error responses

See REST API Errors for common error codes.

Next steps

Need help?

Email me at [email protected]