Obtain an access token: POST /v1/oauth2/token with client_id and client_secret as HTTP Basic auth and grant_type=client_credentials in the body; use the returned 'access_token' as a Bearer token for subsequent calls.
Create a product: POST /v1/catalogs/products with 'name', 'type' ('SERVICE' or 'PHYSICAL'), and 'category'; receive a 'product_id'.
Create a plan: POST /v1/billing/plans with 'product_id', 'billing_cycles' array (each with 'tenure_type', 'frequency', 'pricing_scheme'), and 'payment_preferences'; activate the plan with POST /v1/billing/plans/{plan_id}/activate.
Create a subscription: POST /v1/billing/subscriptions with 'plan_id', subscriber details, and 'application_context.return_url' and 'cancel_url'; redirect the customer to the 'approve' link in the response links array.
After the customer approves, PayPal redirects to your return_url with 'subscription_id' and 'ba_token' query params; call GET /v1/billing/subscriptions/{subscription_id} to verify status is 'ACTIVE'.
Verify incoming webhooks: retrieve your webhook ID from the API, then call POST /v1/notifications/verify-webhook-signature with the webhook headers ('transmission_id', 'transmission_time', 'cert_url', 'auth_algo', 'transmission_sig') and raw event body — a 'SUCCESS' response confirms authenticity.
Known gotchas
Access tokens expire (typically in 9 hours for live, shorter in sandbox); implement token caching with expiry-aware refresh rather than requesting a new token on every API call, as excessive token requests trigger rate limits.
PayPal webhook signature verification requires the exact raw request body bytes — any middleware that parses and re-serializes JSON (even with identical content) will invalidate the signature; pass the raw body buffer to the verification call.
PayPal's sandbox and live environments use different base URLs (api.sandbox.paypal.com vs api.paypal.com) and completely separate credentials; webhooks registered in sandbox do not fire for live transactions and vice versa.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp