# Fix Paddle checkout failing with 400 invalid passthrough

## TL;DR
Invalid passthrough means the passthrough value you sent breaks Paddle's format rules, often bad characters or too much data. Keep passthrough small, URL-safe, and JSON-stringified, then retry the checkout. It is metadata, not a payment problem.

## The error
```text
Paddle checkout failed
HTTP 400: Invalid passthrough value
```

## Use this skill
Agent? Search Vectle for this error:
```bash
curl -s "https://vectle.com/api/v1/search?q=paddle checkout failed 400 invalid passthrough"
```

## Fix it

### Step 1: Inspect the passthrough value you sent

```bash
Log the exact passthrough string your checkout code sends.
```

Expected: You see the offending value.

### Step 2: Check it against Paddle's format rules

```bash
Confirm it is a short string without illegal characters; stringify objects to JSON first.
```

Expected: You find the violation: bad characters, nesting, or excessive length.

### Step 3: Fix the value

```bash
Trim it to the essentials, encode safely, and keep it small.
```

Expected: The value now meets the format rules.

### Step 4: Retry the checkout

```bash
Run the checkout flow again with the fixed value.
```

Expected: Checkout proceeds past the 400.

### Step 5: Add validation before sending

```bash
Validate passthrough values client-side so bad ones never reach Paddle.
```

Expected: Future checkouts fail fast locally instead of at Paddle.

## When this applies

- Paddle checkouts fail with 400 invalid passthrough
- Checkouts worked and broke after adding metadata
- You are passing custom data through Paddle checkout

## When it doesn't

- Checkout fails without passthrough involved (check prices and products)
- The error is about payment methods (different stage)
- Webhooks fail after successful checkout (check the webhook handler)

## Compatibility

Paddle checkout API (Paddle Billing).

## Variant phrasings

### paddle invalid passthrough 400

Same failure. The value format is the whole story.

### paddle checkout 400 bad request

The 400 wrapper with a passthrough detail points at your metadata, not the payment.

### paddle passthrough too long

Oversized passthrough values fail validation. Keep them tiny; store the rest server-side.

## Why it happens

Passthrough is a small metadata field Paddle echoes back to you, and it validates the format strictly. Developers stuff objects, long ids, or unsafe characters into it, and Paddle rejects the checkout before any payment happens. The payment stack is innocent.

## Edge cases

- Passthrough is visible in some contexts; never put secrets or PII in it
- Different Paddle products validate differently; check the docs for the one you use
- Migrating from Paddle Classic changes passthrough behavior; retest after migration

## If it still fails

- Reproduce in test mode with test cards before touching live config.
- Read the full API error object; the code and decline code name the next step.
- Check the provider status page; payment API incidents look like integration bugs.
- Never retry live charges blindly; verify state first and use idempotency keys.
- For money-movement confusion, reconcile against the dashboard before writing code.

## Prevention

- Exercise the full payment flow in test mode on every deploy.
- Alert on failed payment webhooks, not just API errors.
- Keep idempotency keys on every charge-creating call.
- Reconcile payouts against the dashboard on a schedule.
- Document the retry and dunning policy so agents and humans agree.

## Provenance

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