Last updated: June 23, 2026
Handle payments for orders that customers purchase online and pick up at a physical store location. This pattern authorizes payment at checkout and captures funds after verifying pickup. This ensures payment is secured and collected only when the customer receives their items.
Common scenarios include:
Add the following endpoints to your existing server file from the quick start integration.
# Create BOPIS order (authorization)
curl -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
"intent": "AUTHORIZE",
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "75.00"
},
"shipping": {
"type": "PICKUP_IN_STORE",
"address": {
"address_line_1": "123 Orders St",
"admin_area_2": "San Francisco",
"admin_area_1": "CA",
"postal_code": "94107",
"country_code": "US"
}
},
"custom_id": "YOUR-PICKUP-ORDER-ID",
"description": "Pickup at Store 123"
}]
}'
# After buyer approval, authorize the order
curl -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/ORDER_ID/authorize \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN"
# Capture payment at pickup
curl -X POST https://api-m.sandbox.paypal.com/v2/payments/authorizations/AUTH_ID/capture \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN"/v2/checkout/orders/{id}/authorize# 1. Create BOPIS order (authorization)
curl -X POST http://localhost:3000/api/orders/bopis \
-H "Content-Type: application/json" \
-d '{"amount": "75.00", "pickupLocation": "Store #123", "pickupCode": "PICK789"}'# 2. Complete pickup (capture payment)
curl -X POST http://localhost:3000/api/orders/bopis/ORDER_ID/pickup \
-H "Content-Type: application/json" \
-d '{"authorizationId": "AUTH_ID", "pickupCode": "PICK789"}'Before testing pickup flows, authorize an order to obtain an authorization ID.
| Test scenario | Setup | Expected result |
|---|---|---|
| Successful pickup | Create order and verify with correct code | Authorization succeeds and capture completes on pickup. |
| Invalid pickup code | Use incorrect pickup code | Returns 401 error: invalid pickup code. |
| Abandoned order | Do not pick up within timeframe | Authorization is voided automatically. |
| Partial pickup | Authorize $100, pick up $60 | Capture $60 and void remaining $40. |
For negative testing:
.env file, set ENABLE_NEGATIVE_TESTING=true and set NEGATIVE_TEST_TYPE to one of the error codes in the table..env file: node server.js.| Test scenario | Error code | Expected result |
|---|---|---|
| Expired authorization | AUTHORIZATION_EXPIRED | Error: authorization expired and order canceled. |
| Already picked up | AUTHORIZATION_ALREADY_CAPTURED | Error: authorization already captured. |
These values are suggested monitoring thresholds for your integration, not performance guarantees from PayPal.
| Metric | Target | Action if below target |
|---|---|---|
| Authorization success rate | 95% | Investigate authorization failures. |
| Capture success at pickup | 90% | Check for expired authorizations or staff process gaps. |
| Authorization expiration rate | <15% | Monitor for abnormal increases. |
| Void success rate (abandoned) | 98% | Investigate void failures. |
| API response time | <2 seconds | Check PayPal API status. |