Checkbox Docs

Compliance plans API

The agent-to-agent fix loop: an ordered, machine-readable plan of changes (requirement + citation, where, the exact patch / copy / Stripe params, how to verify), verification of each change, and questions for the human where a machine cannot decide.

OperationEndpoint
Get the compliance plan for a siteGET /v1/sites/{site}/plan
Get one task of a compliance planGET /v1/tasks/{task}
Claim, decline or reopen a taskPOST /v1/tasks/{task}
Record the human answer to a manual taskPOST /v1/tasks/{task}/answer
Verify a task after applying its changePOST /v1/tasks/{task}/verify
Re-check the whole site nowPOST /v1/sites/{site}/verify
Get a verification (long-poll with ?wait=30)GET /v1/verifications/{verification}
List verifications of a siteGET /v1/sites/{site}/verifications

The CompliancePlan object

The ordered, machine-readable list of changes that makes a site compliant, recomputed from its latest evaluation.

FieldTypeDescription
idstringUnique identifier of the compliance plan (plan_…).
objectenumString representing the object's type. Always "compliance_plan".
livemodebooleantrue for live-mode objects, false for test mode (ck_test_ keys act on an isolated sandbox).
sitestringThe site.
statusenumaction_required (an agent can apply open tasks now), verifying (changes applied; waiting for confirming observations), compliant (every required check passes or only waits for a live check — an automated assessment, not a legal determination; see compliance.pending_live_checks and coverage), blocked (only human answers ("Your call") or declined critical tasks remain). One of action_required, verifying, compliant, blocked.
evaluationstring | nullThe evaluation the plan was built from (null before the first check).
evaluatedinteger | nullWhen that evaluation ran. Unix timestamp in seconds.
summarystringTwo or three sentences for an LLM: where the site stands and what comes next.
countsobjectTasks per status.
counts.openintegerOpen tasks.
counts.in_progressintegerClaimed tasks.
counts.verifyingintegerTasks waiting for a confirming observation.
counts.manualintegerTasks waiting for a human answer.
counts.pending_live_checkintegerTasks that only wait for a live observation (count as compliant).
counts.doneintegerDone tasks.
counts.wont_fixintegerDeclined tasks.
tasksarray of TasksTasks in the order to do them (done tasks last).
protection_levelenumThe site's protection level: minimum lists required tasks only; balanced adds recommended suggestions; maximum adds extras. Only required tasks change the plan status. One of minimum, balanced, maximum.
groupsobjectTask ids grouped by tier, in plan order.
groups.requiredarray of stringsRequired tasks (the legal floor).
groups.recommendedarray of stringsRecommended suggestions (never block compliant).
groups.extraarray of stringsExtra protections (maximum only).
complianceComplianceRollup | nullRoll-up of the user-facing statuses of the required checks.
coverageobjectWhat the assessment rests on. Tell the human about not_observed and attested items; never call the site "compliant" without them.
coverage.observedarray of stringsLifecycle stages Checkbox observed (signup, acknowledgment_email, reminders, cancellation, policies, billing_settings).
coverage.not_observedarray of stringsStages Checkbox has no observation of: their checks cannot fail, so passing says nothing about them.
coverage.attestedarray of stringsTask keys resting on a human confirmation instead of an observation.
coverage.billing_connectedbooleanA billing platform is connected (dashboard).
next_actionPlanNextActionWhat the caller (usually an AI coding agent) should do next.
email_verificationarray of objectsEvidence level per required email kind. A plan is never compliant on template_checked emails.
rules_versionstring | nullRules / catalog version of the evaluation.
disclaimerstringAutomated assessment; not legal advice.
generatedintegerWhen the plan was computed. Unix timestamp in seconds.
unverified_scanUnverifiedScan | nullWhile the domain is not verified: the newest read-only scan of the site's own public pages (labeled "unverified scan": no checkout submitted, not evidence, replaced by the full scan after verification). Null otherwise.
optional_improvementsobjectOptional improvements beyond compliance. Never tasks, never blocking, never counted toward compliance.
optional_improvements.conversion_suggestionsobjectCompliant conversion suggestions for this site.

