> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tracklysms.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Preflight a Send

> Check whether a message would be eligible to send, plus its segment count and estimated cost — without sending or billing.

Runs the same eligibility gates a live send runs, but delivers nothing and bills nothing. Use it to validate a recipient, preview segment count and cost, and surface any blocker before you send. Works with live and [sandbox](/api-reference/v2/sandbox) keys.

## Body Parameters

<ParamField body="to" type="string" required>
  Recipient phone number (E.164).
</ParamField>

<ParamField body="list_number" type="string" required>
  Sending list phone number (E.164). Must belong to your account.
</ParamField>

<ParamField body="body" type="string" required>
  Message body text.
</ParamField>

## Response Fields

<ResponseField name="eligible" type="boolean">
  Whether the message would be accepted for sending. Equals the AND of all **binding** checks: `sender_ready`, `byoc_webhook_ready`, `not_suppressed`, `billing_ok`, and `byoc_required_ok`. `within_tcpa_hours` is **advisory only** and does not affect `eligible`.
</ResponseField>

<ResponseField name="checks" type="object">
  Per-gate results.

  <Expandable title="checks">
    <ResponseField name="sender_ready" type="boolean">The sending list exists, is active, and belongs to you.</ResponseField>
    <ResponseField name="byoc_webhook_ready" type="boolean">For BYOC lists, the delivery webhook is verified.</ResponseField>
    <ResponseField name="not_suppressed" type="boolean">The recipient is not opted out or blocked.</ResponseField>
    <ResponseField name="within_tcpa_hours" type="boolean">**Advisory.** `true` if the current time is within the recipient's TCPA calling window, `false` if in quiet hours. Computed only for `+1` numbers (defaults `true` otherwise). The raw API send path does not enforce quiet hours — enforce it yourself if you need to.</ResponseField>
    <ResponseField name="billing_ok" type="boolean">The account's billing is in good standing.</ResponseField>
    <ResponseField name="byoc_required_ok" type="boolean">The account is allowed to send from this list (free-tier accounts must use a BYOC list).</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="segment_count" type="integer">Number of SMS segments the body would use.</ResponseField>
<ResponseField name="encoding" type="string">`GSM-7` or `UCS-2`.</ResponseField>
<ResponseField name="estimated_cost" type="number">Marginal cost of the send at the account's current tier and cycle position. **`null` for a child pooled to its parent's billing.**</ResponseField>
<ResponseField name="currency" type="string">Currency of `estimated_cost` (e.g. `usd`).</ResponseField>
<ResponseField name="cost_basis" type="string">How the estimate was derived — or, for a pooled child, that cost is managed by the parent.</ResponseField>
<ResponseField name="contact_on_list" type="boolean">Whether the recipient is already a contact on the list.</ResponseField>

## Examples

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.tracklysms.com/api/v2/messages/preflight \
    -H "X-Api-Key: trk_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{ "to": "+14155551234", "list_number": "+18005551000", "body": "Hello!" }'
  ```
</RequestExample>

<ResponseExample>
  ```json Eligible (200) theme={null}
  {
    "eligible": true,
    "checks": {
      "sender_ready": true,
      "byoc_webhook_ready": true,
      "not_suppressed": true,
      "within_tcpa_hours": true,
      "billing_ok": true,
      "byoc_required_ok": true
    },
    "segment_count": 1,
    "encoding": "GSM-7",
    "estimated_cost": 0.0045,
    "currency": "usd",
    "cost_basis": "estimated at current cycle position; final unit cost is positional within the pooled period",
    "contact_on_list": true
  }
  ```

  ```json Pooled child (200) theme={null}
  {
    "eligible": true,
    "checks": { "sender_ready": true, "byoc_webhook_ready": true, "not_suppressed": true, "within_tcpa_hours": true, "billing_ok": true, "byoc_required_ok": true },
    "segment_count": 1,
    "encoding": "GSM-7",
    "estimated_cost": null,
    "currency": "usd",
    "cost_basis": "cost is managed by the parent account (pooled billing)",
    "contact_on_list": true
  }
  ```
</ResponseExample>

## Error Codes

| HTTP Status | Error Code            | Description                                         |
| ----------- | --------------------- | --------------------------------------------------- |
| 400         | `invalid_payload`     | The body is not a JSON object.                      |
| 400         | `missing_fields`      | `to`, `list_number`, or `body` is missing or empty. |
| 400         | `invalid_phone`       | `to` is not a valid E.164 number.                   |
| 400         | `invalid_list_number` | `list_number` is not a valid E.164 number.          |

<Note>
  Warm-up is not evaluated by preflight (its check would claim a ramp slot). A warm-up-gated list may pass preflight but still defer a live send.
</Note>
