Reviewed on 2026-09-06 against the sources indexed by llms/paypal/llm.txt.
The implemented surface is Orders v2 and Payments v2 for one purchase unit,
one authorization and one final capture per order. Other PayPal products in the
index are not implied by the gateway's computed implemented status.
#Sources
Official Orders and Payments OpenAPI snapshots are in contracts/paypal/.
Adjacent .meta.json files record source URLs, retrieval time and SHA-256 over
exact downloaded bytes. Importing a schema does not imply full schema validation.
#Surface
The /paypal API prefix is optional for authenticated requests.
| Method | Path | Behavior |
|---|---|---|
| POST | /v1/oauth2/token |
Basic client credentials, form-encoded grant |
| POST | /v2/checkout/orders |
Create without moving money |
| GET | /v2/checkout/orders/{id} |
Read order and child payment projections |
| POST | /v2/checkout/orders/{id}/authorize |
Authorize an approved AUTHORIZE order |
| POST | /v2/checkout/orders/{id}/capture |
Capture an approved CAPTURE order |
| GET | /v2/payments/authorizations/{id} |
Read authorization |
| POST | /v2/payments/authorizations/{id}/capture |
One final full or partial capture |
| POST | /v2/payments/authorizations/{id}/void |
Release hold; empty HTTP 204 |
| GET | /v2/payments/captures/{id} |
Read capture, including refund status |
| POST | /v2/payments/captures/{id}/refund |
Full/partial refund; HTTP 201 |
#What is emulated
- Application creation and token rotation return
clientId,clientSecretandaccessTokenonce. Basic OAuth resolves against the same stored token digest; secrets are never stored in plaintext. Rotation invalidates the previous pair. Existing applications must rotate to obtain their new OAuth pair. - Orders without a payment source start as
CREATED; orders supplying the PayPal source wait asPAYER_ACTION_REQUIRED. Both return a local buyer link. - The buyer approves at
/paypal/checkoutnow?token=.... Approval is canonicalapproved/ wireAPPROVED, with no debit and no hold. The merchant then authorizes or captures. Calling either before approval is refused. - AUTHORIZE creates a hold and returns its own authorization ID. Capture, authorization and order identifiers remain stable on retrieval. Currency and capture-intent mismatches are refused. Child resources are tenant-scoped.
- A refund returns its individual amount and ID. Replaying its request ID repeats
the original response without posting twice. Orders remain
COMPLETEDafter a refund; the child capture becomesPARTIALLY_REFUNDEDorREFUNDED. - PayPal's own SDK 2.5.0 exercises OAuth, creation and capture. The SDK hardcodes its hosts: the test configures its HTTP adapter to direct traffic exclusively to the local emulator. SDK authentication, serialization and parsing are used unchanged. This is not native base-URL configuration.
- Webhooks use RSA-SHA256 over transmission ID, timestamp, webhook ID and the
unsigned decimal CRC32 of the body.
webhookSecretis the local webhook ID for this provider./paypal/certs/paypal-test.pemserves a public test fixture. An independent Node crypto verification test constructs the manifest using zlib CRC32. The official SDK has no local webhook verifier. The local verifier applies a configurable 300-second replay window. - The checkout has a narrow PayPal review layout, a synthetic funding card,
approval confirmation and return/cancel links. The return preserves query
parameters and adds
tokenand syntheticPayerID. Cancel returns to the merchant without voiding the order. The UI never requests real PayPal credentials.
#What is not emulated
- OAuth timing and scopes are simplified. Tokens remain valid until application expiry, disabling or rotation. The advertised lifetime does not create a separate expiring OAuth-token collection; scopes are not individually enforced.
- Only one purchase unit and one final capture are supported. Multiple captures, reauthorization, marketplace routing, item breakdowns, shipping updates and order PATCH are absent; unsupported monetary options are refused explicitly.
- Refund history has no independent GET resource. Successful refunds are recorded through idempotency and ledger entries; asynchronous refund states and alternative funding sources are not modeled.
- Webhook bodies are minimal resource stubs. Delivery, RSA signing and local verification work, but complete resource payloads, partial-refund event selection, webhook registration and the remote verification endpoint are not implemented. The bundled certificate and private key are public test fixtures, never PayPal's certificate chain and never suitable for production trust.
- The buyer flow is a local simulation. No real account login, OTP, JS SDK popup, postMessage protocol, card tokenization, Pay Later, Venmo, vaulting, subscription, invoicing or payout APIs. No exact visual match across regional variants is claimed.
- Validation is a selected subset. Official snapshots are available locally, but permissive fields and synthetic IDs are not full OpenAPI compatibility. Accounting fees and timing remain configurable synthetic defaults.