# PayPal

PayPal checkout smart buttons (page render, order create/capture, pool selection)

## GET /v1/ {#v1paypalbuttonspage}

PayPal smart-buttons iframe page

Renders the HTML page that the SDK-managed iframe loads (the iframe `src` in `PaypalShield.init`). Checks origin via `Referer` when the key has `allowedOrigins` configured (anti-hotlink measure, not an authentication boundary). Blocked by the pool guard (POOL_MISMATCH if the key's pool does not include this host).

## GET /v1/card-fields {#v1paypalcardfieldspage}

PayPal advanced card-fields iframe page

Same gating as `/v1/`; renders the card-fields page variant.

## POST /v1/create_order {#v1paypalcreateorder}

Create a PayPal order

Checks origin via `sec-fetch-or-origin` when the key has `allowedOrigins` configured. Called from inside the SDK iframe (same origin as the selected shield domain).

## POST /v1/capture_order {#v1paypalcaptureorder}

Capture a PayPal order and receive a signed envelope

No origin check (enforced at order-create time via the post-charge capture-key binding instead). On success returns a `SignedEnvelope` whose `data` carries PayPal's raw capture result and whose `signed_payload` parses to `PaypalCaptureV1Payload`. The signed proof is the PRIMARY completion path (store completes immediately, no webhook wait). A SUCCESSFUL capture (funds moved) that cannot be signed returns 502 `CAPTURED_PROOF_UNAVAILABLE`: the buyer was already charged; do not retry or show an error — the order is completed by the AIO `transaction.completed` webhook (matched by `settle_ref`) as the fallback path.

## GET /v1/shield/select {#v1paypalshieldselect}

Select a PayPal shield from the key's pool

Called by `PaypalShield.init` before mounting the iframe (skipped when the SDK script carries a `?domain=` pin). Checks origin via `Origin` when the key has `allowedOrigins` configured.