Get the compliance plan for a site

GET /v1/sites/{site}/plan

Ordered tasks that make the site compliant, recomputed from its latest evaluation: each with the requirement and citation, where to change (file / URL / selector / Stripe object), the exact change (unified-diff template with machine-applicable edits, copy, or Stripe params) and how to verify it. Do plan.next_action: apply the first open task, call verifyTask, repeat until status is compliant. Tasks with status manual hold a question for the human (answerTask); they never block the others.

Scope compliance_plans:read · Operation retrieveCompliancePlan

SDK: checkbox.plans.retrieve() (Node) · checkbox.plans.retrieve() (Python). MCP / agents: operation retrieveCompliancePlan.

Parameters

ParameterInTypeDescription
site requiredpathstringUnique identifier of the site (site_…).

Returns

Returns a CompliancePlan object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/plan \
  -u "$CHECKBOX_SECRET_KEY:"
Response
{
  "id": "plan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "compliance_plan",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "status": "action_required",
  "evaluation": "eval_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "evaluated": 1793318400,
  "summary": "StreamMax fails 4 critical checks…",
  "counts": {
    "open": 3,
    "in_progress": 0,
    "verifying": 1,
    "manual": 1,
    "pending_live_check": 2,
    "done": 2,
    "wont_fix": 0
  },
  "tasks": [
    {
      "id": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "object": "task",
      "livemode": false,
      "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "key": "signup_disclosure",
      "title": "Show the renewal terms and an unchecked consent box above the Subscribe button",
      "status": "open",
      "priority": "critical",
      "tier": "required",
      "compliance_status": "pending_live_check",
      "order": 1,
      "check_ids": [
        "signup.disclosure.autorenew_language"
      ],
      "findings": [],
      "requirement": {
        "jurisdictions": [
          "US-FED"
        ],
        "citation": "15 U.S.C. § 8403(1); Cal. Bus. & Prof. Code § 17602(a)(1)",
        "citations": [
          {
            "id": "US-CA.17602.a.1",
            "jurisdiction": "US-CA",
            "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
            "source_url": "https://leginfo.legislature.ca.gov/"
          }
        ],
        "plain_language": "Before the purchase, state clearly that the subscription renews automatically until canceled, the price and frequency, and how to cancel."
      },
      "why": "The checkout in US-CA shows no renewal terms near \"Start now\"; the consent checkbox is pre-checked.",
      "where": {
        "kind": "code",
        "file_hint": "app/checkout/page.tsx",
        "url": "https://shop.example/checkout",
        "selector": "#subscribe-button",
        "stripe_object": "checkout.session"
      },
      "change": {
        "type": "patch",
        "content": "--- a/app/checkout/page.tsx\n+++ b/app/checkout/page.tsx\n@@ …",
        "language": "html",
        "explanation": "Insert directly above the purchase button; never pre-check the box.",
        "edits": [
          {
            "op": "insert_before",
            "target": {},
            "content": "<div class=\"checkbox-renewal-terms\">…</div>",
            "attribute": "checked"
          }
        ],
        "engine_verified": true,
        "operation_id": "updateSite",
        "endpoint": "POST /v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
      },
      "verify": {
        "method": "page_fetch",
        "how": "POST /v1/tasks/task_…/verify",
        "expected": "Every listed check passes (layout checks may stay needs_review on a static fetch until the confirming scan)."
      },
      "blocked_on": null,
      "closed_reason": null,
      "depends_on": [],
      "blocked_by": [],
      "question": {
        "text": "Did your subscribers choose email as the channel for account notices?",
        "options": [
          "yes"
        ],
        "why": "New York requires notices in the manner the subscriber selected; no page or email shows that choice.",
        "effect": "yes records the attestation (site fact notice_channel_email) and re-evaluates."
      },
      "answer": {
        "value": "yes",
        "note": null,
        "answered": 1793318400,
        "confirmed_by_human": false,
        "pending_confirmation_url": null
      },
      "decision": {
        "status": "wont_fix",
        "reason": "Annual plan retired; no subscribers left."
      },
      "last_verification": {
        "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
        "status": "failed",
        "created": 1793318400
      },
      "next_action": {
        "type": "apply_task",
        "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
        "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
        "operation_id": "verifyTask",
        "mcp_tool": "verify_task",
        "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
        "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
      },
      "verification_level": "template_checked",
      "first_seen": 1793318400,
      "done_at": 1793318400
    }
  ],
  "protection_level": "balanced",
  "groups": {
    "required": [],
    "recommended": [],
    "extra": []
  },
  "compliance": {
    "status": "compliant",
    "label": "Compliant · 2 live checks pending",
    "counts": {
      "needs_fix": 0,
      "your_call": 0,
      "pending_live_check": 2,
      "verified_live": 3,
      "compliant": 9,
      "not_applicable": 6,
      "not_set_up": 0,
      "not_checked": 0
    },
    "pending_live_checks": [
      {
        "what": "Your acknowledgment email, seen sent for a real sign-up",
        "completes": "Run a proof, or BCC your real acknowledgment emails to your Checkbox inbound address.",
        "action": "bcc_real_sends",
        "due": "2026-11-20"
      }
    ],
    "suggestions": 1,
    "checkouts": [
      {
        "name": "Annual",
        "kind": "payment_link",
        "plan": "Annual",
        "status": "pending_live_check",
        "label": "Needs a fix",
        "open": [
          {
            "check_id": "signup.disclosure.price",
            "title": "recurring charge is stated",
            "status": "pending_live_check"
          }
        ]
      }
    ]
  },
  "coverage": {
    "observed": [
      "signup"
    ],
    "not_observed": [
      "cancellation"
    ],
    "attested": [],
    "billing_connected": false
  },
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "email_verification": [
    {
      "kind": "acknowledgment",
      "verification_level": "template_checked",
      "reason": "Not seen sent yet: Checkbox has only a template or sample of this email, not a copy sent for a real event — run a proof test or BCC real sends.",
      "email": null,
      "basis": null
    }
  ],
  "rules_version": "1.2.0",
  "disclaimer": "Checkbox checks against its legal catalog; it is not legal advice.",
  "generated": 1793318400,
  "unverified_scan": {
    "id": "uscan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "object": "unverified_scan",
    "unverified": true,
    "label": "unverified scan",
    "status": "completed",
    "created": 1793318400,
    "finished": 1793318400,
    "pages": [],
    "findings": [],
    "counts": {
      "pages_captured": 6,
      "pages_skipped": 1,
      "failing": 2,
      "needs_review": 1,
      "passing": 9
    },
    "error": null,
    "note": "Unverified scan: Checkbox only loaded public pages of this site…"
  },
  "optional_improvements": {
    "conversion_suggestions": {
      "description": "Optional, compliant ways to make the checkout and emails convert better. Never blocking; never counted toward compliance.",
      "blocking": false,
      "counts_toward_compliance": false,
      "operation_id": "listSiteSuggestions",
      "mcp_tool": "suggest_improvements",
      "endpoint": "GET /v1/sites/site_123/suggestions"
    }
  }
}

