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

# Reliable Sends in Python

> Idempotency keys, delivery states, typed errors, retry rules, cancellation, and bounded admission in the Python client.

Every send returns `SendResult` or raises a typed `RepostError` carrying the runtime's best-known delivery state. The runtime keeps the request body and idempotency key stable across all attempts in one operation.

## Idempotency and delivery outcomes

When you omit `idempotency_key`, the runtime generates one key and reuses it across that operation's attempts. Pass your own business-stable key when a queue redelivery, process restart, or application retry may repeat the logical send.

| `DeliveryState`     | Meaning                                                     | What to do                                          |
| ------------------- | ----------------------------------------------------------- | --------------------------------------------------- |
| `ACCEPTED`          | Repost accepted the event.                                  | The send returns `SendResult`.                      |
| `NOT_SENT`          | The request definitely did not leave.                       | Retry with the same key when `retryable` is true.   |
| `POSSIBLY_SENT`     | Repost may have received the request.                       | Reconcile with the same key; do not mint a new one. |
| `REJECTED`          | Repost definitively rejected the request.                   | Fix the request instead of retrying blindly.        |
| `CANCELLED_UNKNOWN` | Cancellation happened after the request may have committed. | Reconcile with the same key.                        |

```python theme={"languages":{"custom":["/languages/repost.json"]}}
from repost_client import DeliveryState, RepostError, is_retryable

try:
    result = client.webhooks.order.created(
        customer_id="customer_123",
        data=order,
        idempotency_key="order_123:created",
    )
except RepostError as error:
    if error.delivery_state in {
        DeliveryState.POSSIBLY_SENT,
        DeliveryState.CANCELLED_UNKNOWN,
    }:
        reconcile(error.idempotency_key)
    elif is_retryable(error):
        retry_later(order, error.idempotency_key)
    else:
        raise
```

Every `RepostError` has a stable `code`, `delivery_state`, `retryable`, `operation_id`, `idempotency_key`, `attempt_count`, and optional `http_status` and `failure_reason`. Error messages and metadata exclude credentials and payloads.

The subclasses are `RepostConfigurationError`, `RepostValidationError`, `RepostSerializationError`, `RepostTransportError`, `RepostPublishError`, and `RepostDescriptorVersionError`. `PublishError` remains a deprecated compatibility base for transport and publish failures; prefer `RepostTransportError` and `RepostPublishError`.

## Retry behavior

The runtime retries classified DNS, connection, I/O, and attempt-timeout failures; `409`, `429`, and `5xx` responses; and malformed successful responses when reconciliation remains possible. TLS verification failures, proxy authentication failures, redirects, and ordinary `4xx` rejections are terminal.

The default is four total attempts. Backoff is exponential with full jitter. Both delta-seconds and HTTP-date `Retry-After` values are supported and capped by `retry_max_delay_ms`, which defaults to 60 seconds. `operation_timeout_ms` bounds connection work, attempts, and retry delays together.

A custom `Transport` performs one attempt at a time. The runtime still owns retry classification, deadlines, idempotency, and response validation around it.

## Cancellation

Python sends are synchronous. Pass a `CancelToken` when another thread or shutdown hook must cancel a blocking operation:

```python theme={"languages":{"custom":["/languages/repost.json"]}}
from repost_client import CancelToken

cancel = CancelToken()

# Another thread may call cancel.cancel().
client.webhooks.order.created(
    customer_id="customer_123",
    data=order,
    idempotency_key="order_123:created",
    cancel=cancel,
)
```

Cancellation is cooperative. A cancelled send raises `RepostTransportError` with `ErrorCode.CANCELLED`. Cancellation before commitment is `NOT_SENT`; cancellation after bytes may have left is `CANCELLED_UNKNOWN`. Cancelling one operation does not close the client or affect other sends.

## Bounded admission

`max_in_flight_operations` is a hard bulkhead, not a queue. A send that cannot enter fails immediately with `ErrorCode.OVERLOADED` and `NOT_SENT`.

`max_buffered_bytes` bounds aggregate retained request and response bytes. The runtime rejects new work or an oversized response instead of buffering without a limit. Apply backpressure in your queue or request handler, then retry with the same idempotency key.

## Wire format

The runtime sends `type`, `customerId`, `timestamp`, and `data` in that order. Payload fields follow schema declaration order and their `@map` names. Absent optional values are omitted, defaults are injected only when a value is absent, and unknown dictionary properties are dropped. Datetimes are normalized to millisecond UTC form, enums use their wire values, and non-finite numbers are rejected before the network.

The native pytest suite exercises this shape through the public generated client, real runtime, default HTTP transport, local HTTP server, and response parser.

## Continue

<Columns cols={3} className="gap-y-4">
  <Card title="Observability" icon="activity" href="/docs/send/python/observability" cta="Observe" arrow="true">
    Watch in-flight work, retry lifecycles, failures, and dropped events.
  </Card>

  <Card title="Testing" icon="flask-conical" href="/docs/send/python/testing" cta="Test" arrow="true">
    Script attempts and assert on recorded requests without a network.
  </Card>

  <Card title="Delivery & retries" icon="shield-check" href="/docs/send/delivery" cta="After the 202" arrow="true">
    See what happens after Repost accepts a message.
  </Card>
</Columns>
