# paddle transaction "billing_details" missing: checkout never completed

## TL;DR
The transaction exists but the buyer never completed checkout, so Paddle has no billing details to give you. Only act on completed transactions: gate your fulfillment on the completed status (or the completed webhook), and treat open transactions as abandoned carts, not sales.

```text
paddle transaction "billing_details" missing: checkout never completed
```

## Steps

1. Check the transaction status in Paddle; expect open or ready, not completed. Success check: the status explains the missing details.
2. Move all fulfillment logic behind a completed-status check. Success check: open transactions trigger nothing downstream.
3. Listen for the transaction completed webhook as your source of truth instead of polling the transaction. Success check: your handler ignores non-completed events.
4. Build an abandoned-checkout follow-up for transactions stuck open past your window. Success check: stuck transactions get a nudge, not fulfillment.
5. Audit for anything you already fulfilled on incomplete transactions and reverse or hold it. Success check: no customer received value for an unpaid transaction.

## When this applies

- A Paddle transaction has no billing_details because checkout never finished.
- Fulfillment fired on an incomplete transaction.
- You are polling transactions instead of consuming webhooks.

## When it doesn't

- Completed transactions with missing fields; that is a different data issue.
- Paddle API authentication failures.
- Refunds or disputes on completed transactions.

## Tool + version compatibility

Paddle Billing transactions and webhooks (current Paddle Billing API).

### "paddle transaction missing billing details"
The buyer did not finish; wait for completed status.

### "paddle checkout not completed transaction open"
Treat open transactions as abandoned carts.

### "paddle transaction completed webhook"
Make the completed webhook your fulfillment trigger.

## Why it happens

Paddle creates the transaction record when checkout starts, not when it finishes. Fields like billing details only populate on completion. Integrations that read the transaction right after creation, or poll aggressively, see a half-empty record and either crash or fulfill prematurely. The completed webhook is the event that means money moved; everything before it is a maybe.

## Edge cases / pitfalls

- A transaction can sit open indefinitely; put a TTL on your abandoned-checkout follow-up.
- Do not backfill billing details from your own forms and call it complete; only Paddle completion counts.
- Idempotency matters on the webhook too: Paddle can deliver completed more than once.
- If your agent creates transactions and immediately reads them, add the status gate in the same code path.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_GQKVI_fxmKCgJ_l0jllMoQ