Get one task of a compliance plan

GET /v1/tasks/{task}

The task as in the current plan (recomputed): the change to apply, how to verify, its last verification and next_action.

Scope compliance_plans:read · Operation retrieveTask

SDK: checkbox.tasks.retrieve() (Node) · checkbox.tasks.retrieve() (Python). MCP / agents: operation retrieveTask.

Parameters

ParameterInTypeDescription
task requiredpathstringUnique identifier of the task (task_…).

Returns

Returns a Task object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:"
Response
{
  "id": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "task",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "key": "signup_disclosure",
  "title": "Show the renewal terms and an unchecked consent box above the Subscribe button",
  "status": "open",
  "priority": "critical",
  "tier": "required",
  "compliance_status": "pending_live_check",
  "order": 1,
  "check_ids": [
    "signup.disclosure.autorenew_language",
    "signup.consent.affirmative"
  ],
  "findings": [],
  "requirement": {
    "jurisdictions": [
      "US-FED"
    ],
    "citation": "15 U.S.C. § 8403(1); Cal. Bus. & Prof. Code § 17602(a)(1)",
    "citations": [
      {
        "id": "US-CA.17602.a.1",
        "jurisdiction": "US-CA",
        "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
        "source_url": "https://leginfo.legislature.ca.gov/"
      }
    ],
    "plain_language": "Before the purchase, state clearly that the subscription renews automatically until canceled, the price and frequency, and how to cancel."
  },
  "why": "The checkout in US-CA shows no renewal terms near \"Start now\"; the consent checkbox is pre-checked.",
  "where": {
    "kind": "code",
    "file_hint": "app/checkout/page.tsx",
    "url": "https://shop.example/checkout",
    "selector": "#subscribe-button",
    "stripe_object": "checkout.session"
  },
  "change": {
    "type": "patch",
    "content": "--- a/app/checkout/page.tsx\n+++ b/app/checkout/page.tsx\n@@ …",
    "language": "html",
    "explanation": "Insert directly above the purchase button; never pre-check the box.",
    "edits": [
      {
        "op": "insert_before",
        "target": {
          "selector": "#subscribe-button",
          "text": "Start now",
          "tag": "button"
        },
        "content": "<div class=\"checkbox-renewal-terms\">…</div>",
        "attribute": "checked"
      }
    ],
    "engine_verified": true,
    "operation_id": "updateSite",
    "endpoint": "POST /v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verify": {
    "method": "page_fetch",
    "how": "POST /v1/tasks/task_…/verify",
    "expected": "Every listed check passes (layout checks may stay needs_review on a static fetch until the confirming scan)."
  },
  "blocked_on": null,
  "closed_reason": null,
  "depends_on": [],
  "blocked_by": [],
  "question": {
    "text": "Did your subscribers choose email as the channel for account notices?",
    "options": [
      "yes"
    ],
    "why": "New York requires notices in the manner the subscriber selected; no page or email shows that choice.",
    "effect": "yes records the attestation (site fact notice_channel_email) and re-evaluates."
  },
  "answer": {
    "value": "yes",
    "note": null,
    "answered": 1793318400,
    "confirmed_by_human": false,
    "pending_confirmation_url": null
  },
  "decision": {
    "status": "wont_fix",
    "reason": "Annual plan retired; no subscribers left."
  },
  "last_verification": {
    "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "failed",
    "created": 1793318400
  },
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verification_level": "template_checked",
  "first_seen": 1793318400,
  "done_at": 1793318400
}

Claim, decline or reopen a task

POST /v1/tasks/{task}

status in_progress claims the task (shown to other agents and the dashboard); wont_fix declines it with a reason (the merchant's decision, recorded; a declined critical or high task keeps the plan blocked); open clears the decision. Applying a change does not need this call: call verifyTask.

Scope compliance_plans:write · Idempotent (send Idempotency-Key) · Operation updateTask

SDK: checkbox.tasks.update() (Node) · checkbox.tasks.update() (Python). MCP / agents: operation updateTask.

Parameters

ParameterInTypeDescription
task requiredpathstringUnique identifier of the task (task_…).

Body

FieldTypeDescription
status requiredenumin_progress claims the task (other agents see it), wont_fix declines it (needs reason; a declined critical/high task keeps the plan from being compliant), not_applicable records that the task does not apply to this business (needs reason, e.g. "no price changes are planned"; the task closes as no_longer_applicable and does not block the plan), open clears any of them. One of open, in_progress, wont_fix, not_applicable.
reasonstringWhy (required for wont_fix).

Returns

Returns a Task object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "in_progress"
}'
Response
{
  "id": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "task",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "key": "signup_disclosure",
  "title": "Show the renewal terms and an unchecked consent box above the Subscribe button",
  "status": "open",
  "priority": "critical",
  "tier": "required",
  "compliance_status": "pending_live_check",
  "order": 1,
  "check_ids": [
    "signup.disclosure.autorenew_language",
    "signup.consent.affirmative"
  ],
  "findings": [],
  "requirement": {
    "jurisdictions": [
      "US-FED"
    ],
    "citation": "15 U.S.C. § 8403(1); Cal. Bus. & Prof. Code § 17602(a)(1)",
    "citations": [
      {
        "id": "US-CA.17602.a.1",
        "jurisdiction": "US-CA",
        "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
        "source_url": "https://leginfo.legislature.ca.gov/"
      }
    ],
    "plain_language": "Before the purchase, state clearly that the subscription renews automatically until canceled, the price and frequency, and how to cancel."
  },
  "why": "The checkout in US-CA shows no renewal terms near \"Start now\"; the consent checkbox is pre-checked.",
  "where": {
    "kind": "code",
    "file_hint": "app/checkout/page.tsx",
    "url": "https://shop.example/checkout",
    "selector": "#subscribe-button",
    "stripe_object": "checkout.session"
  },
  "change": {
    "type": "patch",
    "content": "--- a/app/checkout/page.tsx\n+++ b/app/checkout/page.tsx\n@@ …",
    "language": "html",
    "explanation": "Insert directly above the purchase button; never pre-check the box.",
    "edits": [
      {
        "op": "insert_before",
        "target": {
          "selector": "#subscribe-button",
          "text": "Start now",
          "tag": "button"
        },
        "content": "<div class=\"checkbox-renewal-terms\">…</div>",
        "attribute": "checked"
      }
    ],
    "engine_verified": true,
    "operation_id": "updateSite",
    "endpoint": "POST /v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verify": {
    "method": "page_fetch",
    "how": "POST /v1/tasks/task_…/verify",
    "expected": "Every listed check passes (layout checks may stay needs_review on a static fetch until the confirming scan)."
  },
  "blocked_on": null,
  "closed_reason": null,
  "depends_on": [],
  "blocked_by": [],
  "question": {
    "text": "Did your subscribers choose email as the channel for account notices?",
    "options": [
      "yes"
    ],
    "why": "New York requires notices in the manner the subscriber selected; no page or email shows that choice.",
    "effect": "yes records the attestation (site fact notice_channel_email) and re-evaluates."
  },
  "answer": {
    "value": "yes",
    "note": null,
    "answered": 1793318400,
    "confirmed_by_human": false,
    "pending_confirmation_url": null
  },
  "decision": {
    "status": "wont_fix",
    "reason": "Annual plan retired; no subscribers left."
  },
  "last_verification": {
    "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "failed",
    "created": 1793318400
  },
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verification_level": "template_checked",
  "first_seen": 1793318400,
  "done_at": 1793318400
}

Record the human answer to a manual task

POST /v1/tasks/{task}/answer

For tasks with status manual: record the human's answer to task.question (ask them; never answer on their behalf). Answers that assert a legal fact (yes, confirmed) are stored as a proposal and return next_action.type "ask_human_to_confirm" with a link the human opens while signed in to Checkbox; only their confirmation writes the attestation, sets the site fact and re-evaluates. no / needs_change turn the task into a change for the agent; done (after a dashboard-only step) re-checks at once. Every answer is stored in the evidence vault.

Scope compliance_plans:write · Idempotent (send Idempotency-Key) · Operation answerTask

SDK: checkbox.tasks.answer() (Node) · checkbox.tasks.answer() (Python). MCP / agents: operation answerTask.

Parameters

ParameterInTypeDescription
task requiredpathstringUnique identifier of the task (task_…).

Body

FieldTypeDescription
answer requiredstringOne of the task's question.options (yes / no, or confirmed / needs_change).
notestringContext from the human (stored with the attestation).

Returns

Returns a Task object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/answer \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
  "answer": "yes"
}'
Response
{
  "id": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "task",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "key": "signup_disclosure",
  "title": "Show the renewal terms and an unchecked consent box above the Subscribe button",
  "status": "open",
  "priority": "critical",
  "tier": "required",
  "compliance_status": "pending_live_check",
  "order": 1,
  "check_ids": [
    "signup.disclosure.autorenew_language",
    "signup.consent.affirmative"
  ],
  "findings": [],
  "requirement": {
    "jurisdictions": [
      "US-FED"
    ],
    "citation": "15 U.S.C. § 8403(1); Cal. Bus. & Prof. Code § 17602(a)(1)",
    "citations": [
      {
        "id": "US-CA.17602.a.1",
        "jurisdiction": "US-CA",
        "citation": "Cal. Bus. & Prof. Code § 17602(a)(1)",
        "source_url": "https://leginfo.legislature.ca.gov/"
      }
    ],
    "plain_language": "Before the purchase, state clearly that the subscription renews automatically until canceled, the price and frequency, and how to cancel."
  },
  "why": "The checkout in US-CA shows no renewal terms near \"Start now\"; the consent checkbox is pre-checked.",
  "where": {
    "kind": "code",
    "file_hint": "app/checkout/page.tsx",
    "url": "https://shop.example/checkout",
    "selector": "#subscribe-button",
    "stripe_object": "checkout.session"
  },
  "change": {
    "type": "patch",
    "content": "--- a/app/checkout/page.tsx\n+++ b/app/checkout/page.tsx\n@@ …",
    "language": "html",
    "explanation": "Insert directly above the purchase button; never pre-check the box.",
    "edits": [
      {
        "op": "insert_before",
        "target": {
          "selector": "#subscribe-button",
          "text": "Start now",
          "tag": "button"
        },
        "content": "<div class=\"checkbox-renewal-terms\">…</div>",
        "attribute": "checked"
      }
    ],
    "engine_verified": true,
    "operation_id": "updateSite",
    "endpoint": "POST /v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verify": {
    "method": "page_fetch",
    "how": "POST /v1/tasks/task_…/verify",
    "expected": "Every listed check passes (layout checks may stay needs_review on a static fetch until the confirming scan)."
  },
  "blocked_on": null,
  "closed_reason": null,
  "depends_on": [],
  "blocked_by": [],
  "question": {
    "text": "Did your subscribers choose email as the channel for account notices?",
    "options": [
      "yes"
    ],
    "why": "New York requires notices in the manner the subscriber selected; no page or email shows that choice.",
    "effect": "yes records the attestation (site fact notice_channel_email) and re-evaluates."
  },
  "answer": {
    "value": "yes",
    "note": null,
    "answered": 1793318400,
    "confirmed_by_human": false,
    "pending_confirmation_url": null
  },
  "decision": {
    "status": "wont_fix",
    "reason": "Annual plan retired; no subscribers left."
  },
  "last_verification": {
    "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "failed",
    "created": 1793318400
  },
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "verification_level": "template_checked",
  "first_seen": 1793318400,
  "done_at": 1793318400
}

Verify a task after applying its change

POST /v1/tasks/{task}/verify

Runs the fastest re-check that can confirm the task (static fetch of the live checkout or the html you send, the Stripe params you send, the email copy you send, a re-fetch of the Terms) and queues the confirming observation (a scan, a billing-platform sync, the next email). A failing pre-check fails the verification at once with a diff. Pass ?wait=30 to long-poll; otherwise poll retrieveVerification or wait for the task.verified webhook. Then follow next_action.

Scope compliance_plans:write · Idempotent (send Idempotency-Key) · Operation verifyTask

SDK: checkbox.tasks.verify() (Node) · checkbox.tasks.verify() (Python). MCP / agents: operation verifyTask.

Parameters

ParameterInTypeDescription
task requiredpathstringUnique identifier of the task (task_…).
waitqueryinteger | nullLong-poll: wait up to this many seconds (0-30) for the verification to resolve before answering.

Body

FieldTypeDescription
htmlstringpage_fetch tasks: the rendered page HTML before you deploy, at most ~900 KB (request bodies are limited to 1 MB). Pre-check only; the confirming scan runs on the live page.
stripe_checkout_sessionobjectstripe_params tasks: exactly what your code now passes to stripe.checkout.sessions.create.
stripe_checkout_sessionsarray of objectsstripe_params tasks with several Checkout code paths (one per plan, e.g. monthly and annual-with-trial): every params object your code passes to stripe.checkout.sessions.create. The pre-check fails when any of them fails. Without either field, every registered config (newest per name) is checked.
emailobjectemail_copy tasks: the new email template (pre-check; the real email confirms).
email.kindenumEmail kind (default: from the task). One of acknowledgment, trial_reminder, renewal_reminder, price_change, annual_terms, charge_notice, cancellation_confirmation.
email.subject requiredstringSubject.
email.textstringPlain-text body.
email.htmlstringHTML body.
recheckbooleanRe-check a task that is already done (or declined) instead of returning its last result: Checkbox evaluates the site again now and queues a confirming scan, so a regression shows up (pilot: a cancel page switched to phone-only stayed "passed").

Returns

Returns a Verification object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{}'
Response
{
  "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "verification",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "scope": "task",
  "status": "pending",
  "method": "page_fetch",
  "precheck": {
    "source": "static_fetch",
    "verdict": "pass",
    "url": "https://shop.example/checkout",
    "note": "Static fetch: text checks are exact; layout is estimated until the confirming scan.",
    "checks": []
  },
  "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "checks": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "diff": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "plan_status": "action_required",
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "created": 1793318400,
  "completed": 1793318400,
  "expires": 1793318400
}

Re-check the whole site now

POST /v1/sites/{site}/verify

Re-fetches the registered policies, pre-checks the checkout, re-evaluates and queues a scan. Use it for the first check after setup, or after applying several tasks. Pass ?wait=30 to long-poll; then get the plan (retrieveCompliancePlan).

Scope compliance_plans:write · Idempotent (send Idempotency-Key) · Operation verifySite

SDK: checkbox.sites.verify() (Node) · checkbox.sites.verify() (Python). MCP / agents: operation verifySite.

Parameters

ParameterInTypeDescription
site requiredpathstringUnique identifier of the site (site_…).
waitqueryinteger | nullLong-poll: wait up to this many seconds (0-30) for the verification to resolve before answering.

Returns

Returns a Verification object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify \
  -u "$CHECKBOX_SECRET_KEY:" \
  -X POST
Response
{
  "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "verification",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "scope": "task",
  "status": "pending",
  "method": "page_fetch",
  "precheck": {
    "source": "static_fetch",
    "verdict": "pass",
    "url": "https://shop.example/checkout",
    "note": "Static fetch: text checks are exact; layout is estimated until the confirming scan.",
    "checks": []
  },
  "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "checks": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "diff": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "plan_status": "action_required",
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "created": 1793318400,
  "completed": 1793318400,
  "expires": 1793318400
}

Get a verification (long-poll with ?wait=30)

GET /v1/verifications/{verification}

The verification's status (pending, passed, failed), expected vs observed per check, the diff and next_action. ?wait=N (≤ 30) holds the request until it resolves or N seconds pass.

Scope compliance_plans:read · Operation retrieveVerification

SDK: checkbox.verifications.retrieve() (Node) · checkbox.verifications.retrieve() (Python). MCP / agents: operation retrieveVerification.

Parameters

ParameterInTypeDescription
verification requiredpathstringUnique identifier of the verification (ver_…).
waitqueryinteger | nullLong-poll: wait up to this many seconds (0-30) for the verification to resolve before answering.

Returns

Returns a Verification object.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl https://app.checkbox.site/v1/verifications/ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:"
Response
{
  "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "verification",
  "livemode": false,
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "scope": "task",
  "status": "pending",
  "method": "page_fetch",
  "precheck": {
    "source": "static_fetch",
    "verdict": "pass",
    "url": "https://shop.example/checkout",
    "note": "Static fetch: text checks are exact; layout is estimated until the confirming scan.",
    "checks": []
  },
  "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "checks": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "diff": [
    {
      "check_id": "signup.disclosure.price",
      "expected": "pass",
      "observed": "fail",
      "source": "static_fetch",
      "detail": "No recurring price near the purchase button."
    }
  ],
  "plan_status": "action_required",
  "next_action": {
    "type": "apply_task",
    "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
    "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "operation_id": "verifyTask",
    "mcp_tool": "verify_task",
    "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
    "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
  },
  "created": 1793318400,
  "completed": 1793318400,
  "expires": 1793318400
}

List verifications of a site

GET /v1/sites/{site}/verifications

Verifications newest first (optionally for one task).

Scope compliance_plans:read · Operation listVerifications

SDK: checkbox.verifications.list() (Node) · checkbox.verifications.list() (Python). MCP / agents: operation listVerifications.

Parameters

ParameterInTypeDescription
site requiredpathstringUnique identifier of the site (site_…).
limitqueryintegerNumber of objects to return, 1-100 (default 10).
starting_afterquerystringCursor: an object id; returns the objects after it (older).
ending_beforequerystringCursor: an object id; returns the objects before it (newer).
taskquerystringOnly this task (task_…).

Returns

Returns a list ({ object: "list", data, has_more, url }) of Verification objects.

Errors use the standard envelope with a stable code and, where useful, next_action.

curl -G https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verifications \
  -u "$CHECKBOX_SECRET_KEY:" \
  -d limit=3
Response
{
  "object": "list",
  "data": [
    {
      "id": "ver_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "object": "verification",
      "livemode": false,
      "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "scope": "task",
      "status": "pending",
      "method": "page_fetch",
      "precheck": {
        "source": "static_fetch",
        "verdict": "pass",
        "url": "https://shop.example/checkout",
        "note": "Static fetch: text checks are exact; layout is estimated until the confirming scan.",
        "checks": []
      },
      "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "checks": [
        {
          "check_id": "signup.disclosure.price",
          "expected": "pass",
          "observed": "fail",
          "source": "static_fetch",
          "detail": "No recurring price near the purchase button."
        }
      ],
      "diff": [
        {
          "check_id": "signup.disclosure.price",
          "expected": "pass",
          "observed": "fail",
          "source": "static_fetch",
          "detail": "No recurring price near the purchase button."
        }
      ],
      "plan_status": "action_required",
      "next_action": {
        "type": "apply_task",
        "description": "Apply task_… (add the renewal terms above the Subscribe button in app/checkout/page.tsx), then call verifyTask.",
        "task": "task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
        "operation_id": "verifyTask",
        "mcp_tool": "verify_task",
        "endpoint": "POST /v1/tasks/task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify",
        "command": "checkbox fix task_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b"
      },
      "created": 1793318400,
      "completed": 1793318400,
      "expires": 1793318400
    }
  ],
  "has_more": false,
  "url": "/v1/sites"
}

Checkbox is compliance software, not a law firm; nothing in these docs is legal advice (details). You remain solely responsible for your subscription program, and Checkbox takes on no legal liability for it (Terms). Checkbox is a System1 company; Trust center · Status. For AI agents: every page is available as Markdown at the same URL plus .md; the index is /llms.txt.