Inspect API Reference
All Inspect endpoints are under /v1/inspect and require data-plane authentication via X-WORKSPACE-ID + X-API-KEY headers.
Scopes:
inspect:read-- Read job status, findings, credits, and configinspect:write-- Trigger runs, snooze/mark findings, create overrides, update config
Roles with Inspect access: Owner, Admin, Developer, Marketing.
POST /v1/inspect
Trigger a new inspect run against a template or raw HTML.
Scope: inspect:write
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
channel | string | No | email | Inspect channel: email, push, in_app, sms, or whatsapp |
template_id | UUID | No | -- | Email template ID to inspect (channel=email) |
template_slug | string | No | -- | Email template slug (alternative to template_id) |
body_html | string | No | -- | Raw HTML to inspect (channel=email only; alternative to template lookup) |
subject | string | No | -- | The subject the email will send with (channel=email). When supplied, suppresses the SJ001 (subject missing) finding. Ignored on other channels. |
preheader | string | No | -- | The preheader/preview text the email will send with (channel=email). When supplied, suppresses the SJ007 (preheader missing) finding. Ignored on other channels. |
push_template_id | UUID | No | -- | Push template ID to inspect (channel=push) |
push_template_slug | string | No | -- | Push template slug (alternative to push_template_id) |
in_app_message_id | UUID | No | -- | In-app message ID to inspect (channel=in_app) |
in_app_message_slug | string | No | -- | In-app message slug (alternative to in_app_message_id) |
sms_template_id | UUID | No | -- | SMS template ID to inspect (channel=sms) |
sms_template_slug | string | No | -- | SMS template slug (alternative to sms_template_id) |
whatsapp_template_id | UUID | No | -- | WhatsApp template ID to inspect (channel=whatsapp) |
whatsapp_template_slug | string | No | -- | WhatsApp template slug (alternative to whatsapp_template_id) |
quick_check | boolean | No | false | Run only Stages 1--3 for email (free, fast). For SMS / WhatsApp, quick_check makes the run free but does not change which checks run — those channels are single-stage. |
Supply exactly the fields for the channel you name. Each channel requires its own identifier:
channel | Provide one of |
|---|---|
email (default) | template_id, template_slug, or body_html |
push | push_template_id or push_template_slug |
in_app | in_app_message_id or in_app_message_slug |
sms | sms_template_id or sms_template_slug |
whatsapp | whatsapp_template_id or whatsapp_template_slug |
Mixing fields across channels is rejected with 422 Unprocessable Entity — for example, sending body_html with channel=sms, or sms_template_id with channel=email.
Inspecting content-only templates. Synapse email templates are content-only — a template stores the body content, not a <title> or a hidden preheader element. A raw fragment (for example <p>Hello</p>) therefore has no subject or preheader for Inspect to read, and the subject/preheader checks would otherwise always fire. Pass the subject and preheader the email will actually send with so Inspect evaluates the real, complete email:
- Supplying
subjectsuppressesSJ001(subject missing). - Supplying
preheadersuppressesSJ007(preheader missing).
Omitting them preserves the prior behavior: Inspect reads any <title> / hidden preheader element in the HTML, and SJ001 / SJ007 fire when neither the request nor the body provides one. When both a request value and an in-body value are present, the request value takes precedence.
Response (200)
The run completes synchronously — the response returns a completed job (there is no queued / polling step). The channel field echoes the channel that ran, and exactly one of the per-channel *_template_id / *_message_id fields is populated:
For SMS and WhatsApp, stages_completed is 1 — those channels run a single analysis stage.
SMS and WhatsApp channels
Both SMS and WhatsApp run a single analysis stage against the stored template, rendered against a sample contact. The request, response, and findings all use the same endpoints as email — only the channel field and the template identifier differ.
For the concepts behind each channel's checks, see SMS Quality Checks and WhatsApp Pre-Submission Inspect.
Inspect an SMS template
Inspect a WhatsApp template
A WhatsApp template is inspected regardless of its Meta approval status — a pending or rejected template is fully inspectable, since the point is to catch format issues before or after a Meta rejection.
Fetching SMS / WhatsApp findings
Fetch findings with the same GET /v1/inspect/{job_id}/findings endpoint. The finding shape is identical; category is sms or whatsapp, and channel-specific detail is carried in context:
ast_node_id and client_specific are always null for SMS and WhatsApp — these channels have no template AST and no per-email-client rendering matrix.
Credits
SMS and WhatsApp runs consume 1 credit each, like email and push, unless quick_check: true is set (which makes the run free). Because both channels are single-stage, quick_check does not change which checks run — it only waives the credit.
WhatsApp Inspect does not gate sending. It is a pre-submission format check only — it does not submit your template to Meta and it is not wired into any send-time block. See WhatsApp Pre-Submission Inspect for the full boundary.
GET /v1/inspect/{job_id}
Get inspect job status and summary.
Scope: inspect:read
Response (200)
Same shape as the POST /v1/inspect response.
GET /v1/inspect/{job_id}/findings
List findings for an inspect job with optional filters.
Scope: inspect:read
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
severity | string | -- | Filter by severity (critical, warning, info) |
category | string | -- | Filter by category (html, css, images, links, spam, accessibility, rendering, dark_mode, subject, tracking) |
status | string | -- | Filter by status (open, snoozed, fixed, false_positive) |
page | integer | 1 | Page number |
per_page | integer | 50 | Items per page (max 200) |
Response (200)
POST /v1/inspect/findings/{finding_id}/snooze
Snooze a finding for a specified number of days.
Scope: inspect:write
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
duration_days | integer | No | 30 | Snooze duration (1--365 days) |
Response (200)
Returns the updated finding with status: "snoozed" and snoozed_until set.
POST /v1/inspect/findings/{finding_id}/mark-fixed
Mark a finding as fixed.
Scope: inspect:write
Response (200)
Returns the updated finding with status: "fixed".
POST /v1/inspect/findings/{finding_id}/mark-false-positive
Mark a finding as a false positive.
Scope: inspect:write
Response (200)
Returns the updated finding with status: "false_positive".
GET /v1/inspect/credits
Get the current inspect credit balance and recent ledger entries.
Scope: inspect:read
Response (200)
POST /v1/inspect/override
Create a single-use override token for sending despite critical findings.
Scope: inspect:write
The token is valid for 5 minutes and bound to the specific inspect job. An audit log entry is created for the override.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
job_id | UUID | Yes | Inspect job ID to override |
reason | string | Yes | Free-text reason (10--500 characters) |
Response (200)
POST /v1/inspect/pre-send-check
Check if a template can be sent based on inspect results.
Scope: inspect:read
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
channel | string | No | email | Channel to check: email, push, or sms. template_id is interpreted as that channel's template. |
template_id | UUID | Yes | -- | Template ID to check (email, push, or SMS template per channel) |
override_token | string | No | -- | Override token if sending despite critical findings |
The pre-send check accepts email, push, and sms only. WhatsApp is not a valid channel here — WhatsApp Inspect is a pre-submission format check and is not wired into any send-time gate. Passing channel=whatsapp returns 422.
Response (200)
Decision Values
| Decision | Meaning |
|---|---|
allow | Template passed inspection or blocking is disabled |
allow_with_override | Critical findings exist but a valid override token was provided |
block_no_inspect | No completed inspect run found within the last 7 days for this template version |
block_critical | Open critical findings exist and no valid override was provided |
GET /v1/inspect/config
Get workspace inspect configuration.
Scope: inspect:read
Response (200)
PUT /v1/inspect/config
Update workspace inspect configuration. Only provided fields are updated.
Scope: inspect:write
Request Body
| Field | Type | Description |
|---|---|---|
default_clients | string[] | Email clients to render in Stage 4 |
auto_run_on_save | boolean | Trigger inspect automatically on template save |
block_send_on_critical | boolean | Block email sends when critical findings exist |
spam_provider | string | Spam scoring provider (internal, spamassassin, mail_tester) |
skip_domains | string[] | Domains to skip in link checking |
snoozed_codes | string[] | Finding codes to auto-snooze |
push_inspect_enabled | boolean | Opt in to push pre-send blocking. Default false. |
sms_inspect_enabled | boolean | Reserved SMS Inspect toggle. Default false. See the note below. |
whatsapp_inspect_enabled | boolean | Reserved WhatsApp Inspect toggle. Default false. See the note below. |
sms_inspect_enabled and whatsapp_inspect_enabled are stored settings that do not yet gate any behavior. You can inspect an SMS or WhatsApp template with POST /v1/inspect regardless of these flags, and neither flag blocks a send today. They are surfaced now for consistency with push_inspect_enabled and for future dashboard gating. WhatsApp Inspect in particular is a standalone pre-submission analysis and is intentionally not part of any send-time gate.
Response (200)
Returns the full updated config.
Error Responses
All endpoints return standard error responses:
| Status | Code | Description |
|---|---|---|
| 400 | bad_request | Missing required field or invalid input |
| 402 | inspect_credits_exhausted | Inspect credits exhausted for the current plan. The response body carries { "detail": ..., "code": "inspect_credits_exhausted" }. |
| 404 | -- | Job, finding, or template not found. On a channel run, a missing template returns 404 with a plain message (e.g. SMS template not found, WhatsApp template not found). |
| 422 | -- | Request validation failed — for example, a required channel identifier is missing, channel fields are mixed, or an unsupported channel value was passed to pre-send-check. |