Gr4vy PayPal Integration
Direct Mode implementation guide.
Related pages
- PayPal Button Options — SDK button layout, Venmo, Pay Later
- PayPal Direct Mode — Shipping — ship-to and shipping-module use cases
- PayPal Direct Mode — Post-authorization data — Gr4vy GET vs PayPal REST after approve
- Pre-Gr4vy fraud — PayPal timing — PayPal GET before Gr4vy complete
- PayPal connector (Gr4vy) — configure PayPal as a payment method in Gr4vy
- PayPal via the API (Redirect method) — full-page redirect flow (not Direct Mode)
Overview
Gr4vy supports PayPal in two ways:
| Method | When to use |
|---|---|
| Redirect | Full-page redirect to PayPal login — see Gr4vy redirect guide |
| Direct Mode | Smart Payment Buttons on your checkout; Gr4vy orchestrates the PayPal order — this document |
Who does what in Direct Mode:
| Actor | Role |
|---|---|
| Shopper | Clicks PayPal, approves in the wallet modal |
| Browser (PayPal JS SDK) | Renders buttons; createOrder / onApprove / onCancel |
| Merchant backend | POST /transactions, session exchange, completion handshake, OMS |
| Gr4vy | Creates PayPal context, session, completion URL, transaction status |
| PayPal | Wallet UI and authorization |
Your Radial account team configures the PayPal payment service and communicates required credentials.
How Direct Mode works
Until the shopper clicks the PayPal button, no Gr4vy transaction exists. That avoids abandoned buyer_approval_pending transactions when shoppers pick another payment method.
Integration steps
- Page load — Load the PayPal SDK with a bootstrap
client-idso the button can render before the first click. See Frontend SDK. - First click (
createOrder) — Merchant backend callsPOST /transactions, thenPOST /transactions/{id}/session. Returnsession_data.orderIdfromcreateOrder(Promise.resolve(orderId)). Do not call PayPal Create Order REST oractions.order.create(). - Shopper approves — PayPal modal completes; SDK fires
onApprovewith the Gr4vy transaction id your backend stored from step 2. - Complete payment — Merchant backend performs
GET default_completion_url(Gr4vy auth headers), thenGET /transactions/{id}for terminal status. Treat 2xx, 204, and common 3xx redirects as successful handshake. - Route the shopper — Thank-you (Pay Now) or back to checkout (Continue) per your flow. See Shopper outcomes.
Terms: Session exchange = POST /transactions/{id}/session. Completion handshake = GET default_completion_url after approve.
Shopper outcomes (Pay Now vs Continue)
| Posture | Typical SDK / connector signals | When to call Gr4vy complete | Where the shopper goes after success |
|---|---|---|---|
| Pay Now | user_action=PAY_NOW, often commit=true | In onApprove (after backend complete succeeds) | Thank-you / confirmation |
| Continue | user_action=CONTINUE, commit=false | When merchant accepts the order (may be after checkout review) | Checkout first, then thank-you |
| Outcome | Gr4vy handling |
|---|---|
| Success (Pay Now) | onApprove → backend complete → route to thank-you. payment_method.redirect_url is the return target for the completion handshake (shopper often stays in the modal). |
| Success (Continue) | After approve, hold completion until checkout is finished; redirect_url may point at checkout or a return handler. |
| Cancel | Implement SDK onCancel → return shopper to checkout (cart preserved). Cancel URL is merchant-controlled in SDK callbacks. |
For Radial PayPal Processing equivalents, see Appendix.
Backend API reference
Step 1 — POST /transactions
Creates a Gr4vy transaction and PayPal checkout context via the connector.
| Field | Required | Role |
|---|---|---|
amount | Yes | Integer minor units (e.g. 2500 = $25.00) |
currency | Yes | ISO 4217 |
country | Yes | ISO 3166-1 alpha-2 |
intent | Yes | authorize or capture — must match PayPal SDK intent |
integration_client | Yes | "web" |
payment_method.method | Yes | "paypal" |
payment_method.redirect_url | Yes | HTTPS return URL for completion handshake |
payment_service_id | Often | Gr4vy UUID for active PayPal payment service |
{
"amount": 2500,
"currency": "USD",
"country": "US",
"intent": "authorize",
"integration_client": "web",
"payment_service_id": "<gr4vy-paypal-payment-service-uuid>",
"payment_method": {
"method": "paypal",
"currency": "USD",
"country": "US",
"redirect_url": "https://merchant.example/order/confirmation"
}
}Typical response (HTTP 201): id, status: buyer_approval_pending, session_token.
Shipping and connection_options.paypal-paypal fields are configured here — see PayPal Direct Mode — Shipping.
Step 2 — POST /transactions/{id}/session
Endpoint: POST {GR4VY_API_BASE}/transactions/{transaction_id}/session?token={session_token}
| Field | Use |
|---|---|
session_data.orderId | PayPal SDK createOrder return value |
session_data.clientId | Must match bootstrap SDK client-id |
session_data.intent / currency | PayPal SDK query params |
default_completion_url | Backend GET target after buyer approves |
After complete — capture, void, sync
| Operation | Endpoint / action |
|---|---|
| Capture (delayed ship) | POST /transactions/{id}/capture |
| Capture at create | intent: capture on transaction create |
| Void / cancel | Gr4vy void or cancel APIs |
| Stale status | POST /transactions/{id}/sync, then poll GET /transactions/{id} |
See Gr4vy PayPal Direct Mode docs for connector-specific behavior.
Frontend SDK
Both Direct Mode and Radial use paypal.Buttons({ createOrder, onApprove, onCancel, onError }). The wallet opens in a modal; your backend contract differs.
| Callback | Gr4vy Direct Mode |
|---|---|
createOrder | Backend → POST /transactions + session; return session_data.orderId |
onApprove | Backend → GET default_completion_url + GET /transactions/{id}; then route shopper |
onCancel | Route to checkout; preserve cart |
onError | Log and surface error |
Client ID (state once): Load the SDK early with a bootstrap client-id. After session exchange, session_data.clientId must match that bootstrap id — or reload the SDK with Gr4vy’s value. Mismatch causes PayPal to reject the handoff. Gr4vy ties the id to the connector PayPal app; do not mint a separate browser-side order context.
https://www.paypal.com/sdk/js
?client-id={session_data.clientId}
¤cy={session_data.currency}
&intent={authorize|capture}
&commit=false
&components=buttonsButton layout, Venmo, and Pay Later patterns: PayPal Button Options.
When you need PayPal REST
| Question | Answer |
|---|---|
Is Gr4vy GET /transactions/{id} enough after a successful payment? | Yes — status, amount, PayPal order id, auth id, payer id, email, shipping. |
| Need PayPal client secret to finalize Direct Mode? | No — completion uses Gr4vy auth + GET default_completion_url + GET /transactions/{id}. |
| When is client secret required? | Merchant backend calling PayPal REST directly — fraud enrichment before complete, void fallback, order PATCH, shipping callbacks. |
For field mapping, timing around onApprove, and OAuth details, see PayPal Direct Mode — Post-authorization data.
For pre-Gr4vy fraud (PayPal GET before Gr4vy complete), see Pre-Gr4vy fraud — PayPal timing.
Appendix: Gr4vy Direct Mode vs Radial PayPal Processing
For teams migrating from Radial PayPal Processing (SetExpress / GetExpress / DoExpress / DoAuthorize).
At-a-glance comparison
| Dimension | Gr4vy Direct Mode | Radial PayPal Processing |
|---|---|---|
| Orchestration | Gr4vy REST | Radial XML APIs |
| Who creates PayPal order | Gr4vy connector | Radial via SetExpress |
createOrder return | session_data.orderId | EC-Token only |
onApprove | Backend complete → thank-you or checkout | Redirect → GetExpress → DoExpress → DoAuthorize |
SDK intent | authorize or capture (match Gr4vy) | intent=order mandatory |
SDK commit | commit=false mandatory | commit=false mandatory |
| Client ID | session_data.clientId from Gr4vy session | Radial-provided test/production id |
| Auth at checkout | Gr4vy transaction status | DoAuthorize ResponseCode |
| Capture / settlement | Gr4vy capture API | PaymentSettlement + Confirm Funds |
| Void | Gr4vy void / cancel | PaymentAuthCancel tender PY |
SDK callback comparison
| Callback | Gr4vy Direct Mode | Radial PayPal Processing |
|---|---|---|
createOrder | Gr4vy POST /transactions + session → orderId | SetExpress → EC-Token |
onApprove | Backend complete → route shopper | actions.redirect(returnUrl) → auth chain |
onCancel | Route to checkout | actions.redirect(cancelUrl) |
OMS and lifecycle
| Concern | Gr4vy Direct Mode | Radial PayPal Processing |
|---|---|---|
| Delayed ship / auth expiry | Gr4vy capture or re-auth | Confirm Funds before settlement |
| Partial / multi-ship | Gr4vy partial capture | Multiple PaymentSettlement debits |
| Refund | Gr4vy refund API | PaymentSettlement credit |
| OMS automation | Merchant implements Gr4vy APIs | ROM automates confirm funds/settlement |
Error handling
| Scenario | Gr4vy Direct Mode | Radial PayPal Processing |
|---|---|---|
| Buyer cancels | SDK onCancel | Redirect to cancel URL |
| Auth failure | Non-terminal Gr4vy status | DoAuthorize failure → PaymentAuthCancel PY |
| Timeout | Retry completion GET / sync | Retry DoAuthorize (~3 max) |
| Settlement duplicate | Gr4vy idempotency | Never resubmit after ACK |
Migration mapping
| Radial step | Gr4vy Direct Mode equivalent |
|---|---|
| SetExpress (EC-Token) | POST /transactions + POST …/session |
| GetExpress + DoExpress | Gr4vy connector + session exchange |
| DoAuthorize | Approve + GET default_completion_url + GET /transactions/{id} |
| Confirm Funds | Gr4vy status / re-auth before capture |
| PaymentSettlement debit | POST /transactions/{id}/capture |
| PaymentSettlement credit | Gr4vy refund |
| PaymentAuthCancel PY | Gr4vy void / cancel |
Treat this table as a planning aid, not a drop-in replacement spec.
Return and cancel URLs (Radial reference)
| Shopper outcome | Gr4vy Direct Mode | Radial PayPal Processing |
|---|---|---|
| Success (Pay Now) | redirect_url + onApprove complete | SetExpress return URL + onApprove redirect → DoAuthorize |
| Cancel | SDK onCancel → checkout | onCancel → cancel URL |
| Continue | Complete when order ready; checkout return | DoAuthorize when merchant ready |