PayPal Deep Integration
I korthet
PayPal Deep Integration mirrors the Stripe model for the PayPal ecosystem — Checkout orders with capture or authorize intent, signature-verified IPN/webhooks dispatched to typed handlers with idempotency, full and partial refunds with reason and seller-payable breakdown, and Express one-click profiles backed by the PayPal Vault API with consent lifecycle — so federations can accept PayPal alongside cards with the same audit, retry, and reconciliation guarantees that the Stripe surface provides.
Så fungerar det
PayPalOrder persists every Checkout order with paypal_order_id, intent (capture or authorize), status (created, saved, approved, voided, completed, payer_action_required), invoice_id, amount, currency, purchase_units, payer_email, payer_id, capture_id, authorization_id, the approval_url returned from PayPal, a typed PayPalOrderMetadata block (invoice_id, debtor_id, debtor_type, fee_category, season_id, custom), brand_name, sandbox flag, and an optional express_profile_id. The /paypal/orders/ CRUD surface filters by status, invoice_id, and payer_id and provides capture, void, and sync endpoints to drive the order through the PayPal lifecycle. Inbound notifications land at POST /paypal/webhooks/, which verifies each call against the PayPal Notifications API, stamps an idempotency_key from the paypal_event_id, and dispatches verified events to typed handlers (CHECKOUT.ORDER.APPROVED, CHECKOUT.ORDER.COMPLETED, CHECKOUT.ORDER.DECLINED, PAYMENT.CAPTURE.COMPLETED, PAYMENT.CAPTURE.DENIED, PAYMENT.CAPTURE.REFUNDED, PAYMENT.CAPTURE.REVERSED, PAYMENT.CAPTURE.PENDING).
Failed verifications are stored with status=failed_verification so operators can investigate without losing the payload. PayPalRefund records every refund with paypal_refund_id, paypal_capture_id, paypal_order_id, refund_type (full or partial), reason, note_to_payer, and the seller_payable_breakdown returned by PayPal; sync endpoints reconcile state if a webhook is missed. PayPalExpressProfile stores per-user one-click metadata — paypal_payer_id, payer_email, a vault payment_token, consent_status (pending, active, revoked, expired), display_name, preferred flag, and last_used_at — with activate, revoke, and set-preferred endpoints, integrating with PayPal Vault so saved payment sources can be charged again without sending the user back to the PayPal site.
Centrala funktioner
- PayPalOrder with capture/authorize intent and full lifecycle states
- Signature-verified webhooks with idempotency_key and audit log
- Capture, void, and sync endpoints per order
- PayPalRefund with reason, note_to_payer, and seller_payable_breakdown
- Express one-click profiles backed by PayPal Vault
- Consent lifecycle (pending, active, revoked, expired) on stored profiles
- Sandbox mode and brand_name override per order
I praktiken
A federation enables PayPal as an alternative to cards for international license payments. A player from outside the SEPA zone selects PayPal at checkout; the API creates a PayPalOrder with intent=capture, returns the approval_url, and redirects the player to PayPal. After approval, the platform calls the capture endpoint, the order flips to completed, and a PAYMENT.CAPTURE.COMPLETED webhook arrives — verified, idempotency-checked, and dispatched.
The player ticks Save for next time, so a PayPalExpressProfile is created with consent_status=active and a vault payment_token. Twelve months later they renew their license; the API charges the saved profile directly, no redirect required, and the order completes in under two seconds.
Features i detta subsystem
4| ID | Status | Funktioner |
|---|---|---|
| F14.08.01 | Levererad | PayPal Checkout — PayPalOrder-samling tenant-scopad med paypal_order_id/intent (capture/authorize)/status (created/saved/approved/voided/completed/payer_action_required)/invoice_id/payment_id/amount/currency/purchase_units[PayPalPurchaseUnit]/payer_email/payer_id/capture_id/authorization_id/approval_url/metadata (PayPalOrderMetadata invoice_id/debtor_id/debtor_type/fee_category/season_id/custom)/brand_name/sandbox/express_profile_id; CRUD /paypal/orders/ med filtrering status/invoice_id/payer_id, capture/void/sync-endpoints ✅ PL-F1408 |
| F14.08.02 | Levererad | PayPal IPN/Webhooks — PayPalWebhookEvent-samling tenant-scopad med paypal_event_id/event_type/resource_type/status (received/verified/failed_verification/processed/processing_failed)/signature_valid/idempotency_key/related_resource_id/related_order_id/webhook_id/processing_error; POST /paypal/webhooks/ med signaturverifiering via PayPal Notifications API, idempotens-kontroll, dispatch till handlers (CHECKOUT.ORDER.APPROVED/COMPLETED/DECLINED, PAYMENT.CAPTURE.COMPLETED/DENIED/REFUNDED/REVERSED/PENDING); GET /paypal/webhooks/events för audit-loggning ✅ PL-F1408 |
| F14.08.03 | Levererad | PayPal Refunds — PayPalRefund-samling tenant-scopad med paypal_refund_id/paypal_capture_id/paypal_order_id/order_doc_id/invoice_id/refund_type (full/partial)/amount/currency/status (pending/completed/failed/cancelled)/reason/note_to_payer/seller_payable_breakdown; CRUD /paypal/refunds/ med filtrering status/capture_id/order_id/invoice_id, sync-endpoint ✅ PL-F1408 |
| F14.08.04 | Levererad | PayPal Express för one-click — PayPalExpressProfile-samling tenant-scopad med user_id/paypal_payer_id/payer_email/payment_token (vault token)/consent_status (pending/active/revoked/expired)/display_name/preferred/last_used_at; CRUD /paypal/express/profiles med activate/revoke/set-preferred-endpoints, integration med PayPal Vault API för sparade betalningskällor ✅ PL-F1408 |