> ## 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.

# Send an Approved Send

> Execute an approved send through the ordinary send path under the calling key.

Sends an `approved` pending send. The stored payload goes through exactly the path a direct [`POST /v2/send`](/api-reference/v2/messages/send-single) or [`/v2/send/bulk`](/api-reference/v2/messages/send-bulk) would take, under the key making this call: suppression, double opt-in, warmup, the key's list policy and daily send cap, and attribution (`api_key_id` on the message rows) all apply at this moment. A sandbox key executes a simulation.

On completed submission the pending send moves to `sent` and `result` carries the send response (`message_id` and `status`, or the bulk `queued_count` / `error_count` / `errors`). A partially accepted batch can be `sent` even when some messages were refused; read `result.errors` for those.

If every bulk recipient is refused before publication, the response is `207`, the hold remains `approved`, and `last_error` contains the refusal details. Partial submission with a known completed result returns `201 sent`; inspect per-recipient errors.

A refusal before any publication intent can leave the send `approved`, with `last_error` set, for retry before `expires_at`. Once publication may have occurred, an uncertain or interrupted execution becomes `unknown_execution`. Do not create a replacement or automatically resend it: poll the same pending ID and inspect its `execution` evidence. Recovery requires every recipient to have positive publication evidence or an explicit recorded refusal before publication, and preserves exact bulk counts and indexed errors. Missing evidence never implies refusal. An expired claim with valid evidence and no publication intents can return to `approved`, including an all-refused batch.

Only one concurrent caller can claim execution. Any authorized key on the same account and in the same sandbox mode may execute; that caller's current list restrictions and quota apply. Sandbox execution stores a simulation result without SMS/carrier submission. Single-send simulation may emit a best-effort signed account webhook; bulk simulation does not. Retrying a simulation after an expired empty claim can repeat that webhook. Completion emits best-effort `pending_send.sent` activity; an activity-write failure does not undo durable send state. For live sends, `sent` means submitted, not delivered.

The dashboard review pins rendered recipients, senders, message text, and destinations. Allocated message and short-link IDs appear as placeholders. A changed render or link configuration is refused before the first publication with `409 pending_send_render_changed`; submit a new hold for review. Holds with missing or malformed reviews cannot execute.

## Path Parameters

<ParamField path="id" type="string" required>Pending send ID.</ParamField>

## Errors

| HTTP Status | Error Code                    | Description                                                                                                                                |
| ----------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| 404         | `not_found`                   | No pending send with this ID on the account.                                                                                               |
| 409         | `pending_send_not_approved`   | The send is not `approved`: still `pending`, or already `sent`, `rejected`, `cancelled`, or `expired`. The response's `status` says which. |
| 409         | `sandbox_mode_mismatch`       | The calling key's sandbox mode differs from the key that held the send. Nothing changes.                                                   |
| 429         | `daily_cap_exceeded`          | The calling key's daily send cap is reached; the send stays approved.                                                                      |
| 409         | `pending_send_render_changed` | The reviewed render or configuration changed; create a new hold for review.                                                                |
| 409         | `render_snapshot_missing`     | The immutable review is missing or malformed; reject or cancel the hold and create a new one.                                              |
| 409 / 503   | `unknown_execution`           | Publication or durable claim outcome is uncertain. Read the same pending ID; do not automatically resend.                                  |
| 500         | `execution_failed`            | Execution failed before any durable publication intent; inspect the pending record before retrying.                                        |

Underlying send errors can be returned when no publication intent exists. An error after publication may have started returns `unknown_execution` instead. Also `401 invalid_credentials`.

## Examples

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.tracklysms.com/api/v2/pending-sends/66f1c2a9b8e4d3f0a1b2c3d4/send \
    -H "X-Api-Key: trk_your_api_key"
  ```
</RequestExample>

<ResponseExample>
  ```json Sent (201) theme={null}
  {
    "id": "66f1c2a9b8e4d3f0a1b2c3d4",
    "status": "sent",
    "kind": "send",
    "recipient_count": 1,
    "executed_at": "2026-09-04T14:13:02.000000Z",
    "executed_by_key_id": "66e0a1b2c3d4e5f6a7b8c9d0",
    "result": { "success": true, "message_id": "a1b2c3d4", "status": "queued" },
    "last_error": null
  }
  ```

  ```json Not yet approved (409) theme={null}
  { "error": "Only an approved send can be executed", "code": "pending_send_not_approved", "status": "pending" }
  ```
</ResponseExample>
