beta
Documentation

Capture Batches

A capture batch captures every enabled page of one environment. Each page is a capture task.

Start a capture batch

endpoint
POST /api/v1/projects/{project_id}/environments/{environment_id}/capture-batches

Captures the environment's enabled pages now. No body. Minimum key role: Member.

shell
curl -X POST https://deploydiff.com/api/v1/projects/{project_id}/environments/{environment_id}/capture-batches \
  -H "Authorization: Bearer dd_…"

Answers 201 with the new capture_batch, tasks included, and its address in the Location header. The batch is PENDING, or already RUNNING: read it again to follow it — see Capture after a deploy.

StatuscodeWhen
404not_foundNo such environment in the project.
402usage_limit_reachedThe organization's usage limit is reached for the period.
402billing_blockedThe organization has an unpaid invoice that was cancelled.
429capture_intervalThe environment had a capture on demand too recently. retry_after gives the seconds to wait.
422not_runnableThe batch was created and ended in Error at once: no enabled page, or the domain is not validated. capture_batch_id names it, and the message says why.

The batch carries "trigger": "API", and counts in the environment's interval for captures on demand, together with those launched from the dashboard.

Read a capture batch

endpoint
GET /api/v1/projects/{project_id}/capture-batches/{capture_batch_id}

One capture_batch, with its tasks. Minimum key role: Participant.

List capture batches

endpoint
GET /api/v1/projects/{project_id}/environments/{environment_id}/capture-batches

The environment's capture batches, newest first, as a list of capture_batch objects without their tasks. Takes limit and cursor. Minimum key role: Participant.

?limit=1 reads the latest.

The capture_batch object

capture_batch
{
  "object": "capture_batch",
  "id": "00000000-0000-0000-0000-000000000002",
  "environment_id": "00000000-0000-0000-0000-000000000001",
  "environment_title": "Production",
  "status": "DONE",
  "trigger": "API",
  "error": null,
  "pages_over_plan_limit": null,
  "auto_diffs": {
    "settled_at": "2026-11-06T10:02:11.904Z",
    "self": {
      "status": "launched",
      "diff_batch_id": "00000000-0000-0000-0000-000000000004"
    },
    "reference": {
      "status": "launched",
      "diff_batch_id": "00000000-0000-0000-0000-000000000011"
    }
  },
  "task_counts": {
    "pending": 0,
    "running": 0,
    "done": 12,
    "error": 0
  },
  "tasks": [
    {
      "id": "00000000-0000-0000-0000-000000000005",
      "url": "https://example.com/pricing",
      "viewport": {
        "width": 1280,
        "height": 800
      },
      "page_title": "Pricing",
      "status": "DONE",
      "error_code": null
    }
  ],
  "created_at": "2026-11-06T10:00:00.31+00:00",
  "updated_at": "2026-11-06T10:02:11.904+00:00"
}
FieldTypeValue
environment_iduuid stringThe environment captured.
environment_titlestringIts name today.
statusstringPENDING, RUNNING, DONE, WARN or ERROR — see lifecycle. DONE, WARN and ERROR are final.
triggerstringWhat started it: MANUAL (from the dashboard), CRON (the environment's schedule), API (an API call).
errorobject | nullWhy the batch failed as a whole, when it did: code and message (see below). null otherwise. A page that fails does not fail the batch: see tasks.
pages_over_plan_limitnumber | nullHow many enabled pages the plan's limit per environment left out of this batch; null when none.
auto_diffsobject | nullWhat happened to its automatic diffs. null until it is settled, shortly after the batch ends.
task_countsobjectIts tasks by status: pending, running, done, error.
tasksarrayOne entry per page captured, by page title. Not in lists.
tasks[].iduuid stringThe capture task's id.
tasks[].urlstring | nullThe address captured.
tasks[].viewportobject | nullwidth and height in pixels, as captured.
tasks[].page_titlestring | nullThe page's title today; null once the page is deleted.
tasks[].statusstringPENDING, RUNNING, DONE or ERROR.
tasks[].error_codestring | nullWhy the capture failed — see when a page capture fails.

Batch errors

A batch in ERROR failed as a whole, before capturing any page: it has no tasks, and error says why. Test code in your code; show message to people as it is — it is written for them, and says what to do.

error.codeWhenerror.message
NO_ENABLED_PAGESThe environment has no enabled page."This environment has no enabled pages to capture."
DOMAIN_VALIDATION_FAILEDThe domain could not be validated.Names the domain and what was found there — HTTP 404, network error, no answer in time, a file too large or whose content is not the organization's id — or that it failed less than a minute ago and was not checked again; and the file to publish, as in the example below, unless the address is not a public domain name.
DOMAIN_VALIDATION_CHECK_FAILEDWe could not check the domain, on our side."The domain could not be checked because of an internal error, so no page was captured. Launch a new capture batch to try again."

A batch can also end in ERROR with error at null, when it could not be started on our side: start it again.

capture_batch
{
  "object": "capture_batch",
  "id": "00000000-0000-0000-0000-000000000013",
  "environment_id": "00000000-0000-0000-0000-000000000001",
  "environment_title": "Production",
  "status": "ERROR",
  "trigger": "API",
  "error": {
    "code": "DOMAIN_VALIDATION_FAILED",
    "message": "Domain https://example.com could not be validated (HTTP 404). Create /.well-known/deploy-diff-org-00000000-0000-0000-0000-000000000012.txt at your domain root containing exactly: 00000000-0000-0000-0000-000000000012"
  },
  "pages_over_plan_limit": null,
  "auto_diffs": {
    "settled_at": "2026-11-06T10:00:01.204Z",
    "self": {
      "status": "batch_failed"
    },
    "reference": {
      "status": "batch_failed"
    }
  },
  "task_counts": {
    "pending": 0,
    "running": 0,
    "done": 0,
    "error": 0
  },
  "tasks": [],
  "created_at": "2026-11-06T10:00:00.31+00:00",
  "updated_at": "2026-11-06T10:00:01.204+00:00"
}

auto_diffs

Once the batch has ended and its automated diffs have been started, or not, auto_diffs says what happened to each: self, the comparison with the environment's previous capture, and reference, the comparison with its reference environment. settled_at is when it was decided.

Each of the two is an object with a status, and a diff_batch_id when a diff batch was started:

statusMeaning
launchedA diff batch was started: diff_batch_id names it. It may end in Error, as when the reference environment has no capture yet.
not_configuredThis comparison is not set up on the environment.
no_previous_captureself on the environment's first capture: there is nothing earlier to compare with.
usage_blockedThe organization's usage limit was reached: no diff was started.
environment_deletedThe environment, its project or its organization was deleted.
batch_failedThe capture batch ended in Error before capturing anything.
failedNo diff could be started, on our side.
sweptThe batch was stopped by our safety net for stuck work, which starts no diff.

A diff started automatically has "trigger": "AUTO". To wait for a capture and its diffs, see Capture after a deploy.