Voids the authorization of an AUTHORIZE-intent payment. CAPTURE-intent orders cannot be cancelled via the API — they expire on their own, so cancelling one is rejected rather than faked.
Manual capture of an AUTHORIZE-intent payment; pspPaymentId is the order id. Each partial capture is its own charge under its own required key — a reused key replays the earlier capture via PayPal-Request-Id and moves no new money.
Tokenize-first completion: the client's confirm() resolves with the approved order id as clientToken; money moves here. CAPTURE-intent orders capture, AUTHORIZE-intent orders authorize (capture comes later via capturePayment).
Missed-webhook recovery over GET /v1/notifications/webhooks-events: the same payload shapes webhooks deliver, normalized by the same mapper, so dedupe by event.id — which real PayPal events always carry — works identically for delivered and fetched events. PayPal retains roughly 30 days.
Pages the merchant's Subscriptions v1 subscriptions as unified records. The cursor is the next page number (GET /v1/billing/subscriptions pages by number: page_size 1–20, default 10). List items omit the inline plan, so each item is completed by the same fields=plan detail GET retrieve uses — a page costs 1 + N requests (N ≤ 20). total_required=true rides every page so the last page is detected from total_pages; a next link or a full page are honored as fallbacks (a possibly-empty final page beats silently truncating the walk). The unfiltered list returns PayPal's own default status set — the reference does not enumerate it, and no undocumented statuses filter is guessed here.
Throws PayFanoutError (code "invalid_request") on unparseable payloads; maps genuinely unknown-but-valid event types to type "unknown" rather than throwing.
Refunds settle against the CAPTURE — order ids are resolved to it here.
Accepts the order id (active payment window) or the capture id (the durable canonical id — PaymentInfo.pspPaymentId after capture). Orders age out of GET a few days after completion, captures do not.
Polls an async refund (eCheck-funded ones sit PENDING) to a terminal state.
PATCH-amends a CREATED/APPROVED order in place (same order id, so the mounted PayPal button keeps working). COMPLETED orders reject with invalid_request. Currency changes require an explicit amount — the old minor amount is not silently reinterpreted in the new currency.
Side-effect-free credential probe behind a host's "Test connection" button. The client-credentials token mint IS the ideal probe: it reads nothing and moves no money, yet it exercises the exact clientId/clientSecret the adapter authenticates with. Always performs a real token fetch (never trusting a warm cache), and classifies from the RAW HTTP status so a rejected key (401/403) is never confused with a transient outage — the mint issues a single request, so an auth rejection is never retried. Secrets are never echoed back in the message.
Postback verification: PayPal itself confirms the delivery headers + exact raw bytes. Missing headers, a missing webhookId, or an empty body answer false locally without a network call; transport trouble fails closed (false), never open.
Stops PayPal-side billing, verified-idempotent. The cancel endpoint accepts only ACTIVE/SUSPENDED subscriptions (anything else answers 422 SUBSCRIPTION_STATUS_INVALID). The derived PayPal-Request-Id header is forwarded best-effort even though the cancel operation declares no such parameter — replay safety rests on the state machine plus re-fetch: on any cancel rejection the subscription is re-fetched, and a terminal billing state (CANCELLED or EXPIRED — billing already stopped) resolves as success with the honest record. Non-terminal states rethrow the cancel error. The required
reasonbody field is filled with a fixed factual default.